2007-Dec-02 Here is a tool to synchronize two filesystem directories, which the name of means 'Tcl File Updater'. -- Sarnold
Usage:
tfu ?--debug boolean? ?--repare boolean? /src/dir/ /target/dir/
Output:
U /updated/file C /created/directory/ R /restored/file A /file/added/to/target/dir
Notes
I use this script daily for the sake of not to use any tool like CVS for small development. I think it is close to rsync, with the restriction that it will not operate with distant machines like rsync does.
The script
#!/usr/bin/env tclsh set cwd [pwd] array set opts [list debug off repare off] proc testopt {key val} { global opts foreach {opt oname} {-d debug -r repare} { if {$key eq $opt || $key eq "--$oname"} { set opts($oname) $val return true } } return false } proc usage {} { puts {usage: tfu [options] sourcedir/ targetdir/ Options are: -d --debug boolean debug mode (does not alter the filesystem) -h --help prints this message} exit 0 } if {[llength $argv]<2} { usage } foreach {source target} [lrange $argv end-1 end] break foreach {key val} [lrange $argv 0 end-2] { if {[testopt $key $val]} continue error "unknown option $key" } proc Repare {dir with} { cd $with if {![file exists $dir]} { puts "C $dir" Mkdir $dir } set dirs [list] foreach f [glob -nocomplain *] { if {[file isdirectory $f]} { lappend dirs $f } elseif {[file isfile $f] && ![file exists $dir/$f]} { puts "R $dir/$f" Copy $f $dir/$f } } foreach d $dirs { Repare $dir/$d $with/$d } } proc Update {dir with} { cd $with if {![file exists $dir]} { puts "C $dir" Mkdir $dir } set dirs [list] foreach f [glob -nocomplain *] { if {[file isdirectory $f]} { lappend dirs $f } elseif {[file isfile $f]} { if {![file exists $dir/$f]} { puts "A $dir/$f" Copy $f $dir/$f } elseif {[file mtime $dir/$f] < [file mtime $f]} { puts "U $dir/$f" Copy-force $f $dir/$f } } } foreach d $dirs { Update $dir/$d $with/$d } } proc CreateShadowProcs {} { global opts if {!$opts(debug)} { interp alias {} Cd {} cd interp alias {} Copy {} file copy interp alias {} Copy-force {} file copy -force interp alias {} Mkdir {} file mkdir } else { proc Cd {dir} {catch {cd $dir}} proc Copy {a b} {catch {file copy $a $b}} proc Copy-force {a b} {catch {file copy -force $a $b}} proc Mkdir {d} {catch {file mkdir $d}} } } proc main {args} { global source target opts set source [checkDir $source] set target [checkDir $target] CreateShadowProcs if {$opts(repare)} { Repare $source $target } Update $target $source } proc checkDir {name} { if {![file isdirectory $name]} {error "not a valid directory: $name"} file normalize $name } catch {tcldebug::debug} main