update debian copyright: tweak clscan and then manually fixup: revisit next release
[gnulib.git] / debian / clscan / clscan
index 594452d..0e427e2 100755 (executable)
@@ -17,26 +17,117 @@ our $FILESCACHE="$CLSCANDIR/files.yaml";
 our $NEWFILES="$CLSCANDIR/new.txt";
 our $COPYRIGHTSTUB="$CLSCANDIR/copyright.in";
 
+my $gpl_boilerplate=<<"EOL";
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+ .
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ .
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+EOL
+
+my $lgpl2_boilerplate=<<"EOL";
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Library General Public License as published
+ by the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+ .
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ Library General Public License for more details.
+ .
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA.
+EOL
+
+my $lgpl3_boilerplate=<<"EOL";
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+ .
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ .
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+EOL
+
+# license overrides as specified in modules/*
+our $module_licenses = {
+    "public domain" => {
+       license => "PD",
+       license_text => "",
+    },
+    "unlimited" => {
+        license => "other",
+       license_text => "This file is free software; the Free Software Foundation\n" .
+                       "gives unlimited permission to copy and/or distribute it,\n" .
+                        "with or without modifications, as long as this notice is preserved.\n",
+    },
+    "LGPL" => {
+       license => "LGPL",
+       license_text => $lgpl3_boilerplate,
+    },
+    "LGPLv2+" => {
+       license => "LGPL-2+",
+       license_text => $lgpl2_boilerplate,
+    },
+    "LGPLv3+" => {
+       license => "LGPL-3+",
+       license_text => $lgpl3_boilerplate,
+    },
+    "unmodifiable license text" => {
+       license => "other",
+       license_text => "Everyone is permitted to copy and distribute verbatim copies\n" .
+                        "of this license document, but changing it is not allowed.\n",
+    },
+    "GPLed build tool" => {
+       license => "GPL",
+       license_text => $gpl_boilerplate,
+    },
+    "GPL" => {
+       license => "GPL",
+       license_text => $gpl_boilerplate,
+    },
+};
+
 our @filenames=();
-our @modules=();
+our %overrides=();
 our $files={};
 our $new={};
+our @deleted_files=();
 
+# actions
 my $scan=0;
 my $merge=0;
+my $help=0;
 my $writecopyright=0;
 
 usage() unless(@ARGV);
-usage() unless GetOptions("scan|s" => \$scan,
+usage() unless GetOptions("scan|s"  => \$scan,
                          "merge|m" => \$merge,
                          "write|w" => \$writecopyright,
-                         "help|h" => sub { usage(); });
+                         "help|h"  => \$help);
+usage() if $help;
 
 load_cache();
 scan() if($scan);
 merge() if($merge);
 write_copyright() if ($merge || $writecopyright);
 
+
 sub scan
 {
     get_filenames();
@@ -44,13 +135,14 @@ sub scan
     {
        scan_file($file);
     }
-    write_new();
     find_deleted();
+    write_new();
 }
 
 sub merge
 {
     merge_new();
+    load_overrides();
     save_cache();
 }
 
@@ -73,13 +165,15 @@ sub write_copyright
     my $licenses={};
     for my $file (sort keys(%$files))
     {
-       my $license=$files->{$file}->{license};
+       my $license=$files->{$file}->{license_override} || $files->{$file}->{license};
        my $copyright=$files->{$file}->{copyright};
-       my $license_text=$files->{$file}->{license_text};
+       my $license_text=$files->{$file}->{license_text_override} ||
+           $files->{$file}->{license_text};
        push(@{$licenses->{$license}->{$license_text}->{$copyright}}, $file);
     }
     my %refs=();
     my $refnum="00";
+    print COPYRIGHT license_trailer(sort keys(%$licenses));
     for my $license (sort keys(%$licenses))
     {
        for my $license_text (sort keys(%{$licenses->{$license}}))
@@ -96,28 +190,45 @@ sub write_copyright
                $licensestr .= " [REF$refnum]";
                $refs{$licensestr}=$license_text;
            }
+            else
+            {
+                if(!length($license)) {
+                    $licensestr="unknown";
+                }
+            }
            for my $copyright (sort keys(%{$licenses->{$license}->{$license_text}}))
            {
                next if(!length($license) && !length($copyright) && !length($license_text));
                my @filelist=sort @{$licenses->{$license}->{$license_text}->{$copyright}};
-               print COPYRIGHT "Files: ", join(', ', @filelist), "\n";
-               print COPYRIGHT "Copyright: $copyright\n" if length($copyright);
+               print COPYRIGHT "Files: ", join(' ', @filelist), "\n";
+               print COPYRIGHT "Copyright: ". (length($copyright) ? $copyright : "unknown" ) . "\n";
                print COPYRIGHT "License: $licensestr\n" if length($licensestr);
                print COPYRIGHT "\n";
            }
        }
     }
