[Bps-public-commit] r11071 - in SVN-PropDB: . lib/Prophet

jesse at bestpractical.com jesse at bestpractical.com
Fri Mar 14 17:26:46 EDT 2008


Author: jesse
Date: Fri Mar 14 17:26:44 2008
New Revision: 11071

Added:
   SVN-PropDB/lib/Prophet/ConflictingChange.pm
   SVN-PropDB/lib/Prophet/ConflictingPropChange.pm
Modified:
   SVN-PropDB/   (props changed)
   SVN-PropDB/lib/Prophet/ChangeSet.pm
   SVN-PropDB/lib/Prophet/Conflict.pm
   SVN-PropDB/lib/Prophet/Sync/Source/SVN.pm

Log:
 r28275 at 31b:  jesse | 2008-03-14 17:24:21 -0400
 * now we generate nullification changesets. next up, RESOLUTIONS


Modified: SVN-PropDB/lib/Prophet/ChangeSet.pm
==============================================================================
--- SVN-PropDB/lib/Prophet/ChangeSet.pm	(original)
+++ SVN-PropDB/lib/Prophet/ChangeSet.pm	Fri Mar 14 17:26:44 2008
@@ -7,11 +7,11 @@
 
 use base qw/Class::Accessor/;
 
-__PACKAGE__->mk_accessors(qw/sequence_no source_uuid original_source_uuid original_sequence_no/);
+__PACKAGE__->mk_accessors(qw/sequence_no source_uuid original_source_uuid original_sequence_no is_nullification is_resolution/);
 
 sub add_change {
     my $self = shift;
-    my %args = validate( @_, { change => 1 } );
+    my %args = validate( @_, { change => { isa => 'Prophet::Change'} } );
     push @{ $self->{changes} }, $args{change};
 
 }

Modified: SVN-PropDB/lib/Prophet/Conflict.pm
==============================================================================
--- SVN-PropDB/lib/Prophet/Conflict.pm	(original)
+++ SVN-PropDB/lib/Prophet/Conflict.pm	Fri Mar 14 17:26:44 2008
@@ -4,8 +4,10 @@
 package Prophet::Conflict;
 
 use base qw/Class::Accessor/;
+use Prophet::ConflictingPropChange;
+use Prophet::ConflictingChange;
 
-__PACKAGE__->mk_accessors(qw/prophet_handle   source_change target_change/);
+__PACKAGE__->mk_accessors(qw/prophet_handle   source_change target_change nullification/);
 
 =head2 analyze_changeset Prophet::ChangeSet
 
@@ -17,73 +19,84 @@
     my $self = shift;
     my ($changeset) = validate_pos( @_, { isa => 'Prophet::ChangeSet' } );
 
-    # XXX TODO
+    $self->generate_changeset_conflicts($changeset);
+    $self->generate_nullification_changeset;
+    $self->generate_conflict_resolution;
 
-#    - a ConflictingChange if there are any conflicts in the change
-#    - for each conflictingchange, we need to create a conflicting change property for each and every property that conflicts
 
