#!/apps/perl5/bin/perl -w

use strict;
use Getopt::Long qw(GetOptions);
use File::DirSync;

my $usage   = undef;
my $rebuild = undef;
my $nocache = undef;
my $verbose = undef;
my $localmode = undef;
my $concur  = undef;
my @ignore  = ();
my @only    = ();

GetOptions
  ("help"    => \$usage,
   "rebuild" => \$rebuild,
   "nocache" => \$nocache,
   "verbose" => \$verbose,
   "ignore=s"=> \@ignore,
   "only=s"  => \@only,
   "local"   => \$localmode,
   "concur=s"=> \$concur,
   ) || &usage();

$| = 1 if $verbose;

&usage() if $usage;

my $dirsync = new File::DirSync {
  verbose => $verbose,
  nocache => $nocache,
  localmode => $localmode,
};

if ($concur) {
  $dirsync->lockfile( $concur );
}


my $dir_from = shift;
my $dir_to = shift;

if ((!defined $dir_from) || (!length $dir_from)) {
  &usage("Missing <source_dir>\n");
}

if (!$rebuild &&
    ((!defined $dir_to) || (!length $dir_to))) {
  &usage("Missing <dest_dir>\n");
}

if (!-d $dir_from) {
  &usage("Not a directory [$dir_from]\n");
}

$dirsync->ignore( @ignore );

if ($rebuild) {
  foreach my $dir (@only) {
    if ($dir =~ /^$dir_from/) {
      $dirsync->only( $dir );
    } else {
      &usage("$dir is not a subdirectory of $dir_from\n");
    }
  }
  $dirsync->rebuild( $dir_from );
}

if ($dir_to) {
  $dirsync->dirsync( $dir_from, $dir_to );
  exit;
}

sub usage {
  print STDERR @_;
  print <<HELP;
Usage:
  $0  [ options ]  <source_dir> <dest_dir>

  Mirrors all files and symlinks recursively
  from source_dir to dest_dir.

  --help (or -h)
  Show this screen

  --rebuild (or -r)
  Rebuilds the dirsync cache on source_dir.
  Write access to source_dir is required to rebuild.
  If dest_dir is not specified when this option is,
  then nothing is mirrored to anywhere after the
  cache is rebuilt.

  --local (or -l)
  Local directory only, no recursion.

  --nocache (or -n)
  When mirroring from source_dir to dest_dir, do not
  assume that --rebuild has built the dirsync cache
  on source_dir already.  It is ignored and all files
  are mirrored.  This option will significantly slow
  the performance of the mirroring process.

  --ignore <dir> (or -i=<dir>)
  Avoid recursing into directories named <dir> within
  the entire descent of source_dir.  This option
  applies to both the --rebuild option and the mirroring
  process if a second directory is supplied.  It may be
  specified multiple times to ignore several directories.

  --only <node> (or -o=<node>)
  If this option is used, this will be the only node
  checked for changes, but the cache will still be
  rebuilt all the way to source_dir.  This only node
  must always be a subdirectory or a file within a
  subdirectory of source_dir.  This option only applies
  to the --rebuild option.  It may be specified multiple
  times to rebuild several nodes.

  --concur <lockfile> (or -c=<lockfile>)
  If this option is used, <lockfile> will be used to
  ensure that only one dirsync process is running at
  a time.  If another process is concurrently running,
  this process will immediately abort without doing
  anything.  If <lockfile> does not exist, it will be
  created.

  --verbose (or -v)
  Show extra details.

HELP
  exit;
}

__END__

The --rebuild option should just ensure that the epoc timestamp
of the modified time for the "." node is always greater than or
equal to all file, directory, and symlink timestamps within the
recursive descent of that directory.

Sample structure:

t1/dir1/file1.txt
t1/dir1/dira
t1/dir1/dira/file1.txt
t1/dir1/dira/file2.txt
t1/dir1/dirb
t1/dir1/dirb/file1.txt
t1/dir1/dirb/file2.txt
t1/dir1/file2.txt
t1/dir2/dira/file1.txt
t1/dir2/dira/file2.txt
t1/dir2/dirb/file1.txt
t1/dir2/dirb/file2.txt
