diff --git a/CONTRIBUTING.mkdn b/CONTRIBUTING.mkdn new file mode 100644 index 0000000..c58ea70 --- /dev/null +++ b/CONTRIBUTING.mkdn @@ -0,0 +1,100 @@ +## HOW TO CONTRIBUTE + +Thank you for considering contributing to this distribution. This file +contains instructions that will help you work with the source code. + +The distribution is managed with Dist::Zilla. This means that many of the +usual files you might expect are not in the repository, but are generated at +release time, as is much of the documentation. Some generated files are +kept in the repository as a convenience (e.g. Makefile.PL or cpanfile). + +Generally, **you do not need Dist::Zilla to contribute patches**. You do need +Dist::Zilla to create a tarball. See below for guidance. + +### Getting dependencies + +If you have App::cpanminus 1.6 or later installed, you can use `cpanm` to +satisfy dependencies like this: + + $ cpanm --installdeps . + +Otherwise, look for either a `Makefile.PL` or `cpanfile` file for +a list of dependencies to satisfy. + +### Running tests + +You can run tests directly using the `prove` tool: + + $ prove -l + $ prove -lv t/some_test_file.t + +For most of my distributions, `prove` is entirely sufficient for you to test any +patches you have. I use `prove` for 99% of my testing during development. + +### Code style and tidying + +Please try to match any existing coding style. If there is a `.perltidyrc` +file, please install Perl::Tidy and use perltidy before submitting patches. + +If there is a `tidyall.ini` file, you can also install Code::TidyAll and run +`tidyall` on a file or `tidyall -a` to tidy all files. + +### Patching documentation + +Much of the documentation Pod is generated at release time. Some is +generated boilerplate; other documentation is built from pseudo-POD +directives in the source like C<=method> or C<=func>. + +If you would like to submit a documentation edit, please limit yourself to +the documentation you see. + +If you see typos or documentation issues in the generated docs, please +email or open a bug ticket instead of patching. + +### Where to send patches and pull requests + +If you found this distribution on Github, sending a pull-request is the +best way to contribute. + +If a pull-request isn't possible, a bug ticket with a patch file is the +next best option. + +As a last resort, an email to the author(s) is acceptable. + +## Installing and using Dist::Zilla + +Dist::Zilla is not required for contributing, but if you'd like to learn +more, this section will get you up to speed. + +Dist::Zilla is a very powerful authoring tool, optimized for maintaining a +large number of distributions with a high degree of automation, but it has a +large dependency chain, a bit of a learning curve and requires a number of +author-specific plugins. + +To install it from CPAN, I recommend one of the following approaches for +the quickest installation: + + # using CPAN.pm, but bypassing non-functional pod tests + $ cpan TAP::Harness::Restricted + $ PERL_MM_USE_DEFAULT=1 HARNESS_CLASS=TAP::Harness::Restricted cpan Dist::Zilla + + # using cpanm, bypassing *all* tests + $ cpanm -n Dist::Zilla + +In either case, it's probably going to take about 10 minutes. Go for a walk, +go get a cup of your favorite beverage, take a bathroom break, or whatever. +When you get back, Dist::Zilla should be ready for you. + +Then you need to install any plugins specific to this distribution: + + $ cpan `dzil authordeps` + $ dzil authordeps | cpanm + +Once installed, here are some dzil commands you might try: + + $ dzil build + $ dzil test + $ dzil xtest + +You can learn more about Dist::Zilla at http://dzil.org/ + diff --git a/Changes b/Changes new file mode 100644 index 0000000..d6e898c --- /dev/null +++ b/Changes @@ -0,0 +1,857 @@ +Revision history for Path-Tiny + +0.104 2017-02-17 07:17:00-05:00 America/New_York + + - No changes from 0.103-TRIAL. + +0.103 2017-02-10 17:25:06-05:00 America/New_York (TRIAL RELEASE) + + [Bug fixes] + + - Path::Tiny 0.101 on Windows made `$path->absolute("/foo")` return an + absolute path starting with 'C:/foo', which was an unintentional + behavior change. This release now uses any absolute base without + further normalization. + +0.101 2017-02-05 09:56:46-05:00 America/New_York (TRIAL RELEASE) + + [Changes] + + - The 'absolute' method now always returns an absolute path, even if a + user provided a relative path for the base path. The old, odd + behavior was documented, but people often don't read docs. The new + behavior avoids suprises. + + [Additions] + + - Added 'cached_temp' method. + +0.100 2017-01-14 22:47:55-05:00 America/New_York + + - No changes from 0.099-TRIAL. + +0.099 2017-01-10 15:12:13-05:00 America/New_York (TRIAL RELEASE) + + [Tests] + + - Fixed tests for eventual removal of '.' from `@INC` in Perl. + + [Documentation] + + - Fixed filehandle mode typo. + + - Fixed typo in relative() that mentioned rel2abs instead of abs2rel. + +0.098 2016-10-09 23:25:11-04:00 America/New_York + + - No changes from 0.097-TRIAL. + +0.097 2016-09-30 22:03:10-04:00 America/New_York (TRIAL RELEASE) + + [Additions] + + - Added 'realpath' option for 'tempfile' and 'tempdir' for situations + where an absolute temporary path just isn't enough. + +0.096 2016-07-02 21:25:33-04:00 America/New_York + + - No changes from 0.095 + +0.095 2016-06-28 12:05:03-04:00 America/New_York (TRIAL RELEASE) + + [Tests] + + - Improved method for hiding some modules during tests. + +0.094 2016-05-23 12:45:19-04:00 America/New_York + + - Fixed Changes note typo in 0.092. 0.092 had no changes since 0.091, + not 0.090, meaning that all 0.091 changes were (and are) included. + +0.092 2016-05-23 11:36:54-04:00 America/New_York + + - No changes from 0.091 + +0.091 2016-05-17 13:32:21-04:00 America/New_York (TRIAL RELEASE) + + [Changes] + + - Path::Tiny will prefer PerlIO::utf8_strict over encoding(UTF-8) + if available and Unicode::UTF8 is not installed. + + [Fixes] + + - The 'touch' method can now set the current time on files that aren't + owned, as long as they are writeable. + + [Tests] + + - Improved consistency of symlink support inspection; now always + looks at $Config{d_symlink}. + + - Skips impossible test on 'msys' platform. + +0.090 2016-05-02 07:08:58-04:00 America/New_York + + - No changes from 0.089 + +0.089 2016-04-26 22:21:00-04:00 America/New_York (TRIAL RELEASE) + + [Fixes] + + - Fix spew_utf8 to allow array references as input. + +0.088 2016-04-15 08:41:07-04:00 America/New_York + + - No changes from 0.087 + +0.087 2016-04-12 12:13:14-04:00 America/New_York (TRIAL RELEASE) + + [Fixes] + + - Fixed bugs in relative symlink resolution for realpath, spew and + edit_lines. + + [Changes] + + - Symlink resolution will detect circular loops and throw an error. + +0.086 2016-04-03 13:49:37-04:00 America/New_York + + [Documented] + + - Improved documentation of copy and move. + +0.084 2016-03-04 07:17:49-05:00 America/New_York + + [Fixes] + + - Fixed relative() for the case with regex metacharacters in the path + +0.082 2016-03-01 18:23:26-05:00 America/New_York + + [!!! INCOMPATIBLE CHANGES !!!] + + - (This warning repeated from 0.079-TRIAL) The relative() method no + longer uses File::Spec's buggy abs2rel method. The new Path::Tiny + algorithm should be comparable and passes File::Spec abs2rel test + cases, except that it correctly accounts for symlinks. For common + use, you are not likely to notice any difference. For uncommon use, + this should be an improvement. As a side benefit, this change drops + the minimum File::Spec version required, allowing Path::Tiny to be + fatpacked if desired. + + [Changes] + + - no other changes from 0.081 + +0.081 2016-02-18 16:55:37-05:00 America/New_York (TRIAL RELEASE) + + [Fixed] + + - Fixed lines_utf8+chomp and relative() bugs on Windows + +0.079 2016-02-15 20:52:10-07:00 America/Mazatlan (TRIAL RELEASE) + + [!!! INCOMPATIBLE CHANGES !!!] + + - The relative() method no longer uses File::Spec's buggy rel2bs + method. The new Path::Tiny algorithm should be comparable and passes + File::Spec abs2rel test cases, except that it correctly accounts for + symlinks. For common use, you are not likely to notice any + difference. For uncommon use, this should be an improvement. As a + side benefit, this change drops the minimum File::Spec version + required, allowing Path::Tiny to be fatpacked if desired. + + [FIXED] + + - Fixed lines_utf8() with chomping for repeated empty lines. + + [DOCS] + + - Documented that subclassing is not supported + +0.077 2016-02-10 14:17:32-07:00 America/Mazatlan (TRIAL RELEASE) + + [ADDED] + + - Added 'edit' and 'edit_lines' plus _utf8 and _raw variants; this + is similar to perl's -i flag (though without backups) + +0.076 2015-11-16 10:47:24-05:00 America/New_York + + - no changes from 0.075 + +0.075 2015-11-15 21:02:18-05:00 America/New_York (TRIAL RELEASE) + + [FIXED] + + - Tilde expansion on Windows was resulting in backslashes. Now they + are correctly normalized to forward slashes. + + [DOCS] + + - Typos fixed + +0.073 2015-10-30 10:36:18-04:00 America/New_York (TRIAL RELEASE) + + [FIXED] + + - Fixed spewing to a symlink that crosses a filesystem boundary + + [PREREQS] + + - Add Test::MockRandom to META as an recommended test prerequisite. + +0.072 2015-07-20 16:07:20-04:00 America/New_York + + - No changes from 0.071 + +0.071 2015-07-17 13:40:08-04:00 America/New_York (TRIAL RELEASE) + + [FIXED] + + - Fixed incorrect error argument for File::Path functions + (mkpath and remove_tree) + +0.070 2015-06-28 13:50:16-04:00 America/New_York + + - No changes from 0.069 + +0.069 2015-06-18 18:09:44-04:00 America/New_York (TRIAL RELEASE) + + [CHANGED] + + - The 'copy' method now returns the object for the copied file + + [FIXED] + + - The 'visit' method only dereferences the callback return value + for scalar refs, avoiding some common bugs + +0.068 2015-03-23 20:42:56-04:00 America/New_York + + [META] + + - Jumping to 0.068 to get to an even-version for a stable release + + [DOCUMENTED] + + - Noted that 0.66 changed the 'filehandle' method + +0.066 2015-03-20 23:59:08-04:00 America/New_York (TRIAL RELEASE) + + [ADDED] + + - Added exclusive locking option to filehandle opens; spew now + exclusively locks tempfile used for atomic writes + +0.065 2015-03-06 05:59:56-05:00 America/New_York + + [ADDED] + + - Added 'assert' method + + - Added 'visit' method + + - Added support for a negative count for 'lines' to get the + last lines of a file + + [FIXED] + + - Fixed tilde expansion if path has spaces + + - Make realpath non-fatal if the parent path exists and only the final + path component does not. (Was fatal on Windows and some Unixes.) + + - Removed rendundant locking on tempfile use for spewing + + - Work around File::Temp bugs on older ActiveState Windows Perls + https://bugs.activestate.com/show_bug.cgi?id=104767 + + [DOCUMENTED] + + - Fixed SYNOPSIS example + +0.064 2015-03-05 03:58:42-05:00 America/New_York (TRIAL RELEASE) + +0.063 2015-03-04 16:00:17-05:00 America/New_York (TRIAL RELEASE) + +0.062 2015-03-04 13:59:31-05:00 America/New_York (TRIAL RELEASE) + +0.061 2014-11-13 16:50:05-05:00 America/New_York + + [FIXED] + + - Fixed append_utf8 and append_raw with 'truncate' option. + +0.060 2014-11-04 17:33:39-05:00 America/New_York + + [ADDED] + + - Added 'truncate' option to append for in-place replacement of + file contents. + +0.059 2014-10-14 12:45:46-04:00 America/New_York + + [FIXED] + + - Fixed precedence bug in the check for Unicode::UTF8 + +0.058 2014-09-23 11:00:24-04:00 America/New_York + + [ADDED] + + - Added a 'sibling' method as a more efficient form of + calling $path->parent->child(...). + + [DOCUMENTED] + + - Every method annotated with the version number of the + last API change. + +0.057 2014-09-19 11:23:05-04:00 America/New_York + + [FIXED] + + - On AIX, reads that default to locking would fail without + write permissions, because locking needs write permissions. + The fix is only to lock reads if write permissions exist; + otherwise locking is skipped. + +0.056 2014-08-07 15:08:41-04:00 America/New_York + + [*** DEPRECATIONS ***] + + - The 'dirname' method is deprecated due to exposing File::Spec + inconsistencies + + [ADDED] + + - The 'digest' method now takes a 'chunk_size' option to avoid + slurping files entirely into memory. + + [FIXED] + + - Fixed problem throwing errors from 'remove' + +0.055 2014-06-30 10:29:28-04:00 America/New_York + + [FIXED] + + - tempfile/tempdir won't warn if used as functions without arguments + +0.054 2014-05-04 13:56:11-04:00 America/New_York + + [ADDED] + + - The 'basename' method now takes a list of suffixes to remove before + returning the name + + - FREEZE/THAW/TO_JSON serialization helpers + + [CHANGED] + + - When constructing a Path::Tiny object from another, the original + is returned unless it's a temp dir/file. This significantly + speeds up calling path($path) if $path is already a Path::Tiny + object. (Thanks to Michael Schwern for prompting such benchmarking.) + + [FIXED] + + - Constructing any path -- e.g. with child() -- with undef or + zero-length parts throws an error instead of constructing an + invalid path + +0.053 2014-03-24 09:25:51-04:00 America/New_York (TRIAL RELEASE) + + [INCOMPATIBLE CHANGES] + + - The 'is_file' method now does -e && ! -d and not -f because -f + is often more restrictive than people intend or expect. + + [ADDED] + + - Added 'chmod' method with symbolic chmod support ("a=r,u+rx") + +0.052 2014-01-14 15:58:03-05:00 America/New_York + + [FIXED] + + - Backslash-to-slash conversion now only happens on Windows + (since backslash is legal on Unix, we must allow it) + +0.051 2013-12-20 07:34:14 America/New_York + + [FIXED] + + - Fixed file order bug in the new test file + +0.050 2013-12-20 07:27:20 America/New_York + + [FIXED] + + - Recursive iteration won't throw an exception if a directory is + removed or unreadable during iteration. + +0.049 2013-12-12 00:48:01 America/New_York + + [FIXED] + + - Generates filename for atomic writes independent of thread-ID. + Fixes crashing bug on Win32 when fork() is called. + +0.048 2013-12-11 21:56:23 America/New_York + + [ADDED] + + - Added 'subsumes' method + + [CHANGED] + + - The 'chomp' option for 'lines' will remove any end-of-line sequences + fully instead of just chomping the last character + + - The 'flock' package will no longer indexed by PAUSE + + [FIXED] + + - Hides warnings and fixes possible fatal errors from pure-perl Cwd, + particularly on MSWin32 + +0.047 2013-11-26 15:11:13 America/New_York + + [FIXED] + + - Previous lock testing fixes broke on Windows (sigh); now fixed, + I hope. + +0.046 2013-11-22 17:07:24 America/New_York + + [FIXED] + + - Revised locking tests for portability again: locks are now tested + from a separate process + +0.045 2013-11-22 15:28:50 America/New_York + + [FIXED] + + - Fixed locking test on AIX + +0.044 2013-10-17 17:00:41 America/New_York + + [FIXED] + + - Fixed child path construction against the root path. + + - Fixed path construction when a relative volume is provided as the + first argument on Windows; e.g. path("C:", "lib") must be like + path("C:lib"), not path("C:/lib"). + + - On AIX, shared locking is replaced by exclusive locking on a R/W + filehandle, as locking read handles is not supported + +0.043 2013-10-14 06:24:06 America/New_York + + [CHANGED] + + - Calling 'absolute' on Windows will add the volume if it is missing + (E.g. "/foo" will become "C:/foo"). This matches the behavior + of File::Spec->rel2abs. + + [FIXED] + + - Fixed t/00-report-prereqs.t for use with older versions of + CPAN::Meta::Requirements + +0.042 2013-10-13 11:02:02 America/New_York + + [FIXED] + + - When 'realpath' can't be resolved (because intermediate directories + don't exist), the exception now explains the error clearly instead of + complaining about path() needing a defined, positive-length argument. + + - On Windows, fixed resolution of relative paths with a volume. + E.g. "C:foo" is now correctly translated into getdcwd on "C:" + plus "foo". + +0.041 2013-10-11 08:56:31 America/New_York + + [FIXES] + + - Removes duplicate test dependency on File::Spec that triggers + a CPAN.pm bug + +0.040 2013-10-08 22:01:50 America/New_York + + [FIXES] + + - Fixed broken locking test on *bsd + + - When using 'filehandle' to request a locked handle that truncates an + existing file and has a binmode starting with ":unix", this fixes a + bug where pseudo-layers weren't being cleared properly. + +0.039 2013-10-08 16:39:23 America/New_York + + [ADDITIONS] + + - The 'filehandle' method now offers an option to return locked handles + based on the file mode. Input-output methods now rely on this + feature internally. Truncating file modes defer truncation until + after an exclusive lock is acquired. + + [FIXES] + + - The 'filehandle' method now respects default encoding set by + the caller's open pragma. + +0.038 2013-10-01 18:20:05 America/New_York + + [ADDITIONS] + + - Added 'is_rootdir' method to simplify testing if a path is + the root directory + +0.037 2013-09-25 13:00:25 America/New_York + + [FIXES] + + - Fixed for v5.8 + +0.036 2013-09-25 09:34:28 America/New_York + + [PREREQS] + + - No longer lists 'threads' as a prerequisite. If you have a threaded + perl, you have it and if you're not, Path::Tiny doesn't care. + +0.035 2013-09-24 07:21:55 America/New_York + + [FIXED] + + - Fixed flock warning on BSD that was broken with the autodie + removal; now also applies to all BSD flavors + +0.034 2013-09-23 16:16:36 America/New_York + + [INCOMPATIBLE CHANGE] + + - Exceptions are now Path::Tiny::Error objects, not autodie exceptions; + this removes the last dependency on autodie, which allows us to + support Perls as far back as v5.8.1 + + [FIXED] + + - BSD/NFS flock fix was not backwards compatible before v5.14. This + fixes it harder. + + [PREREQS] + + - dropped autodie + + - lowered ExtUtils::MakeMaker configure_requires version to 6.17 + +0.033 2013-09-12 08:54:30 America/New_York + + [FIXED] + + - Perl on BSD may not support locking on an NFS filesystem. If this is + detected, Path::Tiny warns and continues in an unsafe mode. The + 'flock' warning category may be fatalized to die instead. + + [DOCUMENTED] + + - Added 'iterator' example showing defaults + +0.032 2013-09-06 17:52:48 America/New_York + + [PREREQS] + + - Removed several test dependencies. Path::Tiny now only needs + core modules, though some must be upgraded on old Perls + +0.031 2013-08-27 10:03:57 America/New_York + + [FIXED] + + - parent() on paths with internal double dots (e.g. /foo..bar.txt) now works + correctly + +0.030 2013-08-20 16:10:04 America/New_York + + [FIXED] + + - t/zzz-spec.t used getcwd() instead of getdcwd(), which breaks + on Windows if the build directory isn't on the 'C' drive + +0.029 2013-08-19 11:52:24 America/New_York + + [FIXED] + + - On Win32, "C:/" no longer is changed to "C:". Also, "C:" is + converted to the absolute path of cwd on the "C:" volume. UNC paths + ("//server/share/") now retain their trailing slash to correctly + distinguish volume and directory paths when split + +0.028 2013-08-14 13:12:49 America/New_York + + [ADDED] + + - The 'children()' method now takes an optional regular expression to + filter the results + +0.027 2013-07-25 19:38:44 America/New_York + + [ADDED] + + - Added the 'digest' method to produce a hexadecimal SHA-256 + (or user-specified) digest of a file + +0.026 2013-07-14 21:25:22 America/New_York + + [FIXED] + + - Fixed bug where lines() with a count longer than the + file would return undef for the extra lines. Now returns + only the lines in the file if the count is greater than + the number of lines. + +0.025 2013-07-10 09:32:13 America/New_York + + [FIXED] + + - Spew to an existing symlink now atomically replaces + the resolved destination, not the symlink + +0.024 2013-06-17 18:12:36 America/New_York + + [FIXED] + + - Win32 pseudo-forks don't load threads.pm, so we do that + in CLONE to ensure we get the thread ID + +0.023 2013-06-12 07:18:31 America/New_York + + [FIXED] + + - Removing dangling symlinks now works + +0.022 2013-05-28 11:57:15 America/New_York + + [ADDED] + + - The 'touch' method can now take an epoch secs argument + +0.021 2013-05-17 22:53:18 America/New_York + + [FIXED] + + - Fixed fatal bug with lines_utf8 using chomp + + [DOCS] + + - Pod typos fixed + +0.020 2013-04-13 06:58:11 Europe/London + + [FIXED] + + - More descriptive error message if copy() fails + +0.019 2013-04-12 06:58:18 Europe/London + + [FIXED] + + - Fixed warning about -l on dirhandle in iterator() + +0.018 2013-04-08 12:44:31 America/New_York + + [ADDED] + + - cwd, rootdir, tempfile and tempdir can now be exported on request + and used as functions instead of as methods + + [FIXED] + + - Fixed regression in lines() where it no longer returned count + of lines in scalar context + +0.017 2013-03-28 16:49:15 America/New_York + + [ADDED] + + - path() constructor now glob-expands tildes (~) + + [CHANGED] + + - Improved options validation; invalid options now throw errors + +0.016 2013-03-26 14:59:36 America/New_York + + [ADDED] + + - The iterator now has an optional recursive mode + + [CHANGED] + + - We no longer use autodie directly, but we throw our + own autodie::exceptions on error. This avoids the overhead + of wrapping built-ins with function calls. + + - Most dependencies are now loaded on demand, reducing startup + time. + +0.015 2013-03-13 13:20:38 America/New_York + + [CHANGED] + + - touch and touchpath now return the object to allow easy chaining + with spew + +0.014 2013-03-09 08:54:26 America/New_York + + [ADDED] + + - parent now takes an optional argument to look upwards multiple + times in one call. e.g. $path->parent(2) + +0.013 2013-02-22 10:58:05 America/New_York + + [CHANGED] + + - remove_tree now defaults to safe mode and will not attempt to chmod + and remove directories with insufficient permissions + + - Temporary files and directories are always created with an + absolute path. + + [FIXED] + + - Failures from autodie are reported from our caller's location + (as if we called croak()); bumped autodie prereq to 2.14 for + this feature + + - Failures from mkpath and remove_tree are now trapped and + thrown as exceptions. (Making an existing path or removing + a non-existant path return false and are not errors); + +0.012 2013-02-20 09:34:50 America/New_York + + [REMOVED] + + - The 'remove' function no longer works on directories. The new + 'remove_tree' method should be used instead. + + [CHANGED] + + - path() now requires a defined, positive-length argument to keep you + safe from subtle bugs in your code that pass an undef or empty + argument to path suddenly having you operating in the current + directory. + + [ADDED] + + - Added Path::Tiny->cwd as a constructor to give an absolute + path to the current working directory + + - Added 'remove_tree' as a method for recursively removing + a directory + +0.011 2013-02-19 11:08:44 America/New_York + + [CHANGED] + + - slurp/spew/etc and openr/openw/etc now repect default layers + set by -C or the open pragma + + - spew and append can now be given array references to output + to avoid extra copying + +0.010 2013-02-16 10:26:38 America/New_York + + [FIXED] + + - The 'tempdir' and 'tempfile' methods can now both take either leading + templates or a TEMPLATE option, so you don't have to remember which + one File::Temp wants + +0.009 2013-02-15 16:05:39 America/New_York + + [CHANGED] + + - Dropped use of '//' to allow Path::Tiny to run on Perl 5.008 + +0.008 2013-02-15 13:49:54 America/New_York + + [ADDED] + + - Added 'touchpath' method combining 'mkpath' and 'touch' + +0.007 2013-02-12 17:41:44 America/New_York + + [FIXED] + + - Unicode::UTF8 0.58 is necessary for optional faster + Unicode processing + +0.006 2013-02-11 13:22:18 America/New_York + + [FIXED] + + - t/parent.t is amended to work on Windows + + - new() now correctly takes multiple path arguments, like path() + +0.005 2013-02-07 15:41:32 America/New_York + + [FIXED] + + - Fixed test for platforms with /sbin symlinked to /usr/sbin + +0.004 2013-02-05 19:19:46 America/New_York + + [ADDED] + + - Added slurp_raw and other *_raw helper methods + + - Added realpath method (with thanks to ether) + + - Added canonpath method (with thanks to sjmiller) + + [FIXED] + + - slurp/lines/spew/append now do appropriate flocking + + - Fixed test that fails if run as root (bingos) + + - Fixed test that fails if cwd/getcwd don't agree + + [CHANGED] + + - internal optimizations + +0.003 2013-01-31 06:59:50 America/New_York + + [FIXED] + + - lstat was calling the wrong stat [rt.cpan.org #83063] + + - make atomic writes thread-safe [rt.cpan.org #83064] + + [CHANGED] + + - updated bugtracker to point to github + +0.002 2013-01-30 22:09:37 America/New_York + + [FIXED] + + - s/File::Stat/File::stat/; # OMG! I hate case insensitivity + +0.001 2013-01-30 19:36:22 America/New_York + + - First release + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..71ec0f9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,207 @@ +This software is Copyright (c) 2014 by David Golden. + +This is free software, licensed under: + + The Apache License, Version 2.0, January 2004 + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000..ab0164c --- /dev/null +++ b/MANIFEST @@ -0,0 +1,53 @@ +# This file was automatically generated by Dist::Zilla::Plugin::Manifest v6.008. +CONTRIBUTING.mkdn +Changes +LICENSE +MANIFEST +META.json +META.yml +Makefile.PL +README +cpanfile +dist.ini +lib/Path/Tiny.pm +perlcritic.rc +t/00-report-prereqs.dd +t/00-report-prereqs.t +t/README +t/basename.t +t/basic.t +t/children.t +t/chmod.t +t/data/chmod.txt +t/digest.t +t/exception.t +t/exports.t +t/filesystem.t +t/input_output.t +t/input_output_no_PU_UU.t +t/input_output_no_UU.t +t/lib/TestUtils.pm +t/locking.t +t/mkpath.t +t/mutable_tree_while_iterating.t +t/normalize.t +t/overloading.t +t/parent.t +t/recurse.t +t/rel-abs.t +t/subsumes.t +t/symlinks.t +t/temp.t +t/visit.t +t/zz-atomic.t +t/zzz-spec.t +tidyall.ini +xt/author/00-compile.t +xt/author/critic.t +xt/author/pod-coverage.t +xt/author/pod-spell.t +xt/author/pod-syntax.t +xt/author/portability.t +xt/author/test-version.t +xt/release/distmeta.t +xt/release/minimum-version.t diff --git a/META.json b/META.json new file mode 100644 index 0000000..c188976 --- /dev/null +++ b/META.json @@ -0,0 +1,167 @@ +{ + "abstract" : "File path utility", + "author" : [ + "David Golden " + ], + "dynamic_config" : 0, + "generated_by" : "Dist::Zilla version 6.008, CPAN::Meta::Converter version 2.150010", + "license" : [ + "apache_2_0" + ], + "meta-spec" : { + "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", + "version" : 2 + }, + "name" : "Path-Tiny", + "no_index" : { + "directory" : [ + "corpus", + "examples", + "t", + "xt" + ], + "package" : [ + "DB", + "flock" + ] + }, + "prereqs" : { + "configure" : { + "requires" : { + "ExtUtils::MakeMaker" : "6.17", + "perl" : "5.008001" + }, + "suggests" : { + "JSON::PP" : "2.27300" + } + }, + "develop" : { + "requires" : { + "Dist::Zilla" : "5", + "Dist::Zilla::Plugin::MinimumPerl" : "0", + "Dist::Zilla::Plugin::OnlyCorePrereqs" : "0", + "Dist::Zilla::Plugin::Prereqs" : "0", + "Dist::Zilla::Plugin::ReleaseStatus::FromVersion" : "0", + "Dist::Zilla::Plugin::RemovePrereqs" : "0", + "Dist::Zilla::PluginBundle::DAGOLDEN" : "0.072", + "English" : "0", + "File::Spec" : "0", + "File::Temp" : "0", + "IO::Handle" : "0", + "IPC::Open3" : "0", + "Pod::Coverage::TrustPod" : "0", + "Pod::Wordlist" : "0", + "Software::License::Apache_2_0" : "0", + "Test::CPAN::Meta" : "0", + "Test::MinimumVersion" : "0", + "Test::More" : "0", + "Test::Pod" : "1.41", + "Test::Pod::Coverage" : "1.08", + "Test::Portability::Files" : "0", + "Test::Spelling" : "0.12", + "Test::Version" : "1", + "blib" : "1.01" + } + }, + "runtime" : { + "recommends" : { + "Unicode::UTF8" : "0.58" + }, + "requires" : { + "Carp" : "0", + "Cwd" : "0", + "Digest" : "1.03", + "Digest::SHA" : "5.45", + "Exporter" : "5.57", + "Fcntl" : "0", + "File::Copy" : "0", + "File::Glob" : "0", + "File::Path" : "2.07", + "File::Spec" : "0.86", + "File::Temp" : "0.19", + "File::stat" : "0", + "constant" : "0", + "if" : "0", + "overload" : "0", + "perl" : "5.008001", + "strict" : "0", + "warnings" : "0" + } + }, + "test" : { + "recommends" : { + "CPAN::Meta" : "2.120900", + "Test::FailWarnings" : "0", + "Test::MockRandom" : "0" + }, + "requires" : { + "ExtUtils::MakeMaker" : "0", + "File::Basename" : "0", + "File::Spec" : "0.86", + "File::Spec::Functions" : "0", + "File::Spec::Unix" : "0", + "File::Temp" : "0.19", + "Test::More" : "0.96", + "lib" : "0", + "open" : "0", + "perl" : "5.008001" + } + } + }, + "provides" : { + "Path::Tiny" : { + "file" : "lib/Path/Tiny.pm", + "version" : "0.104" + }, + "Path::Tiny::Error" : { + "file" : "lib/Path/Tiny.pm", + "version" : "0.104" + } + }, + "release_status" : "stable", + "resources" : { + "bugtracker" : { + "web" : "https://github.com/dagolden/Path-Tiny/issues" + }, + "homepage" : "https://github.com/dagolden/Path-Tiny", + "repository" : { + "type" : "git", + "url" : "https://github.com/dagolden/Path-Tiny.git", + "web" : "https://github.com/dagolden/Path-Tiny" + } + }, + "version" : "0.104", + "x_authority" : "cpan:DAGOLDEN", + "x_contributors" : [ + "Alex Efros ", + "Chris Williams ", + "Dave Rolsky ", + "David Steinbrunner ", + "Doug Bell ", + "Gabor Szabo ", + "Gabriel Andrade ", + "George Hartzell ", + "Geraud Continsouzas ", + "Goro Fuji ", + "Graham Knop ", + "Graham Ollis ", + "James Hunt ", + "John Karr ", + "Karen Etheridge ", + "Mark Ellis ", + "Martin Kjeldsen ", + "Michael G. Schwern ", + "Nigel Gregoire ", + "Philippe Bruhat (BooK) ", + "Regina Verbae ", + "Roy Ivy III ", + "Shlomi Fish ", + "Smylers ", + "Tatsuhiko Miyagawa ", + "Toby Inkster ", + "Yanick Champoux ", + "\uae40\ub3c4\ud615 - Keedi Kim " + ], + "x_serialization_backend" : "Cpanel::JSON::XS version 3.0225" +} + diff --git a/META.yml b/META.yml new file mode 100644 index 0000000..d9b4960 --- /dev/null +++ b/META.yml @@ -0,0 +1,98 @@ +--- +abstract: 'File path utility' +author: + - 'David Golden ' +build_requires: + ExtUtils::MakeMaker: '0' + File::Basename: '0' + File::Spec: '0.86' + File::Spec::Functions: '0' + File::Spec::Unix: '0' + File::Temp: '0.19' + Test::More: '0.96' + lib: '0' + open: '0' + perl: '5.008001' +configure_requires: + ExtUtils::MakeMaker: '6.17' + perl: '5.008001' +dynamic_config: 0 +generated_by: 'Dist::Zilla version 6.008, CPAN::Meta::Converter version 2.150010' +license: apache +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.4.html + version: '1.4' +name: Path-Tiny +no_index: + directory: + - corpus + - examples + - t + - xt + package: + - DB + - flock +provides: + Path::Tiny: + file: lib/Path/Tiny.pm + version: '0.104' + Path::Tiny::Error: + file: lib/Path/Tiny.pm + version: '0.104' +recommends: + Unicode::UTF8: '0.58' +requires: + Carp: '0' + Cwd: '0' + Digest: '1.03' + Digest::SHA: '5.45' + Exporter: '5.57' + Fcntl: '0' + File::Copy: '0' + File::Glob: '0' + File::Path: '2.07' + File::Spec: '0.86' + File::Temp: '0.19' + File::stat: '0' + constant: '0' + if: '0' + overload: '0' + perl: '5.008001' + strict: '0' + warnings: '0' +resources: + bugtracker: https://github.com/dagolden/Path-Tiny/issues + homepage: https://github.com/dagolden/Path-Tiny + repository: https://github.com/dagolden/Path-Tiny.git +version: '0.104' +x_authority: cpan:DAGOLDEN +x_contributors: + - 'Alex Efros ' + - 'Chris Williams ' + - 'Dave Rolsky ' + - 'David Steinbrunner ' + - 'Doug Bell ' + - 'Gabor Szabo ' + - 'Gabriel Andrade ' + - 'George Hartzell ' + - 'Geraud Continsouzas ' + - 'Goro Fuji ' + - 'Graham Knop ' + - 'Graham Ollis ' + - 'James Hunt ' + - 'John Karr ' + - 'Karen Etheridge ' + - 'Mark Ellis ' + - 'Martin Kjeldsen ' + - 'Michael G. Schwern ' + - 'Nigel Gregoire ' + - 'Philippe Bruhat (BooK) ' + - 'Regina Verbae ' + - 'Roy Ivy III ' + - 'Shlomi Fish ' + - 'Smylers ' + - 'Tatsuhiko Miyagawa ' + - 'Toby Inkster ' + - 'Yanick Champoux ' + - '김도형 - Keedi Kim ' +x_serialization_backend: 'YAML::Tiny version 1.69' diff --git a/Makefile.PL b/Makefile.PL new file mode 100644 index 0000000..6f5f08c --- /dev/null +++ b/Makefile.PL @@ -0,0 +1,93 @@ +# This file was automatically generated by Dist::Zilla::Plugin::MakeMaker v6.008. +use strict; +use warnings; + +use 5.008001; + +use ExtUtils::MakeMaker 6.17; + +my %WriteMakefileArgs = ( + "ABSTRACT" => "File path utility", + "AUTHOR" => "David Golden ", + "CONFIGURE_REQUIRES" => { + "ExtUtils::MakeMaker" => "6.17" + }, + "DISTNAME" => "Path-Tiny", + "LICENSE" => "apache", + "MIN_PERL_VERSION" => "5.008001", + "NAME" => "Path::Tiny", + "PREREQ_PM" => { + "Carp" => 0, + "Cwd" => 0, + "Digest" => "1.03", + "Digest::SHA" => "5.45", + "Exporter" => "5.57", + "Fcntl" => 0, + "File::Copy" => 0, + "File::Glob" => 0, + "File::Path" => "2.07", + "File::Spec" => "0.86", + "File::Temp" => "0.19", + "File::stat" => 0, + "constant" => 0, + "if" => 0, + "overload" => 0, + "strict" => 0, + "warnings" => 0 + }, + "TEST_REQUIRES" => { + "ExtUtils::MakeMaker" => 0, + "File::Basename" => 0, + "File::Spec" => "0.86", + "File::Spec::Functions" => 0, + "File::Spec::Unix" => 0, + "File::Temp" => "0.19", + "Test::More" => "0.96", + "lib" => 0, + "open" => 0 + }, + "VERSION" => "0.104", + "test" => { + "TESTS" => "t/*.t" + } +); + + +my %FallbackPrereqs = ( + "Carp" => 0, + "Cwd" => 0, + "Digest" => "1.03", + "Digest::SHA" => "5.45", + "Exporter" => "5.57", + "ExtUtils::MakeMaker" => 0, + "Fcntl" => 0, + "File::Basename" => 0, + "File::Copy" => 0, + "File::Glob" => 0, + "File::Path" => "2.07", + "File::Spec" => "0.86", + "File::Spec::Functions" => 0, + "File::Spec::Unix" => 0, + "File::Temp" => "0.19", + "File::stat" => 0, + "Test::More" => "0.96", + "constant" => 0, + "if" => 0, + "lib" => 0, + "open" => 0, + "overload" => 0, + "strict" => 0, + "warnings" => 0 +); + + +unless ( eval { ExtUtils::MakeMaker->VERSION(6.63_03) } ) { + delete $WriteMakefileArgs{TEST_REQUIRES}; + delete $WriteMakefileArgs{BUILD_REQUIRES}; + $WriteMakefileArgs{PREREQ_PM} = \%FallbackPrereqs; +} + +delete $WriteMakefileArgs{CONFIGURE_REQUIRES} + unless eval { ExtUtils::MakeMaker->VERSION(6.52) }; + +WriteMakefile(%WriteMakefileArgs); diff --git a/README b/README new file mode 100644 index 0000000..5b3957f --- /dev/null +++ b/README @@ -0,0 +1,1098 @@ +NAME + Path::Tiny - File path utility + +VERSION + version 0.104 + +SYNOPSIS + use Path::Tiny; + + # creating Path::Tiny objects + + $dir = path("/tmp"); + $foo = path("foo.txt"); + + $subdir = $dir->child("foo"); + $bar = $subdir->child("bar.txt"); + + # stringifies as cleaned up path + + $file = path("./foo.txt"); + print $file; # "foo.txt" + + # reading files + + $guts = $file->slurp; + $guts = $file->slurp_utf8; + + @lines = $file->lines; + @lines = $file->lines_utf8; + + ($head) = $file->lines( {count => 1} ); + ($tail) = $file->lines( {count => -1} ); + + # writing files + + $bar->spew( @data ); + $bar->spew_utf8( @data ); + + # reading directories + + for ( $dir->children ) { ... } + + $iter = $dir->iterator; + while ( my $next = $iter->() ) { ... } + +DESCRIPTION + This module provides a small, fast utility for working with file paths. + It is friendlier to use than File::Spec and provides easy access to + functions from several other core file handling modules. It aims to be + smaller and faster than many alternatives on CPAN, while helping people + do many common things in consistent and less error-prone ways. + + Path::Tiny does not try to work for anything except Unix-like and Win32 + platforms. Even then, it might break if you try something particularly + obscure or tortuous. (Quick! What does this mean: + "///../../..//./././a//b/.././c/././"? And how does it differ on Win32?) + + All paths are forced to have Unix-style forward slashes. Stringifying + the object gives you back the path (after some clean up). + + File input/output methods "flock" handles before reading or writing, as + appropriate (if supported by the platform). + + The *_utf8 methods ("slurp_utf8", "lines_utf8", etc.) operate in raw + mode. On Windows, that means they will not have CRLF translation from + the ":crlf" IO layer. Installing Unicode::UTF8 0.58 or later will speed + up *_utf8 situations in many cases and is highly recommended. + Alternatively, installing PerlIO::utf8_strict 0.003 or later will be + used in place of the default ":encoding(UTF-8)". + + This module depends heavily on PerlIO layers for correct operation and + thus requires Perl 5.008001 or later. + +CONSTRUCTORS + path + $path = path("foo/bar"); + $path = path("/tmp", "file.txt"); # list + $path = path("."); # cwd + $path = path("~user/file.txt"); # tilde processing + + Constructs a "Path::Tiny" object. It doesn't matter if you give a file + or directory path. It's still up to you to call directory-like methods + only on directories and file-like methods only on files. This function + is exported automatically by default. + + The first argument must be defined and have non-zero length or an + exception will be thrown. This prevents subtle, dangerous errors with + code like "path( maybe_undef() )->remove_tree". + + If the first component of the path is a tilde ('~') then the component + will be replaced with the output of "glob('~')". If the first component + of the path is a tilde followed by a user name then the component will + be replaced with output of "glob('~username')". Behaviour for + non-existent users depends on the output of "glob" on the system. + + On Windows, if the path consists of a drive identifier without a path + component ("C:" or "D:"), it will be expanded to the absolute path of + the current directory on that volume using "Cwd::getdcwd()". + + If called with a single "Path::Tiny" argument, the original is returned + unless the original is holding a temporary file or directory reference + in which case a stringified copy is made. + + $path = path("foo/bar"); + $temp = Path::Tiny->tempfile; + + $p2 = path($path); # like $p2 = $path + $t2 = path($temp); # like $t2 = path( "$temp" ) + + This optimizes copies without proliferating references unexpectedly if a + copy is made by code outside your control. + + Current API available since 0.017. + + new + $path = Path::Tiny->new("foo/bar"); + + This is just like "path", but with method call overhead. (Why would you + do that?) + + Current API available since 0.001. + + cwd + $path = Path::Tiny->cwd; # path( Cwd::getcwd ) + $path = cwd; # optional export + + Gives you the absolute path to the current directory as a "Path::Tiny" + object. This is slightly faster than "path(".")->absolute". + + "cwd" may be exported on request and used as a function instead of as a + method. + + Current API available since 0.018. + + rootdir + $path = Path::Tiny->rootdir; # / + $path = rootdir; # optional export + + Gives you "File::Spec->rootdir" as a "Path::Tiny" object if you're too + picky for "path("/")". + + "rootdir" may be exported on request and used as a function instead of + as a method. + + Current API available since 0.018. + + tempfile, tempdir + $temp = Path::Tiny->tempfile( @options ); + $temp = Path::Tiny->tempdir( @options ); + $temp = tempfile( @options ); # optional export + $temp = tempdir( @options ); # optional export + + "tempfile" passes the options to "File::Temp->new" and returns a + "Path::Tiny" object with the file name. The "TMPDIR" option is enabled + by default. + + The resulting "File::Temp" object is cached. When the "Path::Tiny" + object is destroyed, the "File::Temp" object will be as well. + + "File::Temp" annoyingly requires you to specify a custom template in + slightly different ways depending on which function or method you call, + but "Path::Tiny" lets you ignore that and can take either a leading + template or a "TEMPLATE" option and does the right thing. + + $temp = Path::Tiny->tempfile( "customXXXXXXXX" ); # ok + $temp = Path::Tiny->tempfile( TEMPLATE => "customXXXXXXXX" ); # ok + + The tempfile path object will be normalized to have an absolute path, + even if created in a relative directory using "DIR". If you want it to + have the "realpath" instead, pass a leading options hash like this: + + $real_temp = tempfile({realpath => 1}, @options); + + "tempdir" is just like "tempfile", except it calls "File::Temp->newdir" + instead. + + Both "tempfile" and "tempdir" may be exported on request and used as + functions instead of as methods. + + Note: for tempfiles, the filehandles from File::Temp are closed and not + reused. This is not as secure as using File::Temp handles directly, but + is less prone to deadlocks or access problems on some platforms. Think + of what "Path::Tiny" gives you to be just a temporary file name that + gets cleaned up. + + Note 2: if you don't want these cleaned up automatically when the object + is destroyed, File::Temp requires different options for directories and + files. Use "CLEANUP => 0" for directories and "UNLINK => 0" for files. + + Note 3: Don't lose the temporary object by chaining a method call + instead of storing it: + + my $lost = tempdir()->child("foo"); # tempdir cleaned up right away + + Note 4: The cached object may be accessed with the "cached_temp" method. + Keeping a reference to, or modifying the cached object may break the + behavior documented above and is not supported. Use at your own risk. + + Current API available since 0.097. + +METHODS + absolute + $abs = path("foo/bar")->absolute; + $abs = path("foo/bar")->absolute("/tmp"); + + Returns a new "Path::Tiny" object with an absolute path (or itself if + already absolute). If no argument is given, the current directory is + used as the absolute base path. If an argument is given, it will be + converted to an absolute path (if it is not already) and used as the + absolute base path. + + This will not resolve upward directories ("foo/../bar") unless + "canonpath" in File::Spec would normally do so on your platform. If you + need them resolved, you must call the more expensive "realpath" method + instead. + + On Windows, an absolute path without a volume component will have it + added based on the current drive. + + Current API available since 0.101. + + append, append_raw, append_utf8 + path("foo.txt")->append(@data); + path("foo.txt")->append(\@data); + path("foo.txt")->append({binmode => ":raw"}, @data); + path("foo.txt")->append_raw(@data); + path("foo.txt")->append_utf8(@data); + + Appends data to a file. The file is locked with "flock" prior to + writing. An optional hash reference may be used to pass options. Valid + options are: + + * "binmode": passed to "binmode()" on the handle used for writing. + + * "truncate": truncates the file after locking and before appending + + The "truncate" option is a way to replace the contents of a file in + place, unlike "spew" which writes to a temporary file and then replaces + the original (if it exists). + + "append_raw" is like "append" with a "binmode" of ":unix" for fast, + unbuffered, raw write. + + "append_utf8" is like "append" with a "binmode" of + ":unix:encoding(UTF-8)" (or PerlIO::utf8_strict). If Unicode::UTF8 0.58+ + is installed, a raw append will be done instead on the data encoded with + "Unicode::UTF8". + + Current API available since 0.060. + + assert + $path = path("foo.txt")->assert( sub { $_->exists } ); + + Returns the invocant after asserting that a code reference argument + returns true. When the assertion code reference runs, it will have the + invocant object in the $_ variable. If it returns false, an exception + will be thrown. The assertion code reference may also throw its own + exception. + + If no assertion is provided, the invocant is returned without error. + + Current API available since 0.062. + + basename + $name = path("foo/bar.txt")->basename; # bar.txt + $name = path("foo.txt")->basename('.txt'); # foo + $name = path("foo.txt")->basename(qr/.txt/); # foo + $name = path("foo.txt")->basename(@suffixes); + + Returns the file portion or last directory portion of a path. + + Given a list of suffixes as strings or regular expressions, any that + match at the end of the file portion or last directory portion will be + removed before the result is returned. + + Current API available since 0.054. + + canonpath + $canonical = path("foo/bar")->canonpath; # foo\bar on Windows + + Returns a string with the canonical format of the path name for the + platform. In particular, this means directory separators will be "\" on + Windows. + + Current API available since 0.001. + + cached_temp + Returns the cached "File::Temp" or "File::Temp::Dir" object if the + "Path::Tiny" object was created with "/tempfile" or "/tempdir". If there + is no such object, this method throws. + + WARNING: Keeping a reference to, or modifying the cached object may + break the behavior documented for temporary files and directories + created with "Path::Tiny" and is not supported. Use at your own risk. + + Current API available since 0.101. + + child + $file = path("/tmp")->child("foo.txt"); # "/tmp/foo.txt" + $file = path("/tmp")->child(@parts); + + Returns a new "Path::Tiny" object relative to the original. Works like + "catfile" or "catdir" from File::Spec, but without caring about file or + directories. + + Current API available since 0.001. + + children + @paths = path("/tmp")->children; + @paths = path("/tmp")->children( qr/\.txt$/ ); + + Returns a list of "Path::Tiny" objects for all files and directories + within a directory. Excludes "." and ".." automatically. + + If an optional "qr//" argument is provided, it only returns objects for + child names that match the given regular expression. Only the base name + is used for matching: + + @paths = path("/tmp")->children( qr/^foo/ ); + # matches children like the glob foo* + + Current API available since 0.028. + + chmod + path("foo.txt")->chmod(0777); + path("foo.txt")->chmod("0755"); + path("foo.txt")->chmod("go-w"); + path("foo.txt")->chmod("a=r,u+wx"); + + Sets file or directory permissions. The argument can be a numeric mode, + a octal string beginning with a "0" or a limited subset of the symbolic + mode use by /bin/chmod. + + The symbolic mode must be a comma-delimited list of mode clauses. + Clauses must match "qr/\A([augo]+)([=+-])([rwx]+)\z/", which defines + "who", "op" and "perms" parameters for each clause. Unlike /bin/chmod, + all three parameters are required for each clause, multiple ops are not + allowed and permissions "stugoX" are not supported. (See File::chmod for + more complex needs.) + + Current API available since 0.053. + + copy + path("/tmp/foo.txt")->copy("/tmp/bar.txt"); + + Copies the current path to the given destination using File::Copy's + "copy" function. Upon success, returns the "Path::Tiny" object for the + newly copied file. + + Current API available since 0.070. + + digest + $obj = path("/tmp/foo.txt")->digest; # SHA-256 + $obj = path("/tmp/foo.txt")->digest("MD5"); # user-selected + $obj = path("/tmp/foo.txt")->digest( { chunk_size => 1e6 }, "MD5" ); + + Returns a hexadecimal digest for a file. An optional hash reference of + options may be given. The only option is "chunk_size". If "chunk_size" + is given, that many bytes will be read at a time. If not provided, the + entire file will be slurped into memory to compute the digest. + + Any subsequent arguments are passed to the constructor for Digest to + select an algorithm. If no arguments are given, the default is SHA-256. + + Current API available since 0.056. + + dirname (deprecated) + $name = path("/tmp/foo.txt")->dirname; # "/tmp/" + + Returns the directory portion you would get from calling + "File::Spec->splitpath( $path->stringify )" or "." for a path without a + parent directory portion. Because File::Spec is inconsistent, the result + might or might not have a trailing slash. Because of this, this method + is deprecated. + + A better, more consistently approach is likely + "$path->parent->stringify", which will not have a trailing slash except + for a root directory. + + Deprecated in 0.056. + + edit, edit_raw, edit_utf8 + path("foo.txt")->edit( \&callback, $options ); + path("foo.txt")->edit_utf8( \&callback ); + path("foo.txt")->edit_raw( \&callback ); + + These are convenience methods that allow "editing" a file using a single + callback argument. They slurp the file using "slurp", place the contents + inside a localized $_ variable, call the callback function (without + arguments), and then write $_ (presumably mutated) back to the file with + "spew". + + An optional hash reference may be used to pass options. The only option + is "binmode", which is passed to "slurp" and "spew". + + "edit_utf8" and "edit_raw" act like their respective "slurp_*" and + "spew_*" methods. + + Current API available since 0.077. + + edit_lines, edit_lines_utf8, edit_lines_raw + path("foo.txt")->edit_lines( \&callback, $options ); + path("foo.txt")->edit_lines_utf8( \&callback ); + path("foo.txt")->edit_lines_raw( \&callback ); + + These are convenience methods that allow "editing" a file's lines using + a single callback argument. They iterate over the file: for each line, + the line is put into a localized $_ variable, the callback function is + executed (without arguments) and then $_ is written to a temporary file. + When iteration is finished, the temporary file is atomically renamed + over the original. + + An optional hash reference may be used to pass options. The only option + is "binmode", which is passed to the method that open handles for + reading and writing. + + "edit_lines_utf8" and "edit_lines_raw" act like their respective + "slurp_*" and "spew_*" methods. + + Current API available since 0.077. + + exists, is_file, is_dir + if ( path("/tmp")->exists ) { ... } # -e + if ( path("/tmp")->is_dir ) { ... } # -d + if ( path("/tmp")->is_file ) { ... } # -e && ! -d + + Implements file test operations, this means the file or directory + actually has to exist on the filesystem. Until then, it's just a path. + + Note: "is_file" is not "-f" because "-f" is not the opposite of "-d". + "-f" means "plain file", excluding symlinks, devices, etc. that often + can be read just like files. + + Use "-f" instead if you really mean to check for a plain file. + + Current API available since 0.053. + + filehandle + $fh = path("/tmp/foo.txt")->filehandle($mode, $binmode); + $fh = path("/tmp/foo.txt")->filehandle({ locked => 1 }, $mode, $binmode); + $fh = path("/tmp/foo.txt")->filehandle({ exclusive => 1 }, $mode, $binmode); + + Returns an open file handle. The $mode argument must be a Perl-style + read/write mode string ("<" ,">", ">>", etc.). If a $binmode is given, + it is set during the "open" call. + + An optional hash reference may be used to pass options. + + The "locked" option governs file locking; if true, handles opened for + writing, appending or read-write are locked with "LOCK_EX"; otherwise, + they are locked with "LOCK_SH". When using "locked", ">" or "+>" modes + will delay truncation until after the lock is acquired. + + The "exclusive" option causes the open() call to fail if the file + already exists. This corresponds to the O_EXCL flag to sysopen / + open(2). "exclusive" implies "locked" and will set it for you if you + forget it. + + See "openr", "openw", "openrw", and "opena" for sugar. + + Current API available since 0.066. + + is_absolute, is_relative + if ( path("/tmp")->is_absolute ) { ... } + if ( path("/tmp")->is_relative ) { ... } + + Booleans for whether the path appears absolute or relative. + + Current API available since 0.001. + + is_rootdir + while ( ! $path->is_rootdir ) { + $path = $path->parent; + ... + } + + Boolean for whether the path is the root directory of the volume. I.e. + the "dirname" is "q[/]" and the "basename" is "q[]". + + This works even on "MSWin32" with drives and UNC volumes: + + path("C:/")->is_rootdir; # true + path("//server/share/")->is_rootdir; #true + + Current API available since 0.038. + + iterator + $iter = path("/tmp")->iterator( \%options ); + + Returns a code reference that walks a directory lazily. Each invocation + returns a "Path::Tiny" object or undef when the iterator is exhausted. + + $iter = path("/tmp")->iterator; + while ( $path = $iter->() ) { + ... + } + + The current and parent directory entries ("." and "..") will not be + included. + + If the "recurse" option is true, the iterator will walk the directory + recursively, breadth-first. If the "follow_symlinks" option is also + true, directory links will be followed recursively. There is no + protection against loops when following links. If a directory is not + readable, it will not be followed. + + The default is the same as: + + $iter = path("/tmp")->iterator( { + recurse => 0, + follow_symlinks => 0, + } ); + + For a more powerful, recursive iterator with built-in loop avoidance, + see Path::Iterator::Rule. + + See also "visit". + + Current API available since 0.016. + + lines, lines_raw, lines_utf8 + @contents = path("/tmp/foo.txt")->lines; + @contents = path("/tmp/foo.txt")->lines(\%options); + @contents = path("/tmp/foo.txt")->lines_raw; + @contents = path("/tmp/foo.txt")->lines_utf8; + + @contents = path("/tmp/foo.txt")->lines( { chomp => 1, count => 4 } ); + + Returns a list of lines from a file. Optionally takes a hash-reference + of options. Valid options are "binmode", "count" and "chomp". + + If "binmode" is provided, it will be set on the handle prior to reading. + + If a positive "count" is provided, that many lines will be returned from + the start of the file. If a negative "count" is provided, the entire + file will be read, but only "abs(count)" will be kept and returned. If + "abs(count)" exceeds the number of lines in the file, all lines will be + returned. + + If "chomp" is set, any end-of-line character sequences ("CR", "CRLF", or + "LF") will be removed from the lines returned. + + Because the return is a list, "lines" in scalar context will return the + number of lines (and throw away the data). + + $number_of_lines = path("/tmp/foo.txt")->lines; + + "lines_raw" is like "lines" with a "binmode" of ":raw". We use ":raw" + instead of ":unix" so PerlIO buffering can manage reading by line. + + "lines_utf8" is like "lines" with a "binmode" of ":raw:encoding(UTF-8)" + (or PerlIO::utf8_strict). If Unicode::UTF8 0.58+ is installed, a raw + UTF-8 slurp will be done and then the lines will be split. This is + actually faster than relying on ":encoding(UTF-8)", though a bit memory + intensive. If memory use is a concern, consider "openr_utf8" and + iterating directly on the handle. + + Current API available since 0.065. + + mkpath + path("foo/bar/baz")->mkpath; + path("foo/bar/baz")->mkpath( \%options ); + + Like calling "make_path" from File::Path. An optional hash reference is + passed through to "make_path". Errors will be trapped and an exception + thrown. Returns the list of directories created or an empty list if the + directories already exist, just like "make_path". + + Current API available since 0.001. + + move + path("foo.txt")->move("bar.txt"); + + Move the current path to the given destination path using Perl's + built-in rename function. Returns the result of the "rename" function. + + Current API available since 0.001. + + openr, openw, openrw, opena + $fh = path("foo.txt")->openr($binmode); # read + $fh = path("foo.txt")->openr_raw; + $fh = path("foo.txt")->openr_utf8; + + $fh = path("foo.txt")->openw($binmode); # write + $fh = path("foo.txt")->openw_raw; + $fh = path("foo.txt")->openw_utf8; + + $fh = path("foo.txt")->opena($binmode); # append + $fh = path("foo.txt")->opena_raw; + $fh = path("foo.txt")->opena_utf8; + + $fh = path("foo.txt")->openrw($binmode); # read/write + $fh = path("foo.txt")->openrw_raw; + $fh = path("foo.txt")->openrw_utf8; + + Returns a file handle opened in the specified mode. The "openr" style + methods take a single "binmode" argument. All of the "open*" methods + have "open*_raw" and "open*_utf8" equivalents that use ":raw" and + ":raw:encoding(UTF-8)", respectively. + + An optional hash reference may be used to pass options. The only option + is "locked". If true, handles opened for writing, appending or + read-write are locked with "LOCK_EX"; otherwise, they are locked for + "LOCK_SH". + + $fh = path("foo.txt")->openrw_utf8( { locked => 1 } ); + + See "filehandle" for more on locking. + + Current API available since 0.011. + + parent + $parent = path("foo/bar/baz")->parent; # foo/bar + $parent = path("foo/wibble.txt")->parent; # foo + + $parent = path("foo/bar/baz")->parent(2); # foo + + Returns a "Path::Tiny" object corresponding to the parent directory of + the original directory or file. An optional positive integer argument is + the number of parent directories upwards to return. "parent" by itself + is equivalent to parent(1). + + Current API available since 0.014. + + realpath + $real = path("/baz/foo/../bar")->realpath; + $real = path("foo/../bar")->realpath; + + Returns a new "Path::Tiny" object with all symbolic links and upward + directory parts resolved using Cwd's "realpath". Compared to "absolute", + this is more expensive as it must actually consult the filesystem. + + If the parent path can't be resolved (e.g. if it includes directories + that don't exist), an exception will be thrown: + + $real = path("doesnt_exist/foo")->realpath; # dies + + However, if the parent path exists and only the last component (e.g. + filename) doesn't exist, the realpath will be the realpath of the parent + plus the non-existent last component: + + $real = path("./aasdlfasdlf")->realpath; # works + + The underlying Cwd module usually worked this way on Unix, but died on + Windows (and some Unixes) if the full path didn't exist. As of version + 0.064, it's safe to use anywhere. + + Current API available since 0.001. + + relative + $rel = path("/tmp/foo/bar")->relative("/tmp"); # foo/bar + + Returns a "Path::Tiny" object with a path relative to a new base path + given as an argument. If no argument is given, the current directory + will be used as the new base path. + + If either path is already relative, it will be made absolute based on + the current directly before determining the new relative path. + + The algorithm is roughly as follows: + + * If the original and new base path are on different volumes, an + exception will be thrown. + + * If the original and new base are identical, the relative path is + ".". + + * If the new base subsumes the original, the relative path is the + original path with the new base chopped off the front + + * If the new base does not subsume the original, a common prefix path + is determined (possibly the root directory) and the relative path + will consist of updirs ("..") to reach the common prefix, followed + by the original path less the common prefix. + + Unlike "File::Spec::abs2rel", in the last case above, the calculation + based on a common prefix takes into account symlinks that could affect + the updir process. Given an original path "/A/B" and a new base "/A/C", + (where "A", "B" and "C" could each have multiple path components): + + * Symlinks in "A" don't change the result unless the last component of + A is a symlink and the first component of "C" is an updir. + + * Symlinks in "B" don't change the result and will exist in the result + as given. + + * Symlinks and updirs in "C" must be resolved to actual paths, taking + into account the possibility that not all path components might + exist on the filesystem. + + Current API available since 0.001. New algorithm (that accounts for + symlinks) available since 0.079. + + remove + path("foo.txt")->remove; + + This is just like "unlink", except for its error handling: if the path + does not exist, it returns false; if deleting the file fails, it throws + an exception. + + Current API available since 0.012. + + remove_tree + # directory + path("foo/bar/baz")->remove_tree; + path("foo/bar/baz")->remove_tree( \%options ); + path("foo/bar/baz")->remove_tree( { safe => 0 } ); # force remove + + Like calling "remove_tree" from File::Path, but defaults to "safe" mode. + An optional hash reference is passed through to "remove_tree". Errors + will be trapped and an exception thrown. Returns the number of + directories deleted, just like "remove_tree". + + If you want to remove a directory only if it is empty, use the built-in + "rmdir" function instead. + + rmdir path("foo/bar/baz/"); + + Current API available since 0.013. + + sibling + $foo = path("/tmp/foo.txt"); + $sib = $foo->sibling("bar.txt"); # /tmp/bar.txt + $sib = $foo->sibling("baz", "bam.txt"); # /tmp/baz/bam.txt + + Returns a new "Path::Tiny" object relative to the parent of the + original. This is slightly more efficient than + "$path->parent->child(...)". + + Current API available since 0.058. + + slurp, slurp_raw, slurp_utf8 + $data = path("foo.txt")->slurp; + $data = path("foo.txt")->slurp( {binmode => ":raw"} ); + $data = path("foo.txt")->slurp_raw; + $data = path("foo.txt")->slurp_utf8; + + Reads file contents into a scalar. Takes an optional hash reference + which may be used to pass options. The only available option is + "binmode", which is passed to "binmode()" on the handle used for + reading. + + "slurp_raw" is like "slurp" with a "binmode" of ":unix" for a fast, + unbuffered, raw read. + + "slurp_utf8" is like "slurp" with a "binmode" of ":unix:encoding(UTF-8)" + (or PerlIO::utf8_strict). If Unicode::UTF8 0.58+ is installed, a raw + slurp will be done instead and the result decoded with "Unicode::UTF8". + This is just as strict and is roughly an order of magnitude faster than + using ":encoding(UTF-8)". + + Note: "slurp" and friends lock the filehandle before slurping. If you + plan to slurp from a file created with File::Temp, be sure to close + other handles or open without locking to avoid a deadlock: + + my $tempfile = File::Temp->new(EXLOCK => 0); + my $guts = path($tempfile)->slurp; + + Current API available since 0.004. + + spew, spew_raw, spew_utf8 + path("foo.txt")->spew(@data); + path("foo.txt")->spew(\@data); + path("foo.txt")->spew({binmode => ":raw"}, @data); + path("foo.txt")->spew_raw(@data); + path("foo.txt")->spew_utf8(@data); + + Writes data to a file atomically. The file is written to a temporary + file in the same directory, then renamed over the original. An optional + hash reference may be used to pass options. The only option is + "binmode", which is passed to "binmode()" on the handle used for + writing. + + "spew_raw" is like "spew" with a "binmode" of ":unix" for a fast, + unbuffered, raw write. + + "spew_utf8" is like "spew" with a "binmode" of ":unix:encoding(UTF-8)" + (or PerlIO::utf8_strict). If Unicode::UTF8 0.58+ is installed, a raw + spew will be done instead on the data encoded with "Unicode::UTF8". + + NOTE: because the file is written to a temporary file and then renamed, + the new file will wind up with permissions based on your current umask. + This is a feature to protect you from a race condition that would + otherwise give different permissions than you might expect. If you + really want to keep the original mode flags, use "append" with the + "truncate" option. + + Current API available since 0.011. + + stat, lstat + $stat = path("foo.txt")->stat; + $stat = path("/some/symlink")->lstat; + + Like calling "stat" or "lstat" from File::stat. + + Current API available since 0.001. + + stringify + $path = path("foo.txt"); + say $path->stringify; # same as "$path" + + Returns a string representation of the path. Unlike "canonpath", this + method returns the path standardized with Unix-style "/" directory + separators. + + Current API available since 0.001. + + subsumes + path("foo/bar")->subsumes("foo/bar/baz"); # true + path("/foo/bar")->subsumes("/foo/baz"); # false + + Returns true if the first path is a prefix of the second path at a + directory boundary. + + This does not resolve parent directory entries ("..") or symlinks: + + path("foo/bar")->subsumes("foo/bar/../baz"); # true + + If such things are important to you, ensure that both paths are resolved + to the filesystem with "realpath": + + my $p1 = path("foo/bar")->realpath; + my $p2 = path("foo/bar/../baz")->realpath; + if ( $p1->subsumes($p2) ) { ... } + + Current API available since 0.048. + + touch + path("foo.txt")->touch; + path("foo.txt")->touch($epoch_secs); + + Like the Unix "touch" utility. Creates the file if it doesn't exist, or + else changes the modification and access times to the current time. If + the first argument is the epoch seconds then it will be used. + + Returns the path object so it can be easily chained with other methods: + + # won't die if foo.txt doesn't exist + $content = path("foo.txt")->touch->slurp; + + Current API available since 0.015. + + touchpath + path("bar/baz/foo.txt")->touchpath; + + Combines "mkpath" and "touch". Creates the parent directory if it + doesn't exist, before touching the file. Returns the path object like + "touch" does. + + Current API available since 0.022. + + visit + path("/tmp")->visit( \&callback, \%options ); + + Executes a callback for each child of a directory. It returns a hash + reference with any state accumulated during iteration. + + The options are the same as for "iterator" (which it uses internally): + "recurse" and "follow_symlinks". Both default to false. + + The callback function will receive a "Path::Tiny" object as the first + argument and a hash reference to accumulate state as the second + argument. For example: + + # collect files sizes + my $sizes = path("/tmp")->visit( + sub { + my ($path, $state) = @_; + return if $path->is_dir; + $state->{$path} = -s $path; + }, + { recurse => 1 } + ); + + For convenience, the "Path::Tiny" object will also be locally aliased as + the $_ global variable: + + # print paths matching /foo/ + path("/tmp")->visit( sub { say if /foo/ }, { recurse => 1} ); + + If the callback returns a reference to a false scalar value, iteration + will terminate. This is not the same as "pruning" a directory search; + this just stops all iteration and returns the state hash reference. + + # find up to 10 files larger than 100K + my $files = path("/tmp")->visit( + sub { + my ($path, $state) = @_; + $state->{$path}++ if -s $path > 102400 + return \0 if keys %$state == 10; + }, + { recurse => 1 } + ); + + If you want more flexible iteration, use a module like + Path::Iterator::Rule. + + Current API available since 0.062. + + volume + $vol = path("/tmp/foo.txt")->volume; # "" + $vol = path("C:/tmp/foo.txt")->volume; # "C:" + + Returns the volume portion of the path. This is equivalent to what + File::Spec would give from "splitpath" and thus usually is the empty + string on Unix-like operating systems or the drive letter for an + absolute path on "MSWin32". + + Current API available since 0.001. + +EXCEPTION HANDLING + Simple usage errors will generally croak. Failures of underlying Perl + functions will be thrown as exceptions in the class "Path::Tiny::Error". + + A "Path::Tiny::Error" object will be a hash reference with the following + fields: + + * "op" — a description of the operation, usually function call and any + extra info + + * "file" — the file or directory relating to the error + + * "err" — hold $! at the time the error was thrown + + * "msg" — a string combining the above data and a Carp-like short + stack trace + + Exception objects will stringify as the "msg" field. + +CAVEATS + Subclassing not supported + For speed, this class is implemented as an array based object and uses + many direct function calls internally. You must not subclass it and + expect things to work properly. + + File locking + If flock is not supported on a platform, it will not be used, even if + locking is requested. + + See additional caveats below. + + NFS and BSD + On BSD, Perl's flock implementation may not work to lock files on an NFS + filesystem. Path::Tiny has some heuristics to detect this and will warn + once and let you continue in an unsafe mode. If you want this failure to + be fatal, you can fatalize the 'flock' warnings category: + + use warnings FATAL => 'flock'; + + AIX and locking + AIX requires a write handle for locking. Therefore, calls that normally + open a read handle and take a shared lock instead will open a read-write + handle and take an exclusive lock. If the user does not have write + permission, no lock will be used. + + utf8 vs UTF-8 + All the *_utf8 methods by default use ":encoding(UTF-8)" -- either as + ":unix:encoding(UTF-8)" (unbuffered) or ":raw:encoding(UTF-8)" + (buffered) -- which is strict against the Unicode spec and disallows + illegal Unicode codepoints or UTF-8 sequences. + + Unfortunately, ":encoding(UTF-8)" is very, very slow. If you install + Unicode::UTF8 0.58 or later, that module will be used by some *_utf8 + methods to encode or decode data after a raw, binary input/output + operation, which is much faster. Alternatively, if you install + PerlIO::utf8_strict, that will be used instead of ":encoding(UTF-8)" and + is also very fast. + + If you need the performance and can accept the security risk, + "slurp({binmode => ":unix:utf8"})" will be faster than + ":unix:encoding(UTF-8)" (but not as fast as "Unicode::UTF8"). + + Note that the *_utf8 methods read in raw mode. There is no CRLF + translation on Windows. If you must have CRLF translation, use the + regular input/output methods with an appropriate binmode: + + $path->spew_utf8($data); # raw + $path->spew({binmode => ":encoding(UTF-8)"}, $data; # LF -> CRLF + + Default IO layers and the open pragma + If you have Perl 5.10 or later, file input/output methods ("slurp", + "spew", etc.) and high-level handle opening methods ( "filehandle", + "openr", "openw", etc. ) respect default encodings set by the "-C" + switch or lexical open settings of the caller. For UTF-8, this is almost + certainly slower than using the dedicated "_utf8" methods if you have + Unicode::UTF8. + +TYPE CONSTRAINTS AND COERCION + A standard MooseX::Types library is available at + MooseX::Types::Path::Tiny. A Type::Tiny equivalent is available as + Types::Path::Tiny. + +SEE ALSO + These are other file/path utilities, which may offer a different feature + set than "Path::Tiny". + + * File::chmod + + * File::Fu + + * IO::All + + * Path::Class + + These iterators may be slightly faster than the recursive iterator in + "Path::Tiny": + + * Path::Iterator::Rule + + * File::Next + + There are probably comparable, non-Tiny tools. Let me know if you want + me to add a module to the list. + + This module was featured in the 2013 Perl Advent Calendar + . + +SUPPORT + Bugs / Feature Requests + Please report any bugs or feature requests through the issue tracker at + . You will be notified + automatically of any progress on your issue. + + Source Code + This is open source software. The code repository is available for + public review and contribution under the terms of the license. + + + + git clone https://github.com/dagolden/Path-Tiny.git + +AUTHOR + David Golden + +CONTRIBUTORS + * Alex Efros + + * Chris Williams + + * Dave Rolsky + + * David Steinbrunner + + * Doug Bell + + * Gabor Szabo + + * Gabriel Andrade + + * George Hartzell + + * Geraud Continsouzas + + * Goro Fuji + + * Graham Knop + + * Graham Ollis + + * James Hunt + + * John Karr + + * Karen Etheridge + + * Mark Ellis + + * Martin Kjeldsen + + * Michael G. Schwern + + * Nigel Gregoire + + * Philippe Bruhat (BooK) + + * Regina Verbae + + * Roy Ivy III + + * Shlomi Fish + + * Smylers + + * Tatsuhiko Miyagawa + + * Toby Inkster + + * Yanick Champoux + + * 김도형 - Keedi Kim + +COPYRIGHT AND LICENSE + This software is Copyright (c) 2014 by David Golden. + + This is free software, licensed under: + + The Apache License, Version 2.0, January 2004 + diff --git a/cpanfile b/cpanfile new file mode 100644 index 0000000..4c8c118 --- /dev/null +++ b/cpanfile @@ -0,0 +1,74 @@ +requires "Carp" => "0"; +requires "Cwd" => "0"; +requires "Digest" => "1.03"; +requires "Digest::SHA" => "5.45"; +requires "Exporter" => "5.57"; +requires "Fcntl" => "0"; +requires "File::Copy" => "0"; +requires "File::Glob" => "0"; +requires "File::Path" => "2.07"; +requires "File::Spec" => "0.86"; +requires "File::Temp" => "0.19"; +requires "File::stat" => "0"; +requires "constant" => "0"; +requires "if" => "0"; +requires "overload" => "0"; +requires "perl" => "5.008001"; +requires "strict" => "0"; +requires "warnings" => "0"; +recommends "Unicode::UTF8" => "0.58"; + +on 'test' => sub { + requires "ExtUtils::MakeMaker" => "0"; + requires "File::Basename" => "0"; + requires "File::Spec" => "0.86"; + requires "File::Spec::Functions" => "0"; + requires "File::Spec::Unix" => "0"; + requires "File::Temp" => "0.19"; + requires "Test::More" => "0.96"; + requires "lib" => "0"; + requires "open" => "0"; + requires "perl" => "5.008001"; +}; + +on 'test' => sub { + recommends "CPAN::Meta" => "2.120900"; + recommends "Test::FailWarnings" => "0"; + recommends "Test::MockRandom" => "0"; +}; + +on 'configure' => sub { + requires "ExtUtils::MakeMaker" => "6.17"; + requires "perl" => "5.008001"; +}; + +on 'configure' => sub { + suggests "JSON::PP" => "2.27300"; +}; + +on 'develop' => sub { + requires "Dist::Zilla" => "5"; + requires "Dist::Zilla::Plugin::MinimumPerl" => "0"; + requires "Dist::Zilla::Plugin::OnlyCorePrereqs" => "0"; + requires "Dist::Zilla::Plugin::Prereqs" => "0"; + requires "Dist::Zilla::Plugin::ReleaseStatus::FromVersion" => "0"; + requires "Dist::Zilla::Plugin::RemovePrereqs" => "0"; + requires "Dist::Zilla::PluginBundle::DAGOLDEN" => "0.072"; + requires "English" => "0"; + requires "File::Spec" => "0"; + requires "File::Temp" => "0"; + requires "IO::Handle" => "0"; + requires "IPC::Open3" => "0"; + requires "Pod::Coverage::TrustPod" => "0"; + requires "Pod::Wordlist" => "0"; + requires "Software::License::Apache_2_0" => "0"; + requires "Test::CPAN::Meta" => "0"; + requires "Test::MinimumVersion" => "0"; + requires "Test::More" => "0"; + requires "Test::Pod" => "1.41"; + requires "Test::Pod::Coverage" => "1.08"; + requires "Test::Portability::Files" => "0"; + requires "Test::Spelling" => "0.12"; + requires "Test::Version" => "1"; + requires "blib" => "1.01"; +}; diff --git a/dist.ini b/dist.ini new file mode 100644 index 0000000..745b6ad --- /dev/null +++ b/dist.ini @@ -0,0 +1,63 @@ +name = Path-Tiny +author = David Golden +license = Apache_2_0 +copyright_holder = David Golden +copyright_year = 2014 + +[@DAGOLDEN] +:version = 0.072 +-remove = MinimumPerlFast +stopwords = AIX +stopwords = BENCHMARKING +stopwords = CRLF +stopwords = SHA +stopwords = NFS +stopwords = canonpath +stopwords = codepoints +stopwords = cwd +stopwords = dirname +stopwords = fatalize +stopwords = lstat +stopwords = mkpath +stopwords = opena +stopwords = openr +stopwords = openrw +stopwords = openw +stopwords = realpath +stopwords = stringifying +stopwords = subclasses +stopwords = touchpath +stopwords = UNC +stopwords = unlinked +stopwords = utf +MetaNoIndex.package = flock + +[ReleaseStatus::FromVersion] +testing = third_decimal_odd + +[MinimumPerl] + +[RemovePrereqs] +remove = Unicode::UTF8 +remove = PerlIO::utf8_strict +remove = Path::Class +remove = Test::FailWarnings +remove = threads + +; Digest/Digest::SHA are fine in 5.10.0+ +[Prereqs] +Digest = 1.03 +Digest::SHA = 5.45 +File::Path = 2.07 +File::Temp = 0.19 ; newdir + +[Prereqs / Recommends] +Unicode::UTF8 = 0.58 + +[Prereqs / TestRecommends] +Test::FailWarnings = 0 +Test::MockRandom = 0 + +[OnlyCorePrereqs] +starting_version = current +check_dual_life_versions = 0 diff --git a/lib/Path/Tiny.pm b/lib/Path/Tiny.pm new file mode 100644 index 0000000..9190108 --- /dev/null +++ b/lib/Path/Tiny.pm @@ -0,0 +1,3398 @@ +use 5.008001; +use strict; +use warnings; + +package Path::Tiny; +# ABSTRACT: File path utility + +our $VERSION = '0.104'; + +# Dependencies +use Config; +use Exporter 5.57 (qw/import/); +use File::Spec 0.86 (); # shipped with 5.8.1 +use Carp (); + +our @EXPORT = qw/path/; +our @EXPORT_OK = qw/cwd rootdir tempfile tempdir/; + +use constant { + PATH => 0, + CANON => 1, + VOL => 2, + DIR => 3, + FILE => 4, + TEMP => 5, + IS_BSD => ( scalar $^O =~ /bsd$/ ), + IS_WIN32 => ( $^O eq 'MSWin32' ), +}; + +use overload ( + q{""} => sub { $_[0]->[PATH] }, + bool => sub () { 1 }, + fallback => 1, +); + +# FREEZE/THAW per Sereal/CBOR/Types::Serialiser protocol +sub FREEZE { return $_[0]->[PATH] } +sub THAW { return path( $_[2] ) } +{ no warnings 'once'; *TO_JSON = *FREEZE }; + +my $HAS_UU; # has Unicode::UTF8; lazily populated + +sub _check_UU { + !!eval { require Unicode::UTF8; Unicode::UTF8->VERSION(0.58); 1 }; +} + +my $HAS_PU; # has PerlIO::utf8_strict; lazily populated + +sub _check_PU { + !!eval { require PerlIO::utf8_strict; PerlIO::utf8_strict->VERSION(0.003); 1 }; +} + +my $HAS_FLOCK = $Config{d_flock} || $Config{d_fcntl_can_lock} || $Config{d_lockf}; + +# notions of "root" directories differ on Win32: \\server\dir\ or C:\ or \ +my $SLASH = qr{[\\/]}; +my $NOTSLASH = qr{[^\\/]}; +my $DRV_VOL = qr{[a-z]:}i; +my $UNC_VOL = qr{$SLASH $SLASH $NOTSLASH+ $SLASH $NOTSLASH+}x; +my $WIN32_ROOT = qr{(?: $UNC_VOL $SLASH | $DRV_VOL $SLASH | $SLASH )}x; + +sub _win32_vol { + my ( $path, $drv ) = @_; + require Cwd; + my $dcwd = eval { Cwd::getdcwd($drv) }; # C: -> C:\some\cwd + # getdcwd on non-existent drive returns empty string + # so just use the original drive Z: -> Z: + $dcwd = "$drv" unless defined $dcwd && length $dcwd; + # normalize dwcd to end with a slash: might be C:\some\cwd or D:\ or Z: + $dcwd =~ s{$SLASH?$}{/}; + # make the path absolute with dcwd + $path =~ s{^$DRV_VOL}{$dcwd}; + return $path; +} + +# This is a string test for before we have the object; see is_rootdir for well-formed +# object test +sub _is_root { + return IS_WIN32() ? ( $_[0] =~ /^$WIN32_ROOT$/ ) : ( $_[0] eq '/' ); +} + +BEGIN { + *_same = IS_WIN32() ? sub { lc( $_[0] ) eq lc( $_[1] ) } : sub { $_[0] eq $_[1] }; +} + +# mode bits encoded for chmod in symbolic mode +my %MODEBITS = ( om => 0007, gm => 0070, um => 0700 ); ## no critic +{ my $m = 0; $MODEBITS{$_} = ( 1 << $m++ ) for qw/ox ow or gx gw gr ux uw ur/ }; + +sub _symbolic_chmod { + my ( $mode, $symbolic ) = @_; + for my $clause ( split /,\s*/, $symbolic ) { + if ( $clause =~ m{\A([augo]+)([=+-])([rwx]+)\z} ) { + my ( $who, $action, $perms ) = ( $1, $2, $3 ); + $who =~ s/a/ugo/g; + for my $w ( split //, $who ) { + my $p = 0; + $p |= $MODEBITS{"$w$_"} for split //, $perms; + if ( $action eq '=' ) { + $mode = ( $mode & ~$MODEBITS{"${w}m"} ) | $p; + } + else { + $mode = $action eq "+" ? ( $mode | $p ) : ( $mode & ~$p ); + } + } + } + else { + Carp::croak("Invalid mode clause '$clause' for chmod()"); + } + } + return $mode; +} + +# flock doesn't work on NFS on BSD. Since program authors often can't control +# or detect that, we warn once instead of being fatal if we can detect it and +# people who need it strict can fatalize the 'flock' category + +#<<< No perltidy +{ package flock; use if Path::Tiny::IS_BSD(), 'warnings::register' } +#>>> + +my $WARNED_BSD_NFS = 0; + +sub _throw { + my ( $self, $function, $file, $msg ) = @_; + if ( IS_BSD() + && $function =~ /^flock/ + && $! =~ /operation not supported/i + && !warnings::fatal_enabled('flock') ) + { + if ( !$WARNED_BSD_NFS ) { + warnings::warn( flock => "No flock for NFS on BSD: continuing in unsafe mode" ); + $WARNED_BSD_NFS++; + } + } + else { + $msg = $! unless defined $msg; + Path::Tiny::Error->throw( $function, ( defined $file ? $file : $self->[PATH] ), + $msg ); + } + return; +} + +# cheapo option validation +sub _get_args { + my ( $raw, @valid ) = @_; + if ( defined($raw) && ref($raw) ne 'HASH' ) { + my ( undef, undef, undef, $called_as ) = caller(1); + $called_as =~ s{^.*::}{}; + Carp::croak("Options for $called_as must be a hash reference"); + } + my $cooked = {}; + for my $k (@valid) { + $cooked->{$k} = delete $raw->{$k} if exists $raw->{$k}; + } + if ( keys %$raw ) { + my ( undef, undef, undef, $called_as ) = caller(1); + $called_as =~ s{^.*::}{}; + Carp::croak( "Invalid option(s) for $called_as: " . join( ", ", keys %$raw ) ); + } + return $cooked; +} + +#--------------------------------------------------------------------------# +# Constructors +#--------------------------------------------------------------------------# + +#pod =construct path +#pod +#pod $path = path("foo/bar"); +#pod $path = path("/tmp", "file.txt"); # list +#pod $path = path("."); # cwd +#pod $path = path("~user/file.txt"); # tilde processing +#pod +#pod Constructs a C object. It doesn't matter if you give a file or +#pod directory path. It's still up to you to call directory-like methods only on +#pod directories and file-like methods only on files. This function is exported +#pod automatically by default. +#pod +#pod The first argument must be defined and have non-zero length or an exception +#pod will be thrown. This prevents subtle, dangerous errors with code like +#pod C<< path( maybe_undef() )->remove_tree >>. +#pod +#pod If the first component of the path is a tilde ('~') then the component will be +#pod replaced with the output of C. If the first component of the path +#pod is a tilde followed by a user name then the component will be replaced with +#pod output of C. Behaviour for non-existent users depends on +#pod the output of C on the system. +#pod +#pod On Windows, if the path consists of a drive identifier without a path component +#pod (C or C), it will be expanded to the absolute path of the current +#pod directory on that volume using C. +#pod +#pod If called with a single C argument, the original is returned unless +#pod the original is holding a temporary file or directory reference in which case a +#pod stringified copy is made. +#pod +#pod $path = path("foo/bar"); +#pod $temp = Path::Tiny->tempfile; +#pod +#pod $p2 = path($path); # like $p2 = $path +#pod $t2 = path($temp); # like $t2 = path( "$temp" ) +#pod +#pod This optimizes copies without proliferating references unexpectedly if a copy is +#pod made by code outside your control. +#pod +#pod Current API available since 0.017. +#pod +#pod =cut + +sub path { + my $path = shift; + Carp::croak("Path::Tiny paths require defined, positive-length parts") + unless 1 + @_ == grep { defined && length } $path, @_; + + # non-temp Path::Tiny objects are effectively immutable and can be reused + if ( !@_ && ref($path) eq __PACKAGE__ && !$path->[TEMP] ) { + return $path; + } + + # stringify objects + $path = "$path"; + + # expand relative volume paths on windows; put trailing slash on UNC root + if ( IS_WIN32() ) { + $path = _win32_vol( $path, $1 ) if $path =~ m{^($DRV_VOL)(?:$NOTSLASH|$)}; + $path .= "/" if $path =~ m{^$UNC_VOL$}; + } + + # concatenations stringifies objects, too + if (@_) { + $path .= ( _is_root($path) ? "" : "/" ) . join( "/", @_ ); + } + + # canonicalize, but with unix slashes and put back trailing volume slash + my $cpath = $path = File::Spec->canonpath($path); + $path =~ tr[\\][/] if IS_WIN32(); + $path = "/" if $path eq '/..'; # for old File::Spec + $path .= "/" if IS_WIN32() && $path =~ m{^$UNC_VOL$}; + + # root paths must always have a trailing slash, but other paths must not + if ( _is_root($path) ) { + $path =~ s{/?$}{/}; + } + else { + $path =~ s{/$}{}; + } + + # do any tilde expansions + if ( $path =~ m{^(~[^/]*).*} ) { + require File::Glob; + my ($homedir) = File::Glob::bsd_glob($1); + $homedir =~ tr[\\][/] if IS_WIN32(); + $path =~ s{^(~[^/]*)}{$homedir}; + } + + bless [ $path, $cpath ], __PACKAGE__; +} + +#pod =construct new +#pod +#pod $path = Path::Tiny->new("foo/bar"); +#pod +#pod This is just like C, but with method call overhead. (Why would you +#pod do that?) +#pod +#pod Current API available since 0.001. +#pod +#pod =cut + +sub new { shift; path(@_) } + +#pod =construct cwd +#pod +#pod $path = Path::Tiny->cwd; # path( Cwd::getcwd ) +#pod $path = cwd; # optional export +#pod +#pod Gives you the absolute path to the current directory as a C object. +#pod This is slightly faster than C<< path(".")->absolute >>. +#pod +#pod C may be exported on request and used as a function instead of as a +#pod method. +#pod +#pod Current API available since 0.018. +#pod +#pod =cut + +sub cwd { + require Cwd; + return path( Cwd::getcwd() ); +} + +#pod =construct rootdir +#pod +#pod $path = Path::Tiny->rootdir; # / +#pod $path = rootdir; # optional export +#pod +#pod Gives you C<< File::Spec->rootdir >> as a C object if you're too +#pod picky for C. +#pod +#pod C may be exported on request and used as a function instead of as a +#pod method. +#pod +#pod Current API available since 0.018. +#pod +#pod =cut + +sub rootdir { path( File::Spec->rootdir ) } + +#pod =construct tempfile, tempdir +#pod +#pod $temp = Path::Tiny->tempfile( @options ); +#pod $temp = Path::Tiny->tempdir( @options ); +#pod $temp = tempfile( @options ); # optional export +#pod $temp = tempdir( @options ); # optional export +#pod +#pod C passes the options to C<< File::Temp->new >> and returns a C +#pod object with the file name. The C option is enabled by default. +#pod +#pod The resulting C object is cached. When the C object is +#pod destroyed, the C object will be as well. +#pod +#pod C annoyingly requires you to specify a custom template in slightly +#pod different ways depending on which function or method you call, but +#pod C lets you ignore that and can take either a leading template or a +#pod C