#! /usr/bin/perl
# dd5d029143ebb09cab96d0e26f571ab34836a6f1
# Makefile:
#define add-BUILDID
#	@# 'tee -a' would let VIM :make parse H:M:S as an error file:line.
#	@echo "$$(readelf -n $@|sed -n 's/^ *Build ID: //p') $@ $$(if git status|grep -q ^Changes;then echo dirty;else echo clean;fi) $$(git rev-parse HEAD) $$(git status|sed -n 's/^On branch //p') $$(sed -n 's/^CPE_NAME="\(.*\)"$$/\1/p' </etc/os-release) $$(date --iso=seconds)" >>BUILDID
#endef
#TARGET:
#	$(add-BUILDID)
use strict;
use warnings;
my $n=shift @ARGV if ($ARGV[0]||"") eq "-n";
sub readfile($) {
  my($fn)=@_;
  local *F;
  open F,$fn or die "open $fn: $!";
  defined(my $f=do { local $/; <F>; }) or die "read $fn: $!";
  close F or die "close $fn: $!";
  return $f;
}
my $gn="git status|";
my $g=readfile $gn;
$g=~/^.* detached at .*/ and die "detached $gn: $&";
my $branch=($g=~/^On branch (.*)$/m)[0] or die "parse $gn: $g";
warn "branch $branch\n";
my $dirty=($g=~/^Changes/m);
warn(($dirty?"dirty":"clean")."\n");
my $branchhash=readfile "git rev-parse HEAD|";
chomp $branchhash;
$branchhash=~/^[0-9a-f]{40}$/ or die "rev-parse: $branchhash";
my $f=readfile "BUILDID";
$f=join "",(map "$_\n",keys(%{{map(($_=>1),split /\n/,$f)}}));
die "$0: <build-id>" if @ARGV!=1;
my $hash=shift @ARGV;
$hash=~/^[0-9a-f]{40}$/ or die "Invalid argument: $hash";
while (1) {
  my @l=($f=~/^($hash .* clean .*)$/mg);
  die "Not found: $hash" if !@l;
  my $rerun;
  while (1) {
    $rerun=0;
    my $l=$l[0];
    my $lix=1;
    while ($lix<@l) {
      my $li=$l[$lix];
      sub l_strip($) {
	local $_;
	$_=$_[0];
	s/^$hash .* clean ([0-9a-f]{40}) .*$/$1/ or die $_;
	return $_;
      }
      sub is_parent_of($$) {
	my($parent,$child)=@_;
	die if $parent eq $child;
	my $f=readfile "git log --format=%H $parent|";
	die if $f!~/^$parent\n/;
	return if $f!~/^${child}$/m;
	warn "$parent is a parent of $child\n";
	return 1;
      }
      my $done;
      $done=1 if l_strip($l) eq l_strip($li);
      if (!$done&&is_parent_of l_strip($l),l_strip($li)) {
	$l[0]=$li;
	$done=1;
      }
      if ( $done||is_parent_of l_strip($li),l_strip($l)) {
	@l=(@l[0..$lix-1],@l[$lix+1..$#l]);
	$rerun=1;
	next;
      }
      ++$lix;
    }
    next if $rerun;
    last if @l<=1;
    warn "Ambiguous: $hash\n";
    warn "$_\n" for @l;
    die;
  }
  die if @l!=1;
  my $l=$l[0];
  print "$l\n";
  if ($l=~/ clean ([0-9a-f]{40}) /) {
    my $target=$1;
    if ($target eq $branchhash) {
      print "already switched\n";
    } else {
      my $cmd="git checkout $target";
      print "$cmd\n";
      if (!$n) {
	die "dirty" if $dirty;
	my $rc=system $cmd;
	die "system=$rc" if $rc;
      }
    }
    exit 0;
  }
  die "Invalid line: $l";
}
