[Bps-public-commit] r11014 - in SVN-PropDB: bin lib/Prophet lib/Prophet/Sync/Source lib/Prophet/Sync/Source/SVN t/samples/createt/db

jesse at bestpractical.com jesse at bestpractical.com
Wed Mar 5 16:56:28 EST 2008


Author: jesse
Date: Wed Mar  5 16:56:26 2008
New Revision: 11014

Added:
   SVN-PropDB/lib/Prophet/Change.pm
   SVN-PropDB/lib/Prophet/ChangeSet.pm
   SVN-PropDB/lib/Prophet/PropChange.pm
Modified:
   SVN-PropDB/   (props changed)
   SVN-PropDB/bin/merger
   SVN-PropDB/bin/svn-replay
   SVN-PropDB/lib/Prophet/Handle.pm
   SVN-PropDB/lib/Prophet/Sync/Source/SVN.pm
   SVN-PropDB/lib/Prophet/Sync/Source/SVN/ReplayEditor.pm
   SVN-PropDB/notes
   SVN-PropDB/t/samples/createt/db/current

Log:
 r28131 at 103:  jesse | 2008-03-05 16:48:06 -0500
 * checkppoint


Modified: SVN-PropDB/bin/merger
==============================================================================
--- SVN-PropDB/bin/merger	(original)
+++ SVN-PropDB/bin/merger	Wed Mar  5 16:56:26 2008
@@ -5,67 +5,75 @@
 
 my $opts = {};
 
