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 df77a9f..ffce80d 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
        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
                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 (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:
 
     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:
                        ("# 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
 
 
     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:
 
 
 <full-name> has the format:
index 5dcfb71..33aec76 100644 (file)
@@ -25,7 +25,7 @@ BEGIN {
                      setup_config check_no_unwanted_metadata
                      patch_matches_spec
                      foreach_patch
                      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 = ( );
                      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 () {
 #----- 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) {
     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,
        return {
            Kind => 'foreign',
            Ref => $ref,
-           DepSpec => "/$ref",
+           DepSpec => ".f $ref",
        };
     } else {
        return {
        };
     } else {
        return {
@@ -361,7 +361,7 @@ sub patch_matches_spec ($$) {
 
 sub foreach_patch ($$$$) {
     my ($spec, $deleted_ok, $want, $body) = @_;
 
 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
     #                                   $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;
        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,
 
            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;
            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};
            }
                debug("foreach_patch  Deleted"), return
                    if !$deleted_ok && $data{Deleted};
            }
@@ -418,19 +425,41 @@ sub foreach_patch ($$$$) {
 
 #----- updating topbloke metadata -----
 
 
 #----- 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;
     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, "$_\n");
     }
     FI->error and die $!;
     close FI or die $!;
-    wf($wf, "$flag\n");
+    wf($wf, "$depspec\n");
     wf_done($wf);
 }
 
     wf_done($wf);
 }
 
index 5c620f3..0e93c45 100755 (executable)
@@ -107,12 +107,12 @@ my $baseref = "refs/topbloke-bases/$newpatch";
 create_and_switch($baseref, 'base');
 
 meta_and_stage('msg', "# not applicable\n");
 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");
 
 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");
 }
 
 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");
 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");
 stage_meta('included');
 
 run_git(qw(commit -q -m), "tb-create $newpatch tip");
index 72c749d..891bfa4 100755 (executable)
@@ -4,36 +4,41 @@ set -e
 fail () { echo >&2 "$0: $*"; exit 127; }
 
 case "$1" in
 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
 *) fail "bad usage" ;;
 esac
 
 whichfile=$1
 ancestor=$2
-current=$3
-other=$4
+ours=$3
+theirs=$4
 markersize=$5
 
 markersize=$5
 
+set -- "$ours" "$ancestor" "$theirs"
+
 case $on.$whichfile in
 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)
        ;;
 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 ?"
        ;;
 *)
        fail "huh $on $whichfile ?"
index c717c4f..ef87b13 100755 (executable)
@@ -7,6 +7,8 @@ use IO::Handle;
 our %flag;
 our (@order, @order_final_maybe);
 our $verbose=0;
 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
 
 # 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//) {
 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//) {
        push @order_final_maybe, $_;
     } elsif (s/^-D//) {
-       $flag{$_}{Result} = 1;
+       $flag{$_}{ForceResult} = 1;
+       $flag{$_}{Result} = '';
        push @order_final_maybe, $_;
     } elsif (m/^-v$/) {
        $verbose = 1;
        push @order_final_maybe, $_;
     } elsif (m/^-v$/) {
        $verbose = 1;
+    } elsif (m/^-P$/) {
+       $propsmode = 1;
+    } elsif (m/^-M(\d+)$/) {
+       $marker = $1;
     } elsif (m/^--$/) {
        last;
     } else {
     } 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;
     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 $!;
     }
     F->error and die $!;
     close F or die $!;
@@ -50,27 +58,55 @@ my $current = $ARGV[0];
 
 open O, '>', "$current.tmp" or die "$current.tmp $!";
 
 
 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 $!";
 }
 
 close O or die $!;
 rename "$current.tmp", "$current" or die "$current $!";
-exit 0;
+exit $conficts ? 1 :0;