| Mozilla-Backup documentation | Contained in the Mozilla-Backup distribution. |
Mozilla::Backup::Plugin::FileCopy - A file copy plugin for Mozilla::Backup
use Mozilla::Backup;
my $moz = Mozilla::Backup->new(
plugin => 'Mozilla::Backup::Plugin::FileCopy'
);
This is a plugin for Mozilla::Backup which copies profiles to another directory.
$plugin = Mozilla::Backup::Plugin::FileCopy->new( %options );
The following %options are supported:
The Log::Dispatch objetc used by Mozilla::Backup. This is required.
The debug flag from Mozilla::Backup. This is not used at the moment.
@options = Mozilla::Backup::Plugin::FileCopy->allowed_options();
if (Mozilla::Backup::Plugin::FileCopy->allowed_options('debug')) {
...
}
If no arguments are given, it returns a list of configuration parameters that can be passed to the constructor. If arguments are given, it returns true if all of the arguments are allowable options for the constructor.
$directory = $plugin->munge_location( $directory );
Munges the backup location name for use by this plugin. (Currently has no effect.)
if ($plugin->open_for_backup( $filename, %options )) {
...
}
Creates a new archive for backing the profile. $filename is the
name of the archive file to be used. %options are optional
configuration parameters.
if ($plugin->open_for_restore( $filename, %options )) {
...
}
Opens an existing archive for restoring the profile.
@files = $plugin->get_contents;
Returns a list of files in the archive.
$plugin->backup_file( $local_file, $internal_name );
Backs up the file in the archive, using $internal_name as the
name in the archive.
$plugin->restore_file( $internal_name, $local_file );
Restores the file from the archive.
$plugin->close_backup();
Closes the backup.
$plugin->close_restore();
Closes the restore.
If you would like to create backups in a format for which no plugin is available, you can use Mozilla::Backup::Plugin::FileCopy with a system call to the appropriate archiver. For example,
$moz = Mozilla::backup->new(
plugin => "Mozilla::Backup::Plugin::FileCopy",
);
$dest = $moz->backup_profile(
type => "firefox",
name => "default",
);
system("tar cf - $dest |bzip2 - > firefox-default-profile.tar.bz2");
Robert Rothenberg <rrwo at cpan.org>
Copyright (c) 2005 Robert Rothenberg. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
| Mozilla-Backup documentation | Contained in the Mozilla-Backup distribution. |
package Mozilla::Backup::Plugin::FileCopy; use strict; use Carp; use File::Copy; use File::Find; use File::Spec; use Log::Dispatch; use Mozilla::ProfilesIni; use Params::Smart 0.04; use Return::Value; # require Mozilla::Backup; # $Revision: 1.16 $ our $VERSION = '0.03';
# TODO - option to preserve file perms/ownership, which should be # enabled by default. Possibly specify a callback to run on each # copied file? my @ALLOWED_OPTIONS = ( { name => "log", default => Log::Dispatch->new(), callback => sub { my ($self, $name, $log) = @_; croak "invalid log sink" unless ((ref $log) && $log->isa("Log::Dispatch")); return $log; }, name_only => 1, required => 1, }, { name => "debug", default => 0, name_only => 1, }, ); sub new { my $class = shift || __PACKAGE__; my %args = Params(@ALLOWED_OPTIONS)->args(@_); my $self = { log => $args{log}, debug => $args{debug}, status => "closed", }; return bless $self, $class; }
sub allowed_options { my $class = shift || __PACKAGE__; my %args = Params(qw( ?*options ))->args(@_); my %allowed = map { $_->{name} => 1, } @ALLOWED_OPTIONS; my @opts = @{$args{options}}, if ($args{options}); if (@opts) { my $allowed = 1; while ($allowed && (my $opt = shift @opts)) { $allowed = $allowed && $allowed{$opt}; } return $allowed; } else { return (keys %allowed); } }
sub munge_location { my $self = shift; my %args = Params(qw( file ))->args(@_); my $file = $args{file} || ""; return $file; }
sub open_for_backup { my $self = shift; my %args = Params(qw( path ?*options ))->args(@_); unless ($self->{status} eq "closed") { return failure $self->_log( "cannot create archive: status is \"$self->{status}\"" ); } my $path = File::Spec->rel2abs($args{path}); $self->{opts} = $args{options}; $self->_log( level => "debug", message => "creating archive $path\n" ); mkdir $path; chmod 0700, $path; if ($self->{path} = _catdir($path)) { $self->{status} = "open for backup"; return success; } else { return failure $self->_log( "unable to create path: \"$path\"", ); } }
sub open_for_restore { my $self = shift; my %args = Params(qw( path ?*options ))->args(@_); unless ($self->{status} eq "closed") { return failure $self->_log( "cannot open archive: status is \"$self->{status}\"" ); } my $path = File::Spec->rel2abs($args{path}); if ($self->{path} = _catdir($path)) { $self->{status} = "open for restore"; return success; } else { return failure $self->_log( "cannot find archive: \"$path\"" ); } }
sub get_contents { my $self = shift; unless ($self->{status} ne "closed") { return failure $self->_log( "cannot get contents: status is \"$self->{status}\"" ); } my $path = $self->{path}; my @files = ( ); find({ bydepth => 1, wanted => sub { my $file = $File::Find::name; my $name = substr($file, length($path)); if ($name) { $name = substr($name,1); # remove initial '/' { $name .= '/' if (-d $file); push @files, $name; } } }, }, $path ); unless (@files) { carp $self->_log( level => "warn", message => "no files in backup" ); } return @files; }
sub backup_file { my $self = shift; my %args = Params(qw( file ?internal ))->args(@_); unless ($self->{status} eq "open for backup") { return failure $self->_log( "cannot backup file: status is \"$self->{status}\"" ); } my $file = File::Spec->canonpath($args{file}); # actual file my $name = $args{internal} || $file; # name in archive $self->_log( level => "info", message => "backing up $name\n" ); if (-d $file) { my $dest = File::Spec->catdir($self->{path}, $name); if ($self->_create_dir($name)) { $self->_log( level => "debug", message => "creating $dest\n" ); mkdir $dest; chmod 0700, $dest; } return failure "directory $dest not found" unless (_catdir($dest)); return success; } elsif (-r $file) { my $dest = File::Spec->catfile($self->{path}, $name); if ($self->_create_dir($name)) { $self->_log( level => "debug", message => "copying $file to $dest\n" ); # TODO - options to copy permissions copy($file, $dest) || return failure $self->_log( "copying failed: $!" ); } return failure "file $dest not found" unless (_catfile($dest)); return success; } else { return failure $self->_log( "cannot find file $file" ); } }
sub _create_dir { my $self = shift; my $name = shift; my $root = shift || $self->{path}; my @dirs = File::Spec->splitdir($name); my $file = pop @dirs; foreach my $dir ("", @dirs) { $root = File::Spec->catdir($root, $dir); unless (-d $root) { $self->_log( level => "debug", message => "creating $root\n" ); mkdir $root; chmod 0700, $root; } } return _catdir($root) ? $file : undef; }
sub restore_file { my $self = shift; my %args = Params(qw( internal file ))->args(@_); unless ($self->{status} eq "open for restore") { return failure $self->_log( "cannot restore file: status is \"$self->{status}\"" ); } my $file = $args{internal}; my $dest = $args{file} || return failure $self->_log( "no destination specified" ); unless (-d $dest) { return failure $self->_log( "destination does not exist" ); } my $path = File::Spec->catfile($dest, $file); if (-e $path) { $self->_log( level => "debug", message => "$path exists\n" ); # TODO: confirmation to overwrite? } $self->_log( level => "info", message => "restoring $file\n" ); my $src = File::Spec->catfile($self->{path}, $file); if (-d $src) { if ($self->_create_dir($file, $dest)) { $self->_log( level => "debug", message => "creating $file\n" ); mkdir $path; chmod 0700, $path; } return failure "directory $path not found" unless (_catdir($path)); return success; } elsif (-r $src) { if ($self->_create_dir($file, $dest)) { $self->_log( level => "debug", message => "copying $file\n" ); # TODO - options to copy permissions copy($src, $path) || return failure $self->_log( "copying failed: $!" ); chmod 0600, $path; } return failure "file $path not found" unless (_catfile($path)); return success; } else { return failure $self->_log( "cannot find file $src" ); } }
sub close_backup { my $self = shift; my $path = $self->{path}; $self->_log( level => "debug", message => "closing archive\n" ); $self->{status} = "closed"; return success; }
sub close_restore { my $self = shift; $self->_log( level => "debug", message => "closing archive\n" ); $self->{status} = "closed"; return success; }
sub _log { my $self = shift; my %args = Params(qw( message ?level="error" ))->args(@_); my $msg = $args{message}; # we want log messages to always have a newline, but not necessarily # the returned value that we pass to carp/croak/return value $args{message} .= "\n" unless ($args{message} =~ /\n$/); $self->{log}->log(%args) if ($self->{log}); return $msg; # when used by carp/croak/return value }
sub _catdir { goto \&Mozilla::ProfilesIni::_catdir; } sub _catfile { goto \&Mozilla::ProfilesIni::_catfile; } 1;