[svk-commit] r2382 - in trunk: lib/SVK lib/SVK/Command lib/SVK/Editor lib/SVK/Mirror/Backend

nobody at bestpractical.com nobody at bestpractical.com
Mon Apr 9 03:12:16 EDT 2007


Author: clkao
Date: Mon Apr  9 03:12:15 2007
New Revision: 2382

Added:
   trunk/lib/SVK/Editor/Tee.pm
Modified:
   trunk/   (props changed)
   trunk/MANIFEST
   trunk/lib/SVK/Command/Commit.pm
   trunk/lib/SVK/Command/Delete.pm
   trunk/lib/SVK/Mirror.pm
   trunk/lib/SVK/Mirror/Backend/SVNRa.pm
   trunk/lib/SVK/Mirror/Backend/SVNSync.pm
   trunk/lib/SVK/Path.pm

Log:
When committing or merging to a mirror, avoid roundtripping
the latest revision.

 r9075 at ubuntu:  clkao | 2007-04-08 23:30:03 +0900
 branch for tokyo.
 r9076 at ubuntu:  clkao | 2007-04-08 23:30:46 +0900
 avoid roundtrip commits to mirror.
 r9077 at ubuntu:  clkao | 2007-04-09 00:05:07 +0900
 Fake the output for sync after committing to mirror.
 r9078 at ubuntu:  clkao | 2007-04-09 00:33:18 +0900
 Fix fake_last logic.
 r9090 at ubuntu:  clkao | 2007-04-09 11:15:33 +0900
 Make the tee-based commit actually work.
 
 r9091 at ubuntu:  clkao | 2007-04-09 13:56:54 +0900
 Use youngest_rev when failed to find local revision on seekback.
 r9092 at ubuntu:  clkao | 2007-04-09 13:58:40 +0900
 Bring all txn props when recreating txn for local commit on teeeditors.
 r9093 at ubuntu:  clkao | 2007-04-09 15:09:13 +0900
 cleanup.
 r9094 at ubuntu:  clkao | 2007-04-09 15:24:57 +0900
 little bit more cleanup and comments.
 r9095 at ubuntu:  clkao | 2007-04-09 16:07:47 +0900
 must load fromrev for svnsync backend as well.


Modified: trunk/MANIFEST
==============================================================================
--- trunk/MANIFEST	(original)
+++ trunk/MANIFEST	Mon Apr  9 03:12:15 2007
@@ -86,6 +86,7 @@
 lib/SVK/Editor/Sign.pm
 lib/SVK/Editor/Status.pm
 lib/SVK/Editor/SubTree.pm
+lib/SVK/Editor/Tee.pm
 lib/SVK/Editor/Translate.pm
 lib/SVK/Editor/TxnCleanup.pm
 lib/SVK/Editor/View.pm

Modified: trunk/lib/SVK/Command/Commit.pm
==============================================================================
--- trunk/lib/SVK/Command/Commit.pm	(original)
+++ trunk/lib/SVK/Command/Commit.pm	Mon Apr  9 03:12:15 2007
@@ -249,7 +249,6 @@
 	  check_only => $self->{check_only},
 	  callback => $callback,
 	  message => $self->{message},
-	  notify  => sub { print @_ },
 	  author => $ENV{USER} );
 
     # Note: the case that the target is an xd is actually only used in merge.

Modified: trunk/lib/SVK/Command/Delete.pm
==============================================================================
--- trunk/lib/SVK/Command/Delete.pm	(original)
+++ trunk/lib/SVK/Command/Delete.pm	Mon Apr  9 03:12:15 2007
@@ -98,12 +98,8 @@
     $target->normalize;
     my ( $anchor, $editor ) = $self->get_dynamic_editor($target);
     for (@args) {
-        my $rev = $target->revision;
-        $rev = $m->find_remote_rev($rev)
-          if
-          $m; # XXX: why do we need this? path->get_editor shuold do translation
         $editor->delete_entry( abs2rel( $_->path, $anchor => undef, '/' ),
-            $rev, 0 );
+            $target->revision, 0 );
         $self->adjust_anchor($editor);
     }
     $self->finalize_dynamic_editor($editor);

