#!/usr/bin/perl =head1 NAME brackup-target - Manage your backup targets =head1 SYNOPSIS $ brackup-target [opts] list_backups $ brackup-target [opts] get_backup $ brackup-target [opts] get_backups $ brackup-target [opts] delete_backup $ brackup-target [opts] prune # remove old backups $ brackup-target [opts] gc # run garbage collector =head2 OPTIONS =over 4 =item --dest=DIR Destination to write files to. Defaults to current working directory. =item --verbose|-v Be verbose with status. =item --dry-run Do not actually execute write operations. =item --keep-backups To be used in combination with the I command. This overrides the I option specified in the configuration file. =back =head1 WARRANTY Brackup is distributed as-is and comes without warranty of any kind, expressed or implied. We aren't responsible for your data loss. =head1 SEE ALSO brackup-restore =head1 AUTHOR Brad Fitzpatrick Ebrad@danga.comE Copyright (c) 2006-2007 Six Apart, Ltd. All rights reserved. This module is free software. You may use, modify, and/or redistribute this software under the terms of same terms as perl itself. =cut use strict; use warnings; use Getopt::Long; use Cwd; use FindBin qw($Bin); use lib "$Bin/lib"; use Brackup; my $config_file; my $destdir; my $opt_help; my $opt_verbose; my $opt_keep_backups; my $opt_dryrun; usage() unless GetOptions( 'verbose' => \$opt_verbose, 'dest=s' => \$destdir, 'config=s' => \$config_file, 'keep-backups=i' => \$opt_keep_backups, 'dry-run' => \$opt_dryrun, 'help' => \$opt_help, ); if ($destdir) { chdir $destdir or die "Failed to chdir to $destdir: $!\n"; } if ($opt_help) { eval "use Pod::Usage;"; Pod::Usage::pod2usage( -verbose => 1, -exitval => 0 ); exit 0; } my $config = eval { Brackup::Config->load($config_file) } or usage($@); my $target_name = shift or usage(); my $cmd_name = shift or usage(); my $target = eval { $config->load_target($target_name); } or usage($@); my $code = __PACKAGE__->can("CMD_$cmd_name") or usage("Unknown/unimplemented command."); exit($code->() ? 0 : 1); sub CMD_list_backups { foreach my $si ($target->backups) { printf("%-35s %-20s %10d\n", $si->filename, $si->time, $si->size); } return 1; } sub CMD_get_backup { my $name = shift @ARGV or die "get_backup requires a filename to download"; $target->get_backup($name) or die "Failed to retrieve backup $name\n"; } sub CMD_get_backups { foreach my $si ($target->backups) { my $size = $si->size; my $name = $si->filename; no warnings 'uninitialized'; if (-s "$name.brackup" == $size || -s "$name.brackup.orig" == $size) { debug("Skipping $name; already have it"); next; } debug("Fetching $name"); $target->get_backup($si->filename); } } sub CMD_delete_backup { my $name = shift @ARGV or die "delete_backup requires a filename to download"; $target->delete_backup($name) or die "Failed to delete backup $name\n"; } sub CMD_prune { my $removed_count = $target->prune( keep_backups => $opt_keep_backups, dryrun => $opt_dryrun); debug("$removed_count backups removed from target"); } sub CMD_gc { my $removed_chunks = $target->gc(dryrun => $opt_dryrun); debug("$removed_chunks chunks removed from target"); } sub debug { my $msg = shift; return unless $opt_verbose; warn "$msg\n"; } sub usage { my $why = shift || ""; if ($why) { $why =~ s/\s+$//; $why = "Error: $why\n\n"; } die "${why}brackup-target [...]\nbrackup-target --help\n"; }