From: Mike Frysinger Date: Sun, 10 Jan 2021 03:18:00 +0000 (-0500) Subject: gnulib: import gitlog-to-changelog X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=0fa6376c7ae7bc8d15f7b4d3f2efadd793ffcae6;p=binutils-gdb.git gnulib: import gitlog-to-changelog This is going to be used to generate ChangeLog files. --- diff --git a/gnulib/ChangeLog b/gnulib/ChangeLog index c16fc3f4e9a..810aa1e62da 100644 --- a/gnulib/ChangeLog +++ b/gnulib/ChangeLog @@ -1,3 +1,12 @@ +2021-03-24 Mike Frysinger + + * update-gnulib.sh (IMPORTED_GNULIB_MODULES): Add gitlog-to-changelog. + * Makefile.in, configure: Regenerate. + * import/Makefile.am, import/Makefile.in: Regenerate. + * import/m4/gnulib-cache.m4: Regenerate. + * import/m4/gnulib-comp.m4: Regenerate. + * import/extra/gitlog-to-changelog: New file. + 2021-02-05 Paul E. Murphy * update-gnulib.sh (GNULIB_COMMIT_SHA1): Bump to diff --git a/gnulib/configure b/gnulib/configure index 63b2b1fc431..d6737ac4d3e 100644 --- a/gnulib/configure +++ b/gnulib/configure @@ -6726,6 +6726,7 @@ fi # Code from module getrandom: # Code from module gettext-h: # Code from module gettimeofday: + # Code from module gitlog-to-changelog: # Code from module glob: # Code from module glob-h: # Code from module hard-locale: diff --git a/gnulib/import/Makefile.am b/gnulib/import/Makefile.am index de8d7dec0ba..a79d6e1e537 100644 --- a/gnulib/import/Makefile.am +++ b/gnulib/import/Makefile.am @@ -43,6 +43,7 @@ # frexpl \ # getcwd \ # gettimeofday \ +# gitlog-to-changelog \ # glob \ # inet_ntop \ # inttypes \ @@ -738,6 +739,13 @@ EXTRA_libgnu_a_SOURCES += gettimeofday.c ## end gnulib module gettimeofday +## begin gnulib module gitlog-to-changelog + + +EXTRA_DIST += $(top_srcdir)/import/extra/gitlog-to-changelog + +## end gnulib module gitlog-to-changelog + ## begin gnulib module glob diff --git a/gnulib/import/Makefile.in b/gnulib/import/Makefile.in index 224a5176419..f703f362f73 100644 --- a/gnulib/import/Makefile.in +++ b/gnulib/import/Makefile.in @@ -57,6 +57,7 @@ # frexpl \ # getcwd \ # gettimeofday \ +# gitlog-to-changelog \ # glob \ # inet_ntop \ # inttypes \ @@ -1781,34 +1782,36 @@ EXTRA_DIST = m4/gnulib-cache.m4 alloca.c alloca.in.h arpa_inet.in.h \ fnmatch.c fnmatch_loop.c fnmatch.c fnmatch.in.h fpucw.h free.c \ frexp.c frexp.c frexpl.c fstat.c stat-w32.c stat-w32.h \ at-func.c fstatat.c getcwd.c getcwd-lgpl.c getdtablesize.c \ - getlogin_r.c getrandom.c gettimeofday.c glob.c glob_internal.h \ - glob_pattern_p.c globfree.c glob-libc.h glob.in.h \ - hard-locale.h inet_ntop.c intprops.h inttypes.in.h isblank.c \ - float+.h isnan.c isnand-nolibm.h isnand.c float+.h isnan.c \ - isnanl-nolibm.h isnanl.c cdefs.h libc-config.h limits.in.h \ - localcharset.h locale.in.h lstat.c malloc.c malloca.h \ - math.in.h lc-charset-dispatch.c lc-charset-dispatch.h \ - mbrtowc-impl-utf8.h mbrtowc-impl.h mbrtowc.c mbtowc-lock.c \ - mbtowc-lock.h windows-initguard.h mbsinit.c mbsrtowcs-impl.h \ - mbsrtowcs-state.c mbsrtowcs.c mbtowc-impl.h mbtowc.c memchr.c \ - memchr.valgrind memmem.c memmem.c str-two-way.h mempcpy.c \ - memrchr.c mkdir.c mkdtemp.c mkostemp.c msvc-inval.c \ - msvc-inval.h msvc-nothrow.c msvc-nothrow.h netinet_in.in.h \ - open.c openat.c openat.h dirent-private.h opendir.c pathmax.h \ - pipe.c rawmemchr.c rawmemchr.valgrind dirent-private.h \ - readdir.c readlink.c realloc.c rename.c dirent-private.h \ - rewinddir.c rmdir.c same-inode.h save-cwd.h \ - malloc/scratch_buffer.h scratch_buffer.h setenv.c \ - setlocale-lock.c setlocale_null.h windows-initguard.h \ - signal.in.h _Noreturn.h arg-nonnull.h c++defs.h warn-on-use.h \ - stat-w32.c stat-w32.h stat.c stat-time.h stdalign.in.h \ - stdbool.in.h stddef.in.h stdint.in.h stdio.in.h stdlib.in.h \ - strchrnul.c strchrnul.valgrind strdup.c streq.h strerror.c \ - strerror-override.c strerror-override.h strerror_r.c \ - string.in.h strnlen.c strstr.c str-two-way.h strstr.c \ - strtok_r.c sys_random.in.h sys_socket.in.h sys_stat.in.h \ - sys_time.in.h sys_types.in.h sys_uio.in.h tempname.h time.in.h \ - time_r.c unistd.in.h unistd--.h unistd-safer.h unsetenv.c \ + getlogin_r.c getrandom.c gettimeofday.c \ + $(top_srcdir)/import/extra/gitlog-to-changelog glob.c \ + glob_internal.h glob_pattern_p.c globfree.c glob-libc.h \ + glob.in.h hard-locale.h inet_ntop.c intprops.h inttypes.in.h \ + isblank.c float+.h isnan.c isnand-nolibm.h isnand.c float+.h \ + isnan.c isnanl-nolibm.h isnanl.c cdefs.h libc-config.h \ + limits.in.h localcharset.h locale.in.h lstat.c malloc.c \ + malloca.h math.in.h lc-charset-dispatch.c \ + lc-charset-dispatch.h mbrtowc-impl-utf8.h mbrtowc-impl.h \ + mbrtowc.c mbtowc-lock.c mbtowc-lock.h windows-initguard.h \ + mbsinit.c mbsrtowcs-impl.h mbsrtowcs-state.c mbsrtowcs.c \ + mbtowc-impl.h mbtowc.c memchr.c memchr.valgrind memmem.c \ + memmem.c str-two-way.h mempcpy.c memrchr.c mkdir.c mkdtemp.c \ + mkostemp.c msvc-inval.c msvc-inval.h msvc-nothrow.c \ + msvc-nothrow.h netinet_in.in.h open.c openat.c openat.h \ + dirent-private.h opendir.c pathmax.h pipe.c rawmemchr.c \ + rawmemchr.valgrind dirent-private.h readdir.c readlink.c \ + realloc.c rename.c dirent-private.h rewinddir.c rmdir.c \ + same-inode.h save-cwd.h malloc/scratch_buffer.h \ + scratch_buffer.h setenv.c setlocale-lock.c setlocale_null.h \ + windows-initguard.h signal.in.h _Noreturn.h arg-nonnull.h \ + c++defs.h warn-on-use.h stat-w32.c stat-w32.h stat.c \ + stat-time.h stdalign.in.h stdbool.in.h stddef.in.h stdint.in.h \ + stdio.in.h stdlib.in.h strchrnul.c strchrnul.valgrind strdup.c \ + streq.h strerror.c strerror-override.c strerror-override.h \ + strerror_r.c string.in.h strnlen.c strstr.c str-two-way.h \ + strstr.c strtok_r.c sys_random.in.h sys_socket.in.h \ + sys_stat.in.h sys_time.in.h sys_types.in.h sys_uio.in.h \ + tempname.h time.in.h time_r.c unistd.in.h unistd--.h \ + unistd-safer.h unsetenv.c \ $(top_srcdir)/import/extra/update-copyright verify.h \ wchar.in.h wctype.in.h windows-initguard.h windows-mutex.c \ windows-mutex.h windows-once.c windows-once.h \ diff --git a/gnulib/import/extra/gitlog-to-changelog b/gnulib/import/extra/gitlog-to-changelog new file mode 100755 index 00000000000..de76f658d48 --- /dev/null +++ b/gnulib/import/extra/gitlog-to-changelog @@ -0,0 +1,515 @@ +#!/bin/sh +#! -*-perl-*- + +# Convert git log output to ChangeLog format. + +# Copyright (C) 2008-2021 Free Software Foundation, Inc. +# +# This program 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, either version 3 of the License, or +# (at your option) any later version. +# +# 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 . +# +# Written by Jim Meyering + +# This is a prologue that allows to run a perl script as an executable +# on systems that are compliant to a POSIX version before POSIX:2017. +# On such systems, the usual invocation of an executable through execlp() +# or execvp() fails with ENOEXEC if it is a script that does not start +# with a #! line. The script interpreter mentioned in the #! line has +# to be /bin/sh, because on GuixSD systems that is the only program that +# has a fixed file name. The second line is essential for perl and is +# also useful for editing this file in Emacs. The next two lines below +# are valid code in both sh and perl. When executed by sh, they re-execute +# the script through the perl program found in $PATH. The '-x' option +# is essential as well; without it, perl would re-execute the script +# through /bin/sh. When executed by perl, the next two lines are a no-op. +eval 'exec perl -wSx "$0" "$@"' + if 0; + +my $VERSION = '2020-04-04 15:07'; # UTC +# The definition above must lie within the first 8 lines in order +# for the Emacs time-stamp write hook (at end) to update it. +# If you change this file with Emacs, please let the write hook +# do its job. Otherwise, update this string manually. + +use strict; +use warnings; +use Getopt::Long; +use POSIX qw(strftime); + +(my $ME = $0) =~ s|.*/||; + +# use File::Coda; # https://meyering.net/code/Coda/ +END { + defined fileno STDOUT or return; + close STDOUT and return; + warn "$ME: failed to close standard output: $!\n"; + $? ||= 1; +} + +sub usage ($) +{ + my ($exit_code) = @_; + my $STREAM = ($exit_code == 0 ? *STDOUT : *STDERR); + if ($exit_code != 0) + { + print $STREAM "Try '$ME --help' for more information.\n"; + } + else + { + print $STREAM < ChangeLog + $ME -- -n 5 foo > last-5-commits-to-branch-foo + +SPECIAL SYNTAX: + +The following types of strings are interpreted specially when they appear +at the beginning of a log message line. They are not copied to the output. + + Copyright-paperwork-exempt: Yes + Append the "(tiny change)" notation to the usual "date name email" + ChangeLog header to mark a change that does not require a copyright + assignment. + Co-authored-by: Joe User + List the specified name and email address on a second + ChangeLog header, denoting a co-author. + Signed-off-by: Joe User + These lines are simply elided. + +In a FILE specified via --amend, comment lines (starting with "#") are ignored. +FILE must consist of pairs where SHA is a 40-byte SHA1 (alone on +a line) referring to a commit in the current project, and CODE refers to one +or more consecutive lines of Perl code. Pairs must be separated by one or +more blank line. + +Here is sample input for use with --amend=FILE, from coreutils: + +3a169f4c5d9159283548178668d2fae6fced3030 +# fix typo in title: +s/all tile types/all file types/ + +1379ed974f1fa39b12e2ffab18b3f7a607082202 +# Due to a bug in vc-dwim, I mis-attributed a patch by Paul to myself. +# Change the author to be Paul. Note the escaped "@": +s,Jim .*>,Paul Eggert , + +EOF + } + exit $exit_code; +} + +# If the string $S is a well-behaved file name, simply return it. +# If it contains white space, quotes, etc., quote it, and return the new string. +sub shell_quote($) +{ + my ($s) = @_; + if ($s =~ m![^\w+/.,-]!) + { + # Convert each single quote to '\'' + $s =~ s/\'/\'\\\'\'/g; + # Then single quote the string. + $s = "'$s'"; + } + return $s; +} + +sub quoted_cmd(@) +{ + return join (' ', map {shell_quote $_} @_); +} + +# Parse file F. +# Comment lines (starting with "#") are ignored. +# F must consist of pairs where SHA is a 40-byte SHA1 +# (alone on a line) referring to a commit in the current project, and +# CODE refers to one or more consecutive lines of Perl code. +# Pairs must be separated by one or more blank line. +sub parse_amend_file($) +{ + my ($f) = @_; + + open F, '<', $f + or die "$ME: $f: failed to open for reading: $!\n"; + + my $fail; + my $h = {}; + my $in_code = 0; + my $sha; + while (defined (my $line = )) + { + $line =~ /^\#/ + and next; + chomp $line; + $line eq '' + and $in_code = 0, next; + + if (!$in_code) + { + $line =~ /^([[:xdigit:]]{40})$/ + or (warn "$ME: $f:$.: invalid line; expected an SHA1\n"), + $fail = 1, next; + $sha = lc $1; + $in_code = 1; + exists $h->{$sha} + and (warn "$ME: $f:$.: duplicate SHA1\n"), + $fail = 1, next; + } + else + { + $h->{$sha} ||= ''; + $h->{$sha} .= "$line\n"; + } + } + close F; + + $fail + and exit 1; + + return $h; +} + +# git_dir_option $SRCDIR +# +# From $SRCDIR, the --git-dir option to pass to git (none if $SRCDIR +# is undef). Return as a list (0 or 1 element). +sub git_dir_option($) +{ + my ($srcdir) = @_; + my @res = (); + if (defined $srcdir) + { + my $qdir = shell_quote $srcdir; + my $cmd = "cd $qdir && git rev-parse --show-toplevel"; + my $qcmd = shell_quote $cmd; + my $git_dir = qx($cmd); + defined $git_dir + or die "$ME: cannot run $qcmd: $!\n"; + $? == 0 + or die "$ME: $qcmd had unexpected exit code or signal ($?)\n"; + chomp $git_dir; + push @res, "--git-dir=$git_dir/.git"; + } + @res; +} + +{ + my $since_date; + my $until_date; + my $format_string = '%s%n%b%n'; + my $amend_file; + my $append_dot = 0; + my $cluster = 1; + my $ignore_matching; + my $ignore_line; + my $strip_tab = 0; + my $strip_cherry_pick = 0; + my $srcdir; + GetOptions + ( + help => sub { usage 0 }, + version => sub { print "$ME version $VERSION\n"; exit }, + 'since=s' => \$since_date, + 'until=s' => \$until_date, + 'format=s' => \$format_string, + 'amend=s' => \$amend_file, + 'append-dot' => \$append_dot, + 'cluster!' => \$cluster, + 'ignore-matching=s' => \$ignore_matching, + 'ignore-line=s' => \$ignore_line, + 'strip-tab' => \$strip_tab, + 'strip-cherry-pick' => \$strip_cherry_pick, + 'srcdir=s' => \$srcdir, + ) or usage 1; + + defined $since_date + and unshift @ARGV, "--since=$since_date"; + defined $until_date + and unshift @ARGV, "--until=$until_date"; + + # This is a hash that maps an SHA1 to perl code (i.e., s/old/new/) + # that makes a correction in the log or attribution of that commit. + my $amend_code = defined $amend_file ? parse_amend_file $amend_file : {}; + + my @cmd = ('git', + git_dir_option $srcdir, + qw(log --log-size), + '--pretty=format:%H:%ct %an <%ae>%n%n'.$format_string, @ARGV); + open PIPE, '-|', @cmd + or die ("$ME: failed to run '". quoted_cmd (@cmd) ."': $!\n" + . "(Is your Git too old? Version 1.5.1 or later is required.)\n"); + + my $prev_multi_paragraph; + my $prev_date_line = ''; + my @prev_coauthors = (); + my @skipshas = (); + while (1) + { + defined (my $in = ) + or last; + $in =~ /^log size (\d+)$/ + or die "$ME:$.: Invalid line (expected log size):\n$in"; + my $log_nbytes = $1; + + my $log; + my $n_read = read PIPE, $log, $log_nbytes; + $n_read == $log_nbytes + or die "$ME:$.: unexpected EOF\n"; + + # Extract leading hash. + my ($sha, $rest) = split ':', $log, 2; + defined $sha + or die "$ME:$.: malformed log entry\n"; + $sha =~ /^[[:xdigit:]]{40}$/ + or die "$ME:$.: invalid SHA1: $sha\n"; + + my $skipflag = 0; + if (@skipshas) + { + foreach(@skipshas) + { + if ($sha =~ /^$_/) + { + $skipflag = $_; + last; + } + } + } + + # If this commit's log requires any transformation, do it now. + my $code = $amend_code->{$sha}; + if (defined $code) + { + eval 'use Safe'; + my $s = new Safe; + # Put the unpreprocessed entry into "$_". + $_ = $rest; + + # Let $code operate on it, safely. + my $r = $s->reval("$code") + or die "$ME:$.:$sha: failed to eval \"$code\":\n$@\n"; + + # Note that we've used this entry. + delete $amend_code->{$sha}; + + # Update $rest upon success. + $rest = $_; + } + + # Remove lines inserted by "git cherry-pick". + if ($strip_cherry_pick) + { + $rest =~ s/^\s*Conflicts:\n.*//sm; + $rest =~ s/^\s*\(cherry picked from commit [\da-f]+\)\n//m; + } + + my @line = split /[ \t]*\n/, $rest; + my $author_line = shift @line; + defined $author_line + or die "$ME:$.: unexpected EOF\n"; + $author_line =~ /^(\d+) (.*>)$/ + or die "$ME:$.: Invalid line " + . "(expected date/author/email):\n$author_line\n"; + + # Format 'Copyright-paperwork-exempt: Yes' as a standard ChangeLog + # `(tiny change)' annotation. + my $tiny = (grep (/^(?:Copyright-paperwork-exempt|Tiny-change):\s+[Yy]es$/, @line) + ? ' (tiny change)' : ''); + + my $date_line = sprintf "%s %s$tiny\n", + strftime ("%Y-%m-%d", localtime ($1)), $2; + + my @coauthors = grep /^Co-authored-by:.*$/, @line; + # Omit meta-data lines we've already interpreted. + @line = grep !/^(?:Signed-off-by:[ ].*>$ + |Co-authored-by:[ ] + |Copyright-paperwork-exempt:[ ] + |Tiny-change:[ ] + )/x, @line; + + # Remove leading and trailing blank lines. + if (@line) + { + while ($line[0] =~ /^\s*$/) { shift @line; } + while ($line[$#line] =~ /^\s*$/) { pop @line; } + } + + # Handle Emacs gitmerge.el "skipped" commits. + # Yes, this should be controlled by an option. So sue me. + if ( grep /^(; )?Merge from /, @line ) + { + my $found = 0; + foreach (@line) + { + if (grep /^The following commit.*skipped:$/, $_) + { + $found = 1; + ## Reset at each merge to reduce chance of false matches. + @skipshas = (); + next; + } + if ($found && $_ =~ /^([[:xdigit:]]{7,}) [^ ]/) + { + push ( @skipshas, $1 ); + } + } + } + + # Ignore commits that match the --ignore-matching pattern, if specified. + if (defined $ignore_matching && @line && $line[0] =~ /$ignore_matching/) + { + $skipflag = 1; + } + elsif ($skipflag) + { + ## Perhaps only warn if a pattern matches more than once? + warn "$ME: warning: skipping $sha due to $skipflag\n"; + } + + if (! $skipflag) + { + if (defined $ignore_line && @line) + { + @line = grep ! /$ignore_line/, @line; + while ($line[$#line] =~ /^\s*$/) { pop @line; } + } + + # Record whether there are two or more paragraphs. + my $multi_paragraph = grep /^\s*$/, @line; + + # Format 'Co-authored-by: A U Thor ' lines in + # standard multi-author ChangeLog format. + for (@coauthors) + { + s/^Co-authored-by:\s*/\t /; + s/\s*/ + or warn "$ME: warning: missing email address for " + . substr ($_, 5) . "\n"; + } + + # If clustering of commit messages has been disabled, if this header + # would be different from the previous date/name/etc. header, + # or if this or the previous entry consists of two or more paragraphs, + # then print the header. + if ( ! $cluster + || $date_line ne $prev_date_line + || "@coauthors" ne "@prev_coauthors" + || $multi_paragraph + || $prev_multi_paragraph) + { + $prev_date_line eq '' + or print "\n"; + print $date_line; + @coauthors + and print join ("\n", @coauthors), "\n"; + } + $prev_date_line = $date_line; + @prev_coauthors = @coauthors; + $prev_multi_paragraph = $multi_paragraph; + + # If there were any lines + if (@line == 0) + { + warn "$ME: warning: empty commit message:\n $date_line\n"; + } + else + { + if ($append_dot) + { + # If the first line of the message has enough room, then + if (length $line[0] < 72) + { + # append a dot if there is no other punctuation or blank + # at the end. + $line[0] =~ /[[:punct:]\s]$/ + or $line[0] .= '.'; + } + } + + # Remove one additional leading TAB from each line. + $strip_tab + and map { s/^\t// } @line; + + # Prefix each non-empty line with a TAB. + @line = map { length $_ ? "\t$_" : '' } @line; + + print "\n", join ("\n", @line), "\n"; + } + } + + defined ($in = ) + or last; + $in ne "\n" + and die "$ME:$.: unexpected line:\n$in"; + } + + close PIPE + or die "$ME: error closing pipe from " . quoted_cmd (@cmd) . "\n"; + # FIXME-someday: include $PROCESS_STATUS in the diagnostic + + # Complain about any unused entry in the --amend=F specified file. + my $fail = 0; + foreach my $sha (keys %$amend_code) + { + warn "$ME:$amend_file: unused entry: $sha\n"; + $fail = 1; + } + + exit $fail; +} + +# Local Variables: +# mode: perl +# indent-tabs-mode: nil +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-line-limit: 50 +# time-stamp-start: "my $VERSION = '" +# time-stamp-format: "%:y-%02m-%02d %02H:%02M" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "'; # UTC" +# End: diff --git a/gnulib/import/m4/gnulib-cache.m4 b/gnulib/import/m4/gnulib-cache.m4 index 40873824b2b..00dcf604059 100644 --- a/gnulib/import/m4/gnulib-cache.m4 +++ b/gnulib/import/m4/gnulib-cache.m4 @@ -48,6 +48,7 @@ # frexpl \ # getcwd \ # gettimeofday \ +# gitlog-to-changelog \ # glob \ # inet_ntop \ # inttypes \ @@ -89,6 +90,7 @@ gl_MODULES([ frexpl getcwd gettimeofday + gitlog-to-changelog glob inet_ntop inttypes diff --git a/gnulib/import/m4/gnulib-comp.m4 b/gnulib/import/m4/gnulib-comp.m4 index 682bfc86e78..c3926e0d06d 100644 --- a/gnulib/import/m4/gnulib-comp.m4 +++ b/gnulib/import/m4/gnulib-comp.m4 @@ -107,6 +107,7 @@ AC_DEFUN([gl_EARLY], # Code from module getrandom: # Code from module gettext-h: # Code from module gettimeofday: + # Code from module gitlog-to-changelog: # Code from module glob: # Code from module glob-h: # Code from module hard-locale: @@ -923,6 +924,7 @@ AC_DEFUN([gltests_LIBSOURCES], [ # This macro records the list of files which have been installed by # gnulib-tool and may be removed by future gnulib-tool invocations. AC_DEFUN([gl_FILE_LIST], [ + build-aux/gitlog-to-changelog build-aux/update-copyright lib/_Noreturn.h lib/alloca.c diff --git a/gnulib/update-gnulib.sh b/gnulib/update-gnulib.sh index 02d045b5348..c734829126f 100755 --- a/gnulib/update-gnulib.sh +++ b/gnulib/update-gnulib.sh @@ -40,6 +40,7 @@ IMPORTED_GNULIB_MODULES="\ frexpl \ getcwd \ gettimeofday \ + gitlog-to-changelog \ glob \ inet_ntop inttypes \