Added: trunk/lib/SVK/Editor/Tee.pm
==============================================================================
--- (empty file)
+++ trunk/lib/SVK/Editor/Tee.pm	Mon Apr  9 03:12:15 2007
@@ -0,0 +1,85 @@
+package SVK::Editor::Tee;
+use strict;
+use base 'SVK::Editor';
+use List::MoreUtils qw(any);
+
+__PACKAGE__->mk_accessors(qw(editors baton_maps));
+
+sub new {
+    my $class = shift;
+    my $self = $class->SUPER::new(@_);
+    $self->baton_maps({});
+    $self->{batons} = 0;
+    return $self;
+}
+
+sub run_editors { # if only we have zip..
+    my ($self, $baton, $callback) = @_;
+    my $i = 0;
+    my @ret;
+    for (@{$self->editors}) {
+	push @ret, scalar $callback->($_, defined $baton ? $self->baton_maps->{$baton}[$i++] : undef);
+    }
+    return \@ret;
+}
+
+sub AUTOLOAD {
+    my ($self, @arg) = @_;
+    my $func = our $AUTOLOAD;
+    $func =~ s/^.*:://;
+    return if $func =~ m/^[A-Z]+$/;
+    my $baton;
+    my $baton_at = $self->baton_at($func);
+    $baton = $arg[$baton_at] if $baton_at >= 0;
+
+    my $rets = $self->run_editors
+	( $baton,
+	  sub { my ($editor, $baton) = @_;
+		$arg[$baton_at] = $baton if defined $baton;
+		$editor->$func(@arg);
+	    });
+
+    if ($func =~ m/^close_(?:file|directory)/) {
+	delete $self->baton_maps->{$baton};
+	delete $self->{baton_pools}{$baton};
+    }
+
+    if ($func =~ m/^(?:add|open)/) {
+	$self->baton_maps->{++$self->{batons}} = $rets;
+	return $self->{batons};
+    }
+
+    return;
+}
+
+
+sub window_handler {
+    my ($self, $handlers, $window) = @_;
+    for (@$handlers) {
+	next unless $_;
+	SVN::Delta::invoke_window_handler($_->[0], $_->[1], $window);
+    }
+}
+
+#my $pool = SVN::Pool->new;
+sub apply_textdelta {
+    my ($self, $baton, @arg) = @_;
+    my $rets = $self->run_editors($baton,
+				  sub { my ($editor, $baton) = @_;
+					unless ($baton) {
+					    use Data::Dumper;
+					}
+					$editor->apply_textdelta($baton, @arg);
+				    });
+
+    if (any { defined $_ } @$rets) {
+	my $foo = sub { $self->window_handler($rets, @_) };
+	my $pool = $self->{baton_pools}{$baton} = SVN::Pool->new;
+	return [SVN::Delta::wrap_window_handler($foo, $pool)];
+    }
+
+    return;
+}
+
+
+1;

Modified: trunk/lib/SVK/Mirror.pm
==============================================================================
--- trunk/lib/SVK/Mirror.pm	(original)
+++ trunk/lib/SVK/Mirror.pm	Mon Apr  9 03:12:15 2007
@@ -360,7 +360,7 @@
 }
 
 sub run {
-    my ($self, $torev) = @_;
+    my ($self, $torev, $fake_last) = @_;
     return $self->run_svnmirror_sync({ torev => $torev }) unless $self->_backend->has_replay;
 
     $logger->info(loc("Syncing %1", $self->url).($self->_backend->_relayed ? loc(" via %1", $self->server_url) : ""));
@@ -369,7 +369,7 @@
         sub {
             my ( $changeset, $rev ) = @_;
             $logger->info("Committed revision $rev from revision $changeset.");
-        }
+        }, $fake_last
     );
     die $@ if $@;
 }

