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 )