-GetOptions($opts, 'local=s', 'remote=s');
-
-
-my $local_source = Prophet::MergeSource->new(url => $opts->{'local'});
-my $remote_source = Prophet::MergeSource->new(url => $opts->{'remote'});
-
-
-$local_source->snapshot;
-$remote_source->snapshot;
-
-my @txns_to_integrate = $remote_source->fetch_txns(after => $remote_source->last_txn_seen);
-
+use Getopt::Long;
+GetOptions( $opts, 'target=s', 'source=s' );
+use Prophet::Sync::Source::SVN;
+
+validate_options($opts);
+
+my $target = Prophet::Sync::Source::SVN->new( { url => $opts->{'target'} });
+my $source = Prophet::Sync::Source::SVN->new( {url => $opts->{'source'} });
+
+fatal_error("You appear to be trying to merge two identical replicas. ".
+            "Either you're trying to merge a replica to itself or ".
+            "someone did a bad job cloning your database") if ($target->unique_id eq $source->unique_id);
+
+if ( $target->accepts_changesets ) {
+    my @changesets_to_integrate = $source->fetch_changesets( 
+            after => $target->last_changeset_for_source(source => $source->unique_id) );
+
+    for my $changeset (@changesets_to_integrate) {
+        next if ( $target->has_seen_changeset(source => $source->unique_id, changeset => $changeset->unique_id));
+        if ( $target->changeset_will_conflict($changeset) ) {
+            die "Conflicts are hard";
+
+# make a decision about who wins the conflict
+# For parts of the conflict _source_ should win, write out a nullification changeset beforehand,
+# apply the changeset. it will now apply cleanly
+
+# For parts of the conflict _target_ should win,
+# write out a nullification changeset beforehand,
+# - that way, the source update will apply cleanly
+# Then write out the source changeset
+# Then write out a new changeset which reverts the parts of the source changeset which target should win
 
+        } else {
+            $target->apply_changeset($changeset);
+        }
 
-for my $txn (@txns_to_integrate) {
-    next if ($local_source->has_seen_txn($txn) );
-    if ($local_source->txn_will_conflict($txn)) { 
-        die "Conflicts are hard";
-        # make a decision about who wins the conflict 
-        # For parts of the conflict _remote_ should win, write out a nullification txn beforehand,
-            # apply the txn. it will now apply cleanly
-        
-        # For parts of the conflict _local_ should win, 
-            # write out a nullification txn beforehand,
-                # - that way, the remote update will apply cleanly
-            # Then write out the remote txn
-            # Then write out a new txn which reverts the parts of the remote txn which local should win
+        $target->record_changeset_for_source(source => $source->unique_id, changeset => $changeset->);
+    }
 
+} else {
+    fatal_error($target->url." does not accept changesets. Perhaps it's unwritable or something");
 
-    } else {
-        $local_source->apply_txn($txn);
-    }
 }
 
-if ( $remote_source->accepts_txns ) {
-    my @txns_to_send = $local_source->fetch_txns( after =>
-            $remote_source->last_txn_received( source => $local_source ) );
-
-    for my $txn (@txns_to_send) {
-        next if ( $remote_source->has_seen_txn($txn) );
-        if ( $remote_source->txn_will_conflict($txn) ) {
-            die "Conflicts are hard"
-        } else {
-            $remote_source->apply_txn($txn);
-        }
+sub validate_options {
+    my $opts = shift;
+for (qw(source target)){ 
+die "You need to specify a --$_ url" unless ($opts->{$_});
+}
+}
 
-    }
+sub fatal_error {
+    my $reason = shift;
+    die $reason."\n";
 
 }
 
+
 package Prophet::MergeSource;
 use base 'Class::Accessor';
 
 __PACKAGE__->mk_accessors(qw'url unique_id');
 
-sub accepts_txns {}
-sub has_seen_txn {}
-sub txn_will_conflict {}
-sub apply_txn {}
-sub fetch_txns {}
-sub last_txn_received {}
+sub accepts_changesets {}
+sub has_seen_changeset {}
+sub changeset_will_conflict {}
+sub apply_changeset {}
+sub fetch_changesets {}
+sub last_changeset_seen {}
 
 
 =head2 Assumptions about merge sources
@@ -73,28 +81,28 @@
     - a source represents a branch 
     - a branch has had many revisions applied
     - revisions we apply to a branch from another branch are always applied UNCHANGED
-    - in the event of a conflict, we will apply a "pre-txn" to smooth the application and a "post-txn" if the applied txn doesn't match the desired outcome.
+    - in the event of a conflict, we will apply a "pre-changeset" to smooth the application and a "post-changeset" if the applied changeset doesn't match the desired outcome.
 
     on pull
-        we end up applying every single remote txn this peer has seen since the last time we saw this peer, one by one
-        we possibly apply another two txns for each txn to smooth the application
+        we end up applying every single source changeset this peer has seen since the last time we saw this peer, one by one
+        we possibly apply another two changesets for each changeset to smooth the application
 
 
 
-        we skip any remote txn we've seen from another source before
+        we skip any source changeset we've seen from another source before
         
 
     on push,
-        we publish each txn we've made locally.
-            - including "after" fixup txns
-            - not including "before" fixup txns.
+        we publish each changeset we've made targetly.
+            - including "after" fixup changesets
+            - not including "before" fixup changesets.
 
 
 
 
 
 
-=head2 assumptions about merge txns
+=head2 assumptions about merge changesets
 
 we can get (and hash):
     -original database uuid
@@ -138,11 +146,11 @@
 
         Conflict
 
-        to local c applies a pre-fixup:  
+        to target c applies a pre-fixup:  
             frotz->foo
-        to local c applies a at 2:
+        to target c applies a at 2:
             foo->baz
-        to local c applies a conflict resolution
+        to target c applies a conflict resolution
             baz->frotz
 
 
@@ -162,7 +170,7 @@
             so, what do we push?
             options:
                 fixup to get a to our earliest state unpushed. that's kind of stupid and results in us replaying everthing all the time.
-                compute a single large txn from a at HEAD to c at HEAD and apply that?
+                compute a single large changeset from a at HEAD to c at HEAD and apply that?
 
 
         
@@ -173,40 +181,40 @@
 
     there's a new peer I've not seen before. I need to merge in all their changes:
 
-        if a txn comes from a replica at rev lower than our last-seen version for replica, skip it
+        if a changeset comes from a replica at rev lower than our last-seen version for replica, skip it
 
-        for each of their txns, import it, applying fixups as needed
+        for each of their changesets, import it, applying fixups as needed
     
 
 =head3 push
     
-    get the remote list of all merge tickets.
-    find all local revs which remote has never seen.
-        - genuine local txns
-        - third-party txns that the remote has no merge ticket for
+    get the source list of all merge tickets.
+    find all target revs which source has never seen.
+        - genuine target changesets
+        - third-party changesets that the source has no merge ticket for
 
-        - skip "before" fixup txns 
-        - include "after" fixup txns, since they're merge resolutions
+        - skip "before" fixup changesets 
+        - include "after" fixup changesets, since they're merge resolutions
 
 
-    iterate over these revs the remote has never seen.
-    when the txn applies cleanly, just apply it.
+    iterate over these revs the source has never seen.
+    when the changeset applies cleanly, just apply it.
 
-    when the txn does _not_ apply cleanly, 
+    when the changeset does _not_ apply cleanly, 
         - apply a 'before' fix up transaction
-        - apply the original txn
-        - apply a merge resolution txn.
+        - apply the original changeset
+        - apply a merge resolution changeset.
             - TODO: this doesn't feel quite right
             - the resolution should be the same as the equivalent merge resolution transaction on the "pull" variant if it exists.
 	                    What info do we have here?
 	                        - record uuid
 	                        - nearest parent variant
-	                        - local variant
-	                        - remote variant
-	                        - information from the 'future (local head)' about the eventual desired outcome 
+	                        - target variant
+	                        - source variant
+	                        - information from the 'future (target head)' about the eventual desired outcome 
 	                    
     - audit stage:
-        compare local head and remote head. - they should now be identical, since the last transactions we replayed were all local merge fixup txns. (is that true?)
+        compare target head and source head. - they should now be identical, since the last transactions we replayed were all target merge fixup changesets. (is that true?)
 
 =cut
-
+1;

Modified: SVN-PropDB/bin/svn-replay
==============================================================================
--- SVN-PropDB/bin/svn-replay	(original)
+++ SVN-PropDB/bin/svn-replay	Wed Mar  5 16:56:26 2008
@@ -2,9 +2,8 @@
 use strict;
 
 use Prophet::Sync::Source::SVN;
-my $sync = Prophet::Sync::Source::SVN->new();
+my $sync = Prophet::Sync::Source::SVN->new({ url => shift @ARGV} );
 
-$sync->setup(shift @ARGV);
 my @changes = $sync->fetch_changesets();
 warn YAML::Dump(\@changes); use YAML;
 

Added: SVN-PropDB/lib/Prophet/Change.pm
==============================================================================
--- (empty file)
+++ SVN-PropDB/lib/Prophet/Change.pm	Wed Mar  5 16:56:26 2008
@@ -0,0 +1,26 @@
+use warnings;
+use strict;
+
+package Prophet::Change;
+use base qw/Class::Accessor/;
+
+use Prophet::PropChange;
+
+use Params::Validate;
+__PACKAGE__->mk_accessors(qw/node_type node_uuid change_type/);
+
+sub add_prop_change {
+    my $self = shift;
+    my %args = validate(@_, { name => 1, old => 0, new => 0 } );
+    my $change = Prophet::PropChange->new();
+    $change->name($args{'name'});
+    $change->old_value($args{'old'});
+    $change->new_value($args{'new'});
+
+    push @{$self->{prop_changes}}, $change;
+
+
+}
+
+
+1;

Added: SVN-PropDB/lib/Prophet/ChangeSet.pm
==============================================================================
--- (empty file)
+++ SVN-PropDB/lib/Prophet/ChangeSet.pm	Wed Mar  5 16:56:26 2008
@@ -0,0 +1,20 @@
+use warnings;
+use strict;
+
+package Prophet::ChangeSet;
+use Prophet::Change;
+use Params::Validate;
+
+use base qw/Class::Accessor/;
+
+__PACKAGE__->mk_accessors(qw/change_uuid source_uuid/);
+
+sub add_change {
+    my $self = shift;
+    my %args = validate(@_, { change => 1} );
+    push @{$self->{changes}}, $args{change};
+
+
+}
+
+1;

Modified: SVN-PropDB/lib/Prophet/Handle.pm
==============================================================================
--- SVN-PropDB/lib/Prophet/Handle.pm	(original)
+++ SVN-PropDB/lib/Prophet/Handle.pm	Wed Mar  5 16:56:26 2008
@@ -19,7 +19,7 @@
     my $self  = {};
     bless $self, $class;
     my %args = validate( @_, { repository => 1, db_root => 1 } );
-    $self->db_root($args{'db_root'});
+    $self->db_root( $args{'db_root'} );
     $self->repo_path( $args{'repository'} );
     $self->_connect();
 
@@ -28,42 +28,51 @@
 
 sub current_root {
     my $self = shift;
-     $self->repo_handle->fs->revision_root ($self->repo_handle->fs->youngest_rev);
+    $self->repo_handle->fs->revision_root(
+        $self->repo_handle->fs->youngest_rev );
 }
 
+sub _connect {
+    my $self = shift;
 
+    my $repos;
+    eval {
+        $repos = SVN::Repos::open( $self->repo_path );
+
+    };
+
+    if ( $@ && !-d $self->repo_path ) {
+        $repos = SVN::Repos::create( $self->repo_path, undef, undef, undef,
+            undef );
 
-sub _connect {
-    my $self  = shift;
-    my $repos = SVN::Repos::open( $self->repo_path );
+    }
     $self->repo_handle($repos);
-    $self->_create_nonexistent_dir($self->db_root);
+    $self->_create_nonexistent_dir( $self->db_root );
 }
 
-
 sub _create_nonexistent_dir {
     my $self = shift;
-    my $dir = shift;
-    unless($self->current_root->is_dir($dir) ){
-    my $edit = $self->begin_edit;
-    $edit->root->make_dir($dir);
-    $self->commit_edit($edit);
+    my $dir  = shift;
+    unless ( $self->current_root->is_dir($dir) ) {
+        my $edit = $self->begin_edit;
+        $edit->root->make_dir($dir);
+        $self->commit_edit($edit);
     }
 
 }
 
 sub begin_edit {
     my $self = shift;
-    my $fs = $self->repo_handle->fs;
-    my $txn = $fs->begin_txn($fs->youngest_rev);
+    my $fs   = $self->repo_handle->fs;
+    my $txn  = $fs->begin_txn( $fs->youngest_rev );
 
     return $txn;
 }
 
 sub commit_edit {
     my $self = shift;
-    my $txn = shift;
-    $txn->change_prop('svn:author',$ENV{'USER'});
+    my $txn  = shift;
+    $txn->change_prop( 'svn:author', $ENV{'USER'} );
     $txn->commit;
 
 }
@@ -71,68 +80,105 @@
 sub create_node {
     my $self = shift;
     my %args = validate( @_, { uuid => 1, props => 1, type => 1 } );
-    $self->_create_nonexistent_dir(join('/',$self->db_root, $args{'type'}));
+    $self->_create_nonexistent_dir(
+        join( '/', $self->db_root, $args{'type'} ) );
     my $edit = $self->begin_edit();
-    
 
-    my $file = $self->file_for(uuid => $args{uuid}, type => $args{'type'});
-    $edit->root->make_file( $file );
+    my $file = $self->file_for( uuid => $args{uuid}, type => $args{'type'} );
+    $edit->root->make_file($file);
     {
-        my $stream = $edit->root->apply_text($file, undef);
-        print $stream Dumper($args{'props'});
+        my $stream = $edit->root->apply_text( $file, undef );
+        print $stream Dumper( $args{'props'} );
         close $stream;
     }
-    $self->_set_node_props(uuid => $args{uuid}, props => $args{props}, edit => $edit, type => $args{'type'});
+    $self->_set_node_props(
+        uuid  => $args{uuid},
+        props => $args{props},
+        edit  => $edit,
+        type  => $args{'type'}
+    );
     $self->commit_edit($edit);
 
 }
 
 sub _set_node_props {
-my $self = shift;
-    my %args = validate(@_, { uuid => 1, props=> 1, edit => 1, type => 1});
-    my $file = $self->file_for(uuid => $args{uuid}, type => $args{type});
-    foreach my $prop (keys %{$args{'props'}}) {
-        $args{edit}->root->change_node_prop($file,$prop, $args{'props'}->{$prop}, undef);
+    my $self = shift;
+    my %args
+        = validate( @_, { uuid => 1, props => 1, edit => 1, type => 1 } );
+    my $file = $self->file_for( uuid => $args{uuid}, type => $args{type} );
+    foreach my $prop ( keys %{ $args{'props'} } ) {
+        $args{edit}
+            ->root->change_node_prop( $file, $prop, $args{'props'}->{$prop},
+            undef );
     }
 }
 
 sub delete_node {
     my $self = shift;
-    my %args = validate( @_, { uuid => 1, type => 1} );
+    my %args = validate( @_, { uuid => 1, type => 1 } );
     my $edit = $self->begin_edit();
-    $edit->root->delete($self->file_for(uuid => $args{uuid}, type => $args{type})); 
+    $edit->root->delete(
+        $self->file_for( uuid => $args{uuid}, type => $args{type} ) );
     $self->commit_edit($edit);
 
-
 }
 
 sub set_node_props {
     my $self = shift;
     my %args = validate( @_, { uuid => 1, props => 1, type => 1 } );
     my $edit = $self->begin_edit();
-    my $file = $self->file_for(uuid => $args{uuid}, type => $args{'type'});
-    $self->_set_node_props(uuid => $args{uuid}, props => $args{props} ,edit => $edit, type => $args{'type'});
+    my $file = $self->file_for( uuid => $args{uuid}, type => $args{'type'} );
+    $self->_set_node_props(
+        uuid  => $args{uuid},
+        props => $args{props},
+        edit  => $edit,
+        type  => $args{'type'}
+    );
     $self->commit_edit($edit);
 
 }
 
-    
-
 sub get_node_props {
     my $self = shift;
     my %args = validate( @_, { uuid => 1, type => 1, root => undef } );
     my $root = $args{'root'} || $self->current_root;
-    return $root->node_proplist($self->file_for(uuid => $args{'uuid'}, type => $args{'type'}));
+    return $root->node_proplist(
+        $self->file_for( uuid => $args{'uuid'}, type => $args{'type'} ) );
 }
 
-
-
 sub file_for {
-my $self = shift;
-    my %args = validate( @_, { uuid => 1,  type => 1} );
-    my $file =  join("/",$self->db_root, $args{'type'}, $args{'uuid'});
+    my $self = shift;
+    my %args = validate( @_, { uuid => 1, type => 1 } );
+    my $file = join( "/", $self->db_root, ,$args{'type'}, $args{'uuid'} );
     return $file;
 
 }
 
+
+my $MERGETICKET_METATYPE = '_merge_tickets';
+sub last_changeset_for_source {
+    my $self = shift;
+    my %args = validate( @_, { source => 1, } );
+
+    my %props = $self->get_node_props(uuid => $args{'source'}, type => $MERGETICKET_METATYPE);
+    
+    return $props{'last-rev'};
+
+
+
+}
+
+sub record_changeset_for_source {
+    my $self = shift;
+    my %args = validate( @_, { source => 1,  changeset => 1} );
+    my %props = $self->get_node_props(uuid => $args{'source'}, type => $MERGETICKET_METATYPE);
+    unless ($props{'last-rev'}) {
+            $self->create_node( uuid => $args{'source'}, type => $MERGETICKET_METATYPE );
+    }
+    $self->set_node_props(uuid => $args{'source'}, type => $MERGETICKET_METATYPE, props => { 'last-rev' => $args{'changeset'}});
+
+}
+
+
+
 1;

Added: SVN-PropDB/lib/Prophet/PropChange.pm
==============================================================================
--- (empty file)
+++ SVN-PropDB/lib/Prophet/PropChange.pm	Wed Mar  5 16:56:26 2008
@@ -0,0 +1,9 @@
+use warnings;
+use strict;
+package Prophet::PropChange;
+use base qw/Class::Accessor/;
+
+__PACKAGE__->mk_accessors(qw/name old_value 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	Wed Mar  5 16:56:26 2008
@@ -2,42 +2,51 @@
 use strict;
 
 package Prophet::Sync::Source::SVN;
+use base qw/Class::Accessor/;
+use Params::Validate;
 
 use SVN::Core;
 use SVN::Ra;
 use SVK;
 use SVK::Config;
 use SVN::Delta;
-    
-use Prophet::Sync::Source::SVN::ReplayEditor;
 
+use Prophet::Handle;
+use Prophet::Sync::Source::SVN::ReplayEditor;
+use Prophet::ChangeSet;
 
+__PACKAGE__->mk_accessors(qw/url ra prophet_handle/);
 
 sub new {
-    my $class = shift;
-    my $self = {};
-    bless $self, $class;
+    my $self = shift->SUPER::new(@_);
+    $self->setup();
     return $self;
 }
 
-sub ra {
+sub setup {
     my $self = shift;
-    $self->{'_ra'} = shift if (@_);
-    return $self->{'_ra'};
+    my ( $baton, $ref )
+        = SVN::Core::auth_open_helper( SVK::Config->get_auth_providers );
+    my $config = SVK::Config->svnconfig;
+    $self->ra(
+        SVN::Ra->new( url => $self->url, config => $config, auth => $baton )
+    );
+
+    if ( $self->url =~ /^file:\/\/(.*)$/ ) {
+        warn "Connecting to $1";
+        $self->prophet_handle(
+            Prophet::Handle->new(
+                { repository => $1, db_root => '_prophet' }
+            )
+        );
+    }
 
 }
 
-sub setup{
+sub unique_id {
     my $self = shift;
-    my $url = shift;
-    my ($baton, $ref) = SVN::Core::auth_open_helper(SVK::Config->get_auth_providers);
-    my $config = SVK::Config->svnconfig;
-    $self->ra( SVN::Ra->new( url => $url , config => $config, auth => $baton));
-
-} 
-
-
-
+    return $self->ra->get_uuid;
+}
 
 sub fetch_changesets {
     my $self = shift;
@@ -46,19 +55,98 @@
     my $handle_replayed_txn = sub {
         $last_editor
             = Prophet::Sync::Source::SVN::ReplayEditor->new( _debug => 0 );
-        $last_editor->ra($self->ra);
+        $last_editor->ra( $self->ra );
         return $last_editor;
     };
 
     for my $rev ( 1 .. $self->ra->get_latest_revnum ) {
-        $Prophet::Sync::Source::SVN::ReplayEditor::CURRENT_REMOTE_REVNO = $rev;
-        # This horrible hack is here because I have no idea how to pass custom variables into the editor
+        $Prophet::Sync::Source::SVN::ReplayEditor::CURRENT_REMOTE_REVNO
+            = $rev;
+
+# This horrible hack is here because I have no idea how to pass custom variables into the editor
         $self->ra->replay( $rev, 0, 1, $handle_replayed_txn->() );
 
         push @results, $last_editor->dump_deltas;
 
     }
-    return \@results;
+
+    # XXX TODO, we should be creating the changesets directly earlier
+    my @changesets;
+    for my $entry (@results) {
+        my $changeset = Prophet::ChangeSet->new(
+            {   change_uuid => $entry->{'revision'},
+                source_uuid => $self->unique_id
+            }
+        );
+        for my $path ( keys %{ $entry->{'paths'} } ) {
+            if ( $path =~ qr|^(.+)/(.*?)/(.*?)$| ) {
+                my ( $prefix, $type, $record ) = ( $1, $2, $3 );
+                my $change = Prophet::Change->new(
+                    {   node_type   => $type,
+                        node_uuid   => $record,
+                        change_type => $entry->{'paths'}->{$path}->{'fs'}
+                    }
+                );
+                for my $name (
+                    keys %{ $entry->{'paths'}->{$path}->{prop_deltas} } )
+                {
+                    warn "Changing $name for $change";
+                    $change->add_prop_change(
+                        name => $name,
+                        old =>
+                            $entry->{paths}->{$path}->{prop_deltas}->{$name}
+                            ->{'old'},
+                        new =>
+                            $entry->{paths}->{$path}->{prop_deltas}->{$name}
+                            ->{'new'},
+                    );
+                }
+
+                $changeset->add_change( change => $change );
+            } else {
+                warn "Discarding change to a non-record: $path";
+                warn "Someday, we should be less stupid about this";
+            }
+
+        }
+        warn YAML::Dump($changeset);
+
+    }
+
+    exit;
+    return \@changesets;
+}
+
+sub accepts_changesets {
+    my $self = shift;
+    return 1 if $self->prophet_handle;
+    return undef;
+}
+
+# XXX TODO this is hacky as hell and violates abstraction barriers in the name of doing things over the RA
+sub last_changeset_for_source {
+    my $self = shift;
+    my %args = validate( @_, { source => 1 } );
+    my ( $stream, $pool );
+
+    # XXX HACK
+    my $filename = join( "/",
+        "_prophet", $Prophet::Handle::MERGETICKET_METATYPE,
+        $args{'source'} );
+    my ( $rev_fetched, $props ) = eval {
+        $self->ra->get_file( $filename, $self->ra->get_latest_revnum,
+            $stream, $pool );
+    };
+    return ( $props->{'last-rev'} );
+
+}
+
+sub record_changeset_for_source {
+    my $self = shift;
+    return undef unless ( $self->accepts_changesets );
+    my %args = validate( @_, { source => 1, changeset => 1 } );
+    $self->prophet_handle->record_changeset_for_source(%args);
+
 }
 
 1;

Modified: SVN-PropDB/lib/Prophet/Sync/Source/SVN/ReplayEditor.pm
==============================================================================
--- SVN-PropDB/lib/Prophet/Sync/Source/SVN/ReplayEditor.pm	(original)
+++ SVN-PropDB/lib/Prophet/Sync/Source/SVN/ReplayEditor.pm	Wed Mar  5 16:56:26 2008
@@ -38,7 +38,7 @@
 sub delete_entry { 
     my $self = shift;
     my ($path, $revision, $parent_baton) = (@_);
-    push @{$self->{'paths'}->{ $self->{'dir_stack'}->[-1]->{path} }->{delete_path}}, $path;
+    $self->{'paths'}->{$path}->{fs} = 'delete';
 }
 
 sub add_file { 
@@ -46,14 +46,14 @@
     my ($path, $parent_baton, $copy_path, $copy_revision, $file_pool, $file_baton) = (@_);
     $self->{'current_file'} = $path;
     $self->{'current_file_base_rev'} = "newly created";
-    push @{$self->{'paths'}->{ $self->{'dir_stack'}->[-1]->{path} }->{create_file}}, $path;
+    $self->{'paths'}->{$path}->{fs} = 'add_file';
 }
 
 sub add_directory {
     my $self = shift;
     my ($path, $parent_baton, $copyfrom_path, $copyfrom_revision, $dir_pool, $child_baton) = (@_);
     push @{$self->{'dir_stack'}}, { path => $path, base_rev => -1 };
-    push @{$self->{'paths'}->{ $self->{'dir_stack'}->[-1]->{path} }->{create_dir}}, $path;
+    $self->{'paths'}->{$path}->{fs} = 'add_dir';
 }
 
 sub open_file {
@@ -66,6 +66,7 @@
     my ($stream, $pool);
     my ($rev_fetched, $prev_props)  =  $self->ra->get_file($path, $self->{'revision'}-1, $stream,$pool);
 
+    $self->{'paths'}->{$path}->{fs} = 'update_file';
     $self->{'paths'}->{$path}->{prev_properties} = $prev_props;
 
 

Modified: SVN-PropDB/notes
==============================================================================
--- SVN-PropDB/notes	(original)
+++ SVN-PropDB/notes	Wed Mar  5 16:56:26 2008
@@ -26,7 +26,9 @@
     
 Changeset
     A changeset contains "old" and "new" versions of a set of database "Records", they can be of any Record Type.
-    
+
+Change
+    An entry in a changeset. Contains all the updates to a given record for this changeset
    
 Record
     A Record is composed of zero or more Attributes and a universally unique identifier. Each record is categorized into a Record Type.
@@ -225,4 +227,4 @@
     
     
 Resolution
-    When the local Replica 
\ No newline at end of file
+    When the local Replica 

Modified: SVN-PropDB/t/samples/createt/db/current
==============================================================================
--- SVN-PropDB/t/samples/createt/db/current	(original)
+++ SVN-PropDB/t/samples/createt/db/current	Wed Mar  5 16:56:26 2008
@@ -1 +1 @@
-11 7 1
+12 8 1



More information about the Bps-public-commit mailing list