Modified: trunk/lib/SVK/Mirror/Backend/SVNRa.pm
==============================================================================
--- trunk/lib/SVK/Mirror/Backend/SVNRa.pm	(original)
+++ trunk/lib/SVK/Mirror/Backend/SVNRa.pm	Mon Apr  9 03:12:15 2007
@@ -406,7 +406,7 @@
 	      return $s_changeset <=> $changeset;
           } );
 
-    return unless $result;
+    return $t->revision unless $result;
 
     return $result->revision;
 }
@@ -440,7 +440,7 @@
     my ($self, $code, $torev) = @_;
     $self->refresh;
     my $from = ($self->fromrev || 0)+1;
-    my $to = $torev || -1;
+    my $to = defined $torev ? $torev : -1;
 
     my $ra = $self->_new_ra;
     $to = $ra->get_latest_revnum() if $to == -1;
@@ -551,17 +551,17 @@
 =cut
 
 sub mirror_changesets {
-    my ( $self, $torev, $callback ) = @_;
+    my ( $self, $torev, $callback, $fake_last ) = @_;
     $self->mirror->with_lock(
         'mirror',
-        sub { $self->_mirror_changesets( $torev, $callback ) } );
+        sub { $self->_mirror_changesets( $torev, $callback, $fake_last ) } );
 }
 
 sub _mirror_changesets {
-    my ( $self, $torev, $callback ) = @_;
+    my ( $self, $torev, $callback, $fake_last ) = @_;
     $self->refresh;
     my @revs;
-    $self->traverse_new_changesets( sub { push @revs, [@_] }, $torev );
+    $self->traverse_new_changesets( sub { push @revs, [@_] unless $fake_last && $torev && $_[0] == $torev}, $torev );
     return unless @revs;
 
     # prepare generator for pipelined ra

Modified: trunk/lib/SVK/Mirror/Backend/SVNSync.pm
==============================================================================
--- trunk/lib/SVK/Mirror/Backend/SVNSync.pm	(original)
+++ trunk/lib/SVK/Mirror/Backend/SVNSync.pm	Mon Apr  9 03:12:15 2007
@@ -71,6 +71,8 @@
     $self->source_root( $mirror->url );
     $self->source_path('');
 
+    $self->refresh;
+
     return $self;
 }
 

Modified: trunk/lib/SVK/Path.pm
==============================================================================
--- trunk/lib/SVK/Path.pm	(original)
+++ trunk/lib/SVK/Path.pm	Mon Apr  9 03:12:15 2007
@@ -54,7 +54,8 @@
 use SVK::I18N;
 use autouse 'SVK::Util' => qw( get_anchor catfile abs2rel
 			       IS_WIN32 get_depot_anchor );
-use Class::Autouse qw(SVK::Editor::Dynamic SVK::Editor::TxnCleanup);
+use Class::Autouse qw(SVK::Editor::Dynamic SVK::Editor::TxnCleanup SVK::Editor::Tee);
+
 use SVN::Delta;
 
 use SVK::Logger;
@@ -189,6 +190,23 @@
     return ($editor, \$post_handler);
 }
 
