Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Yet another personal backup script

by EdwardG (Vicar)
on Jul 10, 2003 at 12:55 UTC ( [id://272952]=sourcecode: print w/replies, xml ) Need Help??
Category: Utility Scripts
Author/Contact Info EdwardG (perlmonks@edwardguiness.com)
Description: Yet another personal backup script.
=head1 NAME

backup.pl - Yet Another Script for making rotating backups

=head1 SYNOPSIS

backup.pl --bakdir=??? [--netdir=??? --keep=???
--verbose|noverbose]

Options:

    --bakdir    - required -    where to look for and store
                backup files, uses environment
                variable BAKDIR if it exists

    --netdir    - optional -    where to make a redundant copy of
                the new backup file, can be a
                directory or file name, uses
                environment variable BAKDIR_LAN if
                it exists

    --keep    - optional -    how many backup files to keep before
                recycling the oldest, defaults to 10

    --noverbose    - optional -    will suppress messsages to STDOUT
    | OR
    --verbose    - optional -    (default) will encourage messsages
                to STDOUT

NOTE: The items to be backed up are listed in __DATA__

=head1 DESCRIPTION

Yet another personal backup script.  

This script was written for my current work setup - WinXP with three
hard disk partitions and access to limited space on a network share.

It creates a zip-compressed backup file in $bakdir that contains a
set of files and directories as listed in __DATA__.  Keeping the
list in __DATA__ means that it can't be separated from the backup
script.

It creates a new file each time it is run and it removes the oldest
backup file(s) when the total number of backup files exceeds $keep.  

Backup filenames have the form yyyy-mm-dd-hh-nn-ss-xxx.zip. The
'xxx' part is to avoid a naming conflict when multiple backups are
created in the same second.  The first filename will use '000', the
next '001' etc.  

As an additional precaution it copies the newly created backup file
to $netdir.  Yes this is redundant, but as the saying goes: "Who is
General Failure, and why is he reading my hard disk?"

Features have been minimised in the hope of avoiding the endless
complications of an industrial strength backup application.  If you
want more features then you might want to consider
http://BackupPC.sourceforge.net. 

The usual disclaimers apply.  Please don't rely on this script
unless you have tested it to your own satisfaction.

=head1 BUGS

If you try to make more than 1000 backups in the same second the
script will probably start an infinite loop.  Try to avoid this.

=head1 AUTHOR

EdwardG (perlmonks@edwardguiness.com)

Loosely based on File::Backup by Ken Williams and backfiles.pl by
Jeffa.  

=head1 COPYRIGHT

Copyright 2003 Edward Guiness.  All rights reserved.

This is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.

=head1 SEE ALSO

File::Backup (CPAN)

http://BackupPC.sourceforge.net

http://perlmonks.com/index.pl?node_id=177830 (backfiles.pl)

=cut
use 5.6.1;
use strict;
use warnings;
use Getopt::Long;
use Env qw (BAKDIR BAKDIR_LAN);
use File::Path;
use Archive::Zip;
use File::Find::Rule;
use File::Copy;
use File::Spec;
use Pod::Usage;

my $verbose = 1;
my $keep = 10;
my $bakdir = '';
my $netdir = ''; 

GetOptions(
    'verbose!'    => \$verbose
,   'keep=i'    => \$keep
,   'bakdir=s'    => \$bakdir
,   'netdir=s'    => \$netdir
);

$bakdir ||= $ENV{BAKDIR};
$netdir ||= $ENV{BAKDIR_LAN};

pod2usage(-verbose=>0) unless ($bakdir);

die "Cowardly refusing to keep less than 1 backup file\n" if ($keep < 
+1);

sub yak {
    print @_ if ($verbose);
}

sub newname {
    my @t = reverse((localtime)[0..5]); $t[0]+=1900; $t[1]++;     
    my $newbackup = $bakdir.'\\'.sprintf("%4u-%02u-%02u-%02u-%02u-%02u
+_000",@t).'.zip';
    $newbackup =~ s/(\d\d\d)\.zip$/substr('00'.($1+1),-3).'.zip'/e whi
+le (-e $newbackup);
    return $newbackup;
}

# Ensure that the backup directory exists
eval {mkpath($bakdir)};
die "Unable to find or create directory $bakdir\n$@\n" if ($@);

yak "Attempting a backup of -\n";

# Tell Archive::Zip about the files and directories we want to backup
my $zip = Archive::Zip->new();
$zip->addTree($_,$_) for grep {
    chomp;
    yak "$_\n";
    (($_) and (-e)) or not warn "'".$_."' NOT FOUND";
} <DATA>;

# Choose a name for this backup
my $newbackup=newname();

# Create the backup and confirm its existence
$zip->writeToFileNamed( $newbackup );
die "\$zip->writeToFileNamed() failed to create $newbackup\n" unless (
+-e $newbackup);

yak "New backup created: $newbackup (" . (-s $newbackup) . " bytes)\n"
+;

# Get a list of existing backup filenames sorted by modification time
my @backupfiles = sort {(stat $a)[9] <=> (stat $b)[9]} 
    File::Find::Rule
    ->file()
    ->name(qr/^\d\d\d\d(?:-\d\d){5}_\d\d\d\.zip$/)
    ->in($bakdir); 

yak "Found a total of " . scalar(@backupfiles) . " backup files in $ba
+kdir\n";

# Recycle the oldest backup(s) if necessary
while ( scalar(@backupfiles) > $keep ) {
    yak("Unlinking oldest backup file: ". File::Spec->canonpath($backu
+pfiles[0]) ."\n");
    unlink($backupfiles[0]) or warn "Unable to unlink $backupfiles[0]\
+n";
    shift @backupfiles;
}

if ($netdir) {
    yak "Copying $newbackup to $netdir\n"; 
    copy($newbackup, $netdir) or warn "Copy failed: $!"; 
}

yak "Finished\n"; 

__DATA__
c:\perl\usr\lib
c:\utils
c:\batch
e:\iis
c:\vim
e:\my documents

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: sourcecode [id://272952]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (3)
As of 2024-04-19 22:42 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found