PGXN-API
view release on metacpan or search on metacpan
lib/PGXN/API/Sync.pm view on Meta::CPAN
package PGXN::API::Sync;
use v5.14;
use utf8;
use Moose;
use PGXN::API;
use PGXN::API::Indexer;
use Digest::SHA1;
use List::Util qw(first);
use File::Spec::Functions qw(catfile path rel2abs tmpdir catdir);
use File::Path qw(make_path);
use Cwd;
use Archive::Zip qw(:ERROR_CODES);
use constant WIN32 => $^O eq 'MSWin32';
use Moose::Util::TypeConstraints;
use namespace::autoclean;
our $VERSION = v0.21.0;
subtype Executable => as 'Str', where {
my $exe = $_;
first { -f $_ && -x _ } $exe, map { catfile $_, $exe } path;
};
has rsync_path => (is => 'rw', isa => 'Executable', default => 'rsync', required => 1);
has source => (is => 'rw', isa => 'Str', required => 1);
has verbose => (is => 'rw', isa => 'Int', default => 0);
has log_file => (is => 'rw', isa => 'Str', required => 1, default => sub {
catfile tmpdir, "pgxn-api-sync-$$.txt"
});
has mirror_uri_templates => (is => 'ro', isa => 'HashRef', lazy => 1, default => sub {
my $self = shift;
my $api = PGXN::API->instance;
my $tmpl = $api->read_json_from(catfile $api->mirror_root, 'index.json');
return { map { $_ => URI::Template->new($tmpl->{$_}) } keys %{ $tmpl } };
});
sub run {
my $self = shift;
$self->run_rsync;
$self->update_index;
}
sub DESTROY {
my $self = shift;
unlink $self->log_file;
$self->SUPER::DESTROY;
}
sub run_rsync {
my $self = shift;
# Sync the mirror.
say "Updating the mirror from ", $self->source if $self->verbose;
system (
$self->rsync_path,
qw(--archive --compress --delete --quiet),
'--log-file-format' => '%i %n',
'--log-file' => $self->log_file,
$self->source,
PGXN::API->instance->mirror_root,
) == 0 or die;
}
sub update_index {
my $self = shift;
my $indexer = PGXN::API::Indexer->new(verbose => $self->verbose);
my $meta_re = $self->regex_for_uri_template('meta');
my $mirr_re = $self->regex_for_uri_template('mirrors');
my $spec_re = $self->regex_for_uri_template('spec');
my $stat_re = $self->regex_for_uri_template('stats');
my $user_re = $self->regex_for_uri_template('user');
my $log = $self->log_file;
say 'Parsing the rsync log file' if $self->verbose > 1;
open my $fh, '<:encoding(UTF-8)', $log or die "Canot open $log: $!\n";
while (my $line = <$fh>) {
if ($line =~ $meta_re) {
if (my $params = $self->validate_distribution($1)) {
$indexer->add_distribution($params);
}
}
elsif ($line =~ $stat_re || $line =~ $mirr_re) {
$indexer->copy_from_mirror($1);
}
elsif ($line =~ $spec_re) {
my $path = $1;
$indexer->copy_from_mirror($path);
$indexer->parse_from_mirror($path, 'Multimarkdown');
}
( run in 0.552 second using v1.01-cache-2.11-cpan-39bf76dae61 )