apply unadapted Conway "best practices" where useful
[git-grep-footer.git] / git-grep-footer
index a868319653246030ea7f83e7540b0e78a7ee2e48..92be7b1df1caec6aefaabd3973da1e72e4d1ffa4 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/perl
+#!/usr/bin/env perl
 use 5.010;
 use strict;
 use warnings;
 use 5.010;
 use strict;
 use warnings;
@@ -17,6 +17,7 @@ GetOptions(\my %opt,
        'grep|S=s',
        'min|min-count|unique|u:i',
        'max|max-count|show|n:i',
        'grep|S=s',
        'min|min-count|unique|u:i',
        'max|max-count|show|n:i',
+       'hash|H!',
        'version|V'  => sub { Getopt::Long::VersionMessage() },
        'usage|h'    => sub { Getopt::Long::HelpMessage() },
        'help|man|?' => sub { Getopt::Long::HelpMessage(-verbose => 2) },
        'version|V'  => sub { Getopt::Long::VersionMessage() },
        'usage|h'    => sub { Getopt::Long::HelpMessage() },
        'help|man|?' => sub { Getopt::Long::HelpMessage(-verbose => 2) },
@@ -24,30 +25,28 @@ GetOptions(\my %opt,
 
 my $inputstream = $opt{''} ? \*ARGV : eval {
        require Git;
 
 my $inputstream = $opt{''} ? \*ARGV : eval {
        require Git;
-       Git::command_output_pipe('log', '-z', '--pretty=format:%b', @ARGV);
+       Git::command_output_pipe('log', '-z', '--pretty=format:%h%n%b', @ARGV);
 } || die "Automatic git log failed: $@";
 
 local $| = 1;
 local $/ = "\0";
 
 } || die "Automatic git log failed: $@";
 
 local $| = 1;
 local $/ = "\0";
 
-my $HEADERMATCH = qr/ [a-z]+ (?: (?:-\w+)+ | \ by ) | cc | reference /ix;
+my $HEADERMATCH = qr/ [a-z]+ (?: (?:-\w+)+ | \ by ) | cc | reference /imsx;
 
 my (%headercount, @headercache);
 
 while (readline $inputstream) {
 
 my (%headercount, @headercache);
 
 while (readline $inputstream) {
-       s/^([0-9a-f]{4,40})\n//m and
-       my $hash = $1;
+       s/^ ([0-9a-f]{4,40}) \n//msx;
+       my $hash = $opt{hash} ? $1 : undef;
 
        # strip commit seperator
        chomp;
        # skip expensive checks without potential identifier
        m/:/ or next;
        # try to parse as UTF-8
 
        # strip commit seperator
        chomp;
        # skip expensive checks without potential identifier
        m/:/ or next;
        # try to parse as UTF-8
-       eval { $_ = decode(utf8   => $_, Encode::FB_CROAK()) };
+       eval { $_ = decode(utf8   => $_, Encode::FB_CROAK()); return 1 }
        # if invalid, assume it's latin1
        # if invalid, assume it's latin1
-              $_ = decode(cp1252 => $_) if $@;
-
-       my %attr;
+           or $_ = decode(cp1252 => $_);
 
        BLOCK:
        for (reverse split /\n\n/) {
 
        BLOCK:
        for (reverse split /\n\n/) {
@@ -56,14 +55,14 @@ while (readline $inputstream) {
 
                LINE:
                for (split /\n/) {
 
                LINE:
                for (split /\n/) {
-                       next if not /\S/;
+                       next if not m/\S/;
                        my @header = m{
                                ^
                                (?<key> $HEADERMATCH)
                                : \s*
                        my @header = m{
                                ^
                                (?<key> $HEADERMATCH)
                                : \s*
-                               (?<val> \S .+)
+                               (?<val> \S [^\n]+)
                                $
                                $
-                       }imx or do {
+                       }imsx or do {
                                $prefix++;
                                next LINE;
                        };
                                $prefix++;
                                next LINE;
                        };
@@ -74,16 +73,16 @@ while (readline $inputstream) {
                                for ($header[0]) {
                                        tr/ _/-/;
 
                                for ($header[0]) {
                                        tr/ _/-/;
 
-                                       state $BY = qr{ (?: -? b[yu] )? \Z }ix;
-                                       s{^ si (?:ge?n|n?g) (?:e?[dt])? -? (?:of+)? $BY}{Signed-off-by}ix;
-                                       s{^ ack (?:ed|de)?  $BY}{Acked-by}ix;
-                                       s{^ review (?:e?d)? $BY}{Reviewed-by}ix;
-                                       s{^ teste[dt]       $BY}{Tested-by}ix;
+                                       state $BY = qr{ (?: -? b[yu] )? \Z }imsx;
+                                       s{\A si (?:ge?n|n?g) (?:e?[dt])? -? (?:of+)? $BY}{Signed-off-by}imsx;
+                                       s{\A ack (?:ed|de)?  $BY}{Acked-by}imsx;
+                                       s{\A review (?:e?d)? $BY}{Reviewed-by}imsx;
+                                       s{\A teste[dt]       $BY}{Tested-by}imsx;
                                }
                        }
 
                        if (defined $opt{grep}) {
                                }
                        }
 
                        if (defined $opt{grep}) {
-                               $_ ~~ qr/$opt{grep}/i or next LINE;
+                               $_ ~~ qr/$opt{grep}/im or next LINE;
                        }
 
                        given ($opt{simplify} // 'none') {
                        }
 
                        given ($opt{simplify} // 'none') {
@@ -96,7 +95,7 @@ while (readline $inputstream) {
                                        }{<...>}imsx;
                                }
                                when (['var', 'vars', '']) {
                                        }{<...>}imsx;
                                }
                                when (['var', 'vars', '']) {
-                                       when ($header[0] =~ /[ _-] (?: by | to ) $ | ^cc$/imsx) {
+                                       when ($header[0] =~ m/[ _-] (?: by | to ) $ | ^cc$/imsx) {
                                                $header[1] = undef;
                                        }
                                        for ($header[1]) {
                                                $header[1] = undef;
                                        }
                                        for ($header[1]) {
@@ -134,11 +133,11 @@ while (readline $inputstream) {
 
                for (@headers) {
                        my $line = $_->[2] // join(': ', @$_);
 
                for (@headers) {
                        my $line = $_->[2] // join(': ', @$_);
-                       $line =~ s/^/$hash / if defined $hash;
+                       $line =~ s/\A/$hash /msx if defined $hash;
 
                        if (defined $opt{min} or $opt{max} or $opt{count}) {
                                my $counter = \$headercount{ $_->[0] }->{ $_->[1] // '' };
 
                        if (defined $opt{min} or $opt{max} or $opt{count}) {
                                my $counter = \$headercount{ $_->[0] }->{ $_->[1] // '' };
-                               my $excess = $$counter++ - ($opt{min} // 0);
+                               my $excess = ${$counter}++ - ($opt{min} // 0);
                                next if $excess >= ($opt{max} || 1);
                                next if $excess <  0;
                                if ($opt{count}) {
                                next if $excess >= ($opt{max} || 1);
                                next if $excess <  0;
                                if ($opt{count}) {
@@ -234,6 +233,10 @@ Additional samples are optionally given upto the given maximum.
 Prefixes (unique) lines by the number of occurrences.
 Causes output to be buffered until all input has been read (obviously).
 
 Prefixes (unique) lines by the number of occurrences.
 Causes output to be buffered until all input has been read (obviously).
 
+=item -H, --hash
+
+Prefixes the SHA1 hash of the (or a) matching commit.
+
 =back
 
 =head1 EXAMPLES
 =back
 
 =head1 EXAMPLES
@@ -257,7 +260,7 @@ Compare various capitalisations and (mis)spellings of signoffs.
 
 List the ten most frequently used attribute names.
 
 
 List the ten most frequently used attribute names.
 
-=item git-grep-footer -n2 -i -s -- --reverse
+=item git-grep-footer -n2 -i -s --hash -- --reverse
 
 The earliest two usages of each distinct identifier.
 
 
 The earliest two usages of each distinct identifier.