The idea behind this module is to parallelize several file copies to possibly save time. Instead of this:
file copy sourcefile1 destfile1
file copy sourcefile2 destfile2
file copy sourcefile3 destfile3
one can use something like this:
bgCopy::bgCopySchedule sourcefile1 destfile1
bgCopy::bgCopySchedule sourcefile2 destfile2
bgCopy::bgCopySchedule sourcefile3 destfile3
bgCopy::bgCopyWaitAll
There are several limitations cmpared to file copy. If it's really faster to copy many files via the eventloop in the background instead of doing it sequentially needs to be approved. Perhaps its only really fast to do it with multiple threads (thread pool) or multiple external processes...
But it was an evening fun project :-)
namespace eval bgCopy {
package require Tcl 8.6
variable activeCopies 0
variable allCopies 0
proc bgCopySchedule {src dst args} {
variable activeCopies
variable allCopies
variable options [dict create -mkdir 0 -force 0 -exitcmd {} -limit 0 -idlecmd {}]
set keys [dict keys $options]
foreach {arg val} $args {
set key [lsearch -glob -nocase -inline $keys $arg*]
if {$key ne ""} {
dict set options $key $val
} else {
return -code error "invalid option $arg. Allowed are: $keys"
}
}
if {[dict get $options -force] == 0 && [file exists $dst]} {
return -code error "destination exists: $dst"
}
set dstDir [file dirname $dst]
if {![file isdirectory $dstDir] && [dict get $options -mkdir]} {
file mkdir $dstDir
}
set out [open $dst wb]
try {
set in [open $src rb]
} on error {result options} {
close $out
return -options $options $result
}
while {[dict get $options -limit] > 0 && $activeCopies >= [dict get $options -limit]} {
bgCopyWaitOne
}
fcopy $in $out -command [namespace code [list bgCopyClose $src $dst $in $out [dict get $options -exitcmd]]]
incr activeCopies
incr allCopies
return [list $activeCopies $allCopies $src $in $dst $out]
}
proc bgCopyClose {src dst in out exitcmd args} {
variable activeCopies
catch {
close $in
close $out
}
incr activeCopies -1
if {[llength $exitcmd]} {
catch {uplevel 1 [list {*}$exitcmd $src $dst {*}$args]}
}
}
proc bgCopyWaitOne {} {
variable options
if {[llength [dict get $options -idlecmd]]} {
catch {uplevel 1 [list {*}[dict get $options -idlecmd]]}
}
vwait bgCopy::activeCopies
}
proc bgCopyWaitAll {} {
variable activeCopies
while {$activeCopies > 0} {
bgCopyWaitOne
}
}
proc bgCopyActiveCopies {} {
variable activeCopies
return $activeCopies
}
package provide bgCopy 0.1
}
if {[info exists argv0] && [file tail [info script]] eq [file tail $argv0]} {
proc reportResult {args} {
puts "reportResult-Callback: $args (aktiv: [bgCopy::bgCopyActiveCopies])"
}
proc step {args} {
puts "step-Callback: $args (aktiv: [bgCopy::bgCopyActiveCopies])"
}
foreach {src dst} $argv {
catch {bgCopy::bgCopySchedule $src $dst -mkdir 0 -exitcmd reportResult -force 1 -limit 3 -idlecmd {step hugo}} reslt
puts $reslt
}
bgCopy::bgCopyWaitAll
puts "fertig!"
}