#!/usr/bin/perl use strict; my %config = ( "confFiles"=> ["config/*php.dist","config/conf.xml"] ); my $debug = 1; unless($#ARGV == 1) { DEBUG(1,"usage: $0 sourceDir destinationDir"); exit; } unless (-e $ARGV[0] && -e $ARGV[1]) { DEBUG(0,"sourceDir $ARGV[0] or destinationDir $ARGV[1] not exist"); exit(1); } unless (&farmer($ARGV[0],$ARGV[1])) { DEBUG(0,"Cloning failed"); } sub farmer { my $from = shift; my $to = shift; my %FROM = (); unless ( -d $from ) { &DEBUG($from." not exist or not directory"); return undef; } if (! -e $to ) { unless ($config{"confFiles"}) { symlink $from,$to; return "true"; } else { mkdir $to,0755; } } elsif (! -d $to) { DEBUG(0,"$to exist but not directory"); return undef; } foreach my $conf (@{$config{confFiles}}) { $conf =~ s/\*/[^\/]*/g; $conf =~ s/(\.|\?)/\\$1/g; $conf =~ s/^\///; $conf =~ s/\/$//; } my $dir = ""; my %cdir = (); my @dirs = (); do { unless ( opendir(DIR,$from."/".$dir) ){ DEBUG(0, "Can not open dir $from.$dir: $!"); return undef; } foreach ( grep {! /\.{1,2}$/ } readdir(DIR)) { if ( -f $from."/".$dir."/".$_ ){ $FROM{$dir."/".$_} = "f". &checkCf($dir."/".$_,\%cdir); } elsif ( -d $from."/".$dir."/".$_ ) { $FROM{$dir."/".$_} = "d". &checkCf($dir."/".$_,\%cdir); push @dirs,$dir."/".$_; } else { DEBUG(1, "$_ not file or directory. Skip it."); } } close(DIR); $dir = shift @dirs; } while ($dir); my @list = sort keys %FROM; foreach my $file (@list) { if (exists $cdir{$file} || $FROM{$file} eq "dc"){ if ( -e $to.$file ) { if ( -l $to.$file ) { unlink $to.$file; } elsif (! -d $to.$file) { DEBUG(1,"$file is not a dir. Something wrong. Try to backUp"); unless (&backUp($to.$file)) { return undef; }; } } my ($mode,$uid,$gid) = (stat($from.$file))[2,4,5]; mkdir $to.$file, $mode; chown $uid,$gid,$to.$file; } elsif ($FROM{$file} eq "fc") { if ( -l $to.$file ) { unlink $to.$file; } elsif ( -e $to.$file ) { next; } system("cp","-p",$from.$file,$to.$file); } elsif ($FROM{$file} eq "d") { if ( -l $to.$file ) { unlink $to.$file; } elsif ( -d $to.$file ) { DEBUG(1, "$file is a dir. Can not link it. Try to backUp"); next unless (&backUp($to.$file)); } elsif (-e $to.$file ) { DEBUG(1,"$file not dir. Try to backUp"); unless (&backUp($to.$file)) { return undef; } } symlink($from.$file,$to.$file); foreach my $empty ( grep { /^$file\/.+/ } @list ){ $FROM{$empty} = "empty"; } } elsif ($FROM{$file} eq "f") { if (-l $to.$file) { unlink($from.$to); } elsif ( -e $to.$file) { next unless (&backUp($to.$file)); } symlink($from.$file,$to.$file); } } return "ok"; } sub checkCf { my $file = shift; my $dir = shift; my $ret = undef; my @tmp = (); foreach my $cnf (@{$config{confFiles}}) { next unless ($file =~ /^\/$cnf$/ || $file =~ /^\/$cnf\/.+$/ ); $ret = "c"; @tmp = split(/\//, $file); shift @tmp; pop @tmp; foreach (@tmp) { next if (exists ${$dir}{"/".$_}); ${$dir}{"/".$_} = "c"; } } return $ret; } sub DEBUG { my $level = shift; my $message = shift; if ($level == 0) { print STDERR $message."\n"; } elsif ($level <= $debug) { print $message."\n"; } } sub backUp { my $file = shift; my $backup = $file.".farmer-save"; if (-d $backup) { system("rm","-rf",$backup); } elsif ( -f $backup || -l $backup) { unlink $backup; } elsif ( -e $backup) { return undef; } system("mv",$file,$backup); return "ok"; }