Friday, 16 April 2010

Howto tcl copy file and check for error

# is there a better way to check if file copy worked or not in tcl?
proc fileCopy {sFrom sTo} {
    set bUpdateFile 0
    if {[catch {file stat "$sFrom" aFromStat} r]} {
        FAIL "no 'from' file? $sFrom $::errorCode $::errorInfo"
        return
    }
    if {[catch {file stat "$sTo" aToStat} r]} {
        # no to file to compare with, do update
        set bUpdateFile 1
    }
    if {! $bUpdateFile} {
        # compare file stat info: mtime and size
        #log "stat from=[parray aFromStat] to=[parray aToStat] "
        if {$aFromStat(mtime) != $aToStat(mtime) || $aFromStat(size) != $aToStat(size)} {
            set bUpdateFile 1
            log "stat mtime from=$aFromStat(mtime) to=$aToStat(mtime)"
            log "stat size  from=$aFromStat(size)  to=$aToStat(size)"
        } else {
            log "no update needed. stat from=[parray aFromStat {mtime,size}] to=[parray aToStat {mtime,size}]"
            # did nothing
            PASS "update not needed to:$sTo"
        }
    }
    if {$bUpdateFile} {
        log "file copy -force $sFrom $sTo"
        if {[catch {file copy -force "$sFrom" "$sTo"} sError]} {
            FAIL "file copy failed: err:$sError to:$sTo"
    }
        # check for fail (mutters silly tcl manual!? how check success of file copy?)
        if {[catch {file stat "$sTo" aNewToStat} r]} {
            FAIL "cannot check file stat for copied file? to:$sTo"
        } else {
            if {$aFromStat(mtime) == $aNewToStat(mtime) && $aFromStat(size) == $aNewToStat(size)} {
                PASS "update done to:$sTo"
            } else {
                FAIL "update fstat doesn't match to:$sTo"
                parray aFromStat
                parray aNewToStat
            }
        }
    }
}

proc log {s} {
    puts "$s"
}

proc PASS {s} {
    log "PASS: $s"
}

proc FAIL {s} {
    log "FAIL: $s"
}

exec touch a.txt
fileCopy a.txt b.txt
exec rm -f ne.txt
fileCopy ne.txt b.txt

## OH! you must catch calls to file copy!
fileCopy a.txt notexistdir/fu/b.txt
fileCopy a.txt "K:/notexistdir/fu/b.txt"

log "test finish"


OUTPUT:

$ tclsh Tests/OLC/fileCopy.tcl
stat mtime from=1271431590 to=1271431430
stat size  from=0  to=0
file copy -force a.txt b.txt
PASS: update done to:b.txt
FAIL: no 'from' file? ne.txt POSIX ENOENT {no such file or directory} could not read "ne.txt": no such file or directory
    while executing
"file stat "$sFrom" aFromStat"
file copy -force a.txt notexistdir/fu/b.txt
FAIL: file copy failed: err:error copying "a.txt" to "notexistdir/fu/b.txt": no such file or directory to:notexistdir/fu/b.txt
FAIL: cannot check file stat for copied file? to:notexistdir/fu/b.txt
file copy -force a.txt K:/notexistdir/fu/b.txt
FAIL: file copy failed: err:error copying "a.txt" to "K:/notexistdir/fu/b.txt": no such file or directory to:K:/notexistdir/fu/b.txt
FAIL: cannot check file stat for copied file? to:K:/notexistdir/fu/b.txt
test finish


http://wiki.tcl.tk/10068
http://tmml.sourceforge.net/doc/tcl/file.html
http://www.beedub.com/book/2nd/unix.doc.html

1 comment:

gaoithe said...

Okay so you [catch] calls to file copy and that should cover all errors. The checking of stat on the files is not needed.