Last active
December 7, 2016 18:16
-
-
Save ribasushi/600bcbc0c84f5825b1236fb02c57dda3 to your computer and use it in GitHub Desktop.
Simple perl-centric git blame agregator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env perl | |
use warnings; | |
use strict; | |
use File::Find qw/find/; | |
use Data::Dumper::Concise; | |
my $author_stats; | |
die "Need a list of paths as arguments" unless @ARGV; | |
find({ | |
wanted => \&stat_file, | |
follow => 1, | |
follow_skip => 0, | |
no_chdir => 1, | |
}, @ARGV); | |
my $total; | |
for my $author_counts (values %$author_stats) { | |
$total->{$_} += $author_counts->{$_} | |
for keys %$author_counts; | |
} | |
chomp( my $head = `git rev-parse --short HEAD` ); | |
$author_stats->{"As of $head GRAND_TOTAL"} = $total; | |
print ( "${_} stats => " . Dumper $author_stats->{$_}) for ( (sort { | |
( | |
$author_stats->{$b}{code_lines} | |
|| | |
$author_stats->{$b}{total_lines}) | |
<=> | |
( | |
$author_stats->{$a}{code_lines} | |
|| | |
$author_stats->{$a}{total_lines} | |
) | |
} keys %$author_stats)[0..7]); | |
print "...\n\n"; | |
sub stat_file { | |
my $fn = $_; | |
return unless -f $fn; | |
return unless -s $fn; | |
return if $fn =~ m|\Q/.git/|; | |
return unless $fn =~ / \. (?: pl | pm | t | c | h | xs | pod )? $ /xi; | |
my $line_author; | |
for (split /\n/, `git blame -C -C -M -w -e $fn`) { | |
($line_author->{scalar keys %$line_author}) = $_ =~ /\<(.+?)\>/; | |
} | |
die "$fn not in git: perhaps you need to \`git [ stash | commit -a | clean -fxd ]\` ?\n" | |
unless $line_author; | |
my @file_content = do { local ($/, @ARGV) = ("\n", $fn); <> }; | |
chomp $_ for @file_content; | |
my ($in_pod, $past_end); | |
for my $ln_num (0 .. $#file_content) { | |
my $ln_text = $file_content[$ln_num]; | |
my $is_pod; | |
if ($ln_text eq '__END__' or $ln_text eq '__DATA__') { | |
$past_end = 1; | |
} | |
elsif ( | |
$ln_text =~ /^\=cut/ | |
and | |
$ln_num < $#file_content | |
and | |
$file_content[$ln_num+1] eq '' | |
) { | |
$is_pod = 1; | |
$in_pod = 0; | |
} | |
elsif ( | |
$ln_text =~ /^\=\w/ | |
and | |
$ln_num < $#file_content | |
and | |
$file_content[$ln_num+1] eq '' | |
) { | |
$is_pod = $in_pod = 1; | |
} | |
else { | |
$is_pod = $in_pod; | |
} | |
my $type = | |
( $ln_text =~ /^ \s* $/x ) ? "blank" | |
: $is_pod ? "pod" | |
: $past_end ? "misc" | |
: ( $ln_text =~ /^ \s* \#/x ) ? "comment" | |
: "code" | |
; | |
my $as = $author_stats->{$line_author->{$ln_num}} ||= {}; | |
$as->{"${type}_lines"}++; | |
$as->{total_lines}++; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment