[Bps-public-commit] r11288 - in SVN-PropDB: . lib/Prophet lib/Prophet/Sync/Source t

jesse at bestpractical.com jesse at bestpractical.com
Mon Mar 31 03:44:28 EDT 2008


Author: jesse
Date: Mon Mar 31 03:44:28 2008
New Revision: 11288

Modified:
   SVN-PropDB/   (props changed)
   SVN-PropDB/lib/Prophet/Change.pm
   SVN-PropDB/lib/Prophet/Conflict.pm
   SVN-PropDB/lib/Prophet/Handle.pm
   SVN-PropDB/lib/Prophet/Sync/Source.pm
   SVN-PropDB/lib/Prophet/Sync/Source/SVN.pm
   SVN-PropDB/t/simple-conflicting-merge.t

Log:
 r28827 at 99-205-68-110:  jesse | 2008-03-30 21:44:12 -1000
 debugging a phantom commit


Modified: SVN-PropDB/lib/Prophet/Change.pm
==============================================================================
--- SVN-PropDB/lib/Prophet/Change.pm	(original)
+++ SVN-PropDB/lib/Prophet/Change.pm	Mon Mar 31 03:44:28 2008
@@ -41,7 +41,7 @@
 
 sub prop_changes {
     my $self = shift;
-    return @{$self->{prop_changes}};
+    return @{$self->{prop_changes}||[]};
 }
 
 

Modified: SVN-PropDB/lib/Prophet/Conflict.pm
==============================================================================
--- SVN-PropDB/lib/Prophet/Conflict.pm	(original)
+++ SVN-PropDB/lib/Prophet/Conflict.pm	Mon Mar 31 03:44:28 2008
@@ -8,7 +8,7 @@
 use Prophet::ConflictingPropChange;
 use Prophet::ConflictingChange;
 
-__PACKAGE__->mk_accessors(qw/prophet_handle   nullification_changeset resolution_changeset autoresolved/);
+__PACKAGE__->mk_accessors(qw/prophet_handle resolvers  nullification_changeset resolution_changeset autoresolved/);
 
 =head2 analyze_changeset Prophet::ChangeSet
 
@@ -26,10 +26,40 @@
     return unless (@{$self->conflicting_changes});
 
     $self->generate_nullification_changeset;
-    $self->attempt_automatic_conflict_resolution;
-
+    
     return 1;
+}
 
+sub _resolution_failed {
+
+    return sub { die "conflict not resolved." };
+}
+
+
+sub generate_resolution {
+    my $self = shift;   
+    
+    my @resolvers = (
+    
+        sub { $self->attempt_automatic_conflict_resolution(@_) },
+         @{$self->resolvers || []},
+         $self->_resolution_failed);
+    
+    
+    my $resolutions = Prophet::ChangeSet->new( { is_resolution => 1 } );
+    for my $conflict ( @{ $self->conflicting_changes } ) {
+        for (@resolvers) {
+            if (my $resolution = $_->($conflict)) {
+            warn $_;
+                $resolutions->add_change(change => $resolution);
+                last;
+            }
+        }
+    }
+
+    $self->resolution_changeset($resolutions);
+    
+    return 1;
 }
 
 =head2 attempt_automatic_conflict_resolution
