[Bps-public-commit] r11265 - in SVN-PropDB: . lib/Prophet lib/Prophet/Sync/Source/SVN
jesse at bestpractical.com
jesse at bestpractical.com
Sat Mar 29 21:27:23 EDT 2008
Author: jesse
Date: Sat Mar 29 21:27:22 2008
New Revision: 11265
Modified:
SVN-PropDB/ (props changed)
SVN-PropDB/Makefile.PL
SVN-PropDB/lib/Prophet/ChangeSet.pm
SVN-PropDB/lib/Prophet/Collection.pm
SVN-PropDB/lib/Prophet/ConflictingPropChange.pm
SVN-PropDB/lib/Prophet/HistoryEntry.pm
SVN-PropDB/lib/Prophet/Record.pm
SVN-PropDB/lib/Prophet/Sync/Source/SVN.pm
SVN-PropDB/lib/Prophet/Sync/Source/SVN/ReplayEditor.pm
SVN-PropDB/lib/Prophet/Sync/Source/SVN/Util.pm
Log:
r28786 at 70-5-172-195: jesse | 2008-03-29 15:27:10 -1000
* lots of POD coverage
Modified: SVN-PropDB/Makefile.PL
==============================================================================
--- SVN-PropDB/Makefile.PL (original)
+++ SVN-PropDB/Makefile.PL Sat Mar 29 21:27:22 2008
@@ -4,6 +4,7 @@
requires('Params::Validate');
requires('Class::Accessor');
requires('Data::UUID');
+requires('Path::Class');
requires('SVN::Core'); # SVN::Repos SVN::Fs SVN::Ra SVN::Delta::Editor SVN::Client SVN::Delta
all_from('lib/Prophet.pm');
Modified: SVN-PropDB/lib/Prophet/ChangeSet.pm
==============================================================================
--- SVN-PropDB/lib/Prophet/ChangeSet.pm (original)
+++ SVN-PropDB/lib/Prophet/ChangeSet.pm Sat Mar 29 21:27:22 2008
@@ -2,13 +2,65 @@
use strict;
package Prophet::ChangeSet;
+use base qw/Class::Accessor/;
+
+=head1 NAME
+
+Prophet::ChangeSet
+
+=head1 DESCRIPTION
+
+This class represents a single, atomic Prophet database update. It tracks some metadata about the changeset it self and contains a list of L<Prophet::Change> entries which describe the actual records created, updated and deleted.
+
+=cut
+
use Prophet::Change;
use Params::Validate;
-use base qw/Class::Accessor/;
+=head1 METHODS
+
+=cut
__PACKAGE__->mk_accessors(qw/sequence_no source_uuid original_source_uuid original_sequence_no is_nullification is_resolution/);
+=head2 new
+
+Instantiate a new, empty L<Prophet::ChangeSet> object.
+
+=cut
+
+=head2 sequence_no
+
+The changeset's sequence number (In subversion terms, revision #) on the replica sending us the changeset
+
+=head2 source_uuid
+
+The uuid of the replica sending us the change
+
+=head2 original_source_uuid
+
+The uuid of the replica where the change was authored
+
+=head2 original_sequence_no
+
+The changeset's sequence number (In subversion terms, revision #) on the replica where the change was originally created
+
+=head2 is_nullification
+
+Currently unused
+
+=head2 is_resolution
+
+Currently unused
+
+=cut
+
+=head2 add_change { change => L<Prophet::Change> }
+
+Add a new change, L<$args{'change'}> to this changeset.
+
+=cut
+
sub add_change {
my $self = shift;
my %args = validate( @_, { change => { isa => 'Prophet::Change'} } );
@@ -16,6 +68,12 @@
}
+=head2 changes
+
+Return an array of all the changes in the current changeset.
+
+=cut
+
sub changes {
my $self = shift;
return @{ $self->{'changes'} || [] };
Modified: SVN-PropDB/lib/Prophet/Collection.pm
==============================================================================
--- SVN-PropDB/lib/Prophet/Collection.pm (original)
+++ SVN-PropDB/lib/Prophet/Collection.pm Sat Mar 29 21:27:22 2008
@@ -7,6 +7,25 @@
__PACKAGE__->mk_accessors(qw'handle type');
use Prophet::Record;
+=head1 NAME
+
+Prophet::Collection
+
+=head1 DESCRIPTION
+
+This class allows the programmer to search for L<Prophet::Record>
+objects matching certain criteria and to operate on those records
+as a collection.
+
+=head1 METHODS
+
+
+=head2 new { handle => L<Prophet::Handle>, type => $TYPE }
+
+Instantiate a new, empty L<Prophet::Collection> object to find items of type C<$TYPE>
+
+
+=cut
sub new {
my $class = shift;
@@ -17,6 +36,11 @@
return $self;
}
+=head2 matching $CODEREF
+
+Find all L<Prophet::Record>s of this collection's C<type> where $CODEREF returns true.
+
+=cut
sub matching {
my $self = shift;
@@ -41,6 +65,13 @@
}
+=head2 as_array_ref
+
+Return the set of L<Prophet::Record>s we've found as an array reference or return an empty array ref if none were found.
+
+=cut
+
+
sub as_array_ref {
my $self = shift;
return $self->{_items}||[];
Modified: SVN-PropDB/lib/Prophet/ConflictingPropChange.pm
==============================================================================
--- SVN-PropDB/lib/Prophet/ConflictingPropChange.pm (original)
+++ SVN-PropDB/lib/Prophet/ConflictingPropChange.pm Sat Mar 29 21:27:22 2008
@@ -6,4 +6,32 @@
__PACKAGE__->mk_accessors(qw/name source_old_value target_value source_new_value/);
+=head1 NAME
+
+Prophet::ConflictingPropChange
+
+=head1 DESCRIPTION
+
+Objects of this class describe a case when the a property change can not be cleanly applied to a replica because the old value for the property locally did not match the "begin state" of the change being applied.
+
+=head1 METHODS
+
+=head2 name
+
+The property name for the conflict in question
+
+=head2 source_old_value
+
+The inital (old) state from the change being merged in
+
+=head2 source_new_value
+
+The final (new) state of the property from the change being merged in.
+
+=head2 target_value
+
+The current target-replica value of the property being merged.
+
+=cut
+
1;
Modified: SVN-PropDB/lib/Prophet/HistoryEntry.pm
==============================================================================
--- SVN-PropDB/lib/Prophet/HistoryEntry.pm (original)
+++ SVN-PropDB/lib/Prophet/HistoryEntry.pm Sat Mar 29 21:27:22 2008
@@ -6,9 +6,28 @@
use base qw/Class::Accessor/;
use Params::Validate;
+=head1 NAME
+
+Prophet::HistoryEntry
+
+=head1 DESCRIPTION
+
+This class represents an indivdual, local change in the history of a L<Prophet::Replica>.
+In the future, this class's representation should be merged with the code we're using for L<Prophet::Sync>
+
+
+=cut
__PACKAGE__->mk_accessors(qw/handle rev date author msg action props prop_changes copy_from copy_from_rev/);
+=head1 METHODS
+
+=head2 new { handle => L<Prophet::Handle> }
+
+Create a new, empty history entry.
+
+
+=cut
sub new {
my $class = shift;
@@ -22,4 +41,46 @@
return $self;
}
+
+=head2 rev
+
+The local revision number for this history entry
+
+=head2 date
+
+The date this history entry was recorded. in RFC2445 format
+
+=head2 author
+
+The original author of this commit. Right now, this is a nice, forgable text string. It should likely become an email address or a replica UUID
+
+=head2 msg
+
+The commit message associated with the update
+
+=head2 action
+
+Was a node created, updated or deleted?
+
+XXX TODO FILL IN VALID VALUES
+
+
+=head2 props
+
+The current value of the record's properties after this update?
+
+=head2 prop_changes
+
+NEEDS DESCRIPTION
+
+=head2 copy_from
+
+unused
+
+=head2 copy_from_rev
+
+unused
+
+=cut
+
1;
Modified: SVN-PropDB/lib/Prophet/Record.pm
==============================================================================
--- SVN-PropDB/lib/Prophet/Record.pm (original)
+++ SVN-PropDB/lib/Prophet/Record.pm Sat Mar 29 21:27:22 2008
@@ -1,13 +1,37 @@
-
use warnings;
use strict;
+
package Prophet::Record;
-use Params::Validate;
-use Prophet::HistoryEntry;
+
+=head1 NAME
+
+Prophet::Record
+
+=head1 DESCRIPTION
+
+This class represents a base class for any record in a Prophet database
+
+=cut
+
+
use base qw'Class::Accessor';
+
__PACKAGE__->mk_accessors(qw'handle props uuid type');
+
+use Params::Validate;
+use Prophet::HistoryEntry;
+
my $UUIDGEN = Data::UUID->new();
+=head1 METHODS
+
+=head2 new { handle => Prophet::Handle, type => $type }
+
+Instantiates a new, empty L<Prophet::Record/> of type $type.
+
+=cut
+
+
sub new {
my $class = shift;
my $self = {};
@@ -17,6 +41,17 @@
return $self;
}
+=head2 create { props => { %hash_of_kv_pairs } }
+
+Creates a new Prophet database record in your database. Sets the record's properties to the keys and values passed in.
+
+Automatically canonicalizes and then validates the props.
+
+Upon successful creation, returns the new record's C<uuid>.
+In case of failure, returns undef.
+
+=cut
+
sub create {
my $self = shift;
my %args = validate(@_, { props => 1});
@@ -35,7 +70,11 @@
}
+=head2 load { uuid => $UUID }
+Loads a Prophet record off disk by its uuid.
+
+=cut
sub load {
@@ -45,6 +84,15 @@
}
+
+=head2 set_prop { name => $name, value => $value }
+
+Updates the current record to set an individual property called C<$name> to C<$value>
+
+This is a convenience method around L</set_props>.
+
+=cut
+
sub set_prop {
my $self = shift;
@@ -53,6 +101,17 @@
$self->set_props(props => $props);
}
+=head2 set_props { props => { key1 => val1, key2 => val2} }
+
+Updates the current record to set all the keys contained in the C<props> parameter to their associated values.
+Automatically canonicalizes and validates the props in question.
+
+In case of failure, returns false.
+
+On success, returns ____
+
+=cut
+
sub set_props {
my $self = shift;
@@ -64,19 +123,37 @@
}
+=head2 get_props
+
+Returns a hash of this record's properties as currently set in the database.
+=cut
sub get_props {
my $self = shift;
return $self->handle->get_node_props(uuid => $self->uuid, type => $self->type);
}
+=head2 prop $name
+
+Returns the current value of the property C<$name> for this record.
+(This is a convenience method wrapped around L</get_props>.
+
+=cut
+
sub prop {
my $self = shift;
my $prop = shift;
return $self->get_props->{$prop};
}
+=head2 delete_prop { name => $name }
+
+Deletes the current value for the property $name.
+
+TODO: how is this different than setting it to an empty value?
+
+=cut
sub delete_prop {
my $self = shift;
@@ -84,6 +161,12 @@
$self->handle->delete_node_prop(uuid => $self->uuid, name => $args{'name'});
}
+=head2 delete
+
+Deletes this record from the database. (Note that it does _not_ purge historical versions of the record)
+
+=cut
+
sub delete {
my $self = shift;
$self->handle->delete_node(type => $self->type, uuid => $self->uuid);
@@ -118,12 +201,23 @@
return 1;
}
+=head2 storage_node
+
+Returns the path of this node within the Prophet repository. (Really, it delegates this to L<Prophet::Handle/file_for>.
+
+=cut
+
sub storage_node {
my $self = shift;
return $self->handle->file_for(type => $self->type, uuid => $self->uuid);
}
+=head2 history
+
+Returns an array of L<Prophet::HistoryEntry> objects ordered from oldest to newest. It is important to note that Prophet's merge algorithms guarantee that _local_ record history will never be reordered but that different replicas will often have different history orderings based on when replicas were merged or synced.
+
+=cut
sub history {
my $self = shift;
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 Sat Mar 29 21:27:22 2008
@@ -16,6 +16,14 @@
__PACKAGE__->mk_accessors(qw/url ra prophet_handle/);
+=head2 setup
+
+Open a connection to the SVN source identified by C<$self->url>.
+
+XXX TODO, make the _prophet/ directory in the replica configurable
+
+=cut
+
sub setup {
my $self = shift;
my ( $baton, $ref ) = SVN::Core::auth_open_helper( Prophet::Sync::Source::SVN::Util->get_auth_providers );
@@ -28,6 +36,12 @@
}
+=head2 uuid
+
+Return the replica SVN repository's UUID
+
+=cut
+
sub uuid {
my $self = shift;
return $self->ra->get_uuid;
@@ -188,6 +202,14 @@
}
+=head2 integrate_changeset L<Prophet::ChangeSet>
+
+If there are conflicts, generate a nullification change, figure out a conflict resolution and apply the nullification, original change and resolution all at once (as three separate changes).
+
+If there are no conflicts, just apply the change.
+
+
+=cut
sub integrate_changeset {
my $self = shift;
@@ -211,6 +233,12 @@
# XXX TODO this is hacky as hell and violates abstraction barriers in the name of doing things over the RA
+=head2 last_changeset_from_source $SOURCE_UUID
+
+Returns the last changeset id seen from the source identified by $SOURCE_UUID
+
+=cut
+
sub last_changeset_from_source {
my $self = shift;
# XXX TODO should htis be an object rather than a uuid?
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 Sat Mar 29 21:27:22 2008
@@ -5,13 +5,40 @@
use base qw/SVN::Delta::Editor/;
our $CURRENT_REMOTE_REVNO;
+=head1 NAME
+
+Prophet::Sync::Source::SVN::ReplayEditor
+
+=head1 DESCRIPTION
+
+This class encapsulates a Subversion "replay" editor. Prophet's
+Subversion synchronization client (L<Prophet::Sync::Source::SVN>)
+uses it to turn a set of subversion
+deltas into a set of L<Prophet::ChangeSet> objects.
+
+
+=head1 METHODS
+
+=cut
+
+=head2 new
+
+Instantiates a new subversion "editor" to track a single remote revision
+
+
+=cut
+
sub new {
my $self = shift->SUPER::new(@_);
$self->{'revision'} = $CURRENT_REMOTE_REVNO;
return $self;
}
+=head2 ra [$RA]
+
+Gets or sets the Subversion RA object.
+=cut
sub ra {
my $self = shift;
@@ -20,6 +47,12 @@
}
+=head2 open_root ($edit_baton, $base_rev, $dir_pool, $root_baton)
+
+Called by subversion at the beginning of any edit. We only care about the base_rev
+
+=cut
+
sub open_root {
my $self = shift;
@@ -27,18 +60,37 @@
$self->{'base_rev'} = $base_rev;
}
+=head2 open_directory($path, $parent_baton, $base_rev, $dir_pool, $child_baton)
+
+Called by the subversion RA layer each time SVN descends into a new directory within an open edit.
+Pushes the directory onto the internal L</dir_stack>
+
+=cut
sub open_directory {
my $self = shift;
my ($path, $parent_baton, $base_rev, $dir_pool, $child_baton) = (@_);
push @{$self->{'dir_stack'}}, { path => $path, base_rev => $base_rev};
}
+
+=head2 delete_entry ($path, $revision, $parent_baton)
+
+Called for any file/directory deleted within this edit.
+
+=cut
+
sub delete_entry {
my $self = shift;
my ($path, $revision, $parent_baton) = (@_);
$self->{'paths'}->{$path}->{fs} = 'delete';
}
+=head2 add_file ($path, $parent_baton, $copy_path, $copy_revision, $file_pool, $file_baton)
+
+Called whenever a file is added within an edit.
+
+=cut
+
sub add_file {
my $self = shift;
my ($path, $parent_baton, $copy_path, $copy_revision, $file_pool, $file_baton) = (@_);
@@ -47,6 +99,13 @@
$self->{'paths'}->{$path}->{fs} = 'add_file';
}
+=head2 add_file ($path, $parent_baton, $copy_path, $copy_revision, $dir_pool, $child_baton)
+
+Called whenever a directory is added within an edit.
+
+=cut
+
+
sub add_directory {
my $self = shift;
my ($path, $parent_baton, $copyfrom_path, $copyfrom_revision, $dir_pool, $child_baton) = (@_);
@@ -54,6 +113,16 @@
$self->{'paths'}->{$path}->{fs} = 'add_dir';
}
+
+
+=head2 open_file ($path, $parent_baton, $base_rev, $file_pool, $file_baton)
+
+Called whenever a file is opened for writing within the current
+edit. This routine sets the context of future content or property
+changes.
+
+=cut
+
sub open_file {
my $self = shift;
my ($path, $parent_baton, $base_rev, $file_pool, $file_baton) = (@_);
@@ -69,6 +138,12 @@
}
+=head2 close_file ($file_baton, $text_checksum,$pool)
+
+Called when all edits to a file are complete. This routine ends the 'current file' context
+
+=cut
+
sub close_file {
my $self = shift;
@@ -78,10 +153,16 @@
}
-sub absent_file {
- my $self = shift;
- my ($file_baton, $text_checksum, $pool) = (@_);
-}
+#sub absent_file {
+# my $self = shift;
+# my ($file_baton, $text_checksum, $pool) = (@_);
+#}
+
+=head2 close_directory ($dir_baton, $pool)
+
+Called by Subversion to indicate that all edits inside a directory have been completed
+
+=cut
sub close_directory {
my $self = shift;
@@ -89,10 +170,20 @@
pop @{$self->{dir_stack}};
}
-sub absent_directory {
- my $self = shift;
- my ($path, $parent_baton, $pool) = (@_);
-}
+#sub absent_directory {
+# my $self = shift;
+# my ($path, $parent_baton, $pool) = (@_);
+#}
+
+
+=head2 change_file_prop ($baton, $name, $value,$pool)
+
+Called by Subversion when a file property changes. All Subversion
+tells us is that 'the current node's property called $name has
+changed to $value'. This routine roots around and builds a delta
+from the previous value to the new value.
+
+=cut
sub change_file_prop {
my $self = shift;
@@ -104,6 +195,16 @@
};
}
+=head2 change_file_prop ($baton, $name, $value,$pool)
+
+Called by Subversion when a directory property changes. All Subversion
+tells us is that 'the current node's property called $name has
+changed to $value'. This routine roots around and builds a delta
+from the previous value to the new value.
+
+=cut
+
+
sub change_dir_prop {
my $self = shift;
my ($dir_baton, $name, $value, $pool) = (@_);
@@ -115,10 +216,25 @@
}
-sub close_edit {
- my $self = shift;
- my ($edit_baton, $pool) = (@_);
-}
+
+#sub close_edit {
+# my $self = shift;
+# my ($edit_baton, $pool) = (@_);
+#}
+
+
+=head2 dump_deltas
+
+Returns a data structure describiing the revision and all the changes made to it:
+
+ { revision => 1234,
+ paths => { 'foo' => { ... }
+ }
+ }
+
+
+
+=cut
sub dump_deltas{
Modified: SVN-PropDB/lib/Prophet/Sync/Source/SVN/Util.pm
==============================================================================
--- SVN-PropDB/lib/Prophet/Sync/Source/SVN/Util.pm (original)
+++ SVN-PropDB/lib/Prophet/Sync/Source/SVN/Util.pm Sat Mar 29 21:27:22 2008
@@ -4,6 +4,16 @@
# XXX CARGO CULTED FROM SVK::Util;
package Prophet::Sync::Source::SVN::Util;
+=head1 NAME
+
+Prophet::Sync::Source::SVN
+
+=head1 DESCRIPTION
+
+A library of utility functions for Subversion repository authentication. Ripped from SVK
+
+=cut
+
use base 'Class::Data::Inheritable';
__PACKAGE__->mk_classdata('_svnconfig');
@@ -39,17 +49,31 @@
my $pool = SVN::Pool->new;
+
+=head2 svnconfig
+
+Returns a handle to the user's Subversion configuration.
+
+=cut
+
sub svnconfig {
my $class = shift;
return $class->_svnconfig if $class->_svnconfig;
- return undef if $ENV{SVKNOSVNCONFIG};
+ return undef if $ENV{PROPHET_NO_SVN_CONFIG};
SVN::Core::config_ensure(undef);
return $class->_svnconfig( SVN::Core::config_get_config(undef, $pool) );
}
+=head2 get_auth_providers
+
+Returns an array of Subversion authentication providers
+
# Note: Use a proper default pool when calling get_auth_providers
+
+=cut
+
sub get_auth_providers {
my $class = shift;
return $class->auth_providers->();
More information about the Bps-public-commit
mailing list