File Coverage

blib/lib/Dist/Zilla/Plugin/Git/GatherDir.pm
Criterion Covered Total %
statement 15 19 78.9
branch 0 6 0.0
condition 0 3 0.0
subroutine 5 6 83.3
pod n/a
total 20 34 58.8


line stmt bran cond sub pod time code
1             #
2             # This file is part of Dist-Zilla-Plugin-Git
3             #
4             # This software is copyright (c) 2009 by Jerome Quelin.
5             #
6             # This is free software; you can redistribute it and/or modify it under
7             # the same terms as the Perl 5 programming language system itself.
8             #
9             package Dist::Zilla::Plugin::Git::GatherDir;
10             # ABSTRACT: Gather all tracked files in a Git working directory
11              
12             our $VERSION = '2.046';
13              
14 2     2   2955912 use Moose;
  2         7  
  2         19  
15             extends 'Dist::Zilla::Plugin::GatherDir' => { -version => 4.200016 }; # exclude_match
16              
17             #pod =head1 SYNOPSIS
18             #pod
19             #pod In your F<dist.ini>:
20             #pod
21             #pod [Git::GatherDir]
22             #pod root = . ; this is the default
23             #pod prefix = ; this is the default
24             #pod include_dotfiles = 0 ; this is the default
25             #pod include_untracked = 0 ; this is the default
26             #pod exclude_filename = dir/skip ; there is no default
27             #pod exclude_match = ^local_ ; there is no default
28             #pod
29             #pod =head1 DESCRIPTION
30             #pod
31             #pod This is a trivial variant of the L<GatherDir|Dist::Zilla::Plugin::GatherDir>
32             #pod plugin. It looks in the directory named in the L</root> attribute and adds all
33             #pod the Git tracked files it finds there (as determined by C<git ls-files>). If the
34             #pod root begins with a tilde, the tilde portion is passed through C<glob()> first.
35             #pod
36             #pod Most users just need:
37             #pod
38             #pod [Git::GatherDir]
39             #pod
40             #pod ...and this will pick up all tracked files from the current directory into the
41             #pod dist. You can use it multiple times, as you can any other plugin, by providing
42             #pod a plugin name. For example, if you want to include external specification
43             #pod files into a subdir of your dist, you might write:
44             #pod
45             #pod [Git::GatherDir]
46             #pod ; this plugin needs no config and gathers most of your files
47             #pod
48             #pod [Git::GatherDir / SpecFiles]
49             #pod ; this plugin gets all tracked files in the root dir and adds them under ./spec
50             #pod root = ~/projects/my-project/spec
51             #pod prefix = spec
52             #pod
53             #pod =cut
54              
55 2     2   14578 use List::Util 1.45 qw(uniq);
  2         60  
  2         163  
56 2     2   1355 use Types::Standard 'Bool';
  2         172030  
  2         22  
57              
58 2     2   1876 use namespace::autoclean;
  2         6  
  2         25  
