[Libreoffice-commits] .: bin/lo-commit-stat

Petr Mladek pmladek at kemper.freedesktop.org
Mon Jan 31 10:45:45 PST 2011


 bin/lo-commit-stat |  269 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 269 insertions(+)

New commits:
commit 92f5700e921e2dbd31f93f90d298c83bbee8b528
Author: Petr Mladek <pmladek at suse.cz>
Date:   Mon Jan 31 19:43:03 2011 +0100

    lo-commit-stat: new script for analyzing commit logs
    
    this script can be used to generate the weekly news, release news;
    it might be extended to do even more commit statistics in the future;

diff --git a/bin/lo-commit-stat b/bin/lo-commit-stat
new file mode 100755
index 0000000..aae7ce5
--- /dev/null
+++ b/bin/lo-commit-stat
@@ -0,0 +1,269 @@
+#!/usr/bin/perl
+    eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
+        if $running_under_some_shell;
+#!/usr/bin/perl
+
+use strict;
+
+my $main_repo="bootstrap";
+my @pieces=("artwork", "base", "calc", "components",
+            "extensions", "extras", "filters", "help", "impress",
+            "libs-core", "libs-extern", "libs-extern-sys", "libs-gui",
+            "l10n", "postprocess", "sdk", "testing", "ure", "writer");
+
+sub search_bugs($$$$)
+{
+    my ($pdata, $piece, $commit_id, $line) = @_;
+
+    my $bug = "";
+    my $bug_orig;
+    %{$pdata->{$piece}{$commit_id}{'bugs'}} = ();
+    while (defined $bug) {
+        # match fdo#123, rhz#123, i#123
+        if ( $line =~ m/(\w*\#+\d+)/ ) {
+            $bug_orig = $1;
+            $bug = $1;
+        # match #i123#    
+        } elsif ( $line =~ m/(\#i)(\d+)(\#)/ ) {
+            $bug_orig = $1 . $2 . $3;
+            $bug = $2;
+        } else {
+            $bug = undef;
+            next;
+        }
+        $bug_orig =~ s/\#/\\#/;
+        $line =~ s/[Rr]esolves:\s*$bug_orig\s*//;
+        $line =~ s/\s*-\s*$bug_orig\s*//;
+        $line =~ s/$bug_orig[:,]?\s*//;
+        %{$pdata->{$piece}{$commit_id}{'bugs'}} = () if (! defined %{$pdata->{$piece}{$commit_id}{'bugs'}});
+        $pdata->{$piece}{$commit_id}{'bugs'}{$bug} = 1;
+        $bug = undef;
+        return $line;
+    }
+
+    return $line;
+}
+
+
+sub standardize_summary($)
+{
+    my $line = shift;
+
+    $line =~ s/^\s*//;
+    $line =~ s/\s*$//;
+
+    # lower first letter
+    $line =~ m/(^.)/;
+    my $first_char = lc($1);
+    $line =~ s/^./$first_char/;
+
+    # FIXME: remove do at the end of line
+    #        remove bug numbers
+    return $line;
+}
+
+sub load_git_log($$$$) 
+{
+    my ($pdata, $repo_dir, $piece, $pgit_args) = @_;
+
+    my $cmd = "cd $repo_dir && git log " . join ' ', @{$pgit_args};
+    my $commit_id;
+    my $summary;
+
+    print "Analyzing log from the git repo: $piece...\n";
+
+    open (GIT, "$cmd 2>&1|") || die "Can't run $cmd: $!";
+    %{$pdata->{$piece}} = ();
+
+    while (my $line = <GIT>) {
+        chomp $line;
+
+        if ( $line =~ m/commit ([0-9a-z]{20})/ ) {
+            $commit_id = "$1";
+            $summary=undef;
+            %{$pdata->{$piece}{"$commit_id"}} = ();
+            next;
+        }
+
+        if ( $line =~ /Author:\s*([^\<]*)\<([^\>]*)>/ ) {
+            # get rid of extra empty spaces;
+            my $name = "$1";
+            $name =~ s/\s+$//;
+            die "Error: Author already defined for the commit {$commit_id}\n" if defined ($pdata->{$piece}{$commit_id}{'author'});
+            %{$pdata->{$piece}{$commit_id}{'author'}} = ();
+            $pdata->{$piece}{$commit_id}{'author'}{'name'} = "$name";
+            $pdata->{$piece}{$commit_id}{'author'}{'email'} = "$2";
+            next;
+        }
+        
+        if ( $line =~ /Date:\s+/ ) {
+            # ignore date line
+            next;
+        }
+        
+        if ( $line =~ /^\s*$/ ) {
+            # ignore empty line
+            next;
+        }
+
+        $line = search_bugs($pdata, $piece, $commit_id, $line);
+        # FIXME: need to be implemeted
+#        search_keywords($pdata, $line);
+
+        unless (defined $pdata->{$piece}{$commit_id}{'summary'}) {
+            $summary = standardize_summary($line);
+            $pdata->{$piece}{$commit_id}{'summary'} = $summary;
+        }
+    }
+
+    close GIT;
+}
+
+sub get_repo_name($)
+{
+    my $repo_dir = shift;
+    
+    open (GIT_CONFIG, "$repo_dir/.git/config") ||
+        die "can't open \"$$repo_dir/.git/config\" for reading: $!\n";
+
+    while (my $line = <GIT_CONFIG>) {
+        chomp $line;
+
+        if ( $line =~ /^\s*url\s*=\s*(\S+)$/ ) {
+            my $repo_name = "$1";
+            $repo_name = s/.*\///g;
+            return "$repo_name";
+        }
+    }
+    die "Error: can't find repo name in \"$$repo_dir/.git/config\"\n";
+}
+
+sub load_data($$$$)
+{
+    my ($pdata, $top_dir, $piece, $pgit_args) = @_;
+
+    if (defined $piece) {
+        my $piece_dir;
+        if ("$piece" eq "$main_repo") {
+            $piece_dir = "$top_dir";
+        } else {
+            $piece_dir = "$top_dir/clone/$piece";
+        }
+        load_git_log($pdata, $piece_dir, $piece, $pgit_args);
+    } else {
+        load_git_log($pdata, $top_dir, $main_repo, $pgit_args);
+        foreach my $piece (@pieces) {
+            load_git_log($pdata, "$top_dir/clone/$piece", $piece, $pgit_args);
+        }
+    }
+}
+
+sub print_summary_in_stat($$$$)
+{
+    my ($summary, $pbugs, $pauthors, $prefix) = @_;
+    
+    return if ( $summary eq "" );
+
+    my $bugs = "";
+    if ( %{$pbugs} ) {
+        $bugs = " (" . join (", ", keys %{$pbugs}) . ")";
+    }
+
+    my $authors = "";
+    if ( %{$pauthors} ) {
+        $authors = " [" . join (", ", keys %{$pauthors}) . "]";
+    }
+
+# print only entries with bug numbers
+#    print $prefix . $summary . $bugs . $authors . "\n" if ($bugs ne "");
+    print $prefix . $summary . $bugs . $authors . "\n";
+}
+
+sub print_weekly_stat($)
+{
+    my $pdata = shift;
+
+    foreach my $piece (keys %{$pdata}) {
+        # check if this peice has any entries at all
+        if ( %{$pdata->{$piece}} ) {
+            print "+ $piece\n";
+            my $old_summary="";
+            my %authors = ();
+            my %bugs = ();
+            foreach my $id ( sort { $pdata->{$piece}{$a}{'summary'} cmp $pdata->{$piece}{$b}{'summary'} } keys %{$pdata->{$piece}}) {
+                my $summary = $pdata->{$piece}{$id}{'summary'};
+                if ($summary ne $old_summary) {
+                    print_summary_in_stat($old_summary, \%bugs, \%authors, "    + ");
+                    $old_summary = $summary;
+                    %authors = ();
+                    %bugs = ();
+                }
+                if (defined $pdata->{$piece}{$id}{'bugs'}) {
+                    foreach my $bug (keys %{$pdata->{$piece}{$id}{'bugs'}}) {
+                        $bugs{$bug} = 1;
+                    }
+                }
+                my $author = $pdata->{$piece}{$id}{'author'}{'name'};
+                $authors{$author} = 1;
+            }
+            print_summary_in_stat($old_summary, \%bugs, \%authors, "    + ");
+        }
+    }
+}
+
+########################################################################
+# help
+
+sub usage()
+{
+    print "This script generates LO git commit summary\n\n" .
+          
+          "Usage: lo-commit-stat [--help] [--no-pieces] [--piece=<piece>] topdir [git_log_param...]\n\n" .
+
+          "Options:\n" .
+          "     --help          print this help\n" .
+          "     --no-pieces     read changes just from the main repository, ignore other cloned repos\n" .
+          "     --piece=<piece> summarize just chnages from the given piece\n" .
+          "      topdir         directory with the libreoffice/bootstrap clone; the piece repos\n" .
+          "                     must be cloned in the main-repo-root/clone/<piece> subdirectories\n" .
+          "      git_log_param  extra parameters passed to the git log command to define\n" .
+          "                     the area of interest , e.g. --after=\"2010-09-27\" or\n" .
+          "                     TAG..HEAD";
+}
+
+
+#######################################################################
+#######################################################################
+# MAIN
+#######################################################################
+#######################################################################
+
+
+my $piece;
+my $top_dir;
+my @git_args;
+my %data;
+
+foreach my $arg (@ARGV) {
+    if ($arg eq '--help') {
+        usage();
+        exit;
+    } elsif ($arg eq '--no-pieces') {
+        $piece = "bootstrap";
+    } elsif ($arg =~ m/--piece=(.*)/) {
+	$piece = $1;
+    } else {
+        if (! defined $top_dir) {
+            $top_dir=$arg;
+        } else {
+            push @git_args, $arg;
+        }
+    }
+}
+
+(defined $top_dir) || die "Error: top direcotry is not defined\n";
+(-d "$top_dir") || die "Error: not a directory: $top_dir\n";
+(-f "$top_dir/.git/config") || die "Error: can't find $top_dir/.git/config\n";
+
+load_data(\%data, $top_dir,$piece, \@git_args);
+print_weekly_stat(\%data);


More information about the Libreoffice-commits mailing list