[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