@@ -64,14 +94,29 @@
 
 sub attempt_automatic_conflict_resolution {
     my $self = shift;
+    my $conflict = shift;
+  # for everything from the changeset that is the same as the old value of the target replica
+    # we can skip applying 
+warn "attempting to resolve conflict automatically";
+warn Dumper(@_);use Data::Dumper;
+    return 0 if $conflict->file_op_conflict;
+
+    my $resolution = Prophet::Change->new( { is_resolution => 1, 
+                                             node_type => $conflict->node_type,
+                                             node_uuid => $conflict->node_uuid });
 
 
-    # for everything from the changeset that is the same as the old value of the target replica
-        # we can skip applying 
+    for my $prop_change ( @{$conflict->prop_conflicts} ) {
+        return 0 unless $prop_change->target_value eq $prop_change->source_new_value
+    }
 
-    warn "have not implemented automatic conflict resolution yet";
+warn Dumper($resolution);
     $self->autoresolved(1);
 
+    return $resolution;
+
+
+
 
 
 
@@ -208,7 +253,7 @@
 
 sub generate_nullification_changeset {
     my $self = shift;
-    my $nullification = Prophet::ChangeSet->new();
+    my $nullification = Prophet::ChangeSet->new( {is_nullification => 1});
 
     for my $conflict ( @{ $self->conflicting_changes } ) {
         my $nullify_conflict = Prophet::Change->new( { node_type => $conflict->node_type, node_uuid => $conflict->node_uuid });
@@ -221,7 +266,11 @@
             $nullify_conflict->change_type('delete');
         } elsif ( $conflict->file_op_conflict ) {
             die "We don't know how to deal with a conflict of type " . $conflict->file_op_conflict;
+        } else {
+            $nullify_conflict->change_type('update_file');
         }
+        
+        
 
         # now that we've sorted out all the file-level conflicts, we need to get properties in order
         for my $prop_conflict ( @{ $conflict->prop_conflicts } ) {

Modified: SVN-PropDB/lib/Prophet/Handle.pm
==============================================================================
--- SVN-PropDB/lib/Prophet/Handle.pm	(original)
+++ SVN-PropDB/lib/Prophet/Handle.pm	Mon Mar 31 03:44:28 2008
@@ -113,7 +113,8 @@
     my $changeset = shift;
 
     $self->begin_edit();
-    $self->_integrate_change($_) for ($changeset->changes);
+    $self->record_changeset($changeset);
+    
     $self->_set_original_source_metadata($changeset);
     warn "to commit... " if ($DEBUG);
     my $changed = $self->current_edit->root->paths_changed;
@@ -122,6 +123,19 @@
     $self->commit_edit();
 }
 
+sub record_changeset {
+    my $self = shift;
+    my $changeset = shift;
+
+    
+    my $inside_edit = $self->current_edit ? 1: 0;
+    warn "==> to record $changeset / $inside_edit";
+    $self->begin_edit() unless ($inside_edit);
+    $self->_integrate_change($_) for ($changeset->changes);
+    $self->commit_edit() unless ($inside_edit);
+
+}
+
 sub _set_original_source_metadata {
     my $self = shift;
     my $change = shift;
@@ -137,7 +151,7 @@
     my $change = shift;
 
     my %new_props = map { $_->name => $_->new_value } $change->prop_changes;
- 
+
     if ( $change->change_type eq 'add_file' ) {
         $self->create_node(
             type  => $change->node_type,
@@ -294,7 +308,8 @@
 sub file_for {
     my $self = shift;
     my %args = validate( @_, { uuid => 1, type => 1 } );
-    my $file = join( "/", $self->db_root, ,$args{'type'}, $args{'uuid'} );
+    Carp::cluck unless $args{uuid};
+    my $file = join( "/", $self->db_root ,$args{'type'}, $args{'uuid'} );
     return $file;
 
 }

Modified: SVN-PropDB/lib/Prophet/Sync/Source.pm
==============================================================================
--- SVN-PropDB/lib/Prophet/Sync/Source.pm	(original)
+++ SVN-PropDB/lib/Prophet/Sync/Source.pm	Mon Mar 31 03:44:28 2008
@@ -51,6 +51,7 @@
 sub import_changesets {
     my $self = shift;
     my %args   = validate( @_, { from => { isa => 'Prophet::Sync::Source'},
+                                 resolver => { optional => 1},
                                  conflict_callback => { optional => 1 } } );
     my $source = $args{'from'};
 
@@ -60,7 +61,7 @@
     for my $changeset (@$changesets_to_integrate) {
     
        next if ( $self->has_seen_changeset($changeset) );
-        $self->integrate_changeset( changeset => $changeset, conflict_callback =>$args{conflict_callback});
+        $self->integrate_changeset( changeset => $changeset, conflict_callback => $args{conflict_callback}, resolver => $args{resolver});
 
     }
 }

Modified: SVN-PropDB/lib/Prophet/Sync/Source/SVN.pm
==============================================================================
--- SVN-PropDB/lib/Prophet/Sync/Source/SVN.pm	(original)
+++ SVN-PropDB/lib/Prophet/Sync/Source/SVN.pm	Mon Mar 31 03:44:28 2008
@@ -199,7 +199,6 @@
     my $conflict = Prophet::Conflict->new({ prophet_handle => $self->prophet_handle});
 
     $conflict->analyze_changeset($changeset);
-    
 
     return undef unless @{$conflict->conflicting_changes};
 
@@ -219,6 +218,7 @@
 sub integrate_changeset {
     my $self = shift;
     my %args = validate( @_, { changeset => {isa => 'Prophet::ChangeSet'}, 
+                               resolver => { optional => 1},
                              conflict_callback => { optional => 1 } 
                              } 
                             );
@@ -250,15 +250,22 @@
     if (my $conflict = $self->conflicts_from_changeset($changeset ) ) {
 
         $args{conflict_callback}->($conflict) if $args{'conflict_callback'};
+        $conflict->resolver(sub { $args{resolver}->(@_) }) if $args{resolver};
+        my $resolutions = $conflict->generate_resolution;
         Carp::cluck;
         #figure out our conflict resolution
         
     
 
         # IMPORTANT: these should be an atomic unit. dying here would be poor.  BUT WE WANT THEM AS THREEDIFFERENT SVN REVS
-        #integrate the nullification change
-        #    integrate the original change
-        #    integrate the conflict resolution change
+        # integrate the nullification change
+        $self->prophet_handle->record_changeset($conflict->nullification_changeset);
+
+        # integrate the original change
+        $self->prophet_handle->integrate_changeset($changeset);
+        # integrate the conflict resolution change
+         $self->prophet_handle->record_changeset($conflict->resolution_changeset);
+
 
     } else {
         $self->prophet_handle->integrate_changeset($changeset);

Modified: SVN-PropDB/t/simple-conflicting-merge.t
==============================================================================
--- SVN-PropDB/t/simple-conflicting-merge.t	(original)
+++ SVN-PropDB/t/simple-conflicting-merge.t	Mon Mar 31 03:44:28 2008
@@ -3,7 +3,7 @@
 use warnings;
 use strict;
 
-use Prophet::Test tests => 20;
+use Prophet::Test tests => 28;
 
 as_alice {
     run_ok('prophet-node-create', [qw(--type Bug --status new --from alice )], "Created a record as alice"); 
@@ -55,14 +55,18 @@
 
     my $conflict_obj;
 
+my $repo = repo_uri_for('bob');
+diag `svn log -v $repo`;
+
     eval {
         $target->import_changesets(
             from              => $source,
             conflict_callback => sub {
-                $conflict_obj = shift; die }
+                $conflict_obj = shift;
+            }
         );
     };
-
+#    warn $@;
     isa_ok($conflict_obj, 'Prophet::Conflict');
 
     my @conflicting_changes = @{$conflict_obj->conflicting_changes};
@@ -79,10 +83,27 @@
     is($c->source_new_value,'stalled');
     is($c->target_value,'stalled');
 
-    # Throw away the return. we wanted to inspect the conflict but not apply anything
+    # Check to see if the nullification changeset worked out ok
+    my $nullification = $conflict_obj->nullification_changeset;
 
+    isa_ok($nullification, "Prophet::ChangeSet");
+    ok($nullification->is_nullification);
+    my @reverts = $nullification->changes;
+    is($#reverts, 0, "Found one change");
+    my $revert = shift @reverts;
+    is($revert->change_type, 'update_file');
+    my @prop_changes = $revert->prop_changes;
+    is ( $#prop_changes, 0, "Found one prop change");
+    is ($prop_changes[0]->name, 'status');
+    is($prop_changes[0]->old_value, 'stalled');
+    is($prop_changes[0]->new_value, 'new');
+    
+
+    # Throw away the return. we wanted to inspect the conflict but not apply anything
 
 
+my $repo = repo_uri_for('bob');
+diag `svn log -v $repo`;
 
 
     # at the first sign of conflict, we're going to call back to a routine we inject to see if the conflict object is as we expect it



More information about the Bps-public-commit mailing list