diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2017-04-03 18:23:32 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2017-04-03 18:23:32 +0300 |
commit | caac7dea4cb65a8bed723d705bb6a0b89cf13da1 (patch) | |
tree | 154b3222613264c840cb58f93514bdf04755fade /mu-aux/gencl | |
parent | fcdbdbe218624d26166f502da3d918165bf30da8 (diff) | |
download | mailutils-caac7dea4cb65a8bed723d705bb6a0b89cf13da1.tar.gz mailutils-caac7dea4cb65a8bed723d705bb6a0b89cf13da1.tar.bz2 |
Rewrite gencl as an enhanced replacement of gitlog-to-changelog.
* mu-aux/gencl: Rewritten as a replacement for gitlog-to-changelog.
* ChangeLog.amend: More spell fixes.
* Makefile.am: Use gencl instead of gitlog-to-changelog.
* doc/ChangeLog.CVS: Spell checking
* gnulib.modules: Remove gitlog-to-changelog.
Diffstat (limited to 'mu-aux/gencl')
-rwxr-xr-x | mu-aux/gencl | 527 |
1 files changed, 468 insertions, 59 deletions
diff --git a/mu-aux/gencl b/mu-aux/gencl index af6056bd5..f124cacde 100755 --- a/mu-aux/gencl +++ b/mu-aux/gencl | |||
@@ -5,59 +5,265 @@ eval '(exit $?0)' && eval 'exec perl -wS "$0" "$@"' | |||
5 | use strict; | 5 | use strict; |
6 | use POSIX qw(strftime); | 6 | use POSIX qw(strftime); |
7 | use Getopt::Long qw(:config gnu_getopt no_ignore_case); | 7 | use Getopt::Long qw(:config gnu_getopt no_ignore_case); |
8 | use Text::Wrap; | ||
9 | use Data::Dumper; | ||
10 | use threads; | ||
11 | use Thread::Queue; | ||
12 | use Time::ParseDate; | ||
13 | use Safe; | ||
14 | use Pod::Usage; | ||
15 | use Pod::Man; | ||
16 | use Pod::Find qw(pod_where); | ||
8 | 17 | ||
9 | my @append_files; | 18 | my @append_files; |
10 | my $force; | 19 | my $force; |
11 | my $verbose; | 20 | my $verbose; |
12 | my $changelog_file = 'ChangeLog'; | 21 | my $changelog_file = 'ChangeLog'; |
22 | my $since_date; | ||
23 | my $until_date; | ||
24 | my $strip_cherry_pick; | ||
25 | my $amend_file; | ||
26 | my %amendment; | ||
27 | my $append_dot; | ||
13 | 28 | ||
14 | GetOptions('append|a=s@' => \@append_files, | 29 | sub set_date { |
15 | 'file|F=s' => \$changelog_file, | 30 | my ($time, $err) = parsedate($_[1], PREFER_PAST => 1, UK => 1); |
16 | 'force|f' => \$force, | 31 | unless (defined($time)) { |
17 | 'verbose|v' => \$verbose) or exit(1); | 32 | print STDERR "--$_[0]=$_[1]: $err\n"; |
33 | exit(1); | ||
34 | } | ||
35 | return strftime('%Y-%m-%d', localtime($time)); | ||
36 | } | ||
37 | |||
38 | =head1 NAME | ||
39 | |||
40 | gencl - generate ChangeLog from git log output | ||
41 | |||
42 | =head1 SYNOPSIS | ||
43 | |||
44 | B<gencl> | ||
45 | [B<-fv>] | ||
46 | [B<-a> I<FILE>] | ||
47 | [B<-F> I<FILE>] | ||
48 | [B<--amend=>I<FILE>] | ||
49 | [B<--append-dot>] | ||
50 | [B<--append=>I<FILE>] | ||
51 | [B<--file=>I<FILE>] | ||
52 | [B<--force>] | ||
53 | [B<--since=>I<DATE>] | ||
54 | [B<--strip-cherry-pick>] | ||
55 | [B<--until=>I<DATE>] | ||
56 | [B<--verbose>] | ||
57 | |||
58 | B<gencl> B<-h> | B<--help> | B<--usage> | ||
59 | |||
60 | =head1 DESCRIPTION | ||
61 | |||
62 | Retrieves git log messages and reformats them as a valid ChangeLog | ||
63 | file. The file begins with an automatically generated entry stating | ||
64 | the SHA1 hash of the git HEAD commit. This entry is followed by | ||
65 | the log entries recreated from the git log, in reverse chronological | ||
66 | order. By default, entire log is converted. This can be changed by | ||
67 | using B<--since> and/or B<--until> options. Files specified with the | ||
68 | B<--append> options (if any), are appended after the converted entries. | ||
69 | The file ends with the B<emacs> B<Local Variables> stanza. | ||
70 | |||
71 | If the B<ChangeLog> file exists, B<gencl> verifies if the source tree | ||
72 | has changed since the file was created. The file is re-created only if | ||
73 | there were some changes (whether committed or not). The the B<--force> | ||
74 | (B<-f>) option instructs B<gencl> to recreate the file unconditionally. | ||
75 | |||
76 | The file supplied with the B<--amend> option is used to correct spelling | ||
77 | (and other) errors in the log entries. It consists of entries delimited | ||
78 | with one or more empty lines. Each entry begins with a full SHA1 hash | ||
79 | of the commit it applies to. The hash is followed by one or more lines | ||
80 | with a valid Perl code (typically, B<s///> statements). Comments are | ||
81 | introduced with the B<#> sign. For each git log entry, its hash is looked | ||
82 | up in that file. If found, the B<$_> variable is set to the commit subject, | ||
83 | followed by the commit body and the code is evaluated. | ||
84 | |||
85 | =head1 OPTIONS | ||
86 | |||
87 | =over 4 | ||
88 | |||
89 | =item B<-a>, B<--append=>I<FILE> | ||
90 | |||
91 | Append I<FILE> to the end of the generated file. Multiple B<--append> | ||
92 | are processed in the order of their occurrence on the command line. | ||
93 | The content of I<FILE> is appended verbatim, except that the line beginning | ||
94 | with the text B<Local Variables:> is taken to mark the end of file. | ||
95 | |||
96 | =item B<-F>, B<--file=>I<FILE> | ||
97 | |||
98 | Create I<FILE> instead of the B<ChangeLog>. | ||
99 | |||
100 | =item B<-f>, B<--force> | ||
101 | |||
102 | Force recreating the ChangeLog, even if no new commits were added to the | ||
103 | repository since its creation. | ||
104 | |||
105 | =item B<-v>, B<--verbose> | ||
106 | |||
107 | Increase output verbosity. | ||
108 | |||
109 | =item B<--since=>I<DATE> | ||
110 | |||
111 | Convert only the logs since I<DATE>. See B<Time::ParseDate>(3), for | ||
112 | a list of valid I<DATE> formats. | ||
113 | |||
114 | =item B<--until=>I<DATE> | ||
115 | |||
116 | Convert only the logs until I<DATE>. See B<Time::ParseDate>(3), for | ||
117 | a list of valid I<DATE> formats. | ||
118 | |||
119 | =item B<--strip-cherry-pick> | ||
120 | |||
121 | Remove data inserted by B<git cherry-pick>. This includes the "cherry picked | ||
122 | from commit ..." line, and the possible final "Conflicts:" paragraph. | ||
123 | |||
124 | =item B<--amend=>I<FILE> | ||
125 | |||
126 | Read amendment instructions from I<FILE>. | ||
127 | |||
128 | =item B<--append-dot> | ||
129 | |||
130 | Append a dot to the subject line of each commit message if there is no other | ||
131 | punctuation the end. | ||
132 | |||
133 | =back | ||
134 | |||
135 | =head1 DIFFERENCES FROM GITLOG-TO-CHANGELOG | ||
136 | |||
137 | =over 4 | ||
138 | |||
139 | =item 1 | ||
140 | |||
141 | B<gencl> writes output to the disk file, whereas B<gitlog-to-changelog> | ||
142 | prints it to the standard output. | ||
143 | |||
144 | =item 2 | ||
145 | |||
146 | The created B<ChangeLog> begins with an automatically generated entry and | ||
147 | ends with the B<Local Variables> stanza. | ||
148 | |||
149 | =item 3 | ||
150 | |||
151 | The B<ChangeLog> file is re-created only if the source tree was changed | ||
152 | since it was written (whether these changes have been committed or not). | ||
153 | |||
154 | =item 4 | ||
155 | |||
156 | Arbitrary number of files can be concatenated to the produced file. This | ||
157 | is handy for projects that switched to B<git> from other VCS. | ||
158 | |||
159 | =item 5 | ||
160 | |||
161 | Each entry is reformatted using B<Text::Wrap>. | ||
162 | |||
163 | =item 6 | ||
164 | |||
165 | The following B<gitlab-to-changelog> options are not implemented: B<--cluster>, | ||
166 | B<--ignore-matching>, B<--ignore_line>. | ||
167 | |||
168 | =back | ||
169 | |||
170 | =cut | ||
171 | |||
172 | sub pod_usage_msg { | ||
173 | my ($obj) = @_; | ||
174 | open my $fd, '>', \my $msg; | ||
175 | |||
176 | pod2usage(-verbose => 99, | ||
177 | -sections => 'NAME', | ||
178 | -output => $fd, | ||
179 | -exitval => 'NOEXIT'); | ||
180 | my @a = split /\n/, $msg; | ||
181 | $msg = $a[1]; | ||
182 | $msg =~ s/^\s+//; | ||
183 | $msg =~ s/ - /: /; | ||
184 | return $msg; | ||
185 | } | ||
186 | |||
187 | GetOptions( | ||
188 | 'h' => sub { | ||
189 | pod2usage(-message => pod_usage_msg(), | ||
190 | -exitstatus => 0, | ||
191 | -input => pod_where({-inc => 1}, $0)) | ||
192 | }, | ||
193 | 'help' => sub { | ||
194 | pod2usage(-exitstatus => 0, | ||
195 | -verbose => 2, | ||
196 | -input => pod_where({-inc => 1}, $0)); | ||
197 | }, | ||
198 | 'usage' => sub { | ||
199 | pod2usage(-exitstatus => 0, | ||
200 | -verbose => 0, | ||
201 | -input => pod_where({-inc => 1}, $0)); | ||
202 | }, | ||
203 | 'append|a=s@' => \@append_files, | ||
204 | 'file|F=s' => \$changelog_file, | ||
205 | 'force|f' => \$force, | ||
206 | 'verbose|v' => \$verbose, | ||
207 | 'since=s' => sub { $since_date = set_date(@_) }, | ||
208 | 'until=s' => sub { $until_date = set_date(@_) }, | ||
209 | 'strip-cherry-pick' => \$strip_cherry_pick, | ||
210 | 'amend=s' => \$amend_file, | ||
211 | 'append-dot' => \$append_dot | ||
212 | ) or exit(1); | ||
18 | 213 | ||
19 | if (! -d '.git') { | 214 | if (! -d '.git') { |
20 | exit 0; | 215 | exit 0; |
21 | } | 216 | } |
22 | 217 | ||
23 | my ($hash, $date) = split / /, `git log --max-count=1 --pretty=format:'%H %ad' --date=short HEAD`; | 218 | read_amend_file($amend_file) if $amend_file; |
219 | |||
220 | $Text::Wrap::columns = 72; | ||
24 | 221 | ||
25 | my @modlines; | 222 | create_changelog(); |
26 | if (open(my $fd, '-|', 'git diff-index --name-status HEAD 2>/dev/null')) { | ||
27 | chomp(@modlines = map {chomp; [split /\s+/, $_, 2]} <$fd>); | ||