59              
60             #pod =attr root
61             #pod
62             #pod This is the directory in which to look for files. If not given, it defaults to
63             #pod the dist root -- generally, the place where your F<dist.ini> or other
64             #pod configuration file is located. It may begin with C<~> (or C<~user>)
65             #pod to mean your (or some other user's) home directory. If a relative path,
66             #pod it's relative to the dist root. It does not need to be the root of a
67             #pod Git repository, but it must be inside a repository.
68             #pod
69             #pod =attr prefix
70             #pod
71             #pod This parameter can be set to gather all the files found under a common
72             #pod directory. See the L<description|DESCRIPTION> above for an example.
73             #pod
74             #pod =attr include_dotfiles
75             #pod
76             #pod By default, files will not be included if they begin with a dot. This goes
77             #pod both for files and for directories relative to the C<root>.
78             #pod
79             #pod In almost all cases, the default value (false) is correct.
80             #pod
81             #pod =attr include_untracked
82             #pod
83             #pod By default, files not tracked by Git will not be gathered. If this is
84             #pod set to a true value, then untracked files not covered by a Git ignore
85             #pod pattern (i.e. those reported by C<git ls-files -o --exclude-standard>)
86             #pod are also gathered (and you'll probably want to use
87             #pod L<Git::Check|Dist::Zilla::Plugin::Git::Check> to ensure all files are
88             #pod checked in before a release).
89             #pod
90             #pod C<include_untracked> requires at least Git 1.5.4, but you should
91             #pod probably not use it if your Git is older than 1.6.5.2. Versions
92             #pod before that would not list files matched by your F<.gitignore>, even
93             #pod if they were already being tracked by Git (which means they will not
94             #pod be gathered, even though they should be). Whether that is a problem
95             #pod depends on the contents of your exclude files (including the global
96             #pod one, if any).
97             #pod
98             #pod =attr follow_symlinks
99             #pod
100             #pod Git::GatherDir does not honor GatherDir's
101             #pod L<follow_symlinks|Dist::Zilla::Plugin::GatherDir/follow_symlinks>
102             #pod option. While the attribute exists (because Git::GatherDir is a
103             #pod subclass), setting it has no effect.
104             #pod
105             #pod Directories that are symlinks will not be gathered. Instead, you'll
106             #pod get a message saying C<WARNING: %s is symlink to directory, skipping it>.
107             #pod To suppress the warning, add that directory to C<exclude_filename> or
108             #pod C<exclude_match>. To gather the files in the symlinked directory, use
109             #pod a second instance of GatherDir or Git::GatherDir with appropriate
110             #pod C<root> and C<prefix> options.
111             #pod
112             #pod Files which are symlinks are always gathered.
113             #pod
114             #pod =attr exclude_filename
115             #pod
116             #pod To exclude certain files from being gathered, use the C<exclude_filename>
117             #pod option. This may be used multiple times to specify multiple files to exclude.
118             #pod
119             #pod =attr exclude_match
120             #pod
121             #pod This is just like C<exclude_filename> but provides a regular expression
122             #pod pattern. Files matching the pattern are not gathered. This may be used
123             #pod multiple times to specify multiple patterns to exclude.
124             #pod
125             #pod =cut
126              
127             has include_untracked => (
128             is => 'ro',
129             isa => Bool,
130             default => 0,
131             );
132              
133             around dump_config => sub
134             {
135             my $orig = shift;
136             my $self = shift;
137              
138             my $config = $self->$orig;
139              
140             $config->{+__PACKAGE__} = {
141             include_untracked => $self->include_untracked ? 1 : 0,
142             blessed($self) ne __PACKAGE__ ? ( version => $VERSION ) : (),
143             };
144              
145             return $config;
146             };
147              
148             override gather_files => sub {
149             my ($self) = @_;
150              
151             require Git::Wrapper;
152             require Path::Tiny;
153              
154             my $root = '' . $self->root;
155              
156             # Convert ~ portion to real directory:
157             $root =~ s{^(~[^\\/]*)([\\/])}{$self->_homedir($1) . $2}e;
158              
159             $root = Path::Tiny::path($root)->absolute($self->zilla->root);
160              
161             # Prepare to gather files
162             my $git = Git::Wrapper->new($root->stringify);
163              
164             my @opts;
165             @opts = qw(--cached --others --exclude-standard) if $self->include_untracked;
166              
167             my $exclude_regex = qr/\000/;
168             $exclude_regex = qr/$exclude_regex|$_/
169             for (@{ $self->exclude_match });
170              
171             my %is_excluded = map {; $_ => 1 } @{ $self->exclude_filename };
172              
173             my $prefix = $self->prefix;
174              
175             # Loop over files reported by git ls-files
176             for my $filename (uniq $git->ls_files(@opts)) {
177             # $file is a Path::Tiny relative to $root
178             my $file = Path::Tiny::path($filename);
179              
180             $self->log_debug("considering $file");
181              
182             # Exclusion tests
183             unless ($self->include_dotfiles) {
184             next if grep { /^\./ } split q{/}, $file->stringify;
185             }
186              
187             next if $file =~ $exclude_regex;
188             next if $is_excluded{ $file };
189              
190             # DZil can't gather directory symlinks
191             my $path = $root->child($file);
192              
193             if (-d $path) {
194             $self->log("WARNING: $file is symlink to directory, skipping it");
195             next;
196             }
197              
198             # Gather the file
199             my $fileobj = $self->_file_from_filename($path->stringify);
200              
201             $file = Path::Tiny::path($prefix, $file) if length $prefix;
202              
203             $fileobj->name($file->stringify);
204             $self->add_file($fileobj);
205             $self->log_debug("gathered $file");
206             }
207              
208             return;
209             };
210              
211             sub _homedir {
212 0     0     my ($self, $tilde_dir) = @_;
213              
214             # other architectures have no issue with globbing any kind of ~user path
215 0 0         return (glob($tilde_dir))[0] if $^O ne 'Win32';
216              
217             # on Win32, we can use the environment variable(s) for the current user
218 0 0 0       return "$]" < '5.016' ? $ENV{HOME} || $ENV{USERPROFILE} : (glob('~'))[0]
    0          
219             if $tilde_dir eq '~';
220              
221             # but otherwise, we can't support this at all, on any version.
222 0           $self->log_fatal('expanding "' . $tilde_dir . '" on Win32 not supported');
223             }
224              
225             __PACKAGE__->meta->make_immutable;
226 2     2   1499 no Moose;
  2         9  
  2         23  