+sub _get_local_editor {
+    my ($self, $rev, $author, $message, $callback) = @_;
+    my $fs = $self->repos->fs;
+    my $txn = $self->repos->fs_begin_txn_for_commit
+	($rev, $author, $message);
+
+    $txn->change_prop('svk:commit', '*')
+	if $fs->revision_prop(0, 'svk:notify-commit');
+
+    my ($editor, $post_handler_ref) =
+	$self->_commit_editor($txn, $callback);
+
+    $editor = SVK::Editor::TxnCleanup->new(_editor => [$editor], txn => $txn);
+
+    return ($txn, $editor, $post_handler_ref);
+}
+
 sub pool {
     my $self = shift;
     $self->_pool( SVN::Pool->new )
@@ -207,23 +225,36 @@
 
 sub _get_inspector {
     my $self = shift;
-    my $fs = $self->repos->fs;
     return SVK::Inspector::Root->new
-	({ root => $fs->revision_root($self->revision, $self->pool),
+	({ root => $self->repos->fs->revision_root($self->revision, $self->pool),
 	   _pool => $self->pool,
 	   anchor => $self->path_anchor });
 }
 
+sub _get_remote_editor {
+    my ($self, $m, $mpath, $message, $mcallback) = @_;
+    my ($base_rev, $editor) = $m->get_merge_back_editor
+	($mpath, $message, $mcallback);
+    $editor = SVK::Editor::MapRev->wrap_without_copy($editor, $m->fromrev);
+    $editor = SVK::Editor::CopyHandler->new(
+        _editor => $editor,
+        cb_copy => sub {
+	    my ( $editor, $path, $rev ) = @_;
+	    return ( $path, $rev ) if $rev == -1;
+	    return $self->as_url(0, $path, $rev);
+	});
+    return $editor;
+}
+
+# XXX: split the codepath for using use_tee or not.
 sub get_editor {
     my ($self, %arg) = @_;
-
     my ($m, $mpath) = $arg{ignore_mirror} ? () : $self->is_mirrored;
     my $fs = $self->repos->fs;
     my $yrev = $fs->youngest_rev;
 
     my $root_baserev = $m ? $m->fromrev : $yrev;
 
-
     if ($arg{check_only}) {
 	# XXX: use txn-based inspector as well.
 	return (SVN::Delta::Editor->new, $self->inspector,
@@ -233,45 +264,48 @@
 
     $arg{notify} ||= sub {};
     my $callback = $arg{callback};
+    my $meditor; my $tee_callback;
+    my $use_tee;
+    my $post_handler;
     if ($m) {
-	my $post_handler;
-	my $notify = $arg{notify};
-        my $mcallback = $arg{mcallback} ||= sub {
+	$use_tee = SVN::Delta->can('invoke_window_handler') &&
+	    $m->_backend->has_replay;
+        my $mcallback = sub {
             my $rev = shift;
-            $notify->( loc( "Merge back committed as revision %1.\n", $rev ) );
+            $logger->info( loc( "Merge back committed as revision %1.\n", $rev ) );
             if ($post_handler) {
                 return unless $post_handler->($rev);
             }
-            $m->run($rev);
+            $m->run($rev, $use_tee);
 
-            # XXX: find_local_rev can fail
+            # XXX: find_local_rev can fail (see import.t).
+	    # In case of tee, call callback as local only.
             $callback->( $m->find_local_rev($rev), @_ )
-              if $callback;
+              if $callback && !$use_tee;
+	    $tee_callback->($rev) if $use_tee;
         };
 
-	my ($base_rev, $editor) = $m->get_merge_back_editor
-	    ($mpath, $arg{message}, $mcallback);
-	$editor->{_debug}++ if $logger->is_debug();
-	$editor = SVK::Editor::MapRev->wrap_without_copy($editor, $root_baserev);
-	$editor = SVK::Editor::CopyHandler->new(
-            _editor => $editor,
-            cb_copy => sub {
-                my ( $editor, $path, $rev ) = @_;
-		return ( $path, $rev ) if $rev == -1;
-		return $self->as_url(0, $path, $rev);
-	    });
+	$meditor = $self->_get_remote_editor($m, $mpath, $arg{message}, $mcallback);
 
 	# XXX: fix me, need local knowledge about txn as well
-	return ($editor, $self->inspector,
+	return ($meditor, $self->inspector,
 		mirror => $m,
 		post_handler => \$post_handler,
-		cb_rev => sub { $root_baserev }, #This is the inspector baserev
+		cb_rev => sub { 'x' }, #This is for editor::merge
 		cb_copyfrom => sub { @_ })
+	    unless $use_tee;
     }
 
-    warn "has $arg{txn}" if $arg{txn};
-    my $txn = $arg{txn} || $self->repos->fs_begin_txn_for_commit
-	($yrev, $arg{author}, $arg{message});
+    my $oldc = $callback;
+    my $changeset;
+    $callback = sub {
+	$logger->info("Committed revision $_[0] from revision $changeset.")
+	    if $changeset;
+	$oldc->(@_) if $oldc }
+	if $use_tee;
+
+    my ($txn, $editor, $post_handler_ref) =
+	$self->_get_local_editor($yrev, $arg{author}, $arg{message}, $callback);
 
     # for some reasons, we can't use the txn root got here in
     # inspector, the modified nodes aren't reflected.  Instead, we
@@ -281,13 +315,6 @@
 	   _pool  => $self->pool,
 	   anchor => $self->path_anchor });
 
-    $txn->change_prop('svk:commit', '*')
-	if $fs->revision_prop(0, 'svk:notify-commit');
-
-    my ($editor, $post_handler_ref) =
-	$self->_commit_editor($txn, $callback);
-    $editor = SVK::Editor::TxnCleanup->new(_editor => [$editor], txn => $txn);
-
     $editor = SVK::Editor::CopyHandler->new(
         _editor => $editor,
         cb_copy => sub {
@@ -300,9 +327,60 @@
 	    send_fulltext => 1,
 	    post_handler => $post_handler_ref,
 	    txn => $txn,
-            aborts_txn => $arg{txn} ? 0 : 1,
+            aborts_txn => 1,# $arg{txn} ? 0 : 1,
 	    cb_rev => sub { $root_baserev },
+	    cb_copyfrom => sub { @_ }) unless $meditor;
+
+
+    my $tee = SVK::Editor::Tee->new({editors => [$meditor, $editor]});
+
+    $tee_callback = sub {
+	my ($remote_rev) = @_;
+	# emulate post commit revision sync.
+	{
+	    # XXX: use an api to get proplist please
+	    my $proplist = $m->_backend->_new_ra->rev_proplist($remote_rev);
+	    for (@{$self->depot->mirror->revprop}) {
+		$txn->change_prop($_ => $proplist->{$_});
+	    }
+	}
+
+	if (!keys %{$txn->root->paths_changed}) {
+	    # XXX: This is the case for import's old behaviour importing
+	    # changeless thing.
+	    my $old_editor = pop @{$tee->{editors}};
+	    $old_editor->abort_edit;
+	    $oldc->('__na__');
+	}
+	elsif ((my $new_yrev = $fs->youngest_rev) != $txn->base_revision) {
+	    # XXX: svn's fs_merge is silly about property changes.  We need
+	    # this kludge to recreate a committable txn.
+
+	    my ($ktxn, $keditor) = $self->mclone(path_anchor => '/')->_get_local_editor($new_yrev, undef, undef, $callback);
+	    $keditor = SVK::Editor::MapRev->wrap_without_copy($keditor, $new_yrev);
+	    my $proplist = $txn->proplist;
+	    $ktxn->change_prop($_ => $proplist->{$_}) for keys %$proplist;
+
+	    SVN::Repos::replay2($txn->root, '/', 0, 1, $keditor, undef);
+	    $txn = $ktxn;
+	    $tee->{editors}[1]->abort_edit;
+	    $tee->{editors}[1] = $keditor;
+	}
+
+	# for local editor's wrapped callback to fake output
+	$changeset = $_[0];
+	$m->_backend->_revmap_prop( $txn, $changeset );
+    };
+
+    return ($tee, $inspector,
+	    mirror => $m,
+	    send_fulltext => 0,
+	    post_handler => \$post_handler,
+	    txn => $txn,
+            aborts_txn => 1,
+	    cb_rev => sub { $yrev },
 	    cb_copyfrom => sub { @_ });
+
 }
 
 sub get_dynamic_editor {


More information about the svk-commit mailing list