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
        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 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:
 
     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 5dcfb7124692ad0a6b58bb91ea8adace499a1e22..33aec76b46b6c734e76b1021a0a2d9fca67e319b 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 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");
 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 72c749d5b389dcbf8fa95817880ff67a13992ace..891bfa4ca919c873240369881cff53e1e316473a 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 c717c4f149ba108c3bb7dac8f966976e637b273c..ef87b13b01f070f287ba30e4455e21abe26bd7a3 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;