constant_sync

Top Page
Attachments:
Message as email
+ (text/plain)
Delete this message
Reply to this message
Author: Kevin Buettner
Date:  
Subject: constant_sync
--
--PART-BOUNDARY=.11030911220316.ZM11510.localdomain
Content-Type: text/plain; charset=us-ascii

The recent scp discussion reminded me of a script (attached) that I
wrote a while back. I call it constant_sync and I use it when I want
to develop code on one machine that (nearly instantly) gets mirrored
to another. (I don't like doing any serious editing on remote machines.)

``constant_sync'' uses rsync, and it is made to use ssh (instead of
rsh) as the transport by setting RSYNC_RSH to ssh. As noted in the
script it's a good idea to use ssh-agent to avoid having to constantly
log in.

``constant_sync'' also uses ``fam'' the "file alteration monitor" to
detect changes to files. It'll be necessary to install the perl
module SGI::FAM (and make sure that you have "fam" running) if you
want to use this script.

Kevin

--PART-BOUNDARY=.11030911220316.ZM11510.localdomain
Content-Description: Text
Content-Type: text/plain ; name="constant_sync" ; charset=us-ascii
Content-Disposition: attachment ; filename="constant_sync"
X-Zm-Content-Name: constant_sync

#!/usr/bin/perl -w

use SGI::FAM;
use File::PathConvert qw(realpath abs2rel splitpath);

if (@ARGV != 2) {
die "Usage: $0 <src> <dest>\n";
}

my ($src, $dest) = @ARGV;

if (! -r $src) {
die "$src does not exist!\n";
}

my $src_prefix;

if (-d $src) {
    chdir $src                or die "Can't chdir to $src: $!";
    $src = '.';
    $src_prefix = realpath($src);
}
elsif ($src =~ m#./#) {
    ($src_prefix, $src) = ($src =~ m#^(.*)/([^/]*)$#);
    chdir $src_prefix            or die "Can't chdir to $src_prefix: $!";
    $src_prefix = realpath($src_prefix);
    -r $src                or die "Can't locate $src!\n";
}



# Use rsync to copy $src to $dst. It's best to have ssh_agent running
# to avoid constantly having to log in...

rsync($src, $dest);

my $fam = new SGI::FAM;

my $file_list_length_limit = 4096 - length($dest) - 30;
my @pending_dirs_to_monitor;
my @pending_files_to_copy;

$fam->monitor($src);
while (1) {

    if (!$fam->pending) {
    if (@pending_dirs_to_monitor) {
        my $mfile;
        $mfile = shift @pending_dirs_to_monitor;
        print "Asking for monitor on $mfile\n";
        $fam->monitor($mfile);
    }


    print "DEBUG (before duplicate removal):", join ',',  @pending_files_to_copy, "\n";


    # Sometimes - though I don't know why - a name will appear
    # multiple times.  Eliminate the duplicates.
    @pending_files_to_copy = sort @pending_files_to_copy;
    for (my $i = 1; $i < @pending_files_to_copy;) {
        if ($pending_files_to_copy[$i - 1] eq $pending_files_to_copy[$i]) {
        splice @pending_files_to_copy, $i, 1, ();
        }
        else {
        $i++;
        }
    }


    print "DEBUG (after duplicate removal):", join(',',  @pending_files_to_copy), "\n";


    # Sometimes a CVS operation will create a temporary file that
    # disappears by the time we get here.
    @pending_files_to_copy = grep { -r } @pending_files_to_copy;
    while (@pending_files_to_copy) {
        my $file_list = '';
        # Be careful not to try to copy too many files at a time.
        while (@pending_files_to_copy
            && length($file_list) + length($pending_files_to_copy[0]) + 1
                                      < $file_list_length_limit) {
        $file_list .= ' ' . shift(@pending_files_to_copy);
        }


        rsync($file_list, $dest);
    }
    }


    my $event = $fam->next_event;        # Blocks
    my $type = $event->type;
    my $dirname = realpath($fam->which($event));
    my $filename = $event->filename;
    my $fullname = ($filename =~ m#/#) ? $filename : "$dirname/$filename";
    #print "$fullname: $type\n";


    if (($type eq 'change' && ! -d $fullname) || $type eq 'create') {
    #rsync($src_path, $dest_path);
    #print "rsync $src_path $dest_path\n";
    push @pending_files_to_copy, abs2rel($fullname, $src_prefix);
    }


    if (($type eq 'create' || $type eq 'exist') && -d $fullname 
         && ! $fam->monitored($fullname)) {
    push @pending_dirs_to_monitor, $fullname;
    }
}


sub rsync {
my ($src, $dest) = @_;

  $ENV{RSYNC_RSH} = "ssh";
  print "rsync -CRavuz $src $dest\n";
  $status = system("rsync -CRavuz $src $dest");
  if ($status == -1) {
      die "Couldn't start rsync: $!\n";
  }
  $status /= 256;
  if ($status != 0) {
      warn "Warning: status value from rsync was $status\n";
  }
}


--PART-BOUNDARY=.11030911220316.ZM11510.localdomain--