1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
#!/usr/bin/perl
# Copyright (C) 2017, 2019 Chris Lamb <lamby@debian.org>
use v5.20;
use warnings;
use utf8;
use Cwd qw(realpath);
use File::Basename qw(dirname);
use Unicode::UTF8 qw(decode_utf8 encode_utf8);
# neither Path::This nor lib::relative are in Debian
use constant THISFILE => realpath __FILE__;
use constant THISDIR => dirname realpath __FILE__;
# use Lintian modules that belong to this program
use lib THISDIR . '/../lib';
use Const::Fast;
use Getopt::Long;
use IPC::Run3;
use Lintian::IPC::Run3 qw(safe_qx);
const my $PLUS => q{+};
const my $WAIT_STATUS_SHIFT => 8;
my (%added, %removed, %opt);
my %opthash = ('in-place|i' => \$opt{'in-place'},);
# init commandline parser
Getopt::Long::config('bundling', 'no_getopt_compat', 'no_auto_abbrev',
'permute');
# process commandline options
Getopt::Long::GetOptions(%opthash)
or die encode_utf8("error parsing options\n");
my ($commit_range) = @ARGV;
if (not $commit_range) {
my $bytes = safe_qx(qw(git describe --abbrev=0));
my $status = $? >> $WAIT_STATUS_SHIFT;
die encode_utf8("git describe failed with code $status\n")
if $status;
my $describe = $bytes;
chomp($describe);
if (not $describe) {
die encode_utf8("git describe did not return anything.\n");
}
$commit_range = "${describe}..HEAD";
print encode_utf8("Assuming commit range to be: ${commit_range}\n");
}
my $output;
my @command =(qw{git diff}, $commit_range, qw{-- tags/*/*.tag});
run3(\@command, \undef, \$output);
my @lines = split(/\n/, $output);
while (defined(my $line = shift @lines)) {
next
unless $line =~ m{ \A ([\+-]) Tag: \s*+ ([^ ]++) \s*+ \Z}xsm;
my ($change, $tag) = ($1, $2);
if ($change eq $PLUS) {
$added{$tag} = 1;
} else {
$removed{$tag} = 1;
}
}
for my $tag (keys(%added)) {
if (exists($removed{$tag})) {
# Added and removed? More likely, the tag was moved between
# two files.
delete($added{$tag});
delete($removed{$tag});
}
}
if (not %added and not %removed) {
print {*STDERR} encode_utf8("No tags were added or removed\n");
}
if ($opt{'in-place'}) {
my $matched = 0;
my $infile = 'debian/changelog';
open(my $in_fd, '<:encoding(UTF-8)', $infile)
or die encode_utf8("Cannot open $infile");
my $outfile = 'debian/changelog.tmp';
open(my $out_fd, '>', $outfile)
or die encode_utf8("Cannot open $outfile");
while (my $line = <$in_fd>) {
chomp $line;
if ($line =~ m/^ \* WIP\b/) {
emit_tag_summary($out_fd);
$matched++;
} else {
print {$out_fd} encode_utf8($line . "\n");
}
}
close($out_fd);
close($in_fd);
if ($matched != 1) {
die encode_utf8(
"changelog did not match WIP placeholder exactly once\n");
}
rename($outfile, $infile)
or die encode_utf8("Cannot rename $outfile to $infile");
print encode_utf8("Updated $infile\n");
} else {
emit_tag_summary(\*STDOUT);
}
sub emit_tag_summary {
my ($fd) = @_;
if (%added or %removed) {
print {$fd} encode_utf8(" * Summary of tag changes:\n");
}
if (%added) {
print {$fd} encode_utf8(" + Added:\n");
for my $tag (sort(keys(%added))) {
print {$fd} encode_utf8(" - $tag\n");
}
}
if (%removed) {
print {$fd} encode_utf8(" + Removed:\n");
for my $tag (sort(keys(%removed))) {
print {$fd} encode_utf8(" - $tag\n");
}
}
return;
}
# Local Variables:
# indent-tabs-mode: nil
# cperl-indent-level: 4
# End:
# vim: syntax=perl sw=4 sts=4 sr et
|