Codebase list libfile-next-perl / ec078f8
New upstream version 1.18 Axel Beckert 4 years ago
8 changed file(s) with 102 addition(s) and 59 deletion(s). Raw diff Collapse all Expand all
11
22 File::Next does NOT use rt.cpan.org for bug tracking. Please report
33 problems at http://github.com/petdance/file-next/issues.
4
5 1.18 Tue Aug 27 17:08:38 CDT 2019
6 [SPEEDUP]
7 Updated the internals to minimize the number of times that stat()
8 gets called on each file or directory.
9
10 [FIXES]
11 t/from_file.t would fail under Windows because File::Temp would
12 put a backslash in front of the name of the tempfile. Thanks,
13 Varadinsky. (GH#32)
14
15 Had to specify a minimum version of File::Temp. Thanks, Justin Mohr.
16 (GH#29)
17
418
519 1.16 Thu Jul 7 22:41:30 CDT 2016
620 [FIXES]
33 "Andy Lester <andy@petdance.com>"
44 ],
55 "dynamic_config" : 1,
6 "generated_by" : "ExtUtils::MakeMaker version 7.18, CPAN::Meta::Converter version 2.143240",
6 "generated_by" : "ExtUtils::MakeMaker version 7.24, CPAN::Meta::Converter version 2.150005",
77 "license" : [
88 "artistic_2"
99 ],
1010 "meta-spec" : {
1111 "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
12 "version" : "2"
12 "version" : 2
1313 },
1414 "name" : "File-Next",
1515 "no_index" : {
3131 },
3232 "runtime" : {
3333 "requires" : {
34 "File::Copy" : "0",
3435 "File::Spec" : "0",
36 "File::Temp" : "0.22",
3537 "Test::More" : "0.88"
3638 }
3739 }
4850 "url" : "http://github.com/petdance/file-next/tree/master"
4951 }
5052 },
51 "version" : "1.16"
53 "version" : "1.18",
54 "x_serialization_backend" : "JSON::PP version 4.04"
5255 }
66 configure_requires:
77 ExtUtils::MakeMaker: '0'
88 dynamic_config: 1
9 generated_by: 'ExtUtils::MakeMaker version 7.18, CPAN::Meta::Converter version 2.143240'
9 generated_by: 'ExtUtils::MakeMaker version 7.24, CPAN::Meta::Converter version 2.150005'
1010 license: artistic_2
1111 meta-spec:
1212 url: http://module-build.sourceforge.net/META-spec-v1.4.html
1717 - t
1818 - inc
1919 requires:
20 File::Copy: '0'
2021 File::Spec: '0'
22 File::Temp: '0.22'
2123 Test::More: '0.88'
2224 resources:
2325 bugtracker: http://github.com/petdance/file-next/issues
2426 license: http://dev.perl.org/licenses/
2527 repository: http://github.com/petdance/file-next/tree/master
26 version: '1.16'
28 version: '1.18'
29 x_serialization_backend: 'CPAN::Meta::YAML version 0.018'
1414 LICENSE => 'artistic_2',
1515 PREREQ_PM => {
1616 'Test::More' => 0.88,
17 'File::Copy' => 0,
1718 'File::Spec' => 0,
19 'File::Temp' => 0.22,
1820 },
1921 dist => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', },
2022 clean => { FILES => 'File-Next-*' },
88
99 =head1 VERSION
1010
11 Version 1.16
11 Version 1.18
1212
1313 =cut
1414
15 our $VERSION = '1.16';
15 our $VERSION = '1.18';
1616
1717 =head1 SYNOPSIS
1818
1919 File::Next is a lightweight, taint-safe file-finding module.
20 It's lightweight and has no non-core prerequisites.
20 It has no non-core prerequisites.
2121
2222 use File::Next;
2323
261261
262262 my ($parms,@queue) = _setup( \%files_defaults, @_ );
263263
264 my $filter = $parms->{file_filter};
264265 return sub {
265 my $filter = $parms->{file_filter};
266 while (@queue) {
267 my ($dirname,$file,$fullpath) = splice( @queue, 0, 3 );
268 if ( -f $fullpath || -p _ || $fullpath =~ m{^/dev/fd} ) {
266 while ( my $entry = shift @queue ) {
267 my ( $dirname, $file, $fullpath, $is_dir, $is_file, $is_fifo ) = @{$entry};
268 if ( $is_file || $is_fifo ) {
269269 if ( $filter ) {
270270 local $_ = $file;
271271 local $File::Next::dir = $dirname;
274274 }
275275 return wantarray ? ($dirname,$file,$fullpath) : $fullpath;
276276 }
277 if ( -d _ ) {
277 if ( $is_dir ) {
278278 unshift( @queue, _candidate_files( $parms, $fullpath ) );
279279 }
280280 } # while
290290 my ($parms,@queue) = _setup( \%files_defaults, @_ );
291291
292292 return sub {
293 while (@queue) {
294 my (undef,undef,$fullpath) = splice( @queue, 0, 3 );
295 if ( -d $fullpath ) {
293 while ( my $entry = shift @queue ) {
294 my ( undef, undef, $fullpath, $is_dir, undef, undef ) = @{$entry};
295 if ( $is_dir ) {
296296 unshift( @queue, _candidate_files( $parms, $fullpath ) );
297297 return $fullpath;
298298 }
302302 }; # iterator
303303 }
304304
305
305306 sub everything {
306307 die _bad_invocation() if @_ && defined($_[0]) && ($_[0] eq __PACKAGE__);
307308
308309 my ($parms,@queue) = _setup( \%files_defaults, @_ );
309310
311 my $filter = $parms->{file_filter};
310312 return sub {
311 my $filter = $parms->{file_filter};
312 while (@queue) {
313 my ($dirname,$file,$fullpath) = splice( @queue, 0, 3 );
314 if ( -d $fullpath ) {
313 while ( my $entry = shift @queue ) {
314 my ( $dirname, $file, $fullpath, $is_dir, $is_file, $is_fifo ) = @{$entry};
315 if ( $is_dir ) {
315316 unshift( @queue, _candidate_files( $parms, $fullpath ) );
316317 }
317318 if ( $filter ) {
334335 my $err = $parms->{error_handler};
335336 my $warn = $parms->{warning_handler};
336337
337 my $filename = $queue[1];
338 my $filename = $queue[0]->[1];
338339
339340 if ( !defined($filename) ) {
340341 $err->( 'Must pass a filename to from_file()' );
352353 }
353354 }
354355
356 my $filter = $parms->{file_filter};
355357 return sub {
356 my $filter = $parms->{file_filter};
357358 local $/ = $parms->{nul_separated} ? "\x00" : $/;
358359 while ( my $fullpath = <$fh> ) {
359360 chomp $fullpath;
411412 The queue prep stuff takes the strings in I<@starting_points> and
412413 puts them in the format that queue needs.
413414
414 The C<@queue> that gets passed around is an array that has three
415 elements for each of the entries in the queue: $dir, $file and
416 $fullpath. Items must be pushed and popped off the queue three at
417 a time (spliced, really).
415 The C<@queue> that gets passed around is an array, with each entry an
416 arrayref of $dir, $file and $fullpath.
418417
419418 =cut
420419
433432 }
434433
435434 # Any leftover keys are bogus
436 for my $badkey ( keys %passed_parms ) {
435 for my $badkey ( sort keys %passed_parms ) {
437436 my $sub = (caller(1))[3];
438437 $parms->{error_handler}->( "Invalid option passed to $sub(): $badkey" );
439438 }
446445
447446 for ( @_ ) {
448447 my $start = reslash( $_ );
449 if (-d $start) {
450 push @queue, ($start,undef,$start);
451 }
452 else {
453 push @queue, (undef,$start,$start);
454 }
448 my $is_dir = -d $start;
449 my $is_file = -f _;
450 my $is_fifo = (-p _) || ($start =~ m{^/dev/fd});
451 push @queue,
452 $is_dir
453 ? [ $start, undef, $start, $is_dir, $is_file, $is_fifo ]
454 : [ undef, $start, $start, $is_dir, $is_file, $is_fifo ];
455455 }
456456
457457 return ($parms,@queue);
479479 my @newfiles;
480480 my $descend_filter = $parms->{descend_filter};
481481 my $follow_symlinks = $parms->{follow_symlinks};
482 my $sort_sub = $parms->{sort_files};
483482
484483 for my $file ( grep { !exists $skip_dirs{$_} } readdir $dh ) {
485 my $has_stat;
486
487484 my $fullpath = File::Spec->catdir( $dirname, $file );
488485 if ( !$follow_symlinks ) {
489486 next if -l $fullpath;
490 $has_stat = 1;
491487 }
488 else {
489 stat($fullpath);
490 }
491 my $is_dir = -d _;
492 my $is_file = -f _;
493 my $is_fifo = (-p _) || ($fullpath =~ m{^/dev/fd});
492494
493495 # Only do directory checking if we have a descend_filter
494496 if ( $descend_filter ) {
495 if ( $has_stat ? (-d _) : (-d $fullpath) ) {
497 if ( $is_dir ) {
496498 local $File::Next::dir = $fullpath;
497499 local $_ = $file;
498500 next if not $descend_filter->();
499501 }
500502 }
501 if ( $sort_sub ) {
502 push( @newfiles, [ $dirname, $file, $fullpath ] );
503 }
504 else {
505 push( @newfiles, $dirname, $file, $fullpath );
506 }
503 push @newfiles, [ $dirname, $file, $fullpath, $is_dir, $is_file, $is_fifo ];
507504 }
508505 closedir $dh;
509506
507 my $sort_sub = $parms->{sort_files};
510508 if ( $sort_sub ) {
511 return map { @{$_} } sort $sort_sub @newfiles;
509 @newfiles = sort $sort_sub @newfiles;
512510 }
513511
514512 return @newfiles;
515513 }
514
516515
517516 =head1 DIAGNOSTICS
518517
570569
571570 L<http://github.com/petdance/file-next/issues>
572571
573 =item * AnnoCPAN: Annotated CPAN documentation
574
575 L<http://annocpan.org/dist/File-Next>
576
577572 =item * CPAN Ratings
578573
579574 L<http://cpanratings.perl.org/d/File-Next>
593588 All file-finding in this module is adapted from Mark Jason Dominus'
594589 marvelous I<Higher Order Perl>, page 126.
595590
596 Thanks also for bug fixes and typo finding to
591 Thanks to these fine contributors:
592 Varadinsky,
593 Paulo Custodio,
597594 Gerhard Poul,
598595 Brian Fraser,
599596 Todd Rinaldo,
604601
605602 =head1 COPYRIGHT & LICENSE
606603
607 Copyright 2005-2016 Andy Lester.
604 Copyright 2005-2017 Andy Lester.
608605
609606 This program is free software; you can redistribute it and/or modify
610607 it under the terms of the Artistic License version 2.0.
3434 * Bug Tracker:
3535 * http://github.com/petdance/file-next/issues
3636
37 * AnnoCPAN, annotated CPAN documentation:
38 * http://annocpan.org/dist/File-Next
39
4037 * CPAN Ratings:
4138 * http://cpanratings.perl.org/d/File-Next
4239
1212
1313 [-ErrorHandling::RequireCarping]
1414 [-ErrorHandling::RequireUseOfExceptions]
15
16 [-Miscellanea::RequireRcsKeywords]
1715
1816 [-Modules::RequireVersionVar]
1917 [-Modules::RequirePerlVersion]
11
22 use strict;
33 use warnings;
4 use Test::More tests => 17;
4 use Test::More tests => 22;
55
66 use lib 't';
77 use Util;
7575 my $warn_called;
7676 local $SIG{__WARN__} = sub { $warn_called = 1 };
7777
78 my $tempfile = File::Temp->new;
78 my $tempfile = File::Temp->new(TEMPLATE => 'XXXXXXXXXX');
7979 File::Copy::copy('t/filelist.txt', $tempfile);
8080 print {$tempfile} "t/non-existent-file.txt\n";
8181 $tempfile->close;
9393 my $warn_called;
9494 local $SIG{__WARN__} = sub { $warn_called = 1 };
9595
96 my $tempfile = File::Temp->new;
96 my $tempfile = File::Temp->new(TEMPLATE => 'XXXXXXXXXX');
9797 File::Copy::copy('t/filelist.txt', $tempfile);
9898 print {$tempfile} "t/non-existent-file.txt\n";
9999 $tempfile->close;
110110 ok(!$warn_called, 'CORE::warn() should be not called if a warning occurs but a warning_handler is set');
111111 ok($warning_handler_called, 'The set warning handler should be called if a warning occurs');
112112 }
113
114
115 FROM_MISSING_FILE_WITH_ERROR_HANDLER: {
116 my $error_handler_message;
117 my $error_handler = sub { $error_handler_message = shift; };
118 my $iter = File::Next::from_file( { error_handler => $error_handler }, 'flargle-bargle.txt' );
119
120 ok( !defined($iter), 'Iterator should be null' );
121 like( $error_handler_message, qr/\QUnable to open flargle-bargle.txt/, "Proper error message" );
122 }
123
124
125 FROM_OK_FILE_BUT_MISSING_WITH_WARNING_HANDLER: {
126 my $warning_handler_message;
127 my $warning_handler = sub { $warning_handler_message = shift; };
128
129 my $tempfile = File::Temp->new(TEMPLATE => 'XXXXXXXXXX');
130 File::Copy::copy('t/filelist.txt', $tempfile);
131 print {$tempfile} "t/non-existent-file.txt\n";
132 $tempfile->close;
133
134 my $iter = File::Next::from_file( { warning_handler => $warning_handler }, $tempfile->filename );
135 isa_ok( $iter, 'CODE' );
136
137 my @actual = slurp( $iter );
138 sets_match( \@actual, \@expected, 'FROM_FILESYSTEM_FILE' );
139
140 like( $warning_handler_message, qr/\Qt\/non-existent-file.txt/, "Proper warning message" );
141 }