gecko-dev/webtools/whack-license/whack-license.pl

608 lines
17 KiB
Perl
Executable File

#!/usr/bin/perl -w
#
# whack-license.pl - look at a file, decide what version of the [MN]PL it
# has, if any, and optionally update that boilerplate text.
#
# Dan Mosedale
# dmose@mozilla.org
#
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (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.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is whack-license.pl.
#
# The Initial Developer of the Original Code is Netscape Communications
# Corp. Portions created by Netscape Communications Corp. are
# Copyright (C) 1999, Netscape Communications Corp. All
# Rights Reserved.
#
# Contributor(s): Dan Mosedale <dmose@mozilla.org>
#
#
# invocation options
#
# -c force a " */\n" to be added in after the license
# -d turn on debugging
# -g when updating, add the NPL/GPL alternate licensing clause
# -n don't actually write out any files.
# -q be quiet
# -u update any old licenses found
# -A string set the first part of the "Initial Developer" clause
# to "string" if one is not found in the original boilerplate
# (default is to fail for that file)
# -B string set the second part of the "Initial Developer" clause
# to "string" if one is not found in the original boilerplate
# (default is to fail for that file)
# -C string set the "created by" clause to "string" if one is not found
# in the original boilerplate (default is to fail for that file)
# -D string set the copyright dates clause to "string" if one is not found
# in the original boilerplate (defaults is to fail for that file)
# -E string set the "copyright by" clause to "string" if one is not found
# in the original boilerplate (defaults is to fail for that file)
#
# XXX - weird special cases to be dealt with by hand:
#
# directory/perldap/README, MPL-*.txt
# expat/expat.html
# extensions/transformiix
# network/cache/nu/tests/cb/nsTimeIt.h
# intl/lwbrk/tools/anzx4501.pl
# intl/lwbrk/src/jisx4501class.h
#
# some configurables
#
####################
#
# we've got ugly regexps, so here's where to turn on regexp debugging,
# if necessary
#
#use re 'debugcolor';
#
# regexp to use as a guess as to weather there's anything related to the
# licenses we care about at all
#
my $licGuessExp = '\W(M|N)PL\W';
#
# size, in bytes, of the buffer used to read in sources files for modification.
# this must be big enough to hold the entire license header and everything
# that precedes in it any given source file.
#
my $bufsiz = 10000;
#
# Files with these suffixes will be ignored and not checked.
#
my @IGNORESUFFIXES = ( "Entries", "GenToc", "GenJSLib",
"MacCVSLib", "MANIFESTOLib",
"Repository", "Root", "TestGenJSLib",
".a", ".bkp", ".bmp",
".class", "control", "core", ".cvsignore",
".dll", "edit.cgi", ".gif", ".jpg", ".mcp", "missing",
".o", ".png", ".pp", "release.txt",
".rsrc", ".so", ".spec",
".spec.in", ".timestamp", ".xpt" );
####################
# prerequisites
#
use Getopt::Std;
use strict;
# set up vars
#
use vars qw/$opt_c $opt_n $opt_q $opt_d $opt_u $opt_g $opt_A $opt_B $opt_C
$opt_D $opt_E/;
my @INFILE;
# parse the command line
#
getopts('cdgnquA:B:C:D:E:');
# do this for all requested files
#
foreach my $filename ( @ARGV ) {
my $foundGuess = 0;
my $foundUnique = "";
#
# skip files that end in a suffix listed in @IGNORESUFFIXES
#
next if ( grep
{ substr($filename, -1 * length($_) ) eq $_ }
@IGNORESUFFIXES );
# open the file and read it into an array
#
open(INFILE, $filename) || die "could not open $_";
@INFILE = <INFILE>;
# traverse the file, looking for a reference to the license
#
SCANFILE:
foreach ( @INFILE ) {
if ( /$licGuessExp/o ) {
$foundGuess = 1;
# traverse it again, looking for unique license text
#
foreach ( 0 .. $#INFILE ) {
if ( $INFILE[$_] =~ /Netscape Public License *\r?$/ &&
$INFILE[$_ + 1] =~
/^(.{0,10})Version 1\.0 *\(the ["'](License|NPL)['"]\)/ )
{
$foundUnique = "NPL 1.0";
last SCANFILE;
} elsif ( $INFILE[$_] =~ /Netscape Public *\r?$/ &&
$INFILE[$_ + 1] =~
/^(.{0,10})License Version 1\.1 *\(the ["'](License|NPL)['"]\)/
||
$INFILE[$_] =~ /Netscape Public License *\r?$/ &&
$INFILE[$_ + 1] =~
/^(.{0,10})Version 1\.1 *\(the ["'](License|NPL)['"]\)/
||
$INFILE[$_] =~ /Netscape Public License Version *$/ &&
$INFILE[$_ + 1] =~
/^(.{0,10})1\.1 *\(the ["'](License|NPL)['"]\)/
)
{
$foundUnique = "NPL 1.1";
last SCANFILE;
} elsif ( $INFILE[$_] =~ /Mozilla Public License *$/ &&
$INFILE[$_ + 1] =~
/^(.{0,10})Version 1\.0 *\(the ["'](License|MPL)['"]\)/ )
{
$foundUnique = "MPL 1.0";
last SCANFILE;
} elsif ( $INFILE[$_] =~ /Mozilla Public License *$/ &&
$INFILE[$_ + 1] =~
/^(.{0,10})Version 1\.1 *\(the ["'](License|MPL)['"]\)/
||
$INFILE[$_] =~ /Mozilla Public *$/ &&
$INFILE[$_ + 1] =~
q/^(.{0,10})License Version 1\.1 *\(the ["'](License|MPL)['"]\)/
)
{
$foundUnique = "MPL 1.1";
last SCANFILE;
}
}
last SCANFILE;
}
}
# tell the world what we found (unless we're being quiet)
#
if ( !$opt_q ) {
if ( $foundUnique ne "" ) {
print "$filename contains $foundUnique unique license text";
} elsif ( $foundGuess == 1 ) {
print "$filename mentions a relevant license, " .
"but is missing expected unique text";
} else {
print "$filename contains no relevant license reference";
}
}
# update the file (if invoked with -u)
#
if ( $opt_u && $foundUnique ) {
my $updated = 0; # did we actually update anything?
# go back to beginning of file
#
seek (INFILE, 0, 0) ||
die ("couldn't seek to beginning of $filename");
# read the file head into $buffer
#
read INFILE, my($buffer), $bufsiz;
die ("error reading from $filename")
if ( !defined($buffer));
# update
#
if ( $foundUnique eq "NPL 1.0" ) {
# replace the necessary license text
#
if ( !update10($buffer) ) {
$updated = -1;
} else {
$updated = 1;
}
;
} elsif ( $foundUnique eq "NPL 1.1" ) {
# NPL 1.1 stuff is (currently) considered up-to-date, so
# don't do anything.
#
;
} elsif ( $foundUnique eq "MPL 1.0" ) {
# replace the necessary license text
#
if ( !update10($buffer) ) {
$updated = -1;
} else {
$updated = 1;
}
;
} elsif ( $foundUnique eq "MPL 1.1" ) {
# MPL 1.1 stuff is (currently) considered up-to-date, so
# don't do anything.
#
;
} else {
die ("Internal error: unknown license type");
}
# if we actually updated the license, it's time to finish up by
# writing the file and telling the user
#
if ( $updated == 1 ) {
# unless we've specifically been told to do nothing, write out the
# updated file.
#
if (! $opt_n ) {
# write the file
#
open OUTFILE,">${filename}.new" ||
die ("couldn't open $filename.new");
print OUTFILE $buffer ||
die ("error writing header to $filename.new");
while ( <INFILE> ) {
print OUTFILE $_ ||
die ("error writing body to $filename.new");
}
close OUTFILE || die("couldn't close $filename.new after writing");
rename ($filename, "$filename.bkp") ||
die("couldn't rename $filename to $filename.bkp");
rename ("$filename.new", $filename) ||
die("couldn't rename $filename.new to $filename");
}
if ( !$opt_q ) {
print "... updated.";
}
} elsif ( $updated == -1 ) {
# die ("regexp replacement error attempting to update $filename");
if ( !$opt_q) {
print "... failed.";
}
}
}
print "\n" if ( !$opt_q );
# close the file
#
close(INFILE) || die("couldn't close $filename after reading");
}
# all done!
#
exit 0;
# the return value here is only meaningful in the sense of whether
# it's 0 or non-zero.
#
sub update10 ($) {
my $gplTag;
my $ecrTag = "";
my $cccTag = "XXX__CCCTAG__XXX";
my $needCCommentClose = 0;
my $ocTag = "mozilla.org code.";
my $initDevATag = "";
my $initDevBTag = "";
my $createdByTag = "";
my $datesTag = "";
my $copyrightByTag = "";
# in the mongo-huge s// statement, some of the positional match vars
# (eg $2, $3, $4, $6) do not get defined. however, whenever this is
# the case, it just so happens that we want a null string to be
# inserted anyway, so unless debugging is turned on, we turn off
# warnings, in order to suppress the "uninitialized variable".
#
if ( ! $opt_d ) {
$SIG{__WARN__} = sub { return };
}
# if we need to add on GPL alternate licensing, this is a temporary
# tag to help us do so.
#
if ( $opt_g ) {
$gplTag = "XXX__GPLTAG__XXX";
} else {
$gplTag = "";
}
my $result =
$_[0] =~
s{(^.{0,10}?) ?The contents of this (file|directory) ar(?:handle)?e subject to the (Netscape|Mozilla) Public License {0,5}
(^.{0,10}?) ?Version 1\.0 ?\(the ["'](?:License|NPL)['"]\)(?:=0)?;? you may not use (this file|the files in this directory) except(?: in compliance {0,5}
\4 ?with | in {0,5}
\4 ?compliance with | {0,5}
\4 ?in compliance with )the (?:License|NPL)\.[ \t]{1,4}You may obtain a copy of the (?:License|NPL) at {0,5}
\4 ?http:/{1,2}wwwt?\.m5?ozilla\.org/([MN])P(?:L/|\\|L/\.) {0,5}
(?:.{0,10}) {0,25}(?:
\4 ?Software distributed under the License is distributed on an ['"]AS IS["'] {0,5}
\4 ?basis, WITHOUT WARRANTY OF ANY KIND, either express or implied\. {1,2}See(?: the {0,5}
\4 ?License| {0,5}
\4 ?the License) for the specific language governing rights and limitations {0,5}
\4 ?under the License\. {0,5}|
?\4 ?Software distributed under the (?:NPL|License) is distributed on an ['"]AS IS["'] basis, {0,5}
\4 ?WITHOUT WARRANTY OF ANY KIND, either (?:express|dtd) or implied\. See the (?:NPL|License)(?: {0,5}
{1,3}?\4 ?for | for {0,5}
\4 ?)the specific language governing (?:righ|lef)ts and limitations under theg?(?: License\. {0,5}| {0,5}
\4 ?(?:NPL|License)\.) {0,5})(?:
(?:.{0,10}) {0,4})?(?:
\4 ?The [Oo]riginal [Cc]ode is (.+) {0,5}
(?:(\4)( ?)(.+
))?(?:.{0,10}))?(?:
\4 ?The Initial Developers? of (?:the Original Code|this code under the [MN]PL) (?:is|are) ?(.*) {0,5}
\4 ?(.*(?:\. )?) {0,2}Portions created by (.*) are Copyright \(C\) (199[6-9]|1998-1999|(?:1997, )?1998, ?1999|1997-1999)(?: (\b.*?)\.?)? {0,5}
\4 ?(.*?)\.? {0,2}All Rights Reserved\.|
\4 ?The Initial Developers? of this code under the [MN]PL (?:is|are) ?(.*) {0,5}
\4 ?(.*(?:\. )?)[ \t]{0,4}Portions created by (.*) are {0,5}
\4 ?Copy(?:righ|lef)t ?\(C\) (199[6-9]|1998-1999|1998, ?1999|1997-1999) (.*)\.[ \t]{1,4}All (?:Righ|lef)ts {0,5}
\4 ?Reserved\.1?|
\4 ?The Initial Developers? of (?:the Original Code|this code under the [MN]PL) (?:is|are) ?(.*) {0,5}
\4 ?(.*(?:\. )?) {0,2}Portions created by (.*) are(?: Copyright)? {0,5}
?\4? ?(?:Copyright )?\(C\) (199[6-9]|1998-1999|1998, ?1999|1997-1999) (.*)\. {1,2}All Rights
?\4? ?Reserved\.|
|)(?:( \*/)? {0,5}
)(?:(?:\4 {0,5}
)?\4 ?Contributor\(?s?\)?: ?((?s:.*?))
)?((?!\4)|\4/? ?
)?}{$1 The contents of this $2 are subject to the $3 Public
$4 License Version 1.1 (the "License"); you may not use $5
$4 except in compliance with the License. You may obtain a copy of
$4 the License at http://www.mozilla.org/$6PL/
$4
$4 Software distributed under the License is distributed on an "AS
$4 IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
$4 implied. See the License for the specific language governing
$4 rights and limitations under the License.
$4
$4 The Original Code is XXX__OCTAG__XXX
$8$9$10$4
$4 The Initial Developer of the Original Code is XXX__INITDEVATAG__XXX
$4 XXX__INITDEVBTAG__XXXPortions created by XXX__CREATEDBYTAG__XXX are
$4 Copyright (C) XXX__DATESTAG__XXX XXX__COPYRIGHTBYTAG__XXXXXX__ENDCOPYRIGHTTAG__XXX. All
$4 Rights Reserved.
$4
$4 Contributor(s): $28
$gplTag$29$cccTag}m;
# restore the usual warning behavior
#
delete $SIG{__WARN__};
# if something went wrong, give up
#
if ( !$result ) { return $result; }
# set the initial developer clause to be whatever we found in the
# match.
#
$initDevATag = "$11$17$22";
# if we didn't find anything, and a string was given on the command-line
# with -A, use that.
#
if ( $initDevATag eq "" )
{
if ( $opt_A ne "" )
{
$initDevATag = $opt_A
}
}
# set the initial developer clause to be whatever we found in the
# match.
#
$initDevBTag = "$12$18$23";
# if we didn't find anything, and a string was given on the command-line
# with -B, use that.
#
if ( $initDevBTag eq "" )
{
if ( $opt_B ne "" )
{
$initDevBTag = $opt_B
}
}
# but if BOTH A and B tags remain unset, abort
#
if ( $initDevATag eq "" and $initDevBTag eq "" )
{
return 0;
}
# set the created by tag to be whatever we found in the match. if
# we didn't find anything, and were supplied with a default on the
# command-line by -C, use that. otherwise abort.
#
$createdByTag = "$13$19$24";
if ( $createdByTag eq "")
{
if ( $opt_C ne "" )
{
$createdByTag = $opt_C;
}
}
return 0 if ( $createdByTag eq "" );
# set the dates tag to be whatever we found in the match. if
# we didn't find anything, and were supplied with a default on the
# command-line by -D, use that. otherwise abort.
#
$datesTag = "$14$20$25";
if ( $datesTag eq "")
{
if ( $opt_D ne "" )
{
$datesTag = $opt_D;
}
}
return 0 if ( $datesTag eq "" );
# set the "copyright by" tag to be whatever we found in the match. if
# we didn't find anything, and were supplied with a default on the
# command-line by -E, use that. otherwise abort.
#
$copyrightByTag = "$15$21$26";
if ( $copyrightByTag eq "")
{
if ( $opt_E ne "" )
{
$copyrightByTag = $opt_E;
}
}
# if there was a final clause in the copyright, we need to add
# a space before it
#
if ( $16 ne "" )
{
if ( $copyrightByTag ne "" )
{
$ecrTag = " " . $16;
} else {
$ecrTag = $16;
}
}
return 0 if ( $copyrightByTag eq "" and $ecrTag eq "");
# some copies of the NPL have the C-language comment close sequence
# incorrectly wrapped into the license text. we notice that here.
#
if ( $27 eq " */" ) { $needCCommentClose = 1 };
# if there wasn't an "Original Code" clause in the original,
# add a generic one now
#
if ( $7 ne "" ) { $ocTag = $7; }
# insert the Original Code clause
#
$result = $_[0] =~ s!XXX__OCTAG__XXX!$ocTag!;
if ( !$result ) { return $result; }
# insert the first part of the initial developer tag
#
$result = $_[0] =~ s!XXX__INITDEVATAG__XXX!$initDevATag!;
if ( !$result ) { return $result; }
# insert the second part of the initial developer tag
#
$result = $_[0] =~ s!XXX__INITDEVBTAG__XXX!$initDevBTag!;
if ( !$result ) { return $result; }
# insert the "created by" tag
#
$result = $_[0] =~ s!XXX__CREATEDBYTAG__XXX!$createdByTag!;
if ( !$result ) { return $result; }
# insert the "copyright by" tag
#
$result = $_[0] =~ s!XXX__COPYRIGHTBYTAG__XXX!$copyrightByTag!;
if ( !$result ) { return $result; }
# insert the "dates" tag
#
$result = $_[0] =~ s!XXX__DATESTAG__XXX!$datesTag!;
if ( !$result ) { return $result; }
# insert the ending of the copyright tag
#
$result = $_[0] =~ s!XXX__ENDCOPYRIGHTTAG__XXX!$ecrTag!;
if ( !$result ) { return $result; }
#
# add in the GPL alternate license clause, if requested
#
if ( $opt_g ) {
# remember the comment prefix
#
my $cp = $4;
$result =
$_[0] =~
s!XXX__GPLTAG__XXX!$cp
$cp Alternatively, the contents of this file may be used under the
$cp terms of the GNU Public License (the "GPL"), in which case the
$cp provisions of the GPL are applicable instead of those above.
$cp If you wish to allow use of your version of this file only
$cp under the terms of the GPL and not to allow others to use your
$cp version of this file under the NPL, indicate your decision by
$cp deleting the provisions above and replace them with the notice
$cp and other provisions required by the GPL. If you do not delete
$cp the provisions above, a recipient may use your version of this
$cp file under either the NPL or the GPL.
!;
}
# if we need a c comment closer, substitute it in here
#
if ( $needCCommentClose || $opt_c ) {
$result = $_[0] =~ s!XXX__CCCTAG__XXX! */\n!;
# otherwise, get rid of the tag that we put in earlier.
#
} else {
$result = $_[0] =~ s!XXX__CCCTAG__XXX!!;
}
return $result;
}