Pushmi::Command::Mirror - initialize pushmi mirrors


Pushmi documentation Contained in the Pushmi distribution.

Index


Code Index:

NAME

Top

Pushmi::Command::Mirror - initialize pushmi mirrors

SYNOPSIS

Top

 mirror REPOSPATH URL


Pushmi documentation Contained in the Pushmi distribution.

package Pushmi::Command::Mirror;
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 {
    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 $mirror = SVK::Mirror->new( { depot => $t->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);

    print 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";

}

1;