227             1;
228              
229             __END__
230              
231             =pod
232              
233             =encoding UTF-8
234              
235             =head1 NAME
236              
237             Dist::Zilla::Plugin::Git::GatherDir - Gather all tracked files in a Git working directory
238              
239             =head1 VERSION
240              
241             version 2.046
242              
243             =head1 SYNOPSIS
244              
245             In your F<dist.ini>:
246              
247             [Git::GatherDir]
248             root = . ; this is the default
249             prefix = ; this is the default
250             include_dotfiles = 0 ; this is the default
251             include_untracked = 0 ; this is the default
252             exclude_filename = dir/skip ; there is no default
253             exclude_match = ^local_ ; there is no default
254              
255             =head1 DESCRIPTION
256              
257             This is a trivial variant of the L<GatherDir|Dist::Zilla::Plugin::GatherDir>
258             plugin. It looks in the directory named in the L</root> attribute and adds all
259             the Git tracked files it finds there (as determined by C<git ls-files>). If the
260             root begins with a tilde, the tilde portion is passed through C<glob()> first.
261              
262             Most users just need:
263              
264             [Git::GatherDir]
265              
266             ...and this will pick up all tracked files from the current directory into the
267             dist. You can use it multiple times, as you can any other plugin, by providing
268             a plugin name. For example, if you want to include external specification
269             files into a subdir of your dist, you might write:
270              
271             [Git::GatherDir]
272             ; this plugin needs no config and gathers most of your files
273              
274             [Git::GatherDir / SpecFiles]
275             ; this plugin gets all tracked files in the root dir and adds them under ./spec
276             root = ~/projects/my-project/spec
277             prefix = spec
278              
279             =head1 ATTRIBUTES
280              
281             =head2 root
282              
283             This is the directory in which to look for files. If not given, it defaults to
284             the dist root -- generally, the place where your F<dist.ini> or other
285             configuration file is located. It may begin with C<~> (or C<~user>)
286             to mean your (or some other user's) home directory. If a relative path,
287             it's relative to the dist root. It does not need to be the root of a
288             Git repository, but it must be inside a repository.
289              
290             =head2 prefix
291              
292             This parameter can be set to gather all the files found under a common
293             directory. See the L<description|DESCRIPTION> above for an example.
294              
295             =head2 include_dotfiles
296              
297             By default, files will not be included if they begin with a dot. This goes
298             both for files and for directories relative to the C<root>.
299              
300             In almost all cases, the default value (false) is correct.
301              
302             =head2 include_untracked
303              
304             By default, files not tracked by Git will not be gathered. If this is
305             set to a true value, then untracked files not covered by a Git ignore
306             pattern (i.e. those reported by C<git ls-files -o --exclude-standard>)
307             are also gathered (and you'll probably want to use
308             L<Git::Check|Dist::Zilla::Plugin::Git::Check> to ensure all files are
309             checked in before a release).
310              
311             C<include_untracked> requires at least Git 1.5.4, but you should
312             probably not use it if your Git is older than 1.6.5.2. Versions
313             before that would not list files matched by your F<.gitignore>, even
314             if they were already being tracked by Git (which means they will not
315             be gathered, even though they should be). Whether that is a problem
316             depends on the contents of your exclude files (including the global
317             one, if any).
318              
319             =head2 follow_symlinks
320              
321             Git::GatherDir does not honor GatherDir's
322             L<follow_symlinks|Dist::Zilla::Plugin::GatherDir/follow_symlinks>
323             option. While the attribute exists (because Git::GatherDir is a
324             subclass), setting it has no effect.
325              
326             Directories that are symlinks will not be gathered. Instead, you'll
327             get a message saying C<WARNING: %s is symlink to directory, skipping it>.
328             To suppress the warning, add that directory to C<exclude_filename> or
329             C<exclude_match>. To gather the files in the symlinked directory, use
330             a second instance of GatherDir or Git::GatherDir with appropriate
331             C<root> and C<prefix> options.
332              
333             Files which are symlinks are always gathered.
334              
335             =head2 exclude_filename
336              
337             To exclude certain files from being gathered, use the C<exclude_filename>
338             option. This may be used multiple times to specify multiple files to exclude.
339              
340             =head2 exclude_match
341              
342             This is just like C<exclude_filename> but provides a regular expression
343             pattern. Files matching the pattern are not gathered. This may be used
344             multiple times to specify multiple patterns to exclude.
345              
346             =for Pod::Coverage gather_dir
347             gather_files
348              
349             =head1 SUPPORT
350              
351             Bugs may be submitted through L<the RT bug tracker|https://rt.cpan.org/Public/Dist/Display.html?Name=Dist-Zilla-Plugin-Git>
352             (or L<bug-Dist-Zilla-Plugin-Git@rt.cpan.org|mailto:bug-Dist-Zilla-Plugin-Git@rt.cpan.org>).
353              
354             There is also a mailing list available for users of this distribution, at
355             L<http://dzil.org/#mailing-list>.
356              
357             There is also an irc channel available for users of this distribution, at
358             L<C<#distzilla> on C<irc.perl.org>|irc://irc.perl.org/#distzilla>.
359              
360             =head1 AUTHOR
361              
362             Jerome Quelin
363              
364             =head1 COPYRIGHT AND LICENCE
365              
366             This software is copyright (c) 2009 by Jerome Quelin.
367              
368             This is free software; you can redistribute it and/or modify it under
369             the same terms as the Perl 5 programming language system itself.
370              
371             =cut