]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - tools/mkheaders
Prevent users from sending an empty TAGMSG.
[user/henk/code/inspircd.git] / tools / mkheaders
1 #!/usr/bin/env perl
2 #
3 # InspIRCd -- Internet Relay Chat Daemon
4 #
5 #   Copyright (C) 2020 Sadie Powell <sadie@witchery.services>
6 #
7 # This file is part of InspIRCd.  InspIRCd is free software: you can
8 # redistribute it and/or modify it under the terms of the GNU General Public
9 # License as published by the Free Software Foundation, version 2.
10 #
11 # This program is distributed in the hope that it will be useful, but WITHOUT
12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
14 # details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 #
19
20
21 BEGIN {
22         require 5.10.0;
23         unless (-f 'configure') {
24                 print "Error: $0 must be run from the main source directory!\n";
25                 exit 1;
26         }
27 }
28
29 use feature ':5.10';
30 use strict;
31 use warnings FATAL => qw(all);
32
33 use File::Util ();
34 use FindBin    qw($RealDir);
35 use List::Util qw(uniq);
36 use POSIX      qw(strftime);
37
38 use lib $RealDir;
39 use make::console;
40
41 my @ignored_revisions = (
42         '0b4285abd12323920d92fee51e199edd7527dbec', # adding copyright headers
43         '46a39046196f55b52336e19662bb7bac85b731ac', # adding copyright headers
44         '56375392ba94f2552bbeeeab4fd39e1e50295525', # sadie's name change
45         'bab14f0dd2345c9d7dcbc47c918563709e1ac094', # peavey breaking line endings
46         'f2acdbc3820f0f4f5ef76a0a64e73d2a320df91f', # peavey fixing line endings
47 );
48
49 my @paths = File::Util->new->list_dir('.' => { recurse => 1 });
50 my @updated;
51 for my $path (@paths) {
52         next unless -f $path;
53         next if $path =~ /\/\./;
54         next if $path =~ /\/vendor\//;
55
56         if (system "git ls-files --error-unmatch -- $path 1>/dev/null 2>/dev/null") {
57                 print_format "Skipping <|YELLOW $path|> as it has not been committed.\n" if defined $ENV{MKHEADERS_VERBOSE};
58                 next;
59         }
60
61         open(my $fh, $path) or print_error "unable to read from $path: $!";
62         my ($copyright, $indent, @lines);
63         for my $line (<$fh>) {
64                 chomp $line;
65                 if ($line =~ /^([^0-9A-Za-z]+\s)Copyright\s+\(C\)\s+[^<]+\s+<[^>]+>$/) {
66                         $copyright = scalar @lines;
67                         $indent = $1;
68                 } else {
69                         push @lines, $line;
70                 }
71         }
72         close $fh;
73
74         if (defined $copyright) {
75                 print_format "Updating copyright headers in <|GREEN $path|>.\n" if defined $ENV{MKHEADERS_VERBOSE};
76                 my (%author, %authors);
77                 my $ignored_args = join ' ', map { "--ignore-rev $_" } @ignored_revisions;
78                 for my $line (split /\n+/, `git blame $ignored_args --incremental -w HEAD -- $path`) {
79                         if ($line =~ /^([0-9a-f]{40})(?:\s\d+){3}$/) {
80                                 $author{COMMITS} //= [];
81                                 push @{$author{COMMITS}}, $1;
82                         } elsif ($line =~ /^author (.+)/) {
83                                 $author{NAME} = $1;
84                         } elsif ($line =~ /^author-mail <(.+)>/) {
85                                 $author{EMAIL} = $1;
86                         } elsif ($line =~ /^author-time (.+)/) {
87                                 $author{YEAR} = strftime '%Y', gmtime $1;
88                         } elsif ($line =~ /^filename /) {
89                                 next unless scalar keys %author > 1;
90                                 my $display = sprintf "%s <%s>", $author{NAME}, $author{EMAIL};
91                                 $authors{$display} //= [];
92                                 push $authors{$display}, $author{YEAR};
93                                 for my $commit (uniq @{$author{COMMITS}}) {
94                                         my $details = `git rev-list --format=%B --max-count=1 $commit`;
95                                         while ($details =~ /co-authored-by: ([^<]+<[^>]+>)/gi) {
96                                                 $authors{$1} //= [];
97                                                 push $authors{$1}, $author{YEAR};
98                                         }
99                                 }
100                                 undef %author;
101                         }
102                 }
103
104                 my @copyrights;
105                 while (my ($display, $years) = each %authors) {
106                         next if $display eq 'InspIRCd Robot <noreply@inspircd.org>';
107                         my ($last_year, $start_year, @year_ranges);
108                         for my $year (uniq sort @$years) {
109                                 if (!defined $last_year) {
110                                         $start_year = $last_year = $year
111                                 } elsif ($year == $last_year + 1) {
112                                         $last_year = $year;
113                                 } else {
114                                         if ($last_year == $start_year) {
115                                                 push @year_ranges, $last_year; 
116                                         } else {
117                                                 push @year_ranges, "$start_year-$last_year";
118                                         }
119                                         $start_year = $last_year = $year;
120                                 }
121                         }
122                         if (defined $last_year) {
123                                 if ($last_year == $start_year) {
124                                         push @year_ranges, $last_year; 
125                                 } else {
126                                         push @year_ranges, "$start_year-$last_year";
127                                 }
128                         }
129
130                         my $joined_years = join ', ', @year_ranges;
131                         push @copyrights, "${\$indent}Copyright (C) $joined_years $display";
132                 }
133
134                 splice @lines, $copyright, 0, reverse sort @copyrights;
135                 open(my $fh, '>', $path) or print_error "unable to write to $path: $!";
136                 for my $line (@lines) {
137                         say $fh $line;
138                 }
139                 close $fh;
140                 push @updated, $path;
141         } else {
142                 print_format "Skipping <|YELLOW $path|> as it contains no copyright headers.\n" if defined $ENV{MKHEADERS_VERBOSE};
143         }
144 }
145
146 system 'git', 'commit',
147         '--author', 'InspIRCd Robot <noreply@inspircd.org>',
148         '--message', 'Update copyright headers.',
149         '--', @updated;