chiark / gitweb /
update wip - source sorting and selection done
[topbloke.git] / tb-update.pl
index 9cae816c5fcf4430fc7eed7a58d8c9f8afa75b61..767dcf859db49351cdf5aa7da32d82f7f8b56dbc 100755 (executable)
@@ -14,6 +14,28 @@ die "bad usage\n" if @ARGV;
 check_clean_tree();
 
 
+sub memo ($$$) { 
+    my ($memos,$key,$code) = @_;
+    return $memos->{$key} if exists $memos->{$key};
+    debug("----- $key");
+    $memos->{$key} = $code->();
+}
+
+sub merge_base ($$) {
+    my ($r,$s) = @_; # refs, ideally
+    our %memos;
+    return memo(\%memos, "$r $s", sub {
+       run_git_1line(qw(merge-base), $r, $s);
+               });
+}
+
+sub committ_date ($) {
+    my ($ref) = @_;
+    my $l = run_git_1line(qw(git-log --date=raw -n1 --pretty=format:%cd), $ref);
+    $l =~ m/^(\d+)\s/ or die;
+    return $l;
+}
+
 sub update_base ($) {
     my ($patch) = @_;
 
@@ -54,7 +76,11 @@ sub update_base ($) {
            } elsif ($depline =~ m/^-/) {
                die "$depline ?"; # should have failed earlier
            } else {
-               push @sources, { Ref => "$tiprefs/$depline", Kind => 'tb' };
+               push @sources, { 
+                   Name => $depline,
+                   Ref => "$tiprefs/$depline", 
+                   Kind => 'tb',
+               };
            }
        }
 
@@ -62,7 +88,11 @@ sub update_base ($) {
        if ($obk ne 'missing') {
            $obj eq 'blob' or die "$patch $obk ??";
            chomp $tg or die "$patch ??";
-           push @sources, { Ref => "refs/top-bases/$tg", Kind => 'topgit' };
+           push @sources, {
+               Name => "-topgit $tg",
+               Ref => "refs/top-bases/$tg", 
+               Kind => 'topgit',
+           };
        }
 
        # This bit involves rather too much history walking
@@ -71,14 +101,25 @@ sub update_base ($) {
        # Find the merge base for each source
        foreach my $source (@sources) {
            $source->{Head} = run_git_1line(qw(rev-parse), $source->{Ref});
-           $source->{MergeBase} = 
-               run_git_1line(qw(merge-base), $head, "$baserefs/$patch");
+           $source->{MergeBase} = merge_base($head, "$baserefs/$patch");
        }
        # The merge base is contained in $head, so if it is equal
        # to the source's head, the source is contained in $head -
        # ie we are ahead of the source.  Skip those sources.
        @sources = grep { $source->{MergeBase} ne $source->{Head} } @sources;
 
+       our %cmp_memos;
+       @sources = sort { 
+           memo(\%cmp_memos, "$a->{Name} $b->{Name}", sub {
+               my $mb = merge_base($a->{Ref}, $b->{Ref});
+               return -($mb eq $a->{Ref}) cmp ($mb eq $b->{Ref})
+                   # if merge base is $a then $a must be before $b
+                   # ie the commit equal to the merge base is earlier
+                   or (committ_date($a->{Ref}) cmp committ_date($b->{Ref}));
+           })
+       } @sources;
+
+
        # Now we run git-rev-list to walk the graph back to those
        # sources so we can tell which is the most recent.
        foreach my $source (@sources) {