2 # ------------------------------------------------------------
3 # This script fixes the license headers of all Java sources
4 # to use the Eclipse EDL license template and updates the
5 # copyright statements using author information from git blame
7 # To fix this in all revisions rewrite the history
8 # git filter-branch --tree-filter 'fixHeaders.pl' HEAD
9 # ------------------------------------------------------------
12 # Table of author names, start date, end date, actual copyright owner.
14 my @author_employers = (
15 [ qr/spearce\@spearce.org/, 2008, 8, 9999, 12, 'Google Inc.'],
17 [ qr/\@(.*\.|)google.com/, 0, 0, 9999, 12, 'Google Inc.'],
20 # License text itself.
22 my $license_text = <<'EOF';
23 and other copyright owners as documented in the project's IP log.
25 This program and the accompanying materials are made available
26 under the terms of the Eclipse Distribution License v1.0 which
27 accompanies this distribution, is reproduced below, and is
28 available at http://www.eclipse.org/org/documents/edl-v10.php
32 Redistribution and use in source and binary forms, with or
33 without modification, are permitted provided that the following
36 - Redistributions of source code must retain the above copyright
37 notice, this list of conditions and the following disclaimer.
39 - Redistributions in binary form must reproduce the above
40 copyright notice, this list of conditions and the following
41 disclaimer in the documentation and/or other materials provided
42 with the distribution.
44 - Neither the name of the Eclipse Foundation, Inc. nor the
45 names of its contributors may be used to endorse or promote
46 products derived from this software without specific prior
49 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
50 CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
51 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
52 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
54 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
55 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
56 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
57 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
58 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
59 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
60 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
61 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
66 open( F
, '-|', 'git ls-files' );
73 if (/\.java$/ || $_ eq 'LICENSE') {
74 next if $_ eq 'org.eclipse.jgit/src/org/eclipse/jgit/util/Base64.java';
75 update_file
(\
&java_file
, $_);
77 } elsif (/pom\.xml$/) {
78 update_file
(\
&pom_file
, $_);
81 update_file
(\
&sh_file
, $_);
91 # header is everything before package statement
100 # preamble is everything with blanks or imports
103 last unless (/^import / || /^$/);
107 return ($header, $preamble, $lineno,
108 "/*\n", sub { s
/^/ */mg }, " */\n");
117 # header is everything before project
127 return ($header, $preamble, $lineno,
128 qq{<?xml version
="1.0" encoding
="UTF-8"?
>\n<!--\n},
129 sub { s/^(.)/ $1/mg },
150 return ($header, $preamble, $lineno, $top, sub { s/^/#/mg }, "");
156 my $old_file = shift;
157 my $new_file = "$old_file.license.$$";
159 open(I
, '<', $old_file);
160 my ($header, $preamble, $lineno,
161 $top, $fmt, $btm) = &{$func}(\
*I
);
168 # find explicit copyright statements in sources
169 my @lines = split( /\n/, $header );
170 foreach my $line ( @lines ) {
171 # * Copyright (c) 2008, Example Company Inc.
172 # * Copyright (c) 2008, Joe Developer <joe.dev@example.org>
173 # * Copyright (c) 2008, 2009 Joe Developer <joe.dev@example.org>
174 # * Copyright (c) 2005-2009 Joe Developer <joe.dev@example.org>
175 # * Copyright (c) 2008, 2009 Other Examples Inc.
176 # * Copyright (c) 2008-2010 Example Company Inc.
177 # * Copyright (C) 2009-2010, Yet More Examples Ltd.
178 if( $line =~ m/Copyright \(c\) (\d{4})(?:\s*[,-]\s*(\d{4}))?,?\s*([^<>]+)\s*(<.*?>)?/i ) {
179 my ($y, $y2, $n, $e) = ($1, $2, $3, $4);
181 my $author_name = trim
($n);
182 my $author_email = trim
($e);
183 my $who = $author_name;
184 $who .= " $author_email" if $author_email;
185 update_author_info
(\
%minyear, \
%maxyear, \
%all_years, \
%author_years, $who, $year);
186 if (my $year2 = $y2) {
187 update_author_info
(\
%minyear, \
%maxyear, \
%all_years, \
%author_years, $who, $year2);
192 if ($old_file eq 'LICENSE') {
194 # add implicit copyright statements from authors found in git blame
195 my (%line_counts, %line_authors);
196 my ($last_commit, $author_name, $author_email);
197 my @blame_args = ('git', 'blame', "-L$lineno,", '-C', '-w', '-p');
198 push(@blame_args, $ENV{'GIT_COMMIT'}) if $ENV{'GIT_COMMIT'};
199 push(@blame_args, '--', $old_file);
200 open( B
, '-|', @blame_args);
203 if (/^([0-9a-f]{40}) \d+ \d+ (\d+)$/) {
205 $line_counts{$1} += $2;
208 if (/^author (.*)$/) {
209 $author_name = trim
($1);
212 if (/^author-mail (<.*>)$/) {
213 $author_email = trim
($1);
216 if (/^author-time (\d+)$/) {
217 # skip uncommitted changes
218 my $who = "$author_name $author_email";
219 next if $who eq 'Not Committed Yet <not.committed.yet>';
220 my @tm = localtime($1);
221 my $year = $tm[5] + 1900;
222 my $mon = $tm[4] + 1;
223 $who = translate_author
($who, $year, $mon);
224 $line_authors{$last_commit} = [$who, $year, $mon];
229 my %author_linecounts;
230 foreach $last_commit (keys %line_counts) {
231 my $who = $line_authors{$last_commit}[0];
233 $author_linecounts{$who} += $line_counts{$last_commit};
238 foreach (values %author_linecounts) {
239 $count_big++ if $_ >= $sz;
243 foreach (values %line_authors) {
244 my ($who, $year, $mon) = @
$_;
245 next if ($count_big && $author_linecounts{$who} < $sz);
246 $all_years{$year} = 1;
247 update_author_info
(\
%minyear, \
%maxyear, \
%all_years, \
%author_years, $who, $year, $mon);
252 open( O
, '>', $new_file );
256 foreach my $year ( sort { $a cmp $b } keys %all_years ) {
257 foreach my $who ( sort keys %author_years ) {
258 next if $used_author{$who}++;
259 local $_ = format_copyright
($minyear{$who}, $maxyear{$who}, $who);
265 local $_ = $license_text;
275 rename( $new_file, $old_file );
286 sub update_author_info
288 my ($minyear_ref, $maxyear_ref, $all_years_ref, $author_years_ref, $who, $year, $mon) = @_;
290 $who = translate_author
($who, $year, $mon);
291 $all_years_ref->{$year} = 1;
292 $author_years_ref->{$who}{$year} = 1;
294 my $y = $minyear_ref->{$who};
299 $minyear_ref->{$who} = $year;
301 $y = $maxyear_ref->{$who};
303 $maxyear_ref->{$who} = $year;
309 my ($a_year, $a_mon, $b_year, $b_mon) = @_;
311 if ($a_year < $b_year) {
313 } elsif ($a_year == $b_year) {
314 return ($a_mon <=> $b_mon);
322 my ($who, $year, $mon) = @_;
324 return $who if not defined $mon;
326 foreach my $spec (@author_employers) {
327 next unless $who =~ $spec->[0];
328 next if (date_cmp
($year, $mon, $spec->[1], $spec->[2]) < 0);
329 next if (date_cmp
($year, $mon, $spec->[3], $spec->[4]) > 0);
335 sub format_copyright
{
336 my ($minyear, $maxyear, $who) = @_;
337 if ($minyear < $maxyear) {
338 return " Copyright (C) $minyear-$maxyear, $who\n";
340 return " Copyright (C) $minyear, $who\n";