#!/usr/bin/perl;
#ESYNC: SYNCHRONIZES TARGET FOLDER WITH SOURCE
#EMMETT BUTLER
#NOVEMBER 2010
#KNOWN BUGS:
# WHEN MOVE FLAG IS SET, FILES ARE MOVED BUT DIRECTORIES REMAIN IN SOURCE
# -C FLAG ONLY WORKS FROM INSIDE PERL SCRIPT, NOT COMMAND LINE
use File::Copy;
use File::Path;
use Getopt::Std;
# command line options:
# -d = delete files/directories in target that are no longer present in source
# -v = verbose notifications
# -m = move files, don't copy
# -c = copy directory contents only, not directory itself
# -t [extension] = copy/delete only the given filetypes
my %options=();
getopts("dvmct:", \%options);
#@extargs = split(' ', $options{t});
esync("/Users/emmettbutler/Documents/Test", "/Users/emmettbutler/Desktop/Test", 1, 1, 0, 1, 0, "");
sub esync {
my $root = shift;
my $target = shift;
my $d = shift;
my $v = shift;
my $m = shift;
my $c = shift;
my $t = shift;
my $filetype = shift;
my $parent = ($root =~ /^(.*)(\/.*?)$/)[0];
my $topfolder = ($root =~ /^(.*)(\/.*?)$/)[1];
my $source = $parent.$topfolder;
my $targetpath = ($target =~ /^(.*)(\/.*?)$/)[0];
my $destination = $targetpath.$topfolder;
#recursive method calls
copy_tree($source, $destination, $parent, $targetpath, $topfolder, $v, $m, $c, $t, $filetype);
if($options{d} || $d == 1){
find_deletions($destination, $targetpath, $parent, $topfolder, $v, $c);
}
}
sub copy_tree {
my $path = shift;
my $dest = shift;
my $parent = shift;
my $targetpath = shift;
my $topfolder = shift;
my $v = shift;
my $m = shift;
my $c = shift;
my $t = shift;
my $filetype = shift;
# Open the directory.
opendir (SRCDIR, $path)
or die "Unable to open $path: $!";
my @srcfiles = grep { !/^\.{1,2}$/ } readdir (SRCDIR);
closedir (SRCDIR);
@srcfiles = map { $path . '/' . $_ } @srcfiles;
#create the root target directory
if($c == 0){
if(!-e $dest){
mkdir "$dest";
if($options{v} || $v == 1){
print "Made dir: $dest\n";
}
}
}
for (@srcfiles) { #search all files in current directory
if (-d $_) { #if the file is a directory
$olddir = $_;
if($c == 1){
s/$topfolder//;
}
s/$parent/$targetpath/; #remove source path
if(!-e "$_"){ #if the directory doesn't exist in the target
mkdir "$_"; #create it in target
if($options{v} || $v == 1){ #verbose
print "Made dir: $_\n";
}
}
copy_tree ($olddir, $dest, $parent, $targetpath, $topfolder, $v, $m, $c, $t, $filetype); #recurse for this directory
} else { # if it is not a directory
$oldfile = $_;
if($c == 1){
s/$topfolder//;
}
s/$parent/$targetpath/; #change its path from the source to the target
$ext = ($oldfile =~ m/([^.]+)$/)[0]; #determine filetype
$newfile = $_;
if(-f $newfile){ #if it exists in target
if((-M $newfile) > (-M $oldfile)){ #if target file was modified before source file
if($options{m} || $m == 1){ #if move flag is set
move($oldfile, $newfile); #move the file from source to target
if($options{v} || $v == 1){ #verbose
print "Moved $oldfile to $newfile.(Newer version was in source)\n";
}
} else {
copy($oldfile, $newfile); #copy the file from source to target
if($options{v} || $v == 1){ #verbose
print "Copied $oldfile to $newfile.(Newer version was in source)\n";
}
}
} else {
if($options{v} || $v == 1){ #verbose
print "Did not copy $oldfile, it exists in target.\n";
}
}
}
else{ #if file does not exist in target
if($options{t} || $t == 1){ #if the -t flag is activated
if(($options{t} =~ /$ext/) || ($filetype =~ /$ext/)){ #if the current file's
#type is included in -t arguments
if($options{m} || $m == 1){ #if move flag is set
move($oldfile, $newfile); #move file
if($options{v} || $v == 1){ #verbose
print "Moved $oldfile to $newfile\n";
}
} else {
copy($oldfile, $newfile); #copy file
if($options{v} || $v == 1){ #verbose
print "Copied $oldfile to $newfile\n";
}
}
}
else{ #if the current file's type is not included in -t arguments
if($options{v} || $v == 1){ #do nothing , verbose
print "Did not copy $oldfile, incorrect extension.\n";
}
}
}
else { #if the -t flag is not present
if($options{m} || $m == 1){ #if move flag is set
move($oldfile, $newfile); #move file
if($options{v} || $v == 1){ #verbose
print "Moved $oldfile to $newfile\n";
}
} else {
copy($oldfile, $newfile); #copy file
if($options{v} || $v == 1){ #verbose
print "Copied $oldfile to $newfile\n";
}
}
}
}
}
}
}
sub find_deletions {
my $dest = shift;
my $targetpath = shift;
my $parent = shift;
my $topfolder = shift;
my $v = shift;
my $c = shift;
if($c == 1){
$dest =~ s/$topfolder//;
}
opendir (TRGDIR, $dest)
or die "Unable to open $dest: $!";
my @trgfiles = grep { !/^\.{1,2}$/ } readdir (TRGDIR);
closedir (TRGDIR);
for(@trgfiles){
#print "current: $_\n";
}
@trgfiles = map { $dest . '/' . $_ } @trgfiles;
for (@trgfiles) {
if (-d $_){ #if file is a directory
$olddir = $_;
if($c == 1){
s/$targetpath/$parent$topfolder/; #replace the target's path with the source path
} else {
s/$targetpath/$parent/;
}
if(!-d $_){ #if the directory does not exist in source
rmtree("$olddir"); #delete directory from target
if($options{v} || $v == 1){ #verbose
print "Deleted directory: $olddir does not exist in source.\n";
}
find_deletions($dest, $targetpath, $parent, $topfolder, $v, $c); #recurse from the root directory of target
} else { #if the directory exists in source
find_deletions($olddir, $targetpath, $parent, $topfolder, $v, $c); #recurse from the current directory
}
} else { #if file is not a directory
$trgdelfile = $_;
if($c == 1){
s/$targetpath/$parent$topfolder/; #replace the target's path with the source path
} else {
s/$targetpath/$parent/;
}
if(!-f $_){ # if the file does not exist in the source
unlink("$trgdelfile"); #delete it
if($options{v} || $v == 1){ #verbose
print "Deleted file: $trgdelfile does not exist in source.\n";
}
}
}
}
}