~ubuntu-branches/ubuntu/utopic/coreutils/utopic-proposed

« back to all changes in this revision

Viewing changes to build-aux/gitlog-to-changelog

  • Committer: Package Import Robot
  • Author(s): Colin Watson
  • Date: 2012-11-28 03:03:42 UTC
  • mfrom: (8.3.4 sid)
  • Revision ID: package-import@ubuntu.com-20121128030342-21zanj8354gas5gr
Tags: 8.20-3ubuntu1
* Resynchronise with Debian.  Remaining changes:
  - Make 'uname -i -p' return the real processor/hardware, instead of
    unknown.
  - Build-depend on gettext:any instead of on gettext, so that apt-get can
    properly resolve build-dependencies on the tool when cross-building.

Show diffs side-by-side

added added

removed removed

Lines of Context:
3
3
    if 0;
4
4
# Convert git log output to ChangeLog format.
5
5
 
6
 
my $VERSION = '2009-10-30 13:46'; # UTC
 
6
my $VERSION = '2012-07-29 06:11'; # UTC
7
7
# The definition above must lie within the first 8 lines in order
8
8
# for the Emacs time-stamp write hook (at end) to update it.
9
9
# If you change this file with Emacs, please let the write hook
10
10
# do its job.  Otherwise, update this string manually.
11
11
 
12
 
# Copyright (C) 2008-2011 Free Software Foundation, Inc.
 
12
# Copyright (C) 2008-2012 Free Software Foundation, Inc.
13
13
 
14
14
# This program is free software: you can redistribute it and/or modify
15
15
# it under the terms of the GNU General Public License as published by
47
47
  my $STREAM = ($exit_code == 0 ? *STDOUT : *STDERR);
48
48
  if ($exit_code != 0)
49
49
    {
50
 
      print $STREAM "Try `$ME --help' for more information.\n";
 
50
      print $STREAM "Try '$ME --help' for more information.\n";
51
51
    }
52
52
  else
53
53
    {
60
60
 
61
61
OPTIONS:
62
62
 
 
63
   --amend=FILE FILE maps from an SHA1 to perl code (i.e., s/old/new/) that
 
64
                  makes a change to SHA1's commit log text or metadata.
 
65
   --append-dot append a dot to the first line of each commit message if
 
66
                  there is no other punctuation or blank at the end.
 
67
   --no-cluster never cluster commit messages under the same date/author
 
68
                  header; the default is to cluster adjacent commit messages
 
69
                  if their headers are the same and neither commit message
 
70
                  contains multiple paragraphs.
 
71
   --srcdir=DIR the root of the source tree, from which the .git/
 
72
                  directory can be derived.
63
73
   --since=DATE convert only the logs since DATE;
64
74
                  the default is to convert all log entries.
65
75
   --format=FMT set format string for commit subject and body;
66
76
                  see 'man git-log' for the list of format metacharacters;
67
77
                  the default is '%s%n%b%n'
68
 
 
 
78
   --strip-tab  remove one additional leading TAB from commit message lines.
 
79
   --strip-cherry-pick  remove data inserted by "git cherry-pick";
 
80
                  this includes the "cherry picked from commit ..." line,
 
81
                  and the possible final "Conflicts:" paragraph.
69
82
   --help       display this help and exit
70
83
   --version    output version information and exit
71
84
 
74
87
  $ME --since=2008-01-01 > ChangeLog
75
88
  $ME -- -n 5 foo > last-5-commits-to-branch-foo
76
89
 
 
90
SPECIAL SYNTAX:
 
91
 
 
92
The following types of strings are interpreted specially when they appear
 
93
at the beginning of a log message line.  They are not copied to the output.
 
94
 
 
95
  Copyright-paperwork-exempt: Yes
 
96
    Append the "(tiny change)" notation to the usual "date name email"
 
97
    ChangeLog header to mark a change that does not require a copyright
 
98
    assignment.
 
99
  Co-authored-by: Joe User <user\@example.com>
 
100
    List the specified name and email address on a second
 
101
    ChangeLog header, denoting a co-author.
 
102
  Signed-off-by: Joe User <user\@example.com>
 
103
    These lines are simply elided.
 
104
 
 
105
In a FILE specified via --amend, comment lines (starting with "#") are ignored.
 
106
FILE must consist of <SHA,CODE+> pairs where SHA is a 40-byte SHA1 (alone on
 
107
a line) referring to a commit in the current project, and CODE refers to one
 
108
or more consecutive lines of Perl code.  Pairs must be separated by one or
 
109
more blank line.
 
110
 
 
111
Here is sample input for use with --amend=FILE, from coreutils:
 
112
 
 
113
3a169f4c5d9159283548178668d2fae6fced3030
 
114
# fix typo in title:
 
115
s/all tile types/all file types/
 
116
 
 
117
1379ed974f1fa39b12e2ffab18b3f7a607082202
 
118
# Due to a bug in vc-dwim, I mis-attributed a patch by Paul to myself.
 
119
# Change the author to be Paul.  Note the escaped "@":
 
120
s,Jim .*>,Paul Eggert <eggert\\\@cs.ucla.edu>,
 
121
 
77
122
EOF
78
123
    }
