| 1 | #!/usr/bin/perl |
|---|
| 2 | |
|---|
| 3 | =head1 NAME |
|---|
| 4 | |
|---|
| 5 | brackup - do a backup using Brackup |
|---|
| 6 | |
|---|
| 7 | =head1 SYNOPSIS |
|---|
| 8 | |
|---|
| 9 | $ brackup --from=<source_name> --to=<target_name> --output=my_backup.brackup |
|---|
| 10 | |
|---|
| 11 | =head2 OPTIONS |
|---|
| 12 | |
|---|
| 13 | =over 4 |
|---|
| 14 | |
|---|
| 15 | =item --from=NAME |
|---|
| 16 | |
|---|
| 17 | Required. The source of your backup. Must match a [SOURCE:NAME] |
|---|
| 18 | config section in your ~/.brackup.conf (which is auto-created for you |
|---|
| 19 | on first run, so then you just have to go modify it) |
|---|
| 20 | |
|---|
| 21 | =item --to=NAME |
|---|
| 22 | |
|---|
| 23 | Required. The destination for your backup. Must match a [TARGET:NAME] |
|---|
| 24 | config section in your ~/.brackup.conf |
|---|
| 25 | |
|---|
| 26 | =item --output=FILE |
|---|
| 27 | |
|---|
| 28 | Option. Defaults to "source-YYYYMMDD.brackup". This is the "metafile" index |
|---|
| 29 | you'll need to restore. |
|---|
| 30 | |
|---|
| 31 | =item --verbose|-v |
|---|
| 32 | |
|---|
| 33 | Show status during backup. |
|---|
| 34 | |
|---|
| 35 | =back |
|---|
| 36 | |
|---|
| 37 | =head1 WARRANTY |
|---|
| 38 | |
|---|
| 39 | Brackup is distributed as-is and comes without warranty of any kind, |
|---|
| 40 | expressed or implied. We aren't responsible for your data loss. |
|---|
| 41 | |
|---|
| 42 | =head1 SEE ALSO |
|---|
| 43 | |
|---|
| 44 | brackup-restore |
|---|
| 45 | |
|---|
| 46 | =head1 AUTHOR |
|---|
| 47 | |
|---|
| 48 | Brad Fitzpatrick E<lt>brad@danga.comE<gt> |
|---|
| 49 | |
|---|
| 50 | Copyright (c) 2006-2007 Six Apart, Ltd. All rights reserved. |
|---|
| 51 | |
|---|
| 52 | This module is free software. You may use, modify, and/or redistribute this |
|---|
| 53 | software under the terms of same terms as perl itself. |
|---|
| 54 | |
|---|
| 55 | =cut |
|---|
| 56 | |
|---|
| 57 | use strict; |
|---|
| 58 | use warnings; |
|---|
| 59 | use Getopt::Long; |
|---|
| 60 | |
|---|
| 61 | use Cwd; |
|---|
| 62 | use FindBin qw($Bin); |
|---|
| 63 | use lib "$Bin/lib"; |
|---|
| 64 | |
|---|
| 65 | use Brackup; |
|---|
| 66 | |
|---|
| 67 | my ($src_name, $target_name, $backup_file, $opt_help); |
|---|
| 68 | my $opt_dryrun; |
|---|
| 69 | my $opt_verbose; |
|---|
| 70 | my $opt_du_stats; |
|---|
| 71 | |
|---|
| 72 | my $config_file = Brackup::Config->default_config_file_name; |
|---|
| 73 | |
|---|
| 74 | usage() unless |
|---|
| 75 | GetOptions( |
|---|
| 76 | 'from=s' => \$src_name, |
|---|
| 77 | 'to=s' => \$target_name, |
|---|
| 78 | 'verbose' => \$opt_verbose, |
|---|
| 79 | 'output=s' => \$backup_file, |
|---|
| 80 | 'help' => \$opt_help, |
|---|
| 81 | 'dry-run' => \$opt_dryrun, |
|---|
| 82 | 'du-stats' => \$opt_du_stats, |
|---|
| 83 | 'config=s' => \$config_file, |
|---|
| 84 | ); |
|---|
| 85 | usage() if @ARGV; |
|---|
| 86 | |
|---|
| 87 | if ($opt_help) { |
|---|
| 88 | eval "use Pod::Usage;"; |
|---|
| 89 | Pod::Usage::pod2usage( -verbose => 1, -exitval => 0 ); |
|---|
| 90 | exit 0; |
|---|
| 91 | } |
|---|
| 92 | |
|---|
| 93 | my $config = eval { Brackup::Config->load($config_file) } or |
|---|
| 94 | usage($@); |
|---|
| 95 | |
|---|
| 96 | if ($opt_du_stats && $src_name) { |
|---|
| 97 | my $root = eval { $config->load_root($src_name); } or |
|---|
| 98 | die "Bogus --from name"; |
|---|
| 99 | $root->du_stats; |
|---|
| 100 | exit 0; |
|---|
| 101 | } |
|---|
| 102 | |
|---|
| 103 | usage() unless $src_name && $target_name; |
|---|
| 104 | |
|---|
| 105 | my $cwd = getcwd(); |
|---|
| 106 | |
|---|
| 107 | sub usage { |
|---|
| 108 | my $why = shift || ""; |
|---|
| 109 | if ($why) { |
|---|
| 110 | $why =~ s/\s+$//; |
|---|
| 111 | $why = "Error: $why\n\n"; |
|---|
| 112 | } |
|---|
| 113 | die "${why}brackup --from=[source_name] --to=[target_name] [--output=<backup_metafile.brackup>]\nbrackup --help\n"; |
|---|
| 114 | } |
|---|
| 115 | |
|---|
| 116 | my $root = eval { $config->load_root($src_name); } or |
|---|
| 117 | usage($@); |
|---|
| 118 | |
|---|
| 119 | my $target = eval { $config->load_target($target_name); } or |
|---|
| 120 | usage($@); |
|---|
| 121 | |
|---|
| 122 | |
|---|
| 123 | my @now = localtime(); |
|---|
| 124 | $backup_file ||= $root->name . "-" . sprintf("%04d%02d%02d", $now[5]+1900, $now[4]+1, $now[3]) . ".brackup"; |
|---|
| 125 | $backup_file =~ s!^~/!$ENV{HOME}/! if $ENV{HOME}; |
|---|
| 126 | $backup_file = "$cwd/$backup_file" unless $backup_file =~ m!^/!; |
|---|
| 127 | |
|---|
| 128 | my $backup = Brackup::Backup->new( |
|---|
| 129 | root => $root, |
|---|
| 130 | target => $target, |
|---|
| 131 | dryrun => $opt_dryrun, |
|---|
| 132 | verbose => $opt_verbose, |
|---|
| 133 | ); |
|---|
| 134 | |
|---|
| 135 | if (my $stats = eval { $backup->backup($backup_file) }) { |
|---|
| 136 | warn "Backup complete." if $opt_verbose; |
|---|
| 137 | if ($opt_dryrun || $opt_verbose) { |
|---|
| 138 | $stats->print; |
|---|
| 139 | } |
|---|
| 140 | exit 0; |
|---|
| 141 | } else { |
|---|
| 142 | warn "Error running backup: $@\n"; |
|---|
| 143 | exit 1; |
|---|
| 144 | } |
|---|