-    for my $ref (sort keys(%refs))
+    for my $ref (sort byref keys(%refs))
     {
        print COPYRIGHT "License: $ref\n";
        my @text=split(/\n/, $refs{$ref});
+        @text=map { ($_ eq "") ? "." : $_; } @text;
        print COPYRIGHT map { "    " . $_ . "\n" } @text;
        print COPYRIGHT "\n";
     }
-    print COPYRIGHT license_trailer(sort keys(%$licenses));
     close(COPYRIGHT);
 }
 
+sub byref
+{
+    my $aref=($a=~/\[REF(\d+)\]/)[0];
+    my $bref=($b=~/\[REF(\d+)\]/)[0];
+    if($aref && $bref)
+    {
+       return($aref <=> $bref);
+    }
+    return($a cmp $b);
+}
+
 sub license_trailer
 {
     my @licenses_used=@_;
@@ -137,37 +248,36 @@ sub license_trailer
     };
 
     my %types_found=();
-TYPE: for my $type (reverse sort keys(%$license_data))
+    for my $type (reverse sort keys(%$license_data))
     {
        for my $license (@licenses_used)
        {
-           if($license =~ /$type(\+|\b)/i)
+           if($license =~ /$type(\+|\s|$)/i)
            {
                $types_found{$type}=1;
-               # avoid matching eg GPL-2 *and* GPL
-               next TYPE;
            }
        }
     }
-    my $text="\n";
+    my $text="  .\n";
     # if just one, use standard style
     if(keys(%types_found) == 1)
     {
        my ($file, $name)=each(%types_found);
-       $text .= "The complete text of the $name can be\n";
-       $text .= "found in /usr/share/common-licenses/$file\n";
+       $text .= "  The complete text of the $name can be\n";
+       $text .= "  found in /usr/share/common-licenses/$file\n";
     }
     else
     {
        # more than one, use table.
-       $text .= "The complete text of standard licenses referenced above\n";
-       $text .= "can be found in /usr/share/common-licenses/ as follows:\n\n";
-       $text .= sprintf("%-70s %s\n", "LICENSE", "FILE");
+       $text .= "  The complete text of standard licenses referenced above\n";
+       $text .= "  can be found in /usr/share/common-licenses/ as follows:\n  .\n  ";
+       $text .= sprintf("%-60s %s\n", "LICENSE", "FILE");
        for my $type (sort keys(%types_found))
        {
-           $text .= sprintf("%-70s %s\n", $license_data->{$type}, $type);
+           $text .= sprintf("  %-60s %s\n", $license_data->{$type}, $type);
        }
     }
+    $text .= "\n\n";
     return $text;
 }
 
@@ -243,15 +353,17 @@ sub filechanged
     {
        if(exists($files->{$filename}->{copyright}))
        {
-           $new->{$filename}->{copyright_old}=$files->{$filename}->{copyright};
+           $new->{$filename}->{copyright}=$files->{$filename}->{copyright};
+           $new->{$filename}->{copyright_guess}=$copyright_guess;
        }
        if(exists($files->{$filename}->{license}))
        {
-           $new->{$filename}->{license_old}=$files->{$filename}->{license};
+           $new->{$filename}->{license}=$files->{$filename}->{license};
+           $new->{$filename}->{license_guess}=$license_guess;
        }
        if(exists($files->{$filename}->{license_text}))
        {
-           $new->{$filename}->{license_text_old}=$files->{$filename}->{license_text};
+           $new->{$filename}->{license_text}=$files->{$filename}->{license_text};
        }
     }
 }
