From 494c30db6e5fd21d19e8dfc9a10fd37fe46529d0 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Sat, 28 Jan 2012 16:41:30 +0000 Subject: [PATCH] wip new props arrangements; before abolish props --- BUGS | 4 +++ FORMAT | 36 +++++++++++-------- Topbloke.pm | 57 ++++++++++++++++++++++-------- tb-create.pl | 10 +++--- topbloke-merge-driver | 39 +++++++++++--------- topbloke-merge-lists | 82 +++++++++++++++++++++++++++++++------------ 6 files changed, 154 insertions(+), 74 deletions(-) diff --git a/BUGS b/BUGS index df77a9f..ffce80d 100644 --- a/BUGS +++ b/BUGS @@ -9,6 +9,10 @@ wibblings: topgit import topbloke {base,tip} is ff desc of topgit {base,tip} with metadata adjusted + topbloke branch has all the deps of the topgit + branch (topgit branches mapped into topbloke + branches) plus the topgit branch itself named in + flags reject topbloke imports of topgit branches which also contain topbloke metadata need patch name in metadata diff --git a/FORMAT b/FORMAT index e411d38..1b823f0 100644 --- a/FORMAT +++ b/FORMAT @@ -10,31 +10,37 @@ In-tree, there are metadata files in .topbloke Files which are per-patch and do not inherit any contents or changes from bases or dependencies: - msg brach "commit message" + msg patch "commit message" ("# not applicable" in bases) deps direct dependencies, one per line as either: - topbloke patch name - /refs/heads/ - ("# not applicable" in bases) - - flags flags that apply to this patch, one per line - base has its own, perhaps different, set of flags; - Unknown flags starting with [a-z] are ok; - otherwise fatal. Currently defined flags: - Deleted patch is deleted - (valid on tip only) + + .f + .tg + (empty in base branches) + + props properties that apply to this patch, one per line + in the format "[ ]" (exactly one + space) where value can contain spaces and + a missing value is distinct from a missing property + but value if present must be nonempty + base has its own, perhaps different, set of props; + Unknown props starting with [a-z] are ok; + otherwise fatal. Currently defined props: + patch topbloke patch name (in tip and base) + topgit this is a topgit import (in tip and base) + Deleted patch is deleted (in tip only, no value) Files which not inherit contents and changes from dependencies: included actual included deps, one per line format as for deps - pflags flags that apply to this patch and all its - dependencies (ie, flags that propagate) - Unknown flags starting with [a-z] are ok; - otherwise fatal. No currently defined flags + pprops properties that apply to this patch and all its + dependencies (ie, properties that propagate) + Unknown props starting with [a-z] are ok; + otherwise fatal. No currently defined props. has the format: diff --git a/Topbloke.pm b/Topbloke.pm index 5dcfb71..33aec76 100644 --- a/Topbloke.pm +++ b/Topbloke.pm @@ -25,7 +25,7 @@ BEGIN { setup_config check_no_unwanted_metadata patch_matches_spec foreach_patch - flagsfile_add_flag + propsfile_add_prop depsfile_add_dep wf_start wf wf_abort wf_done wf_contents closeout); %EXPORT_TAGS = ( ); @@ -182,7 +182,7 @@ sub check_no_unwanted_metadata ($) { #----- configuring a tree ----- sub setup_config () { - my (@files) = (qw(msg deps included flags pflags)); + my (@files) = (qw(msg deps included props pprops)); my $version = 1; foreach my $iteration (qw(0 1)) { foreach my $file (@files) { @@ -262,7 +262,7 @@ sub current_branch () { return { Kind => 'foreign', Ref => $ref, - DepSpec => "/$ref", + DepSpec => ".f $ref", }; } else { return { @@ -361,7 +361,7 @@ sub patch_matches_spec ($$) { sub foreach_patch ($$$$) { my ($spec, $deleted_ok, $want, $body) = @_; - # runs $body->($patch, $parsedname, \%flags, \%deps, \%pflags, \%included) + # runs $body->($patch, $parsedname, \%props, \%deps, \%pprops, \%included) # $want->[0] 1 2 3 # where $deps->{$fullname} etc. are 1 for true or nonexistent for false # and if $want->[$item] is not true, the corresponding item may be undef @@ -376,7 +376,7 @@ sub foreach_patch ($$$$) { my @out; my $patch = substr($',19); #'); my $wantix = 0; - foreach my $file (qw(flags deps pflags included)) { + foreach my $file (qw(props deps pprops included)) { if ($file eq 'deps') { # do this check after checking for deleted patches, @@ -400,9 +400,16 @@ sub foreach_patch ($$$$) { my ($got, $data) = git_get_object("$objname:.topbloke/$file"); die "$patch $file ?" unless defined $data; my %data; - $data{$_}=1 foreach split /\n/, $data; + if ($file !~ m/props/) { + $data{$_}=1 foreach split /\n/, $data; + } elseif { + foreach (split /\n/, $data) { + m/ / or m/$/; + $data{$`} = $'; #'; + } + } - if ($file eq 'flags') { + if ($file eq 'props') { debug("foreach_patch Deleted"), return if !$deleted_ok && $data{Deleted}; } @@ -418,19 +425,41 @@ sub foreach_patch ($$$$) { #----- updating topbloke metadata ----- -sub flagsfile_add_flag ($$) { - # works on "deps" too - my ($flagsfile, $flag) = @_; - my $wf = wf_start(".topbloke/$flagsfile"); - open FI, '<', ".topbloke/$flagsfile" or die $!; +sub propsfile_set_prop ($$$) { + # set $value to undef to delete; returns old value + my ($propsfile, $prop, $value) = @_; + my $wf = wf_start(".topbloke/$propsfile"); + my $oldvalue; + open FI, '<', ".topbloke/$propsfile" or die $!; + while () { + chomp or die; + m/ / or m/$/; + if ($` eq $prop) { + die "prop $prop repeated in $propsfile ?!" if defined $oldvalue; + $oldvalue = $'; #'; + } else { + wf($wf, "$_\n"); + } + } + FI->error and die $!; + close FI or die $!; + wf($wf, "$prop $value\n") if defined $value; + wf_done($wf); + return $oldvalue; +} + +sub depssfile_add_dep ($$) { + my ($depsfile, $depspec) = @_; + my $wf = wf_start(".topbloke/$depsfile"); + open FI, '<', ".topbloke/$depsfile" or die $!; while () { chomp or die; - die "flag $flag already set in $flagsfile ?!" if $_ eq $flag; + die "dep $depspec already set in $depsfile ?!" if $_ eq $depspec; wf($wf, "$_\n"); } FI->error and die $!; close FI or die $!; - wf($wf, "$flag\n"); + wf($wf, "$depspec\n"); wf_done($wf); } diff --git a/tb-create.pl b/tb-create.pl index 5c620f3..0e93c45 100755 --- a/tb-create.pl +++ b/tb-create.pl @@ -107,12 +107,12 @@ my $baseref = "refs/topbloke-bases/$newpatch"; create_and_switch($baseref, 'base'); meta_and_stage('msg', "# not applicable\n"); -meta_and_stage('deps', "# not applicable\n"); -meta_and_stage('flags', ''); +meta_and_stage('deps', ""); +meta_and_stage('props', "patch $current->{Fullname}\n"); if ($current->{Kind} eq 'foreign') { meta_and_stage('included', $current->{DepSpec}."\n"); - meta_and_stage('pflags', ''); + meta_and_stage('pprops', ''); } run_git(qw(commit -q -m), "tb-create $newpatch base"); @@ -141,9 +141,9 @@ wf_done($nm); stage_meta('msg'); meta_and_stage('deps', "$current->{DepSpec}\n"); -# we inherit empty flags from the base branch +# we inherit correct props and pprops from the base branch -flagsfile_add_flag('included',$newpatch); +depsfile_add_dep('included','tb',$newpatch); stage_meta('included'); run_git(qw(commit -q -m), "tb-create $newpatch tip"); diff --git a/topbloke-merge-driver b/topbloke-merge-driver index 72c749d..891bfa4 100755 --- a/topbloke-merge-driver +++ b/topbloke-merge-driver @@ -4,36 +4,41 @@ set -e fail () { echo >&2 "$0: $*"; exit 127; } case "$1" in ---v1) how=tip ;; ---v1-base) how=base ;; ---v1-dep) how=dep ;; +--v1) how=tip ;; # merge into tip from another tip of this patch +--v1-base) how=base ;; # merge into tip from a base of this patch +--v1-dep) how=dep ;; # merge into base from a dep's tip *) fail "bad usage" ;; esac whichfile=$1 ancestor=$2 -current=$3 -other=$4 +ours=$3 +theirs=$4 markersize=$5 +set -- "$ours" "$ancestor" "$theirs" + case $on.$whichfile in -dep.msg|dep.deps|dep.flags) - touch "$current" - exit 0 +dep.msg|dep.deps|dep.props) + touch "$ours" ;; -base.msg|base.deps) - echo '# not applicable' >"$current" - exit 0 +base.msg) + echo '# not applicable' >"$ours" +base.deps) + echo >"$ours" + touch >"$ours" ;; -base.flags) - exec topbloke-merge-lists -UDeleted "$current" "$ancestor" "$other" +base.props) + exec topbloke-merge-lists -M$markersize -P -UDeleted "$@" ;; tip.msg) - exec git-merge-file --marker-size=$markersize \ - "$current" "$ancestor" "$other" + exec git-merge-file --marker-size=$markersize "$@" + ;; +tip.deps|*.included) + exec topbloke-merge-lists -M$markersize "$@" ;; -tip.deps|tip.flags|*.included|*.pflags) - exec topbloke-merge-lists "$current" "$ancestor" "$other" +tip.props|*.pprops) + exec topbloke-merge-lists -M$markersize -P "$@" ;; *) fail "huh $on $whichfile ?" diff --git a/topbloke-merge-lists b/topbloke-merge-lists index c717c4f..ef87b13 100755 --- a/topbloke-merge-lists +++ b/topbloke-merge-lists @@ -7,6 +7,8 @@ use IO::Handle; our %flag; our (@order, @order_final_maybe); our $verbose=0; +our $propsmode=0; +our $marker=5; # we don't use Getopt::Long because we want to be quick to start up # and we're not really a very user-facing utility @@ -14,13 +16,19 @@ our $verbose=0; while (@ARGV && $ARGV[0] =~ m/^\-/) { $_ = shift @ARGV; if (s/^-U//) { - $flag{$_}{Result} = 0; + $flag{$_}{ForceResult} = 1; + $flag{$_}{Result} = undef; push @order_final_maybe, $_; } elsif (s/^-D//) { - $flag{$_}{Result} = 1; + $flag{$_}{ForceResult} = 1; + $flag{$_}{Result} = ''; push @order_final_maybe, $_; } elsif (m/^-v$/) { $verbose = 1; + } elsif (m/^-P$/) { + $propsmode = 1; + } elsif (m/^-M(\d+)$/) { + $marker = $1; } elsif (m/^--$/) { last; } else { @@ -34,9 +42,9 @@ foreach my $ix (qw(0 1 2)) { open F, '<', $ARGV[$ix] or die "$ix $!"; while () { chomp or die; - $flag{$_}{Input}[$ix] = 1; - my $ff = $flag{$_}; - push @order, $_ unless $ff->{InOrder}++; + ($propsmode && m/ /) or m/$/; + $flag{$`}{Input}[$ix] = $'; #'; + push @order, $` unless $flag{$`}{InOrder}++; } F->error and die $!; close F or die $!; @@ -50,27 +58,55 @@ my $current = $ARGV[0]; open O, '>', "$current.tmp" or die "$current.tmp $!"; -foreach $_ (@order) { - my $ff = $flag{$_}; - if (!defined $ff->{Result}) { - my $s = ''; - foreach my $ix (qw(0 1 2)) { - $ff->{Input}[$ix] ||= 0; - $s .= $ff->{Input}[$ix]; - } - if ($verbose) { - print STDERR "MERGE-LISTS $s $_\n" or die $!; +sub prmark ($) { + print O $_[0] x $marker, "\n" or die $!; + } +sub prval ($) { + my $v = @_; + print O $v,"\n" or die $! if defined $v; +} + +our $f; + +if ($verbose) { + sub verb ($) { print STDERR "MERGE_LISTS $f @_\n" or die $!; } +} else { + sub verb { } +} + +our $conflicts = 0; + +foreach $f (@order) { + my $ff = $flag{$f}; + verb("BEGIN"); + if (defined $ff->{ForceResult}) { + verb("FORCE"); + } else { + my @in = @{ $ff->{Input} }; + verb(defined ? "DEF $_": "U") foreach @in; + if (iseq($in[0], $in[2])) { + verb("SAME"); + $ff->{Result} = [0]; + } elsif (iseq($in[0], $in[1])) { + verb("THEIRS"); + $ff->{Result} = $in[2]; + } elsif (iseq($in[2], $in[1])) { + verb("OURS"); + $ff->{Result} = $in[0]; + } else { + $conflicts++; + verb("CONFLICT"); + prmark('<'); + prval($in[0]); + prmark('='); + prval($in[2]); + prmark('>'); + next; } - $ff->{Result} = - $s eq '000' ? '000' : - $s eq '111' ? '111' : - !$ff->{Input}[1]; - } - if ($ff->{Result}) { - print O "$_\n" or die $!; } + prval($ff->{Result}); } close O or die $!; rename "$current.tmp", "$current" or die "$current $!"; -exit 0; +exit $conficts ? 1 :0; -- 2.30.2