chiark / gitweb /
wip new props arrangements; before abolish props
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 28 Jan 2012 16:41:30 +0000 (16:41 +0000)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 28 Jan 2012 16:41:30 +0000 (16:41 +0000)
BUGS
FORMAT
Topbloke.pm
tb-create.pl
topbloke-merge-driver
topbloke-merge-lists

diff --git a/BUGS b/BUGS
index df77a9fbd98641bbd0b783780e4111d0ac67e745..ffce80d0d0d12168edcd9deeb295341529d1add6 100644 (file)
--- 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 e411d3875fa978e7908561a3f02ff23bce2ccd4b..1b823f05a1c9f8fe95e9ca412d666163f0e09969 100644 (file)
--- 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/<something>
-                       ("# 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)
+                               <topbloke patch name>
+                               .f <ref name including refs/heads/>
+                               .tg <ref name not including refs/heads/>
+                       (empty in base branches)
+
+       props           properties that apply to this patch, one per line
+                        in the format "<name>[ <value>]" (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 <name>    topbloke patch name (in tip and base)
+               topgit <name>   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.
 
 
 <full-name> has the format:
index 5dcfb7124692ad0a6b58bb91ea8adace499a1e22..33aec76b46b6c734e76b1021a0a2d9fca67e319b 100644 (file)
@@ -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 (<FI>) {
+       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 (<FI>) {
        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);
 }
 
index 5c620f35fb30bd5a0186c2f661ac982619d375b2..0e93c45381a8f723c438fecfd37ebf71d91a33b1 100755 (executable)
@@ -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");
index 72c749d5b389dcbf8fa95817880ff67a13992ace..891bfa4ca919c873240369881cff53e1e316473a 100755 (executable)
@@ -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 ?"
index c717c4f149ba108c3bb7dac8f966976e637b273c..ef87b13b01f070f287ba30e4455e21abe26bd7a3 100755 (executable)
@@ -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 (<F>) {
        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;