| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Dist::Zilla::Plugin::AuthorsFromGit; |
|
2
|
|
|
|
|
|
|
# ABSTRACT: Add per-file per-year copyright info to each Perl document |
|
3
|
|
|
|
|
|
|
$Dist::Zilla::Plugin::AuthorsFromGit::VERSION = '0.007'; |
|
4
|
1
|
|
|
1
|
|
2423
|
use Git::Wrapper; |
|
|
1
|
|
|
|
|
28285
|
|
|
|
1
|
|
|
|
|
38
|
|
|
5
|
1
|
|
|
1
|
|
2060
|
use DateTime; |
|
|
1
|
|
|
|
|
463281
|
|
|
|
1
|
|
|
|
|
60
|
|
|
6
|
1
|
|
|
1
|
|
10
|
use List::MoreUtils 0.4 qw(uniq sort_by true); |
|
|
1
|
|
|
|
|
30
|
|
|
|
1
|
|
|
|
|
9
|
|
|
7
|
|
|
|
|
|
|
|
|
8
|
1
|
|
|
1
|
|
770
|
use Moose; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
10
|
|
|
9
|
|
|
|
|
|
|
with( |
|
10
|
|
|
|
|
|
|
'Dist::Zilla::Role::FileMunger', |
|
11
|
|
|
|
|
|
|
'Dist::Zilla::Role::FileFinderUser' => { |
|
12
|
|
|
|
|
|
|
default_finders => [ ':InstallModules', ':ExecFiles' ], |
|
13
|
|
|
|
|
|
|
}, |
|
14
|
|
|
|
|
|
|
); |
|
15
|
|
|
|
|
|
|
|
|
16
|
1
|
|
|
1
|
|
6658
|
use namespace::autoclean; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
8
|
|
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
sub getblacklist { |
|
20
|
0
|
0
|
|
0
|
0
|
|
open ( my $lf, '<', '.copyright-exclude' ) or return ( ); |
|
21
|
0
|
|
|
|
|
|
my @lines=<$lf>; |
|
22
|
0
|
|
|
|
|
|
chomp @lines; |
|
23
|
0
|
|
|
|
|
|
return @lines; |
|
24
|
|
|
|
|
|
|
}; |
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
sub gitauthorlist { |
|
28
|
0
|
|
|
0
|
0
|
|
my ($file, $git)= @_; |
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
# Switching the warning off when the code works nicely is safer than rewriting |
|
31
|
|
|
|
|
|
|
# the logic to suppress a harmless warning. |
|
32
|
1
|
|
|
1
|
|
188
|
no warnings 'uninitialized'; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
529
|
|
|
33
|
|
|
|
|
|
|
|
|
34
|
0
|
|
|
|
|
|
my @log_lines = $git->RUN('log', '--follow', '-M75%', '--format=%H %at %aN', '--', $file->name); |
|
35
|
0
|
|
|
|
|
|
my @outputlines; |
|
36
|
0
|
|
|
|
|
|
push @outputlines, ""; |
|
37
|
|
|
|
|
|
|
|
|
38
|
0
|
0
|
|
|
|
|
if (@log_lines) { |
|
39
|
|
|
|
|
|
|
|
|
40
|
0
|
|
|
|
|
|
my $earliest_year=3000; |
|
41
|
0
|
|
|
|
|
|
my $latest_year=0; |
|
42
|
0
|
|
|
|
|
|
my %authordata; |
|
43
|
|
|
|
|
|
|
my %authorline; |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
# Get the commit blacklist to ignore |
|
46
|
0
|
|
|
|
|
|
my @blacklist=getblacklist(); |
|
47
|
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
# Extract the author data and separate by year |
|
49
|
0
|
|
|
|
|
|
foreach ( @log_lines ) { |
|
50
|
|
|
|
|
|
|
|
|
51
|
0
|
|
|
|
|
|
my @fields=split(/ /,$_,3); |
|
52
|
0
|
|
|
|
|
|
my $commit=$fields[0]; |
|
53
|
0
|
|
|
|
|
|
my $when=DateTime->from_epoch(epoch => $fields[1]); |
|
54
|
0
|
|
|
|
|
|
my $year=$when->year(); |
|
55
|
0
|
|
|
|
|
|
my $author=$fields[2]; |
|
56
|
|
|
|
|
|
|
|
|
57
|
0
|
|
|
0
|
|
|
my $count = true { /$commit/ } @blacklist; |
|
|
0
|
|
|
|
|
|
|
|
58
|
0
|
0
|
|
|
|
|
if ( $count >= 1 ) { next; }; |
|
|
0
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
|
|
60
|
0
|
0
|
|
|
|
|
if ($year < $earliest_year) { $earliest_year=$year; }; |
|
|
0
|
|
|
|
|
|
|
|
61
|
0
|
0
|
|
|
|
|
if ($year > $latest_year) { $latest_year=$year; }; |
|
|
0
|
|
|
|
|
|
|
|
62
|
0
|
0
|
|
|
|
|
if ( $author ne "unknown" ) { push(@{$authordata{$year}}, $author); }; |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
}; |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
# Remove duplicates within a year, sort and transform to string |
|
66
|
0
|
|
|
|
|
|
foreach my $year (keys %authordata) { |
|
67
|
|
|
|
|
|
|
|
|
68
|
0
|
|
|
|
|
|
my @un=uniq(@{$authordata{$year}}); |
|
|
0
|
|
|
|
|
|
|
|
69
|
0
|
|
|
0
|
|
|
$authorline{$year}=join(', ',sort_by { $_ } @un); |
|
|
0
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
}; |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
# Now deduplicate the years |
|
74
|
0
|
|
|
|
|
|
push @outputlines, " Copyright $earliest_year ".$authorline{$earliest_year}; |
|
75
|
|
|
|
|
|
|
|
|
76
|
0
|
|
|
|
|
|
for ( my $year=$earliest_year+1; $year<=$latest_year; $year++) { |
|
77
|
|
|
|
|
|
|
|
|
78
|
0
|
0
|
0
|
|
|
|
if ( (defined $authorline{$year}) && (defined $authorline{$year-1}) ) { |
|
|
|
0
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
|
|
80
|
0
|
0
|
|
|
|
|
if ($authorline{$year-1} eq $authorline{$year}) { |
|
81
|
|
|
|
|
|
|
|
|
82
|
0
|
|
|
|
|
|
my $lastline=$outputlines[-1]; |
|
83
|
0
|
|
|
|
|
|
$lastline=~ s/([0-9]{4})[\- ][0-9 ]{4}/$1-$year/; |
|
84
|
0
|
|
|
|
|
|
$outputlines[-1]=$lastline; |
|
85
|
|
|
|
|
|
|
} else { |
|
86
|
0
|
|
|
|
|
|
push @outputlines, " $year ".$authorline{$year}; |
|
87
|
|
|
|
|
|
|
}; |
|
88
|
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
} elsif ( defined $authorline{$year} ) { |
|
90
|
|
|
|
|
|
|
|
|
91
|
0
|
|
|
|
|
|
push @outputlines, " $year ".$authorline{$year}; |
|
92
|
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
}; |
|
94
|
|
|
|
|
|
|
}; |
|
95
|
0
|
|
|
|
|
|
push @outputlines, ""; |
|
96
|
|
|
|
|
|
|
}; |
|
97
|
|
|
|
|
|
|
|
|
98
|
1
|
|
|
1
|
|
7
|
use warnings 'uninitialized'; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
557
|
|
|
99
|
|
|
|
|
|
|
|
|
100
|
0
|
|
|
|
|
|
return @outputlines; |
|
101
|
|
|
|
|
|
|
} |
|
102
|
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
sub munge_files { |
|
104
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
|
105
|
0
|
|
|
|
|
|
my $myv="git"; |
|
106
|
0
|
0
|
|
|
|
|
if ( defined $Dist::Zilla::Plugin::AuthorsFromGit::VERSION ) { $myv=$Dist::Zilla::Plugin::AuthorsFromGit::VERSION; }; |
|
|
0
|
|
|
|
|
|
|
|
107
|
0
|
|
|
|
|
|
$self->log([ 'extracting Git commit information, plugin version %s', $myv ]); |
|
108
|
0
|
|
|
|
|
|
my $git = Git::Wrapper->new("."); |
|
109
|
|
|
|
|
|
|
|
|
110
|
0
|
|
|
|
|
|
$self->munge_file($_, $git) for @{ $self->found_files }; |
|
|
0
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
} |
|
112
|
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
sub munge_file { |
|
114
|
0
|
|
|
0
|
0
|
|
my ($self, $file, $git) = @_; |
|
115
|
|
|
|
|
|
|
|
|
116
|
0
|
|
|
|
|
|
my @gal=gitauthorlist($file,$git); |
|
117
|
|
|
|
|
|
|
|
|
118
|
0
|
|
|
|
|
|
return $self->munge_pod($file, @gal); |
|
119
|
|
|
|
|
|
|
} |
|
120
|
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
sub munge_pod { |
|
122
|
0
|
|
|
0
|
0
|
|
my ($self, $file, @gal) = @_; |
|
123
|
|
|
|
|
|
|
|
|
124
|
0
|
|
|
|
|
|
my @content = split /\n/, $file->content; |
|
125
|
|
|
|
|
|
|
|
|
126
|
0
|
|
|
|
|
|
require List::Util; |
|
127
|
0
|
|
|
|
|
|
List::Util->VERSION('1.33'); |
|
128
|
|
|
|
|
|
|
|
|
129
|
0
|
|
|
|
|
|
for (0 .. $#content) { |
|
130
|
0
|
|
|
|
|
|
next until $content[$_] =~ /^=head1 COPYRIGHT AND LICENSE/; |
|
131
|
|
|
|
|
|
|
|
|
132
|
0
|
|
|
|
|
|
$_++; # move past the =head1 line itself |
|
133
|
0
|
|
|
|
|
|
$_++; # and past the subsequent empty line |
|
134
|
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
# Now we should have a line looking like |
|
136
|
|
|
|
|
|
|
# |
|
137
|
|
|
|
|
|
|
# "This software is copyright ... , see the git log." |
|
138
|
|
|
|
|
|
|
# |
|
139
|
|
|
|
|
|
|
# The string ", see the git log." is used as magic to trigger the plugin. |
|
140
|
|
|
|
|
|
|
# We check this format, replace ", see the git log.", |
|
141
|
|
|
|
|
|
|
# and insert the git information afterwards. |
|
142
|
|
|
|
|
|
|
|
|
143
|
0
|
0
|
|
|
|
|
if ($content[$_] =~ /^This software is copyright.*, see the git log\.$/ ) { |
|
144
|
|
|
|
|
|
|
|
|
145
|
0
|
|
|
|
|
|
$content[$_] =~ s/, see the git log\.$/; in detail:/; |
|
146
|
0
|
|
|
|
|
|
splice @content, $_+1, 0, @gal; |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
}; |
|
149
|
|
|
|
|
|
|
|
|
150
|
0
|
|
|
|
|
|
my $content = join "\n", @content; |
|
151
|
0
|
0
|
|
|
|
|
$content .= "\n" if length $content; |
|
152
|
0
|
|
|
|
|
|
$file->content($content); |
|
153
|
0
|
|
|
|
|
|
return; |
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
} |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
} |
|
158
|
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable; |
|
160
|
|
|
|
|
|
|
1; |
|
161
|
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
#pod =head1 SEE ALSO |
|
163
|
|
|
|
|
|
|
#pod |
|
164
|
|
|
|
|
|
|
#pod L<PkgVersion|Dist::Zilla::Plugin::PodVersion>, |
|
165
|
|
|
|
|
|
|
#pod L<PkgVersion|Git::Wrapper>, |
|
166
|
|
|
|
|
|
|
#pod L<PkgVersion|Lab::Measurement> for an application example |
|
167
|
|
|
|
|
|
|
#pod |
|
168
|
|
|
|
|
|
|
#pod =cut |
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
__END__ |
|
171
|
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
=pod |
|
173
|
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
=encoding UTF-8 |
|
175
|
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
=head1 NAME |
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
Dist::Zilla::Plugin::AuthorsFromGit - Add per-file per-year copyright info to each Perl document |
|
179
|
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
=head1 VERSION |
|
181
|
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
version 0.007 |
|
183
|
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
185
|
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
In dist.ini, set |
|
187
|
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
copyright_holder = the Foo-Bar team, see the git log |
|
189
|
|
|
|
|
|
|
; [...] |
|
190
|
|
|
|
|
|
|
[PodWeaver] |
|
191
|
|
|
|
|
|
|
[AuthorsFromGit] |
|
192
|
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
In weaver.ini, set |
|
194
|
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
[@NoAuthor] |
|
196
|
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
Then a copyright section in each module is created as follows: |
|
198
|
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
COPYRIGHT AND LICENSE |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
This software is copyright (c) 2017 by the Foo-Bar team; in detail: |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
Copyright 2014-2015 A. N. Author |
|
204
|
|
|
|
|
|
|
2016 A. N. Author, O. Th. Erautor |
|
205
|
|
|
|
|
|
|
2017 O. Th. Erautor |
|
206
|
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
with names and years extracted from the Git commit log of the specific module. |
|
208
|
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
210
|
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
This Dist::Zilla plugin is intended for large Perl distributions that have been |
|
212
|
|
|
|
|
|
|
existing for some time, where maintainership has changed over the years, and |
|
213
|
|
|
|
|
|
|
where different people have contributed to different parts of the code. It |
|
214
|
|
|
|
|
|
|
provides a means to acknowledge the contribution of different people to |
|
215
|
|
|
|
|
|
|
different modules, where it is not possible to resonably list them all in the |
|
216
|
|
|
|
|
|
|
authors field of the entire distribution. |
|
217
|
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
This is also to reflect that, independent of the chosen license terms, anyone |
|
219
|
|
|
|
|
|
|
who contributes nontrivial code to an open source package retains copyright of |
|
220
|
|
|
|
|
|
|
the contribution. Some legislatures (e.g. Germany) even provide no way of |
|
221
|
|
|
|
|
|
|
"transferring" copyright, since it is always bound to the natural person who |
|
222
|
|
|
|
|
|
|
conceived the code. |
|
223
|
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
=head1 USAGE |
|
225
|
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
Here, the usage in conjunction with the PodWeaver plugin is described. It should |
|
227
|
|
|
|
|
|
|
be possible to use this module without it, but I haven't tested that yet. We |
|
228
|
|
|
|
|
|
|
also assume that your working directory is a Git clone. |
|
229
|
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
Assuming your distribution is called Foo-Bar, in dist.ini, then set |
|
231
|
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
copyright_holder = the Foo-Bar team, see the git log |
|
233
|
|
|
|
|
|
|
; [...] |
|
234
|
|
|
|
|
|
|
[PodWeaver] |
|
235
|
|
|
|
|
|
|
[AuthorsFromGit] |
|
236
|
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
The precise string ", see the git log" at the end of the copyright_holder line |
|
238
|
|
|
|
|
|
|
is important since it triggers this plugin. |
|
239
|
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
In case you do not have a weaver.ini yet, create one with the content |
|
241
|
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
[@NoAuthor] |
|
243
|
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
This is identical to the default plugin bundle of Pod-Weaver, just that it will |
|
245
|
|
|
|
|
|
|
not create a separate AUTHORS section. In case you already have a weaver.ini, |
|
246
|
|
|
|
|
|
|
make sure it does not generate any AUTHORS section. |
|
247
|
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
During the build process, Dist::Zilla will then run "git log" for each processed |
|
249
|
|
|
|
|
|
|
module and extract the list of authors of the module for each year. Then a |
|
250
|
|
|
|
|
|
|
copyright section in the POD of each module is created as follows: |
|
251
|
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
COPYRIGHT AND LICENSE |
|
253
|
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
This software is copyright (c) 2017 by the Foo::Bar team; in detail: |
|
255
|
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
Copyright 2014-2015 A. N. Author |
|
257
|
|
|
|
|
|
|
2016 A. N. Author, O. Th. Erautor |
|
258
|
|
|
|
|
|
|
2017 O. Th. Erautor |
|
259
|
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
=head1 CONFIGURATION |
|
261
|
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
Not much. |
|
263
|
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
=head2 Excluding commits |
|
265
|
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
In case you want to skip some commits which contain trivial, not |
|
267
|
|
|
|
|
|
|
copyright-relevant changes ("increase version number", "perltidy"), create |
|
268
|
|
|
|
|
|
|
a text file named .copyright-exclude in the main distribution directory. It |
|
269
|
|
|
|
|
|
|
should contain exactly one git commit hash per line, nothing else. |
|
270
|
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
Use with care, and only add your own commits! |
|
272
|
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
=head1 KNOWN BUGS |
|
274
|
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
There's something fishy with unicode. |
|
276
|
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
=head1 AUTHOR |
|
278
|
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
Andreas K. Huettel <dilfridge@gentoo.org> |
|
280
|
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
|
282
|
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
This software is copyright (c) 2017 by Andreas K. Huettel. |
|
284
|
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
|
286
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
|
287
|
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
=cut |