@@ -263,7 +375,7 @@ sub get_filenames
 
 sub wanted_files
 {
-    if(/^\.git/ || /^\.cvs/ || /^debian/ || /^modules$/)
+    if(/^\.git/ || /^\.cvs/ || /^debian/ || /^modules$/ || /^\.pc/)
     {
        $File::Find::prune=1;
     }
@@ -275,29 +387,21 @@ sub wanted_files
 
 sub wanted_modules
 {
-    if(/^\./ || /^README$/ || /^COPYING$/)
+    if(/^\.[^\/]/ || /^README$/ || /^COPYING$/)
     {
        $File::Find::prune=1;
+       return;
     }
     elsif(-f)
     {
-       push(@modules, $File::Find::name);
-    }
-}
-
-sub load_overrides
-{
-    find(\&wanted_modules, "modules/");
-    my %modules=();
-    for my $module (@modules)
-    {
-       unless(open(MOD, $module))
+       unless(open(MOD, $File::Find::name))
        {
-           warn("$me: cannot open $module: $!\n");
-           next;
+           warn("$me: cannot open $File::Find::name: $!\n");
+           return;
        }
        my $infiles=0;
        my $inlicense=0;
+       my @files=();
        while(<MOD>)
        {
            chomp;
@@ -307,12 +411,12 @@ sub load_overrides
            }
            if($inlicense)
            {
-               $modules{$module}->{license}=$_;
+               push(@{$overrides{$_}},@files);
                $inlicense=0;
            }
            elsif($infiles)
            {
-               push(@{$modules{$module}->{files}}, $_);
+               push(@files, $_);
            }
            elsif(/^License:/)
            {
@@ -327,6 +431,31 @@ sub load_overrides
     }
 }
 
+sub load_overrides
+{
+    find({ wanted => \&wanted_modules, no_chdir => 1}, "modules/");
+    for my $license (keys(%overrides))
+    {
+       if(!exists($module_licenses->{$license}))
+       {
+           die("$me: license override \"$license\" not found in \$module_licenses\n");
+       }
+       my @overridden_files=map { "./" . $_; } @{$overrides{$license}};
+       for my $file (@overridden_files)
+       {
+           my $override=$module_licenses->{$license};
+           if(length($override->{license}))
+           {
+               $files->{$file}->{license_override}=$override->{license};
+           }
+           if(length($override->{license_text}))
+           {
+               $files->{$file}->{license_text_override}=$override->{license_text};
+           }
+       }
+    }
+}
+
 
 sub load_cache
 {
@@ -362,7 +491,6 @@ sub write_new
     unless(keys(%$new))
     {
        warn("$me: no new/changed files found\n");
-       return;
     }
     unless(open(NEW,">$NEWFILES"))
     {
@@ -373,19 +501,19 @@ sub write_new
        print NEW "File: $file\n";
        print NEW "Hash: ", $new->{$file}->{hash}, "\n";
        print NEW "Copyright: ", $new->{$file}->{copyright}, "\n";
-       print NEW "License: ", $new->{$file}->{license}, "\n";
-       print NEW "License_Text: \n";
-       if($new->{$file}->{license_old})
+       if($new->{$file}->{copyright_guess})
        {
-           print NEW "#License_old: ", $new->{$file}->{license_old}, "\n";
+           print NEW "#Copyright_guess: ", $new->{$file}->{copyright_guess}, "\n";
        }
-       if($new->{$file}->{copyright_old})
+       print NEW "License: ", $new->{$file}->{license}, "\n";
+       if($new->{$file}->{license_guess})
        {
-           print NEW "#Copyright_old: ", $new->{$file}->{copyright_old}, "\n";
+           print NEW "#License_guess: ", $new->{$file}->{license_guess}, "\n";
        }
-       if($new->{$file}->{licence_text_old})
+       if($new->{$file}->{license_text})
        {
-           print NEW "#License_text_old: ", $new->{$file}->{licence_text_old}, "\n";
+           my @text=split(/\n/, $new->{$file}->{license_text});
+           print NEW "\t" . join("\n\t", @text), "\n";
        }
        print NEW "#Header: \n";
        my @headerlines=split(/\n/, $new->{$file}->{header});
@@ -393,6 +521,10 @@ sub write_new
        print NEW join("\n", @headerlines);
        print NEW "\n\n";
     }
+    if(@deleted_files)
+    {
+       print NEW map { "Deleted: $_\n"; } @deleted_files;
+    }
     close NEW;
 }
 
@@ -454,6 +586,13 @@ sub merge_new
            $in_license_text=1;
            $license_text='';
        }
+       elsif(/^Deleted:\s*(.*)/)
+       {
+           if(exists($files->{$1}))
+           {
+               delete($files->{$1});
+           }
+       }
        else
        {
            warn("$me: $NEWFILES: line $line not recognized\n");
@@ -472,19 +611,18 @@ sub merge_new
 
 sub find_deleted
 {
-    my @deleted=();
     my %newnames = map { $_ => 1 } @filenames;
     for my $file (sort keys(%$files))
     {
        unless(exists($newnames{$file}))
        {
-           push(@deleted, $file);
+           push(@deleted_files, $file);
        }
     }
-    if(@deleted)
+    if(@deleted_files)
     {
        print "Removed files:\n";
-       print join("\n", @deleted),"\n";
+       print join("\n", @deleted_files),"\n";
     }
 }