2020-01-11 21:56:54 +00:00
|
|
|
#!/usr/bin/env perl
|
|
|
|
#
|
|
|
|
# InspIRCd -- Internet Relay Chat Daemon
|
|
|
|
#
|
2022-04-28 18:49:16 +01:00
|
|
|
# Copyright (C) 2020-2022 Sadie Powell <sadie@witchery.services>
|
2020-01-11 21:56:54 +00:00
|
|
|
#
|
|
|
|
# This file is part of InspIRCd. InspIRCd 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, version 2.
|
|
|
|
#
|
|
|
|
# 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/>.
|
|
|
|
#
|
|
|
|
|
|
|
|
|
2021-02-28 19:20:08 +00:00
|
|
|
use v5.26.0;
|
2020-01-11 21:56:54 +00:00
|
|
|
use strict;
|
|
|
|
use warnings FATAL => qw(all);
|
|
|
|
|
2020-01-17 14:40:44 +00:00
|
|
|
use File::Basename qw(dirname);
|
|
|
|
use File::Util ();
|
|
|
|
use FindBin qw($RealDir);
|
|
|
|
use List::Util qw(uniq);
|
|
|
|
use POSIX qw(strftime);
|
2020-01-11 21:56:54 +00:00
|
|
|
|
2020-01-17 14:40:44 +00:00
|
|
|
use lib dirname $RealDir;
|
2020-01-18 14:03:18 +00:00
|
|
|
use make::common;
|
2020-01-11 21:56:54 +00:00
|
|
|
use make::console;
|
|
|
|
|
|
|
|
my @ignored_revisions = (
|
|
|
|
'0b4285abd12323920d92fee51e199edd7527dbec', # adding copyright headers
|
|
|
|
'46a39046196f55b52336e19662bb7bac85b731ac', # adding copyright headers
|
2020-04-15 16:43:07 +01:00
|
|
|
'4a6fedd9324d87349a806c9c1d0ae6e7d3c1fd38', # mass-updating descriptions
|
2020-01-11 21:56:54 +00:00
|
|
|
'56375392ba94f2552bbeeeab4fd39e1e50295525', # sadie's name change
|
|
|
|
'bab14f0dd2345c9d7dcbc47c918563709e1ac094', # peavey breaking line endings
|
2021-08-27 09:38:22 +01:00
|
|
|
'de6d4dbd1e8845e08c2d87cd89a919e5b21ba619', # jsoref fixing a ton of typos
|
2020-01-11 21:56:54 +00:00
|
|
|
'f2acdbc3820f0f4f5ef76a0a64e73d2a320df91f', # peavey fixing line endings
|
|
|
|
);
|
|
|
|
|
2022-12-27 14:58:13 +00:00
|
|
|
sub make_range($@) {
|
|
|
|
my ($separator, @nums) = @_;
|
|
|
|
my ($last_num, $start_num, @num_ranges);
|
|
|
|
for my $num (uniq sort { $a <=> $b } @nums) {
|
|
|
|
if (!defined $last_num) {
|
|
|
|
$start_num = $last_num = $num
|
|
|
|
} elsif ($num == $last_num + 1) {
|
|
|
|
$last_num = $num;
|
|
|
|
} else {
|
|
|
|
if ($last_num == $start_num) {
|
|
|
|
push @num_ranges, $last_num;
|
|
|
|
} else {
|
|
|
|
push @num_ranges, "$start_num$separator$last_num";
|
|
|
|
}
|
|
|
|
$start_num = $last_num = $num;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (defined $last_num) {
|
|
|
|
if ($last_num == $start_num) {
|
|
|
|
push @num_ranges, $last_num;
|
|
|
|
} else {
|
|
|
|
push @num_ranges, "$start_num$separator$last_num";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return @num_ranges;
|
|
|
|
}
|
|
|
|
|
2021-01-25 12:13:54 +00:00
|
|
|
my @paths = File::Util->new->list_dir(dirname($RealDir) => { recurse => 1 });
|
2020-01-11 21:56:54 +00:00
|
|
|
my @updated;
|
|
|
|
for my $path (@paths) {
|
|
|
|
next unless -f $path;
|
|
|
|
next if $path =~ /\/\./;
|
2021-01-25 12:13:54 +00:00
|
|
|
next if $path =~ /\/build\//;
|
2020-01-11 21:56:54 +00:00
|
|
|
next if $path =~ /\/vendor\//;
|
|
|
|
|
|
|
|
if (system "git ls-files --error-unmatch -- $path 1>/dev/null 2>/dev/null") {
|
2021-01-27 16:47:08 +00:00
|
|
|
say STDERR console_format "Skipping <|YELLOW $path|> as it has not been committed." if defined $ENV{MKHEADERS_VERBOSE};
|
2020-01-11 21:56:54 +00:00
|
|
|
next;
|
|
|
|
}
|
|
|
|
|
|
|
|
open(my $fh, $path) or print_error "unable to read from $path: $!";
|
2022-12-27 14:58:13 +00:00
|
|
|
my ($copyright, $indent, $linenum, @linenums, @lines);
|
2020-01-11 21:56:54 +00:00
|
|
|
for my $line (<$fh>) {
|
2022-12-27 14:58:13 +00:00
|
|
|
$linenum += 1;
|
2020-01-11 21:56:54 +00:00
|
|
|
chomp $line;
|
2022-04-28 17:58:38 +01:00
|
|
|
if ($line =~ /^([^0-9A-Za-z]+\s)Copyright\s+\(C\)\s+[^<]+(\s+<[^>]+>)?$/) {
|
2020-01-11 21:56:54 +00:00
|
|
|
$copyright = scalar @lines;
|
|
|
|
$indent = $1;
|
|
|
|
} else {
|
|
|
|
push @lines, $line;
|
2022-12-27 14:58:13 +00:00
|
|
|
push @linenums, $linenum;
|
2020-01-11 21:56:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
close $fh;
|
|
|
|
|
|
|
|
if (defined $copyright) {
|
2021-01-27 16:47:08 +00:00
|
|
|
say console_format "Updating copyright headers in <|GREEN $path|>." if defined $ENV{MKHEADERS_VERBOSE};
|
2021-03-05 01:41:52 +00:00
|
|
|
my (%authors, $commit, %commits);
|
2020-01-11 21:56:54 +00:00
|
|
|
my $ignored_args = join ' ', map { "--ignore-rev $_" } @ignored_revisions;
|
2022-12-27 14:58:13 +00:00
|
|
|
my $line_args = join ' ', map { "-L $_" } make_range ',', @linenums;
|
|
|
|
for my $line (split /\n+/, `git blame $ignored_args $line_args --incremental -M -w HEAD -- $path`) {
|
2020-01-11 21:56:54 +00:00
|
|
|
if ($line =~ /^([0-9a-f]{40})(?:\s\d+){3}$/) {
|
2021-03-05 01:41:52 +00:00
|
|
|
$commit = $1;
|
|
|
|
$commits{$commit} //= {};
|
2020-01-11 21:56:54 +00:00
|
|
|
} elsif ($line =~ /^author (.+)/) {
|
2021-03-05 01:41:52 +00:00
|
|
|
$commits{$commit}->{NAME} = $1;
|
2020-01-11 21:56:54 +00:00
|
|
|
} elsif ($line =~ /^author-mail <(.+)>/) {
|
2021-12-10 09:48:30 +00:00
|
|
|
next if $1 eq 'unknown@email.invalid';
|
|
|
|
next if $1 =~ /\@users.noreply.github.com$/;
|
2021-03-05 01:41:52 +00:00
|
|
|
$commits{$commit}->{EMAIL} = $1;
|
2020-01-11 21:56:54 +00:00
|
|
|
} elsif ($line =~ /^author-time (.+)/) {
|
2021-03-05 01:41:52 +00:00
|
|
|
$commits{$commit}->{YEAR} = strftime '%Y', gmtime $1;
|
2020-01-11 21:56:54 +00:00
|
|
|
} elsif ($line =~ /^filename /) {
|
2021-12-10 09:48:30 +00:00
|
|
|
my $display = $commits{$commit}->{NAME};
|
|
|
|
if (exists $commits{$commit}->{EMAIL}) {
|
|
|
|
$display .= sprintf " <%s>", $commits{$commit}->{EMAIL};
|
|
|
|
}
|
2020-01-11 21:56:54 +00:00
|
|
|
$authors{$display} //= [];
|
2021-03-05 01:41:52 +00:00
|
|
|
push @{$authors{$display}}, $commits{$commit}->{YEAR};
|
|
|
|
my $details = `git rev-list --format=%B --max-count=1 $commit`;
|
|
|
|
while ($details =~ /co-authored-by: ([^<]+<[^>]+>)/gi) {
|
|
|
|
$authors{$1} //= [];
|
|
|
|
push @{$authors{$1}}, $commits{$commit}->{YEAR};
|
2020-01-11 21:56:54 +00:00
|
|
|
}
|
2021-03-05 01:41:52 +00:00
|
|
|
undef $commit;
|
2020-01-11 21:56:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
my @copyrights;
|
|
|
|
while (my ($display, $years) = each %authors) {
|
|
|
|
next if $display eq 'InspIRCd Robot <noreply@inspircd.org>';
|
2022-12-27 14:58:13 +00:00
|
|
|
my @year_ranges = make_range '-', @$years;
|
2020-01-11 21:56:54 +00:00
|
|
|
my $joined_years = join ', ', @year_ranges;
|
|
|
|
push @copyrights, "${\$indent}Copyright (C) $joined_years $display";
|
|
|
|
}
|
|
|
|
|
|
|
|
splice @lines, $copyright, 0, reverse sort @copyrights;
|
|
|
|
open(my $fh, '>', $path) or print_error "unable to write to $path: $!";
|
|
|
|
for my $line (@lines) {
|
|
|
|
say $fh $line;
|
|
|
|
}
|
|
|
|
close $fh;
|
|
|
|
push @updated, $path;
|
|
|
|
} else {
|
2021-01-27 16:47:08 +00:00
|
|
|
say STDERR console_format "Skipping <|YELLOW $path|> as it contains no copyright headers." if defined $ENV{MKHEADERS_VERBOSE};
|
2020-01-11 21:56:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-18 14:03:18 +00:00
|
|
|
execute 'git', 'commit',
|
2020-01-11 21:56:54 +00:00
|
|
|
'--author', 'InspIRCd Robot <noreply@inspircd.org>',
|
|
|
|
'--message', 'Update copyright headers.',
|
|
|
|
'--', @updated;
|