From: Ian Jackson Date: Sun, 22 Jan 2012 15:28:46 +0000 (+0000) Subject: wip X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?a=commitdiff_plain;h=98c96c9695b93d1ed7cf2ea81d1851364faad0ba;p=topbloke.git wip --- diff --git a/FORMAT b/FORMAT index 258e073..447a3fb 100644 --- a/FORMAT +++ b/FORMAT @@ -7,6 +7,9 @@ Topbloke branch is: In-tree, there are metadata files in .topbloke + Files which are per-branch and do not inherit any contents + or changes from dependencies: + msg brach "commit message" deps direct dependencies, one per line @@ -14,15 +17,23 @@ In-tree, there are metadata files in .topbloke topbloke branch name /refs/heads/ - included actual included branches, one per line - topbloke branch name - flags flags that apply to this branch, one per line - unknown flags starting with [a-z] are ok; + Unknown flags starting with [a-z] are ok; otherwise fatal. Currently defined flags: Deleted branch is deleted + Files which not inherit contents and changes from dependencies: + + included actual included branches, one per line + topbloke branch name + + pflags flags that apply to this branch and all its + dependencies (ie, flags that propagate) + Unknown flags starting with [a-z] are ok; + otherwise fatal. No currently defined flags + + has the format: @/--
TZ/ where nickname-path's first component must not start with a digit diff --git a/Topbloke.pm b/Topbloke.pm index 2c9abe4..f1c0615 100644 --- a/Topbloke.pm +++ b/Topbloke.pm @@ -25,31 +25,74 @@ sub debug ($) { print STDERR "DEBUG: $msg\n" or die $!; } -sub run_git_1line { +sub run_git { + # takes optional prefix arguments: + # coderef hook to call for each line read, + # with $_ containing chomped line; if not supplied, + # output is not read + # scalarref place to store exit status; if not supplied, + # nonzero exit status is fatal + my ($estatusr,$linecallr); + while (ref $_[0]) { + my $ref = shift @_; + if (ref $ref eq 'SCALAR') { + $estatusr = $ref; + } elsif (ref $ref eq 'CODE') { + $linecallr = $ref; + } else { + die ref($ref)." @_ ?"; + } + } open GIT, "-|", 'git', @_ or die $!; - my $l = ; - $?=0; - close GIT or die "git @_ failed ($?)\n"; - chomp $l or die "@_ ?"; + if ($linecallr) { + while () { + chomp or die "$_ ?"; + $linecallr->(); + } + GIT->eof or die $!; + } + if (!close GIT) { + die "git @_ $!" if $!; + die unless $?; + die "git @_ ($?)" unless $estatusr; + $$estatusr = $?; + } else { + $$estatusr = 0 if $estatusr; + } +} + +sub run_git_1line { + my $l; + run_git(sub { $l = $_; }, @_); + die "git @_ ?" unless defined $l; return $l; } -sub run_git_1line_estatus { - open GIT, "-|", 'git', @_ or die $!; - my $l = ; - $?=0; - if (close GIT) { - chomp $l or die "@_ ?"; - return (0,$l); - } else { - die unless $?; - return ($?,undef); - } +sub run_git_check_nooutput { + my ($what) = shift @_; + run_git(sub { die "$what $_\n"; }, @_); } -sub run_git_nooutput { - my $rc = system('git', @_); - die "git @_ failed ($rc)" if $rc; +sub run_git_test_anyoutput { + my $any = 0; + run_git(sub { $any=1; }, @_); + return $any; +} + +sub git_config ($$) { + my ($cfgvar, $default) = @_; + my ($l, $estatus); + run_git(\$estatus, sub { + die if defined $l; + $l = $_; }, + qw(config), $cfgvar); + if (defined $l) { + die "$cfgvar ($estatus)" if $estatus; + return $l; + } else { + die "$cfgvar ($estatus)" unless $estatus==0 || $estatus==256; + return $default; + } } sub git_dir () { @@ -148,22 +191,23 @@ sub parse_branch_spec ($) { } sub setup_config () { - my (@files) = (qw(msg deps included flags)); + my (@files) = (qw(msg deps included flags pflags)); my $version = 1; foreach my $iteration (qw(0 1)) { foreach my $file (@files) { my $cfgname = "merge.topbloke-$file"; - my ($current_estatus, $current) = - run_git_1line_estatus(qw(config), "$cfgname.driver"); + my $current_estatus; + my $current = run_git_1line(\$current_estatus, + qw(config), "$cfgname.driver"); $current = "## failed $current_estatus" if $current_estatus; next if $current =~ m/^topbloke-merge-driver --v$version /o; die "$file $current ?" if $iteration; debug("setting merge driver $file"); - run_git_nooutput(qw(config), "$cfgname.name", - "topbloke merge driver for $file"); - run_git_nooutput(qw(config), "$cfgname.driver", - "topbloke-merge-driver --v$version". - " $file %O %A %B %L"); + run_git(qw(config), "$cfgname.name", + "topbloke merge driver for $file"); + run_git(qw(config), "$cfgname.driver", + "topbloke-merge-driver --v$version". + " $file %O %A %B %L"); } my ($newattrs, $attrsfile); foreach my $file (@files) { @@ -198,16 +242,12 @@ sub setup_config () { } sub check_no_unwanted_metadata ($) { + # for checking foreign branches aren't contaminated my ($gitbranch) = @_; - open GIT, "-|", 'git', qw(ls-tree --name-status), - "$gitbranch:", qw(.topbloke/included .topbloke/flags) - or die $!; - while () { - chomp or die; - die "foreign unexpectedly contains $_\n"; - } - GIT->error and die $!; - close GIT or die $!; + run_git_check_nooutput('foreign unexpectedly contains', + qw(ls-tree --name-only), + "$gitbranch:", + qw(.topbloke)); } 1; diff --git a/tb-create.pl b/tb-create.pl index 79d4274..591a72e 100755 --- a/tb-create.pl +++ b/tb-create.pl @@ -44,6 +44,13 @@ length($spec->{Date})==18 or die "partial date specified, not supported\n"; check_no_unwanted_metadata('HEAD') if $current->{Kind} ne 'tip'; +# For the metadata files in .topbloke, we hope that the user +# doesn't modify them. If they do then they get to keep all the pieces. +# +# For .topbloke/msg, if it's modified by the user (ie, if working +# version differs from HEAD) we keep that, and we stage it unless +# the cached version differs from the HEAD. + my $newbranch = "$spec->{Email}\@$spec->{Domain}/$spec->{Date}/$spec->{Nick}"; $newbranch = run_git_1line(qw(check-ref-format --print), $newbranch); @@ -52,3 +59,34 @@ printf "creating %s\n", $newbranch; setup_config(); +if (!run_git_test_anyoutput(qw(diff --name-only HEAD -- .topbloke/msg)) { + open NM, '>', ".topbloke/msg.tmp" or die $!; + my $author = run_git_1line(qw(var GIT_AUTHOR_IDENT)); + $author =~ s/ \d+ [-+]\d+$//; + print NM "From: $author\n" or die $!; + foreach my $h (qw(To CC BCC)) { + my $estatus; + run_git(\$estatus, sub { print NM "$h: $_" or die $!; }, + qw(config), "topbloke.".lc $h); + die "$h $estatus" unless $estatus==0 || $estatus==256; + } + $subjprefix = git_config('topbloke.subjectprefix', ''); + print NM {Nick} + + + +Signed-off-by: $author +END + run_git(qw(add .topbloke/msg)); + print " created and staged new .topbloke/msg\n"; +} else { + if (!run_git_test_anyoutput(qw(diff --cached --name-only HEAD -- + .topblokemsg))) { + print " staged your modified .topbloke/msg\n"; + run_git(qw(add .topbloke/msg)); + } else { + print " left your (partially staged?) .topbloke/msg\n"; + } +} + diff --git a/topbloke-merge-driver b/topbloke-merge-driver index c90680e..72c749d 100755 --- a/topbloke-merge-driver +++ b/topbloke-merge-driver @@ -4,8 +4,9 @@ set -e fail () { echo >&2 "$0: $*"; exit 127; } case "$1" in ---v1) on=tip ;; ---base-v1) on=base ;; +--v1) how=tip ;; +--v1-base) how=base ;; +--v1-dep) how=dep ;; *) fail "bad usage" ;; esac @@ -16,21 +17,24 @@ other=$4 markersize=$5 case $on.$whichfile in -tip.msg) - exec git-merge-file --marker-size=$markersize \ - "$current" "$ancestor" "$other" +dep.msg|dep.deps|dep.flags) + touch "$current" + exit 0 ;; base.msg|base.deps) echo '# not applicable' >"$current" exit 0 ;; -*.included|tip.deps|tip.flags) - exec topbloke-merge-lists "$current" "$ancestor" "$other" - ;; base.flags) - exec topbloke-merge-lists -UDeleted \ + exec topbloke-merge-lists -UDeleted "$current" "$ancestor" "$other" + ;; +tip.msg) + exec git-merge-file --marker-size=$markersize \ "$current" "$ancestor" "$other" ;; +tip.deps|tip.flags|*.included|*.pflags) + exec topbloke-merge-lists "$current" "$ancestor" "$other" + ;; *) fail "huh $on $whichfile ?" ;;