79
124
  exit $exit_code;
99
144
  return join (' ', map {shell_quote $_} @_);
100
145
}
101
146
 
102
 
{
103
 
  my $since_date = '1970-01-01 UTC';
 
147
# Parse file F.
 
148
# Comment lines (starting with "#") are ignored.
 
149
# F must consist of <SHA,CODE+> pairs where SHA is a 40-byte SHA1
 
150
# (alone on a line) referring to a commit in the current project, and
 
151
# CODE refers to one or more consecutive lines of Perl code.
 
152
# Pairs must be separated by one or more blank line.
 
153
sub parse_amend_file($)
 
154
{
 
155
  my ($f) = @_;
 
156
 
 
157
  open F, '<', $f
 
158
    or die "$ME: $f: failed to open for reading: $!\n";
 
159
 
 
160
  my $fail;
 
161
  my $h = {};
 
162
  my $in_code = 0;
 
163
  my $sha;
 
164
  while (defined (my $line = <F>))
 
165
    {
 
166
      $line =~ /^\#/
 
167
        and next;
 
168
      chomp $line;
 
169
      $line eq ''
 
170
        and $in_code = 0, next;
 
171
 
 
172
      if (!$in_code)
 
173
        {
 
174
          $line =~ /^([0-9a-fA-F]{40})$/
 
175
            or (warn "$ME: $f:$.: invalid line; expected an SHA1\n"),
 
176
              $fail = 1, next;
 
177
          $sha = lc $1;
 
178
          $in_code = 1;
 
179
          exists $h->{$sha}
 
180
            and (warn "$ME: $f:$.: duplicate SHA1\n"),
 
181
              $fail = 1, next;
 
182
        }
 
183
      else
 
184
        {
 
185
          $h->{$sha} ||= '';
 
186
          $h->{$sha} .= "$line\n";
 
187
        }
 
188
    }
 
189
  close F;
 
190
 
 
191
  $fail
 
192
    and exit 1;
 
193
 
 
194
  return $h;
 
195
}
 
196
 
 
197
# git_dir_option $SRCDIR
 
198
#
 
199
# From $SRCDIR, the --git-dir option to pass to git (none if $SRCDIR
 
200
# is undef).  Return as a list (0 or 1 element).
 
201
sub git_dir_option($)
 
202
{
 
203
  my ($srcdir) = @_;
 
204
  my @res = ();
 
205
  if (defined $srcdir)
 
206
    {
 
207
      my $qdir = shell_quote $srcdir;
 
208
      my $cmd = "cd $qdir && git rev-parse --show-toplevel";
 
209
      my $qcmd = shell_quote $cmd;
 
210
      my $git_dir = qx($cmd);
 
211
      defined $git_dir
 
212
        or die "$ME: cannot run $qcmd: $!\n";
 
213
      $? == 0
 
214
        or die "$ME: $qcmd had unexpected exit code or signal ($?)\n";
 
215
      chomp $git_dir;
 
216
      push @res, "--git-dir=$git_dir/.git";
 
217
    }
 
218
  @res;
 
219
}
 
220
 
 
221
{
 
222
  my $since_date;
104
223
  my $format_string = '%s%n%b%n';
 
224
  my $amend_file;
 
225
  my $append_dot = 0;
 
226
  my $cluster = 1;
 
227
  my $strip_tab = 0;
 
228
  my $strip_cherry_pick = 0;
 
229
  my $srcdir;
105
230
  GetOptions
106
231
    (
107
232
     help => sub { usage 0 },
108
233
     version => sub { print "$ME version $VERSION\n"; exit },
109
234
     'since=s' => \$since_date,
110
235
     'format=s' => \$format_string,
 
236
     'amend=s' => \$amend_file,
 
237
     'append-dot' => \$append_dot,
 
238
     'cluster!' => \$cluster,
 
239
     'strip-tab' => \$strip_tab,
 
240
     'strip-cherry-pick' => \$strip_cherry_pick,
 
241
     'srcdir=s' => \$srcdir,
111
242
    ) or usage 1;
112
243
 
113
 
  my @cmd = (qw (git log --log-size), "--since=$since_date",
114
 
             '--pretty=format:%ct  %an  <%ae>%n%n'.$format_string, @ARGV);
 
244
  defined $since_date
 
245
    and unshift @ARGV, "--since=$since_date";
 
246
 
 
247
  # This is a hash that maps an SHA1 to perl code (i.e., s/old/new/)
 
248
  # that makes a correction in the log or attribution of that commit.
 
249
  my $amend_code = defined $amend_file ? parse_amend_file $amend_file : {};
 
250
 
 
251
  my @cmd = ('git',
 
252
             git_dir_option $srcdir,
 
253
             qw(log --log-size),
 
254
             '--pretty=format:%H:%ct  %an  <%ae>%n%n'.$format_string, @ARGV);
115
255
  open PIPE, '-|', @cmd
116
 
    or die ("$ME: failed to run `". quoted_cmd (@cmd) ."': $!\n"
 
256
    or die ("$ME: failed to run '". quoted_cmd (@cmd) ."': $!\n"
117
257
            . "(Is your Git too old?  Version 1.5.1 or later is required.)\n");
118
258
 
 
259
  my $prev_multi_paragraph;
119
260
  my $prev_date_line = '';
 
261
  my @prev_coauthors = ();
120
262
  while (1)
121
263
    {
122
264
      defined (my $in = <PIPE>)
130
272
      $n_read == $log_nbytes
131
273
        or die "$ME:$.: unexpected EOF\n";
132
274
 
133
 
      my @line = split "\n", $log;
 
275
      # Extract leading hash.
 
276
      my ($sha, $rest) = split ':', $log, 2;
 
277
      defined $sha
 
278
        or die "$ME:$.: malformed log entry\n";
 
279
      $sha =~ /^[0-9a-fA-F]{40}$/
 
280
        or die "$ME:$.: invalid SHA1: $sha\n";
 
281
 
 
282
      # If this commit's log requires any transformation, do it now.
 
283
      my $code = $amend_code->{$sha};
 
284
      if (defined $code)
 
285
        {
 
286
          eval 'use Safe';
 
287
          my $s = new Safe;
 
288
          # Put the unpreprocessed entry into "$_".
 
289
          $_ = $rest;
 
290
 
 
291
          # Let $code operate on it, safely.
 
292
          my $r = $s->reval("$code")
 
293
            or die "$ME:$.:$sha: failed to eval \"$code\":\n$@\n";
 
294
 
 
295
          # Note that we've used this entry.
 
296
          delete $amend_code->{$sha};
 
297
 
 
298
          # Update $rest upon success.
 
299
          $rest = $_;
 
300
        }
 
301
 
 
302
      # Remove lines inserted by "git cherry-pick".
 
303
      if ($strip_cherry_pick)
 
304
        {
 
305
          $rest =~ s/^\s*Conflicts:\n.*//sm;
 
306
          $rest =~ s/^\s*\(cherry picked from commit [\da-f]+\)\n//m;
 
307
        }
 
308
 
 
309
      my @line = split "\n", $rest;
134
310
      my $author_line = shift @line;
135
311
      defined $author_line
136
312
        or die "$ME:$.: unexpected EOF\n";
138
314
        or die "$ME:$.: Invalid line "
139
315
          . "(expected date/author/email):\n$author_line\n";
140
316
 
141
 
      my $date_line = sprintf "%s  $2\n", strftime ("%F", localtime ($1));
142
 
      # If this line would be the same as the previous date/name/email
143
 
      # line, then arrange not to print it.
144
 
      if ($date_line ne $prev_date_line)
 
317
      # Format 'Copyright-paperwork-exempt: Yes' as a standard ChangeLog
 
318
      # `(tiny change)' annotation.
 
319
      my $tiny = (grep (/^Copyright-paperwork-exempt:\s+[Yy]es$/, @line)
 
320
                  ? '  (tiny change)' : '');
 
321
 
 
322
      my $date_line = sprintf "%s  %s$tiny\n",
 
323
        strftime ("%F", localtime ($1)), $2;
 
324
 
 
325
      my @coauthors = grep /^Co-authored-by:.*$/, @line;
 
326
      # Omit meta-data lines we've already interpreted.
 
327
      @line = grep !/^(?:Signed-off-by:[ ].*>$
 
328
                       |Co-authored-by:[ ]
 
329
                       |Copyright-paperwork-exempt:[ ]
 
330
                       )/x, @line;
 
331
 
 
332
      # Remove leading and trailing blank lines.
 
333
      if (@line)
 
334
        {
 
335
          while ($line[0] =~ /^\s*$/) { shift @line; }
 
336
          while ($line[$#line] =~ /^\s*$/) { pop @line; }
 
337
        }
 
338
 
 
339
      # Record whether there are two or more paragraphs.
 
340
      my $multi_paragraph = grep /^\s*$/, @line;
 
341
 
 
342
      # Format 'Co-authored-by: A U Thor <email@example.com>' lines in
 
343
      # standard multi-author ChangeLog format.
 
344
      for (@coauthors)
 
345
        {
 
346
          s/^Co-authored-by:\s*/\t    /;
 
347
          s/\s*</  </;
 
348
 
 
349
          /<.*?@.*\..*>/
 
350
            or warn "$ME: warning: missing email address for "
 
351
              . substr ($_, 5) . "\n";
 
352
        }
 
353
 
 
354
      # If clustering of commit messages has been disabled, if this header
 
355
      # would be different from the previous date/name/email/coauthors header,
 
356
      # or if this or the previous entry consists of two or more paragraphs,
 
357
      # then print the header.
 
358
      if ( ! $cluster
 
359
          || $date_line ne $prev_date_line
 
360
          || "@coauthors" ne "@prev_coauthors"
 
361
          || $multi_paragraph
 
362
          || $prev_multi_paragraph)
145
363
        {
146
364
          $prev_date_line eq ''
147
365
            or print "\n";
148
366
          print $date_line;
 
367
          @coauthors
 
368
            and print join ("\n", @coauthors), "\n";
149
369
        }
150
370
      $prev_date_line = $date_line;
151
 
 
152
 
      # Omit "Signed-off-by..." lines.
153
 
      @line = grep !/^Signed-off-by: .*>$/, @line;
 
371
      @prev_coauthors = @coauthors;
 
372
      $prev_multi_paragraph = $multi_paragraph;
154
373
 
155
374
      # If there were any lines
156
375
      if (@line == 0)
159
378
        }
160
379
      else
161
380
        {
162
 
          # Remove leading and trailing blank lines.
163
 
          while ($line[0] =~ /^\s*$/) { shift @line; }
164
 
          while ($line[$#line] =~ /^\s*$/) { pop @line; }
 
381
          if ($append_dot)
 
382
            {
 
383
              # If the first line of the message has enough room, then
 
384
              if (length $line[0] < 72)
 
385
                {
 
386
                  # append a dot if there is no other punctuation or blank
 
387
                  # at the end.
 
388
                  $line[0] =~ /[[:punct:]\s]$/
 
389
                    or $line[0] .= '.';
 
390
                }
 
391
            }
 
392
 
 
393
          # Remove one additional leading TAB from each line.
 
394
          $strip_tab
 
395
            and map { s/^\t// } @line;
165
396
 
166
397
          # Prefix each non-empty line with a TAB.
167
398
          @line = map { length $_ ? "\t$_" : '' } @line;
178
409
  close PIPE
179
410
    or die "$ME: error closing pipe from " . quoted_cmd (@cmd) . "\n";
180
411
  # FIXME-someday: include $PROCESS_STATUS in the diagnostic
 
412
 
 
413
  # Complain about any unused entry in the --amend=F specified file.
 
414
  my $fail = 0;
 
415
  foreach my $sha (keys %$amend_code)
 
416
    {
 
417
      warn "$ME:$amend_file: unused entry: $sha\n";
 
418
      $fail = 1;
 
419
    }
 
420
 
 
421
  exit $fail;
181
422
}
182
423
 
183
424
# Local Variables: