[Bps-public-commit] r14307 - in Pushmi/branches/lock: . lib/Pushmi lib/Pushmi/Command

clkao at bestpractical.com clkao at bestpractical.com
Fri Jul 18 22:29:18 EDT 2008


Author: clkao
Date: Fri Jul 18 22:29:18 2008
New Revision: 14307

Modified:
   Pushmi/branches/lock/   (props changed)
   Pushmi/branches/lock/lib/Pushmi/Command.pm
   Pushmi/branches/lock/lib/Pushmi/Command/Mirror.pm
   Pushmi/branches/lock/lib/Pushmi/Command/Runhook.pm
   Pushmi/branches/lock/lib/Pushmi/Command/Sync.pm
   Pushmi/branches/lock/lib/Pushmi/Command/Tryauth.pm
   Pushmi/branches/lock/lib/Pushmi/Command/Unlock.pm
   Pushmi/branches/lock/lib/Pushmi/Command/Verify.pm
   Pushmi/branches/lock/lib/Pushmi/Config.pm
   Pushmi/branches/lock/lib/Pushmi/Mirror.pm
   Pushmi/branches/lock/lib/Pushmi/Test.pm
   Pushmi/branches/lock/t/basic.t
   Pushmi/branches/lock/t/concurrency.t
   Pushmi/branches/lock/t/verify.t

Log:
- Merge /bps/mirror/Pushmi/trunk to /bps/mirror/Pushmi/branches/lock

Modified: Pushmi/branches/lock/lib/Pushmi/Command.pm
==============================================================================
--- Pushmi/branches/lock/lib/Pushmi/Command.pm	(original)
+++ Pushmi/branches/lock/lib/Pushmi/Command.pm	Fri Jul 18 22:29:18 2008
@@ -1,5 +1,108 @@
 package Pushmi::Command;
+use strict;
+use warnings;
 use base qw(App::CLI App::CLI::Command);
 
+use Pushmi::Mirror;
+use Pushmi::Config;
+use Path::Class;
+use SVN::Mirror;
+use SVK::Config;
+use SVK::Mirror;
+use SVK::XD;
+use SVN::Delta;
+use SVK::I18N;
+use UNIVERSAL::require;
+
+my $logger = Pushmi::Config->logger('pushmi');
+
+sub setup_auth {
+    my $self = shift;
+    my ($auth) = @_;
+    $auth ||= $self->can("pushmi_auth");
+    my $config = Pushmi::Config->config;
+    SVK::Config->auth_providers(
+    sub {
+        [ $config->{use_cached_auth} ? SVN::Client::get_simple_provider() : (),
+          SVN::Client::get_username_provider(),
+          SVN::Client::get_ssl_server_trust_file_provider(),
+          SVN::Client::get_ssl_server_trust_prompt_provider(
+                \&SVK::Config::_ssl_server_trust_prompt
+          ),
+	  SVN::Client::get_simple_prompt_provider( $auth, 0 ) ]
+    });
+}
+
+sub run {
+    my $self = shift;
+
+    # compat
+    for ($self->subcommands) {
+	if (delete $self->{$_}) {
+	    my $cmd = 'Pushmi::Command::'.ucfirst($_);
+	    $cmd->require or die "can't require $cmd: $@";
+	    return (bless $self, $cmd)->run(@_);
+	}
+    }
+
+    no warnings 'redefine';
+    my $memd = Pushmi::Config->memcached;
+
+    local *SVK::Mirror::lock = sub {
+        my ($self)  = @_;
+        my $fs      = $self->repos->fs;
+        my $token = join(':', $self->repos->path, $self->_lock_token );
+        my $content = $self->_lock_content;
+        my $where = join( ' ', ( caller(0) )[ 0 .. 2 ] );
+
+        my $lock_message = $self->_lock_message;
+    LOCKED:
+        {
+            my $pool = SVN::Pool->new_default;
+            my $trial = 0;
+            while (1) {
+                $pool->clear;
+                my $ret;
+                last LOCKED if $ret = $memd->add( $token, $content );
+                my $who = $memd->get( $token ) or next;
+                last if $who eq $content;
+                $logger->warn('['.$self->repos->path."] lock held by $who...")
+                    unless $trial++ % 60;
+                $lock_message->($self, $who);
+                sleep 1;
+            }
+        }
+        $logger->debug('['.$self->repos->path."] locked by ".$token);
+        $self->_locked(1);
+    };
+
+    local *SVK::Mirror::unlock = sub {
+        my ( $self, $force ) = @_;
+        my $token = join(':', $self->repos->path, $self->_lock_token );
+        my $who = $memd->get( $token );
+        if ($force || $self->_locked ) {
+            my $ret = $memd->delete( $token );
+            $logger->debug('['.$self->repos->path."] unlock result: $ret");
+            $self->_locked(0);
+        }
+    };
+
+    $self->setup_auth;
+    return $self->run_with_auth(@_);
+}
+
+
+sub pushmi_auth {
+    my ($cred, $realm, $default_username, $may_save, $pool) = @_;
+    my $config = Pushmi::Config->config;
+    $logger->logdie("unable to get username from config file.")
+	unless defined $config->{username};
+    $cred->username($config->{username});
+    $cred->password($config->{password});
+    $cred->may_save(0);
+    return $SVN::_Core::SVN_NO_ERROR;
+}
+
+
 1;
 

Modified: Pushmi/branches/lock/lib/Pushmi/Command/Mirror.pm
==============================================================================
--- Pushmi/branches/lock/lib/Pushmi/Command/Mirror.pm	(original)
+++ Pushmi/branches/lock/lib/Pushmi/Command/Mirror.pm	Fri Jul 18 22:29:18 2008
@@ -2,173 +2,32 @@
 use strict;
 use warnings;
 use base 'Pushmi::Command';
-
-use Pushmi::Mirror;
-use Pushmi::Config;
-use Path::Class;
-use SVN::Mirror;
-use SVK::Config;
-use SVK::Mirror;
-use SVK::XD;
-use SVN::Delta;
 use SVK::I18N;
-use UNIVERSAL::require;
 
 my $logger = Pushmi::Config->logger('pushmi.svkmirror');
-{
-no warnings 'redefine';
-my $memd = Pushmi::Config->memcached;
-
-*SVK::Mirror::lock = sub {
-    my ($self)  = @_;
-    my $fs      = $self->repos->fs;
-    my $token = join(':', $self->repos->path, $self->_lock_token );
-    my $content = $self->_lock_content;
-    my $where = join( ' ', ( caller(0) )[ 0 .. 2 ] );
-
-    my $lock_message = $self->_lock_message;
-LOCKED:
-    {
-	my $pool = SVN::Pool->new_default;
-	my $trial = 0;
-        while (1) {
-	    $pool->clear;
-	    my $ret;
-	    last LOCKED if $ret = $memd->add( $token, $content );
-            my $who = $memd->get( $token ) or next;
-	    last if $who eq $content;
-	    $logger->warn('['.$self->repos->path."] lock held by $who...")
-		unless $trial++ % 60;
-	    $lock_message->($self, $who);
-            sleep 1;
-        }
-    }
-    $logger->debug('['.$self->repos->path."] locked by ".$token);
-    $self->_locked(1);
-};
-
-*SVK::Mirror::unlock = sub {
-    my ( $self, $force ) = @_;
-    my $token = join(':', $self->repos->path, $self->_lock_token );
-    my $who = $memd->get( $token );
-    if ($force || $self->_locked ) {
-	my $ret = $memd->delete( $token );
-	$logger->debug('['.$self->repos->path."] unlock result: $ret");
-	$self->_locked(0);
-    }
-};
-
-
-}
 
 sub options { () }
 
-sub run {
-    my $self = shift;
-
-    # compat
-    for ($self->subcommands) {
-	if ($self->{$_}) {
-	    my $cmd = 'Pushmi::Command::'.ucfirst($_);
-	    $cmd->require or die "can't require $cmd: $@";
-	    return (bless $self, $cmd)->run(@_)
-	}
-    }
-
-    $self->run_init(@_);
-}
-
-sub root_svkpath {
-    my ($self, $repos) = @_;
-    my $depot = SVK::Depot->new( { repos => $repos, repospath => $repos->path, depotname => '' } );
-    SVK::Path->real_new(
-        {
-            depot => $depot,
-            path => '/'
-        }
-    )->refresh_revision;
-}
-
-sub setup_auth {
-    my $self = shift;
-    my $config = Pushmi::Config->config;
-    SVK::Config->auth_providers(
-    sub {
-        [ $config->{use_cached_auth} ? SVN::Client::get_simple_provider() : (),
-          SVN::Client::get_username_provider(),
-          SVN::Client::get_ssl_server_trust_file_provider(),
-          SVN::Client::get_ssl_server_trust_prompt_provider(
-                \&SVK::Config::_ssl_server_trust_prompt
-          ),
-	  SVN::Client::get_simple_prompt_provider( $self->can('pushmi_auth'), 0 ) ]
-    });
-}
-
-# XXX: we should be using real providers if we can thunk svn::auth providers
-sub pushmi_auth {
-    my ($cred, $realm, $default_username, $may_save, $pool) = @_;
-    my $config = Pushmi::Config->config;
-    $logger->logdie("unable to get username from config file.")
-	unless defined $config->{username};
-    $cred->username($config->{username});
-    $cred->password($config->{password});
-    $cred->may_save(0);
-    return $SVN::_Core::SVN_NO_ERROR;
-}
-
-sub canonpath {
-    my $self = shift;
-    $_[0] = Path::Class::Dir->new($_[0])->absolute->stringify;
-}
-
-sub run_init {
+sub run_with_auth {
     my ($self, $repospath, $url) = @_;
-    $self->canonpath($repospath);
-    my ($repos, $created);
-    die "url required.\n" unless $url;
-    if (-e $repospath) {
-	$repos = SVN::Repos::open($repospath) or die "Can't open repository: $@";
-    }
-    else {
-	$created = 1;
-	$repos = SVN::Repos::create($repospath, undef, undef, undef, undef )
-	    or die "Unable to create repository on $repospath";
-    }
-
-    my $t = $self->root_svkpath($repos);
+    my $pushmi = Pushmi::Mirror->new( path => $repospath );
+    $pushmi->repos( create => 1 );
 
-    my $mirror = SVK::Mirror->new( { depot => $t->depot, path => '/', url => $url, pool => SVN::Pool->new} );
+    my $mirror = SVK::Mirror->new( { depot => $pushmi->root_svkpath->depot, path => '/', url => $url, pool => SVN::Pool->new} );
     require SVK::Mirror::Backend::SVNSync;
 
     $self->setup_auth;
     my $backend = bless { mirror => $mirror }, 'SVK::Mirror::Backend::SVNSync';
     $mirror->_backend($backend->create( $mirror ));
 
-    Pushmi::Mirror->install_hook($repospath);
-    $mirror->depot->repos->fs->set_uuid($mirror->server_uuid);
+    $pushmi->install_hook($repospath);
+    $pushmi->repos->fs->set_uuid($mirror->server_uuid);
 
-    print loc("Mirror initialized.\n");
+    $logger->info(loc("Mirror initialized.\n"));
 
     return;
 }
 
-sub ensure_consistency {
-    my ($self, $t) = @_;
-    my $repos = $t->repos;
-    my $revision = $repos->fs->revision_prop(0, 'pushmi:inconsistent')
-	or return;
-
-    my $repospath = $repos->path;
-
-    $logger->info("[$repospath] ".ref($self).' blocked by inconsistency');
-
-    my ($mirror) = $t->is_mirrored;
-    my $master = $mirror->url;
-
-    die "Pushmi slave in inconsistency.  Please use the master repository at $master\nand contact your administrator.  Sorry for the inconveniences.\n";
-
-}
-
 =head1 NAME
 
 Pushmi::Command::Mirror - initialize pushmi mirrors

Modified: Pushmi/branches/lock/lib/Pushmi/Command/Runhook.pm
==============================================================================
--- Pushmi/branches/lock/lib/Pushmi/Command/Runhook.pm	(original)
+++ Pushmi/branches/lock/lib/Pushmi/Command/Runhook.pm	Fri Jul 18 22:29:18 2008
@@ -1,5 +1,7 @@
 package Pushmi::Command::Runhook;
-use base 'Pushmi::Command::Mirror';
+use strict;
+use warnings;
+use base 'Pushmi::Command';
 use SVK::Editor::MapRev;
 our $AUTHOR;
 
@@ -9,15 +11,11 @@
     ('txnname=s' => 'txnname')
 }
 
-sub run {
+sub run_with_auth {
     my ($self, $repospath) = @_;
-    die "repospath required" unless $repospath;
-    $self->canonpath($repospath);
     Carp::confess "txnname required" unless $self->{txnname};
-    my $repos = SVN::Repos::open($repospath) or die "Can't open repository: $@";
-
-    my $fs = $repos->fs;
-    my $txn = $fs->open_txn($self->{txnname}) or die 'no such txn';
+    my $pushmi = Pushmi::Mirror->new( path => $repospath );
+    my $txn = $pushmi->repos->fs->open_txn($self->{txnname}) or die 'no such txn';
     if ($txn->prop('svk:commit')) {
 	$txn->change_prop('svk:commit', undef);
 	exit 0;
@@ -28,13 +26,12 @@
 
 #    my $anchor = $self->_find_txn_anchor($txn_root);
 #    warn "doing $self->{txnname}: ".join(',', keys %{ $txn_root->paths_changed });
-    my $t = $self->root_svkpath($repos);
-    $self->ensure_consistency($t);
+    my $t = $pushmi->root_svkpath;
+    $pushmi->ensure_consistency;
 
     # XXX: if we reentrant, the mirror will be in deadlock.
     $AUTHOR = $txn->prop('svn:author');
     $logger->info("[$repospath] committing from txn $self->{txnname} by $AUTHOR");
-    $self->setup_auth;
     # retrieve from memcached as soon as possible, as get_editor might
     # delay because of the server latency of the first response
     _get_password();
@@ -42,7 +39,7 @@
 						    callback => sub {},
 						    caller => '',
 						    message  => $txn->prop('svn:log'));
-    my ($mirror) = $t->is_mirrored;
+    my $mirror = $pushmi->master;
 
     require Pushmi::Editor::Locker;
     $editor = Pushmi::Editor::Locker->new
@@ -100,7 +97,7 @@
 
     # we need to switch back to the sync credential
     delete $mirror->_backend->{_cached_ra};
-    $self->setup_auth(Pushmi::Command::Mirror->can('pushmi_auth'));
+    $self->setup_auth(Pushmi::Command->can('pushmi_auth'));
     my ($first, $last);
 
     # if we failed on out-of-date, we might not have reached the

Modified: Pushmi/branches/lock/lib/Pushmi/Command/Sync.pm
==============================================================================
--- Pushmi/branches/lock/lib/Pushmi/Command/Sync.pm	(original)
+++ Pushmi/branches/lock/lib/Pushmi/Command/Sync.pm	Fri Jul 18 22:29:18 2008
@@ -1,7 +1,7 @@
 package Pushmi::Command::Sync;
 use strict;
 use warnings;
-use base 'Pushmi::Command::Mirror';
+use base 'Pushmi::Command';
 use SVK::I18N;
 
 my $memd = Pushmi::Config->memcached;
@@ -11,28 +11,19 @@
     ('nowait' => 'nowait');
 }
 
-sub run {
+sub run_with_auth {
     my ($self, $repospath) = @_;
-    $self->canonpath($repospath);
-    my $repos = SVN::Repos::open($repospath) or die "Can't open repository: $@";
+    my $pushmi = Pushmi::Mirror->new( path => $repospath );
+    $pushmi->ensure_consistency;
 
-    my $t = $self->root_svkpath($repos);
-    $self->ensure_consistency($t);
-
-    $self->setup_auth;
-    my ($mirror) = $t->is_mirrored;
-
-    if ($self->{nowait}) {
-	my $token   = join(':', $mirror->repos->path, $mirror->_lock_token);
-	if (my $who = $memd->get( $token ) ) {
-	    print loc("Mirror on $repospath is locked by %1, skipping.\n", $who);
-	    return;
-	}
+    if ($self->{nowait} and $pushmi->locked) {
+        print loc("Mirror on $repospath is locked by %1, skipping.\n", $pushmi->locked);
+        return;
     }
 
     my ($first, $last);
     eval {
-    $mirror->mirror_changesets(undef,
+    $pushmi->master->mirror_changesets(undef,
         sub { $first ||= $_[0]; $last = $_[0] });
     };
     $logger->error("[$repospath] sync failed: $@") if $@;

Modified: Pushmi/branches/lock/lib/Pushmi/Command/Tryauth.pm
==============================================================================
--- Pushmi/branches/lock/lib/Pushmi/Command/Tryauth.pm	(original)
+++ Pushmi/branches/lock/lib/Pushmi/Command/Tryauth.pm	Fri Jul 18 22:29:18 2008
@@ -1,5 +1,7 @@
 package Pushmi::Command::Tryauth;
-use base 'Pushmi::Command::Mirror';
+use strict;
+use warnings;
+use base 'Pushmi::Command';
 
 our ($USER, $PASS) = @_;
 
@@ -11,16 +13,11 @@
     return $SVN::_Core::SVN_NO_ERROR;
 }
 
-sub run {
+sub run_with_auth {
     my ($self, $repospath, $user, $pass) = @_;
     ($USER, $PASS) = ($user, $pass);
-    die "repospath required" unless $repospath;
-    $self->canonpath($repospath);
-    my $repos = SVN::Repos::open($repospath) or die "Can't open repository: $@";
-    my $t = $self->root_svkpath($repos);
-    my ($mirror) = $t->is_mirrored;
-    $self->setup_auth;
-    my $editor = eval { $mirror->get_commit_editor('', '*should not be committed*', sub {}) };
+    my $pushmi = Pushmi::Mirror->new( path => $repospath );
+    my $editor = eval { $pushmi->master->get_commit_editor('', '*should not be committed*', sub {}) };
     if ($editor) {
 	$editor->abort_edit;
 	exit 0;

Modified: Pushmi/branches/lock/lib/Pushmi/Command/Unlock.pm
==============================================================================
--- Pushmi/branches/lock/lib/Pushmi/Command/Unlock.pm	(original)
+++ Pushmi/branches/lock/lib/Pushmi/Command/Unlock.pm	Fri Jul 18 22:29:18 2008
@@ -1,9 +1,7 @@
 package Pushmi::Command::Unlock;
-use base 'Pushmi::Command::Mirror';
 use strict;
 use warnings;
-
-use SVK::I18N;
+use base 'Pushmi::Command';
 
 my $logger = Pushmi::Config->logger('pushmi.unlock');
 
@@ -11,29 +9,21 @@
     ( 'revision=i' => 'revision' )
 }
 
-sub run {
+sub run_with_auth {
     my ($self, $repospath) = @_;
-    $self->canonpath($repospath);
-    my $repos = SVN::Repos::open($repospath) or die "Can't open repository: $@";
-
-    my $t = $self->root_svkpath($repos);
-
-    $self->setup_auth;
-    my ($mirror) = $t->is_mirrored;
+    my $pushmi = Pushmi::Mirror->new( path => $repospath );
 
-    my $token   = join(':', $mirror->repos->path, $mirror->_lock_token);
+    my $token = $pushmi->lock_token;
     if ($self->{revision}) {
         # non-runhook commits (like sync), nothing to unlock for.
-        my $expected = $t->repos->fs->revision_prop($self->{revision}, 'svk:committed-by') or return;
+        my $expected = $pushmi->repos->fs->revision_prop($self->{revision}, 'svk:committed-by') or return;
         if ($expected ne $token) {
             $logger->logdie("[$repospath] revision $self->{revision} does not own lock $expected, expecting $token");
         }
     }
-    my $memd = Pushmi::Config->memcached;
-    if (my $content = $memd->get( $token ) ) {
+    if (my $content = $pushmi->locked ) {
         $logger->info("[$repospath] lock $token ($content) removed");
-        print loc("Removing lock %1 on %2.\n", $content, $repospath);
-        $mirror->unlock('force');
+        $pushmi->unlock('force');
     }
     else {
         $logger->info("[$repospath] lock $token not found");

Modified: Pushmi/branches/lock/lib/Pushmi/Command/Verify.pm
==============================================================================
--- Pushmi/branches/lock/lib/Pushmi/Command/Verify.pm	(original)
+++ Pushmi/branches/lock/lib/Pushmi/Command/Verify.pm	Fri Jul 18 22:29:18 2008
@@ -1,13 +1,11 @@
 package Pushmi::Command::Verify;
-use base 'Pushmi::Command::Mirror';
 use strict;
 use warnings;
+use base 'Pushmi::Command';
 use constant subcommands => qw(enable correct);
 
 use IPC::Run3 'run3';
 
-use SVK::I18N;
-
 my $logger = Pushmi::Config->logger('pushmi.verify');
 
 sub options {
@@ -17,24 +15,17 @@
     )
 }
 
-sub get_path {
-    my ($self, $repospath) = @_;
-    $self->canonpath($repospath);
-    my $repos = SVN::Repos::open($repospath) or die "Can't open repository: $@";
-    return $self->root_svkpath($repos);
-}
-
-sub run {
+sub run_with_auth {
     my ($self, $repospath) = @_;
-    my $t = $self->get_path($repospath);
+    my $pushmi = Pushmi::Mirror->new( path => $repospath );
 
-    $t->repos->fs->revision_prop(0, 'pushmi:auto-verify')
+    $pushmi->repos->fs->revision_prop(0, 'pushmi:auto-verify')
 	or return;
 
     die "Revision required.\n" unless $self->{revision};
 
     my $verify_mirror = Pushmi::Config->config->{verify_mirror} || 'verify-mirror';
-    my $path = $t->path;
+    my $path = $pushmi->repos->path;
     my $output;
 
     eval {
@@ -50,7 +41,7 @@
 
     $logger->logdie("[$repospath] can't run verify: $!") if $? == -1;
 
-    $t->repos->fs->change_rev_prop(0, 'pushmi:inconsistent', $self->{revision});
+    $pushmi->repos->fs->change_rev_prop(0, 'pushmi:inconsistent', $self->{revision});
 
     $logger->logdie("[$repospath] can't verify: $output");
 }
@@ -60,9 +51,8 @@
 
 sub run {
     my ($self, $repospath) = @_;
-    my $t = $self->get_path($repospath);
-
-    $t->repos->fs->change_rev_prop(0, 'pushmi:auto-verify', '*');
+    my $pushmi = Pushmi::Mirror->new( path => $repospath );
+    $pushmi->repos->fs->change_rev_prop(0, 'pushmi:auto-verify', '*');
 
     print "Auto-verify enabled for $repospath.\n";
 }
@@ -72,12 +62,12 @@
 
 sub run {
     my ($self, $repospath) = @_;
-    my $t = $self->get_path($repospath);
+    my $pushmi = Pushmi::Mirror->new( path => $repospath );
 
-    my $rev = $t->repos->fs->revision_prop(0, 'pushmi:inconsistent')
+    my $rev = $pushmi->repos->fs->revision_prop(0, 'pushmi:inconsistent')
 	or return;
 
-    $t->repos->fs->change_rev_prop(0, 'pushmi:inconsistent', undef);
+    $pushmi->repos->fs->change_rev_prop(0, 'pushmi:inconsistent', undef);
 
     print "Inconsistency on revision $rev on $repospath cleared.\n";
 }

Modified: Pushmi/branches/lock/lib/Pushmi/Config.pm
==============================================================================
--- Pushmi/branches/lock/lib/Pushmi/Config.pm	(original)
+++ Pushmi/branches/lock/lib/Pushmi/Config.pm	Fri Jul 18 22:29:18 2008
@@ -15,16 +15,18 @@
 	warn "pushmi config $file doesn't exist.\n";
 	return $config = {};
     }
-
-    return $config = LoadFile($file);
+    $config = LoadFile($file);
+    return $config;
 }
 
 sub logger {
     shift;
-    my $file = $ENV{PUSHMI_CONFIG} || '/etc/pushmi.conf';
-    $file =~ s/pushmi/pushmi-log/;
-    Log::Log4perl::init($file) if -e $file;
-    Log::Log4perl::init('/etc/pushmi-log.conf') if -e '/etc/pushmi-log.conf';
+    unless (Log::Log4perl->initialized) {
+        my $file = $ENV{PUSHMI_CONFIG} || '/etc/pushmi.conf';
+        $file =~ s/pushmi/pushmi-log/;
+        Log::Log4perl::init($file) if -e $file;
+        Log::Log4perl::init('/etc/pushmi-log.conf') if -e '/etc/pushmi-log.conf';
+    }
     return Log::Log4perl->get_logger(@_);
 }
 

Modified: Pushmi/branches/lock/lib/Pushmi/Mirror.pm
==============================================================================
--- Pushmi/branches/lock/lib/Pushmi/Mirror.pm	(original)
+++ Pushmi/branches/lock/lib/Pushmi/Mirror.pm	Fri Jul 18 22:29:18 2008
@@ -1,24 +1,101 @@
 package Pushmi::Mirror;
 use strict;
+use warnings;
+
 use SVN::Core;
 use SVN::Repos;
 use SVN::Fs;
 
-use SVK::Util qw(abs_path can_run);
+use Pushmi::Config;
 
-sub install_hook {
-    shift;
-    my $repospath = shift;
-    my $repos = SVN::Repos::open($repospath) or die; # XXX proper error
+use SVK::Util qw(can_run);
+
+sub new {
+    my $class = shift;
+    my %args  = (@_);
+    die "Must provide path to Pushmi::Mirror->new" unless $args{path};
+    $args{path} = Path::Class::Dir->new( $args{path} )->absolute->stringify;
+    return bless \%args, $class;
+}
+
+sub path {
+    my $self = shift;
+    return $self->{path};
+}
 
-    $repos->fs->change_rev_prop(0, 'svk:notify-commit', '*');
+sub repos {
+    my $self = shift;
+    my %args = ( create => 0, @_ );
+    my $repos;
+    if ( -e $self->path ) {
+        $repos = SVN::Repos::open( $self->path )
+            or die "Can't open repository @{[$self->path]}";
+    } elsif ( $args{create} ) {
+        $repos = SVN::Repos::create( $self->path, undef, undef, undef, undef )
+            or die "Unable to create repository @{[$self->path]}";
+    } else {
+        die "Repository @{[$self->path]} doesn't exist; won't create\n";
+    }
+    return $repos;
+}
+
+sub root_svkpath {
+    my $self  = shift;
+    my $depot = SVK::Depot->new(
+        {   repos     => $self->repos,
+            repospath => $self->repos->path,
+            depotname => ''
+        }
+    );
+    return SVK::Path->real_new(
+        {   depot => $depot,
+            path  => '/'
+        }
+    )->refresh_revision;
+}
+
+sub master {
+    my $self = shift;
+    my ($mirror) = $self->root_svkpath->is_mirrored;
+    return $mirror;
+}
 
-    my $perl = join(' ', $^X, map { "'-I$_'" } @INC);
+sub ensure_consistency {
+    my $self = shift;
+    return unless $self->repos->fs->revision_prop( 0, 'pushmi:inconsistent' );
+
+    my $master = $self->master->url;
+    die
+        "Pushmi slave in inconsistency.  Please use the master repository at $master\nand contact your administrator.  Sorry for the inconveniences.\n";
+}
+
+sub lock_token {
+    my $self = shift;
+    return
+        join( ':', $self->master->repos->path, $self->master->_lock_token );
+}
+
+sub locked {
+    my $self = shift;
+    return Pushmi::Config->memcached->get( $self->lock_token );
+}
+
+sub unlock {
+    my $self = shift;
+    return $self->master->unlock(@_);
+}
+
+sub install_hook {
+    my $self  = shift;
+    my $repos = $self->repos;
+    $repos->fs->change_rev_prop( 0, 'svk:notify-commit', '*' );
+
+    my $perl = join( ' ', $^X, map {"'-I$_'"} @INC );
     my $pushmi = can_run('pushmi') or die "can't find pushmi";
 
     no warnings 'uninitialized';
 
-    _install_hook($repospath, 'pre-commit', << "END");
+    _install_hook( $self->path, 'pre-commit', << "END");
 #!/bin/sh
 export SVKNOSVNCONFIG=1
 export PUSHMI_CONFIG=$ENV{PUSHMI_CONFIG}
@@ -29,7 +106,7 @@
 
 END
 
-    _install_hook($repospath, 'post-commit', << "END");
+    _install_hook( $self->path, 'post-commit', << "END");
 #!/bin/sh
 export SVKNOSVNCONFIG=1
 export PUSHMI_CONFIG=$ENV{PUSHMI_CONFIG}
@@ -44,7 +121,7 @@
 }
 
 sub _install_hook {
-    my ($repospath, $hook, $content) = @_;
+    my ( $repospath, $hook, $content ) = @_;
 
     my $hpath = "$repospath/hooks/$hook";
     open my $fh, '>', $hpath or die $!;
@@ -53,9 +130,10 @@
 
     close $fh;
     chmod 0755, $hpath;
-    unless (-x $hpath) {
-	# log info
-	return 0;
+    unless ( -x $hpath ) {
+
+        # log info
+        return 0;
     }
     return 1;
 }

Modified: Pushmi/branches/lock/lib/Pushmi/Test.pm
==============================================================================
--- Pushmi/branches/lock/lib/Pushmi/Test.pm	(original)
+++ Pushmi/branches/lock/lib/Pushmi/Test.pm	Fri Jul 18 22:29:18 2008
@@ -4,7 +4,7 @@
 use Pushmi::Config;
 
 use base 'Exporter';
-our @EXPORT = qw(get_dav_server run_pushmi is_svn_output start_memcached check_apache);
+our @EXPORT = qw(get_dav_server run_pushmi is_svn_output start_memcached check_apache svn_error_txn_outofdate svn_error_commit_hook build_basic_test_ok);
 
 use FindBin;
 BEGIN {
@@ -17,6 +17,7 @@
 use SVK::Util qw(can_run abs_path);
 use IPC::Run3 'run3';
 use Test::More;
+use SVK::Test;
 
 my $apache_port = 5008;
 
@@ -51,7 +52,9 @@
     my ($arg, $exp_stdout, $exp_stderr) = @_;
     my $stdout_err = [];
     $exp_stderr ||= [];
-    my $ret = run3 ['svn', '--non-interactive', @$arg], undef,
+    my $ret = run3 ['svn', ($SVN::Core::VERSION ge '1.5.0'
+                            ? '--non-interactive' : ()),
+                    @$arg], undef,
 	_mk_cmp_closure($exp_stdout, $stdout_err), # stdout
 	_mk_cmp_closure($exp_stderr, $stdout_err); # stderr
     if (@$stdout_err) {
@@ -156,6 +159,57 @@
 			 diag 'stopping memcached'; kill 'TERM', $memcached_pid if $memcached_pid };
 }
 
+sub svn_error_txn_outofdate {
+    my ($file, $txn) = @_;
+
+    my $rel_file = substr($file, 1);
+    return ("Out of date: '$rel_file' in transaction '$txn'")
+        if $SVN::Core::VERSION lt '1.5.0';
+
+    return "File '$file' is out of date";
+}
+
+sub svn_error_commit_hook {
+    my $exit_code = shift;
+
+    return ("svn: 'pre-commit' hook failed with error output:", @_)
+        if $SVN::Core::VERSION lt '1.5.0';
+
+    return ("svn: Commit blocked by pre-commit hook (exit code $exit_code) with output:", @_);
+}
+
+sub build_basic_test_ok {
+    local $Test::Builder::Level = $Test::Builder::Level + 1;
+    my ($xd, $svk) = SVK::Test::build_test('test');
+    my ($srepospath, $spath, $srepos) = $xd->find_repos ('/test/', 1);
+
+    $svk->mkdir('-m', 'init', '/test/A');
+
+    my ($copath,  $corpath)  = get_copath('basic-svn');
+    my ($scopath, $scorpath) = get_copath('basic-svk');
+
+    my $uri = uri($srepospath.($spath eq '/' ? '' : $spath));
+
+    my ($repospath, $path, $repos) = $xd->find_repos ('//', 1);
+    ok( Pushmi::Mirror->new(path => $repospath)->install_hook );
+
+    start_memcached();
+    my $muri = uri($repospath.($path eq '/' ? '' : $path));
+
+    $svk->mirror('//', $uri);
+
+    is_output($svk, 'sync', ['//'],
+              ["Syncing $uri",
+               'Retrieving log information from 1 to 1',
+               'Committed revision 1 from revision 1.']);
+
+    # XXX: this is so lame
+    return ($svk,
+            $uri, $srepos, $spath, $scopath, $scorpath,
+            $muri, $repos, $path, $copath, $corpath);
+}
+
+
 END {
     for (@CLEANUP) {
 	$_->();

Modified: Pushmi/branches/lock/t/basic.t
==============================================================================
--- Pushmi/branches/lock/t/basic.t	(original)
+++ Pushmi/branches/lock/t/basic.t	Fri Jul 18 22:29:18 2008
@@ -8,31 +8,9 @@
 
 plan tests => 28;
 
-my ($xd, $svk) = build_test('test');
-
-our $output;
-
-my ($srepospath, $spath, $srepos) = $xd->find_repos ('/test/', 1);
-
-$svk->mkdir('-m', 'init', '/test/A');
-
-my ($copath,  $corpath)  = get_copath('basic-svn');
-my ($scopath, $scorpath) = get_copath('basic-svk');
-
-my $uri = uri($srepospath.($spath eq '/' ? '' : $spath));
-
-my ($repospath, $path, $repos) = $xd->find_repos ('//', 1);
-ok( Pushmi::Mirror->install_hook($repospath) );
-
-start_memcached();
-my $muri = uri($repospath.($path eq '/' ? '' : $path));
-
-$svk->mirror('//', $uri);
-
-is_output($svk, 'sync', ['//'],
-	  ["Syncing $uri",
-	   'Retrieving log information from 1 to 1',
-	   'Committed revision 1 from revision 1.']);
+my ($svk,
+    $uri, $srepos, undef, undef, $scorpath,
+    $muri, $repos, undef, $copath, undef ) = build_basic_test_ok();
 
 is_output($svk, 'sync', ['//'],
 	  ["Syncing $uri"]);
@@ -77,28 +55,12 @@
 is($repos->fs->youngest_rev, 4, "svn didn't commit through");
 append_file("fromsvn.txt", "to conflict\n");
 
-sub svn_error_txn_outofdate {
-    my ($file, $txn) = @_;
-    # XXX: older svn:
-    #	       "Out of date: '$file' in transaction '$txn'";
-    return "File '$file' is out of date";
-}
-
-sub svn_error_commit_hook {
-    my ($exit_code, $file, $txn) = @_;
-
-    return ("svn: Commit blocked by pre-commit hook (exit code $exit_code) with output:",
-            svn_error_txn_outofdate($file, $txn));
-
-	       qr{svn: 'pre-commit' hook failed.*:},
-	       q{Out of date: 'fromsvn.txt' in transaction '5-1'}
-}
-
 is_svn_output(['ci', -m => 'trying to commit outdated change from svn'],
 	      ['Sending        fromsvn.txt',
 	       'Transmitting file data .'],
 	      ['svn: Commit failed (details follow):',
-               svn_error_commit_hook(255, '/fromsvn.txt'),
+               svn_error_commit_hook(255,
+                                     svn_error_txn_outofdate('/fromsvn.txt', '5-1')),
                '']);
 
 is($srepos->fs->youngest_rev, 5, "svn didn't commit through");

Modified: Pushmi/branches/lock/t/concurrency.t
==============================================================================
--- Pushmi/branches/lock/t/concurrency.t	(original)
+++ Pushmi/branches/lock/t/concurrency.t	Fri Jul 18 22:29:18 2008
@@ -8,31 +8,9 @@
 
 plan tests => 10;
 
-my ($xd, $svk) = build_test('test');
-
-our $output;
-
-my ($srepospath, $spath, $srepos) = $xd->find_repos ('/test/', 1);
-start_memcached();
-
-$svk->mkdir('-m', 'init', '/test/A');
-
-my ($copath,  $corpath)  = get_copath('basic-svn');
-my ($scopath, $scorpath) = get_copath('basic-svk');
-
-my $uri = uri($srepospath.($spath eq '/' ? '' : $spath));
-
-my ($repospath, $path, $repos) = $xd->find_repos ('//', 1);
-ok( Pushmi::Mirror->install_hook($repospath) );
-
-my $muri = uri($repospath.($path eq '/' ? '' : $path));
-
-$svk->mirror('//', $uri);
-
-is_output($svk, 'sync', ['//'],
-	  ["Syncing $uri",
-	   'Retrieving log information from 1 to 1',
-	   'Committed revision 1 from revision 1.']);
+my ($svk,
+    $uri, $srepos, undef, undef, $scorpath,
+    $muri, $repos, undef, $copath, undef ) = build_basic_test_ok();
 
 is_svn_output(['co', $muri, $copath],
 	      ['A    t/checkout/basic-svn/A',

Modified: Pushmi/branches/lock/t/verify.t
==============================================================================
--- Pushmi/branches/lock/t/verify.t	(original)
+++ Pushmi/branches/lock/t/verify.t	Fri Jul 18 22:29:18 2008
@@ -30,6 +30,7 @@
 
     $lf = $f->filename; $lf =~ s/pushmi/pushmi-log/;
     copy 't/pushmi-log.conf', $lf;
+    close $f;
 }
 my $pid = $$;
 
@@ -37,33 +38,9 @@
 
 plan tests => 8;
 
-my ($xd, $svk) = build_test('test');
-
-our $output;
-
-my ($srepospath, $spath, $srepos) = $xd->find_repos ('/test/', 1);
-
-$svk->mkdir('-m', 'init', '/test/A');
-
-my ($copath,  $corpath)  = get_copath('basic-svn');
-my ($scopath, $scorpath) = get_copath('basic-svk');
-
-my $uri = uri($srepospath.($spath eq '/' ? '' : $spath));
-
-my ($repospath, $path, $repos) = $xd->find_repos ('//', 1);
-my $depot = $xd->find_depot('');
-$depot->repos->fs->change_rev_prop(0, 'pushmi:auto-verify', '*');
-ok( Pushmi::Mirror->install_hook($repospath) );
-
-start_memcached();
-my $muri = uri($repospath.($path eq '/' ? '' : $path));
-
-$svk->mirror('//', $uri);
-
-is_output($svk, 'sync', ['//'],
-	  ["Syncing $uri",
-	   'Retrieving log information from 1 to 1',
-	   'Committed revision 1 from revision 1.']);
+my ($svk,
+    $uri, $srepos, undef, undef, $scorpath,
+    $muri, $repos, undef, $copath, undef ) = build_basic_test_ok();
 
 is_output($svk, 'sync', ['//'],
 	  ["Syncing $uri"]);
@@ -88,6 +65,8 @@
            'Retrieving log information from 3 to 3',
 	   'Committed revision 3 from revision 3.']);
 
+my $depot = $svk->{xd}->find_depot('');
+$depot->repos->fs->change_rev_prop(0, 'pushmi:auto-verify', '*');
 
 $depot->repos->fs->change_rev_prop(0, 'pushmi:inconsistent', '2');
 
@@ -97,9 +76,9 @@
 	      ['Sending        fromsvn.txt',
 	       'Transmitting file data .'],
 	      ['svn: Commit failed (details follow):',
-	       qr{svn: 'pre-commit' hook failed.*:},
-	       "Pushmi slave in inconsistency.  Please use the master repository at $uri",
-	       'and contact your administrator.  Sorry for the inconveniences.', '']);
+               svn_error_commit_hook(255,
+                                     "Pushmi slave in inconsistency.  Please use the master repository at $uri",
+                                     'and contact your administrator.  Sorry for the inconveniences.'), '']);
 
 
-END { return unless $$ == $pid; wait; unlink $lf }
+END { return unless $$ == $pid; wait; unlink $lf; exit 0 }



More information about the Bps-public-commit mailing list