+    return 1;
+
+}
+
+sub generate_changeset_conflicts {
+    my $self = shift;
+    my ($changeset) = validate_pos( @_, { isa => 'Prophet::ChangeSet' } );
     for my $change ( $changeset->changes ) {
-        if ( my $change_conflicts = $self->generate_change_onflicts($change) ) {
-            push @{ $self->{conflicting_changes} }, $change_conflicts;
+        if ( my $change_conflicts = $self->_generate_change_conflicts($change) ) {
+            push @{ $self->conflicting_changes }, $change_conflicts;
         }
     }
-
-    return 0;
-
 }
 
-sub generate_change_conflict {
+sub _generate_change_conflicts {
     my $self = shift;
     my ($change) = validate_pos( @_, { isa => "Prophet::Change" } );
-
     my $current_state = $self->prophet_handle->get_node_props( uuid => $change->node_uuid, type => $change->node_type );
-
     my $file_op_conflict = '';
 
     # It's ok to delete a node that exists
     if ( $change->change_type eq 'delete' && !keys %$current_state ) {
         $file_op_conflict = "delete_missing_file";
+    } elsif ( $change->change_type eq 'update' && !keys %$current_state ) {
+        $file_op_conflict = "update_missing_file";
     } elsif ( $change->change_type eq 'add_file' && keys %$current_state ) {
         $file_op_conflict = "create_existing_file";
     } elsif ( $change->change_type eq 'add_dir' && keys %$current_state ) {
         $file_op_conflict = "create_existing_dir";
     }
 
+    my $change_conflict = Prophet::ConflictingChange->new(
+        {   node_type          => $change->node_type,
+            node_uuid          => $change->node_uuid,
+            target_node_exists => ( keys %$current_state ? 1 : 0 ),
+            change_type        => $change->change_type,
+            file_op_conflict   => $file_op_conflict
+        }
+    );
+
+    push @{ $change_conflict->prop_conflicts }, $self->_generate_prop_change_conflicts( $change, $current_state );
+
+    return ( $#{ $change_conflict->prop_conflicts } || $file_op_conflict ) ? $change_conflict : undef;
+}
+
+
+sub _generate_prop_change_conflicts {
+    my $self          = shift;
+    my $change        = shift;
+    my $current_state = shift;
     my @prop_conflicts;
-    for my $propchange ( $change->prop_changes ) {
+    for my $prop_change ( $change->prop_changes ) {
 
         # skip properties added by the change
-        next if ( !defined $current_state->{ $propchange->name } && !defined $propchange->old_value );
+        next if ( !defined $current_state->{ $prop_change->name } && !defined $prop_change->old_value );
 
        # If either the old version didn't have a value or the delta didn't have a value, then we know there's a conflict
         my $s = {
-            source_old_value => $propchange->old_value,
-            target_old_value => $current_state->{$propchange_name},
-            source_new_value => $propchange->new_value
+            name             => $prop_change->name,
+            source_old_value => $prop_change->old_value,
+            target_old_value => $current_state->{ $prop_change->name },
+            source_new_value => $prop_change->new_value
         };
 
-        if (   !exists $current_state->{ $propchange->name }
-            || !defined $propchange->old_value
-            || ( $current_state->{ $propchange->name } ne $propchange->old_value ) )
+        if (   !exists $current_state->{ $prop_change->name }
+            || !defined $prop_change->old_value
+            || ( $current_state->{ $prop_change->name } ne $prop_change->old_value ) )
         {
             push @prop_conflicts, Prophet::ConflictingPropChange->new($s);
-
         }
 
     }
-
-    my $change_conflict = Prophet::ConflictingChange->new(
-        {   node_type          => $change->node_type,
-            node_uuid          => $change->node_uuid,
-            target_node_exists => ( keys %$current_state ? 1 : 0 ),
-            change_type        => $change->change_type,
-            fileop_conflict    => $fileop_conflict
-        }
-    );
-    push @{ $change_conflict->prop_conflicts }, @prop_conflicts;
-
-    return $change_conflict if ( $#prop_conflicts || $fileop_conflict );
-    return undef;
+    return @prop_conflicts;
 }
 
 =head2 conflicting_changes 
@@ -101,36 +114,34 @@
 
 sub generate_nullification_changeset {
     my $self = shift;
-
     my $nullification = Prophet::ChangeSet->new();
-    return $nullification;
-}
-
-package Prophet::ConflictingChange;
-
-use base qw/Class::Accessor/;
-
-# change_type is one of: create update delete
-__PACKAGE__->mk_accessors(qw/node_type node_uuid source_node_exists target_node_exists change_type fileop_conflict/);
 
-=head2 prop_conflicts
+    for my $conflict ( @{ $self->conflicting_changes } ) {
+        my $nullify_conflict = Prophet::Change->new( { node_type => $conflict->node_type, node_uuid => $conflict->node_uuid });
 
-Returns a reference to an array of Prophet::ConflictingPropChange objects
-
-=cut
-
-sub prop_conflicts {
-    my $self = shift;
+        if ( $conflict->file_op_conflict eq "delete_missing_file" ) {
+            $nullify_conflict->change_type('create_file');
+        } elsif ( $conflict->file_op_conflict eq "update_missing_file" ) {
+            $nullify_conflict->change_type('create_file');
+        } elsif ( $conflict->file_op_conflict eq "create_existing_file" ) {
+            $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;
+        }
 
-    $self->{'prop_conflicts'} ||= ();
-    return $self->{prop_conflicts};
+        # 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 } ) {
+            $nullify_conflict->add_prop_change(
+                name => $prop_conflict->name,
+                old  => $prop_conflict->target_value,
+                new  => $prop_conflict->source_old_value
+            );
+        }
+        $nullification->add_change( change => $nullify_conflict );
+    }
 
+    $self->nullification_changeset($nullification);
 }
 
-package Prophet::ConflictingPropChange;
-
-use base qw/Class::Accessor/;
-
-__PACKAGE__->mk_accessors(qw/source_old_value target_value source_new_value/);
-
 1;
+

Added: SVN-PropDB/lib/Prophet/ConflictingChange.pm
==============================================================================
--- (empty file)
+++ SVN-PropDB/lib/Prophet/ConflictingChange.pm	Fri Mar 14 17:26:44 2008
@@ -0,0 +1,27 @@
+
+use warnings;
+use strict;
+
+package Prophet::ConflictingChange;
+use Prophet::ConflictingPropChange;
+
+use base qw/Class::Accessor/;
+
+# change_type is one of: add_file add_dir update delete
+__PACKAGE__->mk_accessors(qw/node_type node_uuid source_node_exists target_node_exists change_type file_op_conflict/);
+
+=head2 prop_conflicts
+
+Returns a reference to an array of Prophet::ConflictingPropChange objects
+
+=cut
+
+sub prop_conflicts {
+    my $self = shift;
+
+    $self->{'prop_conflicts'} ||= ();
+    return $self->{prop_conflicts};
+
+}
+
+1;

Added: SVN-PropDB/lib/Prophet/ConflictingPropChange.pm
==============================================================================
--- (empty file)
+++ SVN-PropDB/lib/Prophet/ConflictingPropChange.pm	Fri Mar 14 17:26:44 2008
@@ -0,0 +1,9 @@
+
+use warnings;
+use strict;
+package Prophet::ConflictingPropChange;
+use base qw/Class::Accessor/;
+
+__PACKAGE__->mk_accessors(qw/name source_old_value target_value source_new_value/);
+
+1;

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	Fri Mar 14 17:26:44 2008
@@ -40,6 +40,15 @@
     return $self->ra->get_uuid;
 }
 
+=head2 fetch_changesets { after => SEQUENCE_NO } 
+
+Fetch all changesets from the source. 
+
+Returns a reference to an array of L<Prophet::ChangeSet> objects.
+
+
+=cut
+
 sub fetch_changesets {
     my $self = shift;
     my %args = validate( @_, { after => 1});
@@ -77,8 +86,7 @@
             original_source_uuid => $revprops->{original_source_uuid},
             original_sequence_no => $revprops->{original_sequence_no},
 
-        }
-    );
+        });
 
     # add each node's changes to the changeset
     for my $path ( keys %{ $entry->{'paths'} } ) {
@@ -193,10 +201,8 @@
     my ($changeset) = validate_pos(@_, { isa => 'Prophet::ChangeSet'});
 
     if (my $conflict = $self->conflicts_from_changeset($changeset ) ) {
-
-    if (there's a conflict ) {
-        figure out our conflict resolution
-        generate a nullification change
+        #figure out our conflict resolution
+        # generate a nullification change
         # IMPORTANT: these should be an atomic unit. dying here would be poor.
         # BUT WE WANT THEM AS THREEDIFFERENT SVN REVS
         #integrate the nullification change



More information about the Bps-public-commit mailing list