Dackup

 view release on metacpan or  search on metacpan

lib/Dackup/Target/SSH.pm  view on Meta::CPAN

            [ [ map { $_->{filename} } @not_in_cache ] ],
            ['filenames'] );
        $code =~ s/XXX/$files/;

        my ( $rin, $in_pid ) = $ssh->pipe_in("cat > $tmpnam")
            or die "pipe_in method failed: " . $ssh->error;
        $rin->print($code) || die $!;
        $rin->close || die $ssh->error;
        waitpid( $in_pid, 0 );

        my %filename_to_d;
        foreach my $d (@not_in_cache) {
            my $filename = $d->{filename};
            $filename_to_d{$filename} = $d;
        }

        my ($lines) = $ssh->capture2("perl $tmpnam")
            || die "ssh failed: " . $ssh->error;

        foreach my $line ( split "\n", $lines ) {

            # chomp $line;
            #warn "[$line]";
            my ( $md5_hex, $filename ) = split / +/, $line, 2;

            #warn "[$md5_hex, $filename]";
            confess "Error with $line"
                unless defined $md5_hex && defined $filename;
            my $d = $filename_to_d{$filename};
            confess "Missing d for $filename" unless $d;
            push @entries,
                Dackup::Entry->new(
                {   key     => $d->{key},
                    md5_hex => $md5_hex,
                    size    => $d->{size},
                }
                );
            $cache->set( $d->{cachekey}, $md5_hex );
        }
        $ssh->system("rm $tmpnam")
            or die "remote command failed: " . $ssh->error;
    }
    return \@entries;
}

sub filename {
    my ( $self, $entry ) = @_;
    return file( $self->prefix, $entry->key );
}

sub name {
    my ( $self, $entry ) = @_;
    my $ssh = $self->ssh;
    return
          'ssh://'
        . $ssh->{_user} . '@'
        . $ssh->{_host}
        . file( $self->prefix, $entry->key );
}

sub update {
    my ( $self, $source, $entry ) = @_;
    my $ssh                   = $self->ssh;
    my $source_type           = ref($source);
    my $destination_filename  = $self->filename($entry);
    my $destination_directory = $destination_filename->parent;
    my $directories           = $self->directories;

    if ( $source_type eq 'Dackup::Target::Filesystem' ) {
        my $source_filename = $source->filename($entry);

        unless ( $directories->{$destination_directory} ) {

            my $quoted_destination_directory
                = $ssh->shell_quote("$destination_directory");

            # warn "mkdir -p $quoted_destination_directory";
            $ssh->system("mkdir -p $quoted_destination_directory")
                || die "mkdir -p $quoted_destination_directory failed: "
                . $ssh->error;
            $directories->{$destination_directory} = 1;
        }

        #warn "$source_filename -> $destination_filename";

        my $scp_options = {};
        my $throttle    = $self->dackup->throttle;
        if ($throttle) {
            my $data_rate       = Number::DataRate->new;
            my $bits_per_second = $data_rate->to_bits_per_second($throttle);
            $scp_options->{bwlimit} = $bits_per_second / 1000;    # in Kbit/s
        }

        $ssh->scp_put( $scp_options, "$source_filename",
            "$destination_filename" )
            || die "scp failed: " . $ssh->error;
    } else {
        confess "Do not know how to update from $source_type";
    }
}

sub delete {
    my ( $self, $entry ) = @_;
    my $ssh      = $self->ssh;
    my $filename = $self->filename($entry);

    $ssh->system("rm -f $filename")
        || die "rm -f $filename failed: " . $ssh->error;
}

1;

__END__

=head1 NAME

Dackup::Target::SSH - Flexible file backup remote hosts via SSH

=head1 SYNOPSIS

  use Dackup;



( run in 2.597 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )