Skip to content

Instantly share code, notes, and snippets.

@ribasushi
Last active December 7, 2016 18:16
Show Gist options
  • Save ribasushi/600bcbc0c84f5825b1236fb02c57dda3 to your computer and use it in GitHub Desktop.
Save ribasushi/600bcbc0c84f5825b1236fb02c57dda3 to your computer and use it in GitHub Desktop.

Revisions

  1. ribasushi revised this gist Nov 2, 2016. 1 changed file with 4 additions and 2 deletions.
    6 changes: 4 additions & 2 deletions perl_git_stats.pl
    100644 → 100755
    Original file line number Diff line number Diff line change
    @@ -17,14 +17,16 @@
    no_chdir => 1,
    }, @ARGV);

    chomp( my $head = `git rev-parse --short HEAD` );
    my $total = $author_stats->{"As of $head GRAND_TOTAL"} = {};

    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}
  2. ribasushi created this gist Nov 2, 2016.
    107 changes: 107 additions & 0 deletions perl_git_stats.pl
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,107 @@
    #!/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);

    chomp( my $head = `git rev-parse --short HEAD` );
    my $total = $author_stats->{"As of $head GRAND_TOTAL"} = {};

    for my $author_counts (values %$author_stats) {
    $total->{$_} += $author_counts->{$_}
    for keys %$author_counts;
    }

    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}++;
    }
    }