| #!/usr/bin/env perl |
| #*************************************************************************** |
| # _ _ ____ _ |
| # Project ___| | | | _ \| | |
| # / __| | | | |_) | | |
| # | (__| |_| | _ <| |___ |
| # \___|\___/|_| \_\_____| |
| # |
| # Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. |
| # |
| # This software is licensed as described in the file COPYING, which |
| # you should have received as part of this distribution. The terms |
| # are also available at https://curl.se/docs/copyright.html. |
| # |
| # You may opt to use, copy, modify, merge, publish, distribute and/or sell |
| # copies of the Software, and permit persons to whom the Software is |
| # furnished to do so, under the terms of the COPYING file. |
| # |
| # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| # KIND, either express or implied. |
| # |
| # SPDX-License-Identifier: curl |
| # |
| ########################################################################### |
| # |
| # Invoke script in the root of the git checkout. Scans all files in git unless |
| # given a specific single file. |
| # |
| # Usage: copyright.pl [file] |
| # |
| |
| my %skips; |
| |
| # file names |
| my %skiplist = ( |
| # REUSE-specific file |
| ".reuse/dep5" => "<built-in>", |
| |
| # License texts |
| "LICENSES/BSD-3-Clause.txt" => "<built-in>", |
| "LICENSES/BSD-4-Clause-UC.txt" => "<built-in>", |
| "LICENSES/ISC.txt" => "<built-in>", |
| "LICENSES/curl.txt" => "<built-in>", |
| "COPYING" => "<built-in>", |
| |
| ); |
| |
| sub scanfile { |
| my ($f) = @_; |
| my $line=1; |
| my $found = 0; |
| open(F, "<$f") || return -1; |
| while (<F>) { |
| chomp; |
| my $l = $_; |
| # check for a copyright statement and save the years |
| if($l =~ /.* ?copyright .* (\d\d\d\d|)/i) { |
| my $count = 0; |
| while($l =~ /([\d]{4})/g) { |
| push @copyright, { |
| year => $1, |
| line => $line, |
| col => index($l, $1), |
| code => $l |
| }; |
| $count++; |
| } |
| if(!$count) { |
| # year-less |
| push @copyright, { |
| year => -1, |
| line => $line, |
| col => index($l, $1), |
| code => $l |
| }; |
| $count++; |
| } |
| $found = $count; |
| } |
| if($l =~ /SPDX-License-Identifier:/) { |
| $spdx = 1; |
| } |
| # allow within the first 100 lines |
| if(++$line > 100) { |
| last; |
| } |
| } |
| close(F); |
| return $found; |
| } |
| |
| sub checkfile { |
| my ($file, $skipped, $pattern) = @_; |
| $spdx = 0; |
| my $found = scanfile($file); |
| |
| if($found < 1) { |
| if($skipped) { |
| # just move on |
| $skips{$pattern}++; |
| return 0; |
| } |
| if(!$found) { |
| print "$file:1: missing copyright range\n"; |
| return 2; |
| } |
| # this means the file couldn't open - it might not exist, consider |
| # that fine |
| return 1; |
| } |
| if(!$spdx) { |
| if($skipped) { |
| # move on |
| $skips{$pattern}++; |
| return 0; |
| } |
| print "$file:1: missing SPDX-License-Identifier\n"; |
| return 2; |
| } |
| |
| if($skipped) { |
| print "$file:1: ignored superfluously by $pattern\n" if($verbose); |
| $superf{$pattern}++; |
| } |
| |
| return 1; |
| } |
| |
| sub dep5 { |
| my ($file) = @_; |
| my @files; |
| my $copy; |
| open(F, "<$file") || die "can't open $file"; |
| my $line = 0; |
| while(<F>) { |
| $line++; |
| if(/^Files: (.*)/i) { |
| push @files, `git ls-files $1`; |
| } |
| elsif(/^Copyright: (.*)/i) { |
| $copy = $1; |
| } |
| elsif(/^License: (.*)/i) { |
| my $license = $1; |
| for my $f (@files) { |
| chomp $f; |
| if($f =~ /\.gitignore\z/) { |
| # ignore .gitignore |
| } |
| else { |
| if($skiplist{$f}) { |
| print STDERR "$f already skipped at $skiplist{$f}\n"; |
| } |
| $skiplist{$f} = "dep5:$line"; |
| } |
| } |
| undef @files; |
| } |
| } |
| close(F); |
| } |
| |
| dep5(".reuse/dep5"); |
| |
| my $checkall = 0; |
| my @all; |
| my $verbose; |
| if($ARGV[0] eq "-v") { |
| $verbose = 1; |
| shift @ARGV; |
| } |
| if($ARGV[0]) { |
| push @all, @ARGV; |
| } |
| else { |
| @all = `git ls-files`; |
| $checkall = 1; |
| } |
| |
| for my $f (@all) { |
| chomp $f; |
| my $skipped = 0; |
| my $miss; |
| my $wro; |
| my $pattern; |
| if($skiplist{$f}) { |
| $pattern = $skip; |
| $skiplisted++; |
| $skipped = 1; |
| $skip{$f}++; |
| } |
| |
| my $r = checkfile($f, $skipped, $pattern); |
| $mis=1 if($r == 2); |
| $wro=1 if(!$r); |
| |
| if(!$skipped) { |
| $missing += $mis; |
| $wrong += $wro; |
| } |
| } |
| |
| if($verbose) { |
| print STDERR "$missing files have no copyright\n" if($missing); |
| print STDERR "$wrong files have wrong copyright year\n" if ($wrong); |
| print STDERR "$skiplisted files are skipped\n" if ($skiplisted); |
| |
| for my $s (@skiplist) { |
| if(!$skips{$s}) { |
| printf ("Never skipped pattern: %s\n", $s); |
| } |
| if($superf{$s}) { |
| printf ("%s was skipped superfluously %u times and legitimately %u times\n", |
| $s, $superf{$s}, $skips{$s}); |
| } |
| } |
| } |
| |
| if($checkall) { |
| for(keys %skiplist) { |
| if(!$skip{$_}) { |
| printf STDERR "$_ is marked for SKIP but is missing!\n"; |
| } |
| } |
| } |
| |
| exit 1 if($missing || $wrong); |