00001
00002
00003 exec tclsh "$0" ${1+"$@"}
00004
00005
00006
00007
00008
00009 distribution = [file dirname [info script]]
00010 lappend auto_path [file join $distribution modules]
00011
00012 critcldefault = {}
00013 critclnotes = {}
00014 dist = _excluded {}
00015
00016 ret package_name (type text) {global package_name ; set package_name $text}
00017 ret package_version (type text) {global package_version ; set package_version $text}
00018 ret dist_exclude (type path) {global dist_excluded ; lappend dist_excluded $path}
00019 ret critcl (type name , type files) {
00020 global critclmodules
00021 set critclmodules($name) $files
00022 return
00023 }
00024 ret critcl_main (type name , type files) {
00025 global critcldefault
00026 set critcldefault $name
00027 critcl $name $files
00028 return
00029 }
00030 ret critcl_notes (type text) {
00031 global critclnotes
00032 set critclnotes [string map {{\n } \n} $text]
00033 return
00034 }
00035
00036 source [file join $distribution support installation version.tcl] ;
00037
00038 package = _nv ${package_name}-${package_version}
00039
00040 catch {eval file delete -force [glob [file rootname [info script]].tmp.*]}
00041
00042
00043
00044
00045
00046 debug = 0
00047
00048 if {$debug} {
00049 ret sakdebug (type script) {uplevel 1 $script ; return}
00050 } else {
00051 ret sakdebug (type args) {}
00052 }
00053
00054
00055
00056
00057
00058 ret getpackage (type package , type tclmodule) {
00059 global distribution
00060 if {[catch {package present $package}]} {
00061 set src [file join \
00062 $distribution modules \
00063 $tclmodule]
00064 if {[file exists $src]} {
00065 uplevel #0 [list source $src]
00066 } else {
00067 # Fallback
00068 package require $package
00069 }
00070 }
00071 }
00072
00073
00074
00075 ret tclfiles () {
00076 global distribution
00077 getpackage fileutil fileutil/fileutil.tcl
00078 set fl [fileutil::findByPattern $distribution -glob *.tcl]
00079 # Remove files under SCCS. They are repository, not sources to check.
00080 set tmp {}
00081 foreach f $fl {
00082 if {[string match *SCCS* $f]} continue
00083 lappend tmp $f
00084 }
00085 proc tclfiles {} [list return $tmp]
00086 return $tmp
00087 }
00088
00089 ret modtclfiles (type modules) {
00090 global mfiles guide
00091 load_modinfo
00092 set mfiles [list]
00093 foreach m $modules {
00094 eval $guide($m,pkg) $m __dummy__
00095 }
00096 return $mfiles
00097 }
00098
00099 ret modules () {
00100 global distribution
00101 set fl [list]
00102 foreach f [glob -nocomplain [file join $distribution modules *]] {
00103 if {![file isdirectory $f]} {continue}
00104 if {[string match CVS [file tail $f]]} {continue}
00105
00106 if {![file exists [file join $f pkgIndex.tcl]]} {continue}
00107
00108 lappend fl [file tail $f]
00109 }
00110 set fl [lsort $fl]
00111 proc modules {} [list return $fl]
00112 return $fl
00113 }
00114
00115 ret modules_mod (type m) {
00116 return [expr {[lsearch -exact [modules] $m] >= 0}]
00117 }
00118
00119 ret dealias (type modules) {
00120 set _ {}
00121 foreach m $modules {
00122 if {[file exists $m]} {
00123 set m [file tail $m]
00124 }
00125 lappend _ $m
00126 }
00127 return $_
00128 }
00129
00130 ret load_modinfo () {
00131 global distribution modules guide
00132 source [file join $distribution support installation modules.tcl] ; # Get list of installed modules.
00133 source [file join $distribution support installation actions.tcl] ; # Get installer support code.
00134 proc load_modinfo {} {}
00135 return
00136 }
00137
00138 ret imodules () {global modules ; load_modinfo ; return $modules}
00139
00140 ret imodules_mod (type m) {
00141 global modules
00142 load_modinfo
00143 return [expr {[lsearch -exact $modules $m] > 0}]
00144 }
00145
00146
00147
00148 ret loadpkglist (type fname) {
00149 set f [open $fname r]
00150 foreach line [split [read $f] \n] {
00151 set line [string trim $line]
00152 if {[string match @* $line]} continue
00153 if {$line == {}} continue
00154 foreach {n v} $line break
00155 lappend p($n) $v
00156 set p($n) [lsort -uniq -dict $p($n)]
00157 }
00158 close $f
00159 return [array get p]
00160 }
00161
00162
00163
00164 ret ipackages (type args) {
00165 # Determine indexed packages (ifneeded, pkgIndex.tcl)
00166
00167 global distribution
00168
00169 if {[llength $args] == 0} {set args [modules]}
00170
00171 array set p {}
00172 foreach m $args {
00173 set f [open [file join $distribution modules $m pkgIndex.tcl] r]
00174 foreach line [split [read $f] \n] {
00175 if { [regexp {#} $line]} {continue}
00176 if {![regexp {ifneeded} $line]} {continue}
00177 regsub {^.*ifneeded } $line {} line
00178 regsub {([0-9]) \[.*$} $line {\1} line
00179
00180 foreach {n v} $line break
00181
00182 if {![info exists p($n)]} {
00183 set p($n) [list $v $m]
00184 } else {
00185 # We have multiple versions of the same package. We
00186 # remember all versions.
00187
00188 foreach {vlist m} $p($n) break
00189 lappend vlist $v
00190 set p($n) [list [lsort -uniq -dict $vlist] $m]
00191 }
00192 }
00193 close $f
00194 }
00195 return [array get p]
00196 }
00197
00198
00199
00200
00201 ret ppackages (type args) {
00202 # Determine provided packages (provide, *.tcl - pkgIndex.tcl)
00203 # We cache results for a bit of speed, some stuff uses this
00204 # multiple times for the same arguments.
00205
00206 global ppcache
00207 if {[info exists ppcache($args)]} {
00208 return $ppcache($args)
00209 }
00210
00211 global p pf currentfile
00212 array set p {}
00213
00214 if {[llength $args] == 0} {
00215 set files [tclfiles]
00216 } else {
00217 set files [modtclfiles $args]
00218 }
00219
00220 getpackage fileutil fileutil/fileutil.tcl
00221 set capout [fileutil::tempfile] ; set capcout [open $capout w]
00222 set caperr [fileutil::tempfile] ; set capcerr [open $caperr w]
00223
00224 foreach f $files {
00225 # We ignore package indices and all files not in a module.
00226
00227 if {[string equal pkgIndex.tcl [file tail $f]]} {continue}
00228 if {![regexp modules $f]} {continue}
00229
00230 # We use two methods to extract the version information from a
00231 # module and its packages. First we do a static scan for
00232 # appropriate statements. If that did not work out we try to
00233 # execute the script in a modified interpreter which lets us
00234 # pick up dynamically generated version data (like stored in
00235 # variables). If the second method fails as well we give up.
00236
00237 # Method I. Static scan.
00238
00239 # We do heuristic scanning of the code to locate suitable
00240 # package provide statements.
00241
00242 set fh [open $f r]
00243
00244 set currentfile [eval file join [lrange [file split $f] end-1 end]]
00245
00246 set ok -1
00247 foreach line [split [read $fh] \n] {
00248 regsub "\#.*$" $line {} line
00249 if {![regexp {provide} $line]} {continue}
00250 if {![regexp {package} $line]} {continue}
00251
00252 # Now a stronger check for the actual command
00253 if {![regexp {package[ ][ ]*provide} $line]} {continue}
00254
00255 set xline $line
00256 regsub {^.*provide } $line {} line
00257 regsub {\].*$} $line {\1} line
00258
00259 sakdebug {puts stderr __$f\ _________$line}
00260
00261 foreach {n v} $line break
00262
00263 # HACK ...
00264 # Module 'page', package 'page::gen::peg::cpkg'.
00265 # Has a provide statement inside a template codeblock.
00266 # Name is placeholder @@. Ignore this specific name.
00267 # Better would be to use general static Tcl parsing
00268 # to find that the string is a variable value.
00269
00270 if {[string equal $n @@]} continue
00271
00272 if {[regexp {^[0-9]+(\.[0-9]+)*$} $v]} {
00273 lappend p($n) $v
00274 set p($n) [lsort -uniq -dict $p($n)]
00275 set pf($n,$v) $currentfile
00276 set ok 1
00277
00278 # We continue the scan. The file may provide several
00279 # versions of the same package, or multiple packages.
00280 continue
00281 }
00282
00283 # 'package provide foo' are tests. Ignore.
00284 if {$v == ""} continue
00285
00286 # We do not set the state to bad if we found ok provide
00287 # statements before, only if nothing was found before.
00288 if {$ok < 0} {
00289 set ok 0
00290
00291 # No good version found on the current line. We scan
00292 # further through the file and hope for more luck.
00293
00294 sakdebug {puts stderr @_$f\ _________$xline\t<$n>\t($v)}
00295 }
00296 }
00297 close $fh
00298
00299 # Method II. Restricted Execution.
00300 # We now try to run the code through a safe interpreter
00301 # and hope for better luck regarding package information.
00302
00303 if {$ok == -1} {sakdebug {puts stderr $f\ IGNORE}}
00304 if {$ok == 0} {
00305 sakdebug {puts -nonewline stderr $f\ EVAL}
00306
00307 # Source the code into a sub-interpreter. The sub
00308 # interpreter overloads 'package provide' so that the
00309 # information about new packages goes directly to us. We
00310 # also make sure that the sub interpreter doesn't kill us,
00311 # and will not get stuck early by trying to load other
00312 # files, or when creating procedures in namespaces which
00313 # do not exist due to us disabling most of the package
00314 # management.
00315
00316 set fh [open $f r]
00317
00318 set ip [interp create]
00319
00320 # Kill control structures. Namespace is required, but we
00321 # skip everything related to loading of packages,
00322 # i.e. 'command import'.
00323
00324 $ip eval {
00325 rename ::if ::_if_
00326 rename ::namespace ::_namespace_
00327
00328 proc ::if {args} {}
00329 proc ::namespace {cmd args} {
00330 #puts stderr "_nscmd_ $cmd"
00331 ::_if_ {[string equal $cmd import]} return
00332 #puts stderr "_nsdo_ $cmd $args"
00333 return [uplevel 1 [linsert $args 0 ::_namespace_ $cmd]]
00334 }
00335 }
00336
00337 # Kill more package stuff, and ensure that unknown
00338 # commands are neither loaded nor abort execution. We also
00339 # stop anything trying to kill the application at large.
00340
00341 interp alias $ip package {} xPackage
00342 interp alias $ip source {} xNULL
00343 interp alias $ip unknown {} xNULL
00344 interp alias $ip proc {} xNULL
00345 interp alias $ip exit {} xNULL
00346
00347 # From here on no redefinitions anymore, proc == xNULL !!
00348
00349 $ip eval {close stdout} ; interp share {} $capcout $ip
00350 $ip eval {close stderr} ; interp share {} $capcerr $ip
00351
00352 if {[catch {$ip eval [read $fh]} msg]} {
00353 sakdebug {puts stderr "ERROR in $currentfile:\n$::errorInfo\n"}
00354 }
00355
00356 sakdebug {puts stderr ""}
00357
00358 close $fh
00359 interp delete $ip
00360 }
00361 }
00362
00363 close $capcout ; file delete $capout
00364 close $capcerr ; file delete $caperr
00365
00366 set pp [array get p]
00367 unset p
00368
00369 set ppcache($args) $pp
00370 return $pp
00371 }
00372
00373 ret xNULL (type args) {}
00374 ret xPackage (type cmd , type args) {
00375 if {[string equal $cmd provide]} {
00376 global p pf currentfile
00377 foreach {n v} $args break
00378
00379 # No version specified, this is an inquiry, we ignore these.
00380 if {$v == {}} {return}
00381
00382 sakdebug {puts stderr \tOK\ $n\ =\ $v}
00383
00384 lappend p($n) $v
00385 set p($n) [lsort -uniq -dict $p($n)]
00386 set pf($n,$v) $currentfile
00387 }
00388 return
00389 }
00390
00391 ret sep () {puts ~~~~~~~~~~~~~~~~~~~~~~~~}
00392
00393 ret gd-cleanup () {
00394 global package_nv
00395
00396 puts {Cleaning up...}
00397
00398 set fl [glob -nocomplain ${package_nv}*]
00399 foreach f $fl {
00400 puts " Deleting $f ..."
00401 catch {file delete -force $f}
00402 }
00403 return
00404 }
00405
00406 ret gd-gen-archives () {
00407 global package_name package_nv
00408
00409 puts {Generating archives...}
00410
00411 set tar [auto_execok tar]
00412 if {$tar != {}} {
00413 puts " Gzipped tarball (${package_nv}.tar.gz)..."
00414 catch {
00415 exec $tar cf - ${package_nv} | gzip --best > ${package_nv}.tar.gz
00416 }
00417
00418 set bzip [auto_execok bzip2]
00419 if {$bzip != {}} {
00420 puts " Bzipped tarball (${package_nv}.tar.bz2)..."
00421 exec tar cf - ${package_nv} | bzip2 > ${package_nv}.tar.bz2
00422 }
00423 }
00424
00425 set zip [auto_execok zip]
00426 if {$zip != {}} {
00427 puts " Zip archive (${package_nv}.zip)..."
00428 catch {
00429 exec $zip -r ${package_nv}.zip ${package_nv}
00430 }
00431 }
00432
00433 set sdx [auto_execok sdx]
00434 if {$sdx != {}} {
00435 file copy -force [file join ${package_nv} support installation main.tcl] \
00436 [file join ${package_nv} main.tcl]
00437 file rename ${package_nv} ${package_name}.vfs
00438
00439 puts " Starkit (${package_nv}.kit)..."
00440 exec sdx wrap ${package_name}
00441 file rename ${package_name} ${package_nv}.kit
00442
00443 if {![file exists tclkit]} {
00444 puts " No tclkit present in current working directory, no starpack."
00445 } else {
00446 puts " Starpack (${package_nv}.exe)..."
00447 exec sdx wrap ${package_name} -runtime tclkit
00448 file rename ${package_name} ${package_nv}.exe
00449 }
00450
00451 file rename ${package_name}.vfs ${package_nv}
00452 }
00453
00454 puts { Keeping directory for other archive types}
00455
00456 ## Keep the directory for 'sdx' - kit/pack
00457 return
00458 }
00459
00460 ret xcopyfile (type src , type dest) {
00461 # dest can be dir or file
00462 global mfiles
00463 lappend mfiles $src
00464 return
00465 }
00466
00467 ret xcopy (type src , type dest , type recurse , optional pattern =*) {
00468 foreach file [glob [file join $src $pattern]] {
00469 set base [file tail $file]
00470 set sub [file join $dest $base]
00471 if {0 == [string compare CVS $base]} {continue}
00472 if {[file isdirectory $file]} then {
00473 if {$recurse} {
00474 xcopy $file $sub $recurse $pattern
00475 }
00476 } else {
00477 xcopyfile $file $sub
00478 }
00479 }
00480 }
00481
00482
00483 ret xxcopy (type src , type dest , type recurse , optional pattern =*) {
00484 global package_name
00485
00486 file mkdir $dest
00487 foreach file [glob -nocomplain [file join $src $pattern]] {
00488 set base [file tail $file]
00489 set sub [file join $dest $base]
00490
00491 # Exclude CVS, SCCS, ... automatically, and possibly the temp
00492 # hierarchy itself too.
00493
00494 if {0 == [string compare CVS $base]} {continue}
00495 if {0 == [string compare SCCS $base]} {continue}
00496 if {0 == [string compare BitKeeper $base]} {continue}
00497 if {[string match ${package_name}-* $base]} {continue}
00498 if {[string match *~ $base]} {continue}
00499
00500 if {[file isdirectory $file]} then {
00501 if {$recurse} {
00502 file mkdir $sub
00503 xxcopy $file $sub $recurse $pattern
00504 }
00505 } else {
00506 puts -nonewline stdout . ; flush stdout
00507 file copy -force $file $sub
00508 }
00509 }
00510 }
00511
00512 ret gd-assemble () {
00513 global package_nv distribution dist_excluded
00514
00515 puts "Assembling distribution in directory '${package_nv}'"
00516
00517 xxcopy $distribution ${package_nv} 1
00518
00519 foreach f $dist_excluded {
00520 file delete -force [file join $package_nv $f]
00521 }
00522 puts ""
00523 return
00524 }
00525
00526 ret normalize-version (type v) {
00527 # Strip everything after the first non-version character, and any
00528 # trailing dots left behind by that, to avoid the insertion of bad
00529 # version numbers into the generated .tap file.
00530
00531 regsub {[^0-9.].*$} $v {} v
00532 return [string trimright $v .]
00533 }
00534
00535 ret gd-gen-tap () {
00536 getpackage textutil textutil/textutil.tcl
00537 getpackage fileutil fileutil/fileutil.tcl
00538
00539 global package_name package_version distribution tcl_platform
00540
00541 set pname [textutil::cap $package_name]
00542
00543 set modules [imodules]
00544 array set pd [getpdesc]
00545 set lines [list]
00546 # Header
00547 lappend lines {format {TclDevKit Project File}}
00548 lappend lines {fmtver 2.0}
00549 lappend lines {fmttool {TclDevKit TclApp PackageDefinition} 2.5}
00550 lappend lines {}
00551 lappend lines "## Saved at : [clock format [clock seconds]]"
00552 lappend lines "## By : $tcl_platform(user)"
00553 lappend lines {##}
00554 lappend lines "## Generated by \"[file tail [info script]] tap\""
00555 lappend lines "## of $package_name $package_version"
00556 lappend lines {}
00557 lappend lines {########}
00558 lappend lines {#####}
00559 lappend lines {###}
00560 lappend lines {##}
00561 lappend lines {#}
00562
00563 # Bundle definition
00564 lappend lines {}
00565 lappend lines {# ###############}
00566 lappend lines {# Complete bundle}
00567 lappend lines {}
00568 lappend lines [list Package [list $package_name [normalize-version $package_version]]]
00569 lappend lines "Base @TAP_DIR@"
00570 lappend lines "Platform *"
00571 lappend lines "Desc \{$pname: Bundle of all packages\}"
00572 lappend lines "Path pkgIndex.tcl"
00573 lappend lines "Path [join $modules "\nPath "]"
00574
00575 set strip [llength [file split $distribution]]
00576 incr strip 2
00577
00578 foreach m $modules {
00579 # File set of module ...
00580
00581 lappend lines {}
00582 lappend lines "# #########[::textutil::strRepeat {#} [string length $m]]" ; # {}
00583 lappend lines "# Module \"$m\""
00584 set n 0
00585 foreach {p vlist} [ppackages $m] {
00586 foreach v $vlist {
00587 lappend lines "# \[[format %1d [incr n]]\] | \"$p\" ($v)"
00588 }
00589 }
00590 if {$n > 1} {
00591 # Multiple packages (*). We create one hidden package to
00592 # contain all the files and then have all the true
00593 # packages in the module refer to it.
00594 #
00595 # (*) This can also be one package for which we have
00596 # several versions. Or a combination thereof.
00597
00598 array set _ {}
00599 foreach {p vlist} [ppackages $m] {
00600 catch {set _([lindex $pd($p) 0]) .}
00601 }
00602 set desc [string trim [join [array names _] ", "] " \n\t\r,"]
00603 if {$desc == ""} {set desc "$pname module"}
00604 unset _
00605
00606 lappend lines "# -------+"
00607 lappend lines {}
00608 lappend lines [list Package [list __$m 0.0]]
00609 lappend lines "Platform *"
00610 lappend lines "Desc \{$desc\}"
00611 lappend lines Hidden
00612 lappend lines "Base @TAP_DIR@/$m"
00613
00614 foreach f [lsort -dict [modtclfiles $m]] {
00615 lappend lines "Path [fileutil::stripN $f $strip]"
00616 }
00617
00618 # Packages in the module ...
00619 foreach {p vlist} [ppackages $m] {
00620 # NO DANGER. As we are listing only the packages P for
00621 # the module any other version of P in a different
00622 # module is _not_ listed here.
00623
00624 set desc ""
00625 catch {set desc [string trim [lindex $pd($p) 1]]}
00626 if {$desc == ""} {set desc "$pname package"}
00627
00628 foreach v $vlist {
00629 lappend lines {}
00630 lappend lines [list Package [list $p [normalize-version $v]]]
00631 lappend lines "See [list __$m]"
00632 lappend lines "Platform *"
00633 lappend lines "Desc \{$desc\}"
00634 }
00635 }
00636 } else {
00637 # A single package in the module. And only one version of
00638 # it as well. Otherwise we are in the multi-pkg branch.
00639
00640 foreach {p vlist} [ppackages $m] break
00641 set desc ""
00642 catch {set desc [string trim [lindex $pd($p) 1]]}
00643 if {$desc == ""} {set desc "$pname package"}
00644
00645 set v [lindex $vlist 0]
00646
00647 lappend lines "# -------+"
00648 lappend lines {}
00649 lappend lines [list Package [list $p [normalize-version $v]]]
00650 lappend lines "Platform *"
00651 lappend lines "Desc \{$desc\}"
00652 lappend lines "Base @TAP_DIR@/$m"
00653
00654 foreach f [lsort -dict [modtclfiles $m]] {
00655 lappend lines "Path [fileutil::stripN $f $strip]"
00656 }
00657 }
00658 lappend lines {}
00659 lappend lines {#}
00660 lappend lines "# #########[::textutil::strRepeat {#} [string length $m]]"
00661 }
00662
00663 lappend lines {}
00664 lappend lines {#}
00665 lappend lines {##}
00666 lappend lines {###}
00667 lappend lines {#####}
00668 lappend lines {########}
00669
00670 # Write definition
00671 set f [open [file join $distribution ${package_name}.tap] w]
00672 puts $f [join $lines \n]
00673 close $f
00674 return
00675 }
00676
00677 ret getpdesc () {
00678 global argv ; if {![checkmod]} return
00679
00680 package require sak::doc
00681 sak::doc::Gen desc l $argv
00682
00683 array set _ {}
00684 foreach file [glob -nocomplain doc/desc
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770 ret contributors () {
00771 global distribution contributors
00772 if {![info exists contributors] || [array size contributors] == 0} {
00773 get_contributors [file join $distribution ChangeLog]
00774
00775 foreach f [glob -nocomplain [file join $distribution modules *]] {
00776 if {![file isdirectory $f]} {continue}
00777 if {[string match CVS [file tail $f]]} {continue}
00778 if {![file exists [file join $f ChangeLog]]} {continue}
00779 get_contributors [file join $f ChangeLog]
00780 }
00781 }
00782 }
00783
00784 ret get_contributors (type changelog) {
00785 global contributors
00786 set f [open $changelog r]
00787 while {![eof $f]} {
00788 gets $f line
00789 if {[regexp {^[\d-]+\s+(.*?)<(.*?)>} $line r name mail]} {
00790 set name [string trim $name]
00791 if {![info exists names($name)]} {
00792 set contributors($name) $mail
00793 }
00794 }
00795 }
00796 close $f
00797 }
00798
00799 ret validate_imodules_cmp (type imvar , type dmvar) {
00800 upvar $imvar im $dmvar dm
00801
00802 foreach m [lsort [array names im]] {
00803 if {![info exists dm($m)]} {
00804 puts " Installed, does not exist: $m"
00805 }
00806 }
00807 foreach m [lsort [array names dm]] {
00808 if {![info exists im($m)]} {
00809 puts " Missing in installer: $m"
00810 }
00811 }
00812 return
00813 }
00814
00815 ret validate_imodules () {
00816 foreach m [imodules] {set im($m) .}
00817 foreach m [modules] {set dm($m) .}
00818
00819 validate_imodules_cmp im dm
00820 return
00821 }
00822
00823 ret validate_imodules_mod (type m) {
00824 array set im {}
00825 array set dm {}
00826 if {[imodules_mod $m]} {set im($m) .}
00827 if {[modules_mod $m]} {set dm($m) .}
00828
00829 validate_imodules_cmp im dm
00830 return
00831 }
00832 ret validate_versions_cmp (type ipvar , type ppvar) {
00833 global pf
00834 getpackage struct::set struct/sets.tcl
00835
00836 upvar $ipvar ip $ppvar pp
00837 set maxl 0
00838 foreach name [array names ip] {if {[string length $name] > $maxl} {set maxl [string length $name]}}
00839 foreach name [array names pp] {if {[string length $name] > $maxl} {set maxl [string length $name]}}
00840
00841 foreach p [lsort [array names ip]] {
00842 if {![info exists pp($p)]} {
00843 puts " Indexed, no provider: $p"
00844 }
00845 }
00846 foreach p [lsort [array names pp]] {
00847 if {![info exists ip($p)]} {
00848 foreach k [array names pf $p,*] {
00849 puts " Provided, not indexed: [format "%-*s | %s" $maxl $p $pf($k)]"
00850 }
00851 }
00852 }
00853 foreach p [lsort [array names ip]] {
00854 if {![info exists pp($p)]} continue
00855 if {[struct::set equal $pp($p) $ip($p)]} continue
00856
00857 # Compute intersection and set differences.
00858 foreach {__ pmi imp} [struct::set intersect3 $pp($p) $ip($p)] break
00859
00860 puts " Index/provided versions differ: [format "%-*s | %8s | %8s" $maxl $p $imp $pmi]"
00861 }
00862 }
00863
00864 ret validate_versions () {
00865 foreach {p vm} [ipackages] {set ip($p) [lindex $vm 0]}
00866 foreach {p vlist} [ppackages] {set pp($p) $vlist}
00867
00868 validate_versions_cmp ip pp
00869 return
00870 }
00871
00872 ret validate_versions_mod (type m) {
00873 foreach {p vm} [ipackages $m] {set ip($p) [lindex $vm 0]}
00874 foreach {p vlist} [ppackages $m] {set pp($p) $vlist}
00875
00876 validate_versions_cmp ip pp
00877 return
00878 }
00879
00880 ret validate_testsuite_mod (type m) {
00881 global distribution
00882 if {[llength [glob -nocomplain [file join $distribution modules $m *.test]]] == 0} {
00883 puts " Without testsuite : $m"
00884 }
00885 return
00886 }
00887
00888 ret bench_mod (type mlist , type paths , type interp , type flags , type norm , type format , type verbose , type output) {
00889 global distribution env tcl_platform
00890
00891 getpackage logger logger/logger.tcl
00892 getpackage bench bench/bench.tcl
00893
00894 ::logger::setlevel $verbose
00895
00896 set pattern tclsh*
00897 if {$interp != {}} {
00898 set pattern [file tail $interp]
00899 set paths [list [file dirname $interp]]
00900 } elseif {![llength $paths]} {
00901 # Using the environment PATH is not a good default for
00902 # SAK. Use the interpreter running SAK as the default.
00903 if 0 {
00904 set paths [split $env(PATH) \
00905 [expr {($tcl_platform(platform) == "windows") ? ";" : ":"}]]
00906 }
00907 set interp [info nameofexecutable]
00908 set pattern [file tail $interp]
00909 set paths [list [file dirname $interp]]
00910 }
00911
00912 set interps [bench::versions \
00913 [bench::locate $pattern $paths]]
00914
00915 if {![llength $interps]} {
00916 puts "No interpreters found"
00917 return
00918 }
00919
00920 if {[llength $flags]} {
00921 set cmd [linsert $flags 0 bench::run]
00922 } else {
00923 set cmd [list bench::run]
00924 }
00925
00926 array set DATA {}
00927
00928 foreach m $mlist {
00929 set files [glob -nocomplain [file join $distribution modules $m *.bench]]
00930 if {![llength $files]} {
00931 bench::log::warn "No benchmark files found for module \"$m\""
00932 continue
00933 }
00934
00935 set run $cmd
00936 lappend run $interps $files
00937 array set DATA [eval $run]
00938 }
00939
00940 _bench_write $output [array get DATA] $norm $format
00941 return
00942 }
00943
00944 ret bench_all (type flags , type norm , type format , type verbose , type output) {
00945 bench_mod [modules] $flags $norm $format $verbose $output
00946 return
00947 }
00948
00949
00950 ret _bench_write (type output , type data , type norm , type format) {
00951 if {$norm != {}} {
00952 getpackage logger logger/logger.tcl
00953 getpackage bench bench/bench.tcl
00954
00955 set data [bench::norm $data $norm]
00956 }
00957
00958 set data [bench::out::$format $data]
00959
00960 if {$output == {}} {
00961 puts $data
00962 } else {
00963 set output [open $output w]
00964 puts $output "# -*- tcl -*- bench/$format"
00965 puts $output $data
00966 close $output
00967 }
00968 }
00969
00970 ret validate_testsuites () {
00971 foreach m [modules] {
00972 validate_testsuite_mod $m
00973 }
00974 return
00975 }
00976
00977 ret validate_pkgIndex_mod (type m) {
00978 global distribution
00979 if {[llength [glob -nocomplain [file join $distribution modules $m pkgIndex.tcl]]] == 0} {
00980 puts " Without package index : $m"
00981 }
00982 return
00983 }
00984
00985 ret validate_pkgIndex () {
00986 global distribution
00987 foreach m [modules] {
00988 validate_pkgIndex_mod $m
00989 }
00990 return
00991 }
00992
00993 ret validate_doc_existence_mod (type m) {
00994 global distribution
00995 if {[llength [glob -nocomplain [file join $distribution modules $m {*.[13n]}]]] == 0} {
00996 if {[llength [glob -nocomplain [file join $distribution modules $m {*.man}]]] == 0} {
00997 puts " Without * any ** manpages : $m"
00998 }
00999 } elseif {[llength [glob -nocomplain [file join $distribution modules $m {*.man}]]] == 0} {
01000 puts " Without doctools manpages : $m"
01001 } else {
01002 foreach f [glob -nocomplain [file join $distribution modules $m {*.[13n]}]] {
01003 if {![file exists [file rootname $f].man]} {
01004 puts " no .man equivalent : $f"
01005 }
01006 }
01007 }
01008 return
01009 }
01010
01011 ret validate_doc_existence () {
01012 global distribution
01013 foreach m [modules] {
01014 validate_doc_existence_mod $m
01015 }
01016 return
01017 }
01018
01019
01020 ret validate_doc_markup_mod (type m) {
01021 package require sak::doc
01022 sak::doc::Gen null null [list $m]
01023 return
01024 }
01025
01026 ret validate_doc_markup () {
01027 package require sak::doc
01028 sak::doc::Gen null null [modules]
01029 return
01030 }
01031
01032 ret run-frink (type args) {
01033 global distribution
01034
01035 set tmp [file rootname [info script]].tmp.[pid]
01036
01037 if {[llength $args] == 0} {
01038 set files [tclfiles]
01039 } else {
01040 set files [lsort -dict [modtclfiles $args]]
01041 }
01042
01043 foreach f $files {
01044 puts "FRINK ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
01045 puts "$f..."
01046 puts "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
01047
01048 catch {exec frink 2> $tmp -HJ $f}
01049 set data [get_input $tmp]
01050 if {[string length $data] > 0} {
01051 puts $data
01052 }
01053 }
01054 catch {file delete -force $tmp}
01055 return
01056 }
01057
01058 ret run-procheck (type args) {
01059 global distribution
01060
01061 if {[llength $args] == 0} {
01062 set files [tclfiles]
01063 } else {
01064 set files [lsort -dict [modtclfiles $args]]
01065 }
01066
01067 foreach f $files {
01068 puts "PROCHECK ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
01069 puts "$f ..."
01070 puts "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
01071
01072 catch {exec procheck >@ stdout $f}
01073 }
01074 return
01075 }
01076
01077 ret run-tclchecker (type args) {
01078 global distribution
01079
01080 if {[llength $args] == 0} {
01081 set files [tclfiles]
01082 } else {
01083 set files [lsort -dict [modtclfiles $args]]
01084 }
01085
01086 foreach f $files {
01087 puts "TCLCHECKER ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
01088 puts "$f ..."
01089 puts "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
01090
01091 catch {exec tclchecker >@ stdout $f}
01092 }
01093 return
01094 }
01095
01096 ret run-nagelfar (type args) {
01097 global distribution
01098
01099 if {[llength $args] == 0} {
01100 set files [tclfiles]
01101 } else {
01102 set files [lsort -dict [modtclfiles $args]]
01103 }
01104
01105 foreach f $files {
01106 puts "NAGELFAR ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
01107 puts "$f ..."
01108 puts "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
01109
01110 catch {exec nagelfar >@ stdout $f}
01111 }
01112 return
01113 }
01114
01115
01116 ret get_input (type f) {return [read [set if [open $f r]]][close $if]}
01117
01118 ret write_out (type f , type text) {
01119 catch {file delete -force $f}
01120 puts -nonewline [set of [open $f w]] $text
01121 close $of
01122 }
01123
01124 ret location_PACKAGES () {
01125 global distribution
01126 return [file join $distribution support releases PACKAGES]
01127 }
01128
01129 ret gd-gen-packages () {
01130 global package_version distribution
01131
01132 set P [location_PACKAGES]
01133 file copy -force $P $P.LAST
01134 set f [open $P w]
01135 puts $f "@@ RELEASE $package_version"
01136 puts $f ""
01137
01138 array set packages {}
01139 foreach {p vm} [ipackages] {
01140 set packages($p) [lindex $vm 0]
01141 }
01142
01143 nparray packages $f
01144 close $f
01145 }
01146
01147
01148
01149 ret modified-modules () {
01150 global distribution
01151
01152 set mlist [modules]
01153 set modified [list]
01154
01155 foreach m $mlist {
01156 set cl [file join $distribution modules $m ChangeLog]
01157 if {![file exists $cl]} {
01158 lappend modified [list $m no-changelog]
01159 continue
01160 }
01161 # Look for 'Released and tagged' within
01162 # the first four lines of the file. If
01163 # not present assume that the line is
01164 # deeper down, indicatating that the module
01165 # has been modified since the last release.
01166
01167 set f [open $cl r]
01168 set n 0
01169 set mod 1
01170 while {$n < 5} {
01171 gets $f line
01172 incr n
01173 if {[string match -nocase "*Released and tagged*" $line]} {
01174 if {$n <= 4} {set mod 0 ; break}
01175 }
01176 }
01177 if {$mod} {
01178 lappend modified $m
01179 }
01180 close $f
01181 }
01182
01183 return $modified
01184 }
01185
01186
01187
01188
01189 ret docstripUser (type m) {
01190 global distribution
01191
01192 set mdir [file join $distribution modules $m]
01193
01194 if {[llength [glob -nocomplain -dir $mdir *.stitch]]} {return 1}
01195 return 0
01196 }
01197
01198 ret docstripRegen (type m) {
01199 global distribution
01200 puts "$m ..."
01201
01202 getpackage docstrip docstrip/docstrip.tcl
01203
01204 set mdir [file join $distribution modules $m]
01205
01206 foreach sf [glob -nocomplain -dir $mdir *.stitch] {
01207 puts "* [file tail $sf] ..."
01208
01209 set here [pwd]
01210 set fail [catch {
01211 cd [file dirname $sf]
01212 docstripRunStitch [file tail $sf]
01213 } msg]
01214 cd $here
01215 if {$fail} {
01216 puts " [join [split $::errorInfo \n] "\n "]"
01217 }
01218 }
01219 return
01220 }
01221
01222 ret docstripRunStitch (type sf) {
01223 # Run the stitch file in a restricted sandbox ...
01224
01225 set box [restrictedIp {
01226 input ::dsrs::Input
01227 options ::dsrs::Options
01228 stitch ::dsrs::Stitch
01229 reset ::dsrs::Reset
01230 }]
01231
01232 ::dsrs::Init
01233 set fail [catch {interp eval $box [get_input $sf]} msg]
01234 if {$fail} {
01235 puts " [join [split $::errorInfo \n] "\n "]"
01236 } else {
01237 ::dsrs::Final
01238 }
01239
01240 interp delete $box
01241 return
01242 }
01243
01244 ret emptyIp () {
01245 set box [interp create]
01246 foreach c [interp eval $box {info commands}] {
01247 if {[string equal $c "rename"]} continue
01248 interp eval $box [list rename $c {}]
01249 }
01250 # Rename command goes last.
01251 interp eval $box [list rename rename {}]
01252 return $box
01253 }
01254
01255 ret restrictedIp (type dict) {
01256 set box [emptyIp]
01257 foreach {cmd localcmd} $dict {
01258 interp alias $box $cmd {} $localcmd
01259 }
01260 return $box
01261 }
01262
01263
01264
01265
01266 namespace ::dsrs {
01267
01268
01269 variable preamble {}
01270 append preamble \n
01271 append preamble "This is the file `@output@'," \n
01272 append preamble "generated with the SAK utility" \n
01273 append preamble "(sak docstrip/regen)." \n
01274 append preamble \n
01275 append preamble "The original source files were:" \n
01276 append preamble \n
01277 append preamble "@input@ (with options: `@guards@')" \n
01278 append preamble \n
01279
01280
01281
01282 variable postamble {}
01283 append postamble \n
01284 append postamble \n
01285 append postamble "End of file `@output@'."
01286
01287
01288
01289
01290
01291 variable defaults {-metaprefix {%} -preamble {} -postamble {}}
01292
01293 variable options ; array options = {}
01294 variable outputs ; array outputs = {}
01295 variable inputs ; array inputs = {}
01296 variable input {}
01297 }
01298
01299 ret ::dsrs::Init () {
01300 variable outputs ; unset outputs ; array set outputs {}
01301 variable inputs ; unset inputs ; array set inputs {}
01302 variable input {}
01303
01304 Reset ; # options
01305 return
01306 }
01307
01308 ret ::dsrs::Reset () {
01309 variable defaults
01310 variable options ; unset options ; array set options {}
01311 eval [linsert $defaults 0 Options]
01312 return
01313 }
01314
01315 ret ::dsrs::Input (type sourcefile) {
01316 # Relative to current directory = directory containing the active
01317 # stitch file.
01318
01319 variable input $sourcefile
01320 }
01321
01322 ret ::dsrs::Options (type args) {
01323 variable options
01324 variable preamble
01325 variable postamble
01326
01327 while {[llength $args]} {
01328 set opt [lindex $args 0]
01329
01330 switch -exact -- $opt {
01331 -nopreamble -
01332 -nopostamble {
01333 set o -[string range $opt 3 end]
01334 set options($o) ""
01335 set args [lrange $args 1 end]
01336 }
01337 -preamble {
01338 set val $preamble[lindex $args 1]
01339 set options($opt) $val
01340 set args [lrange $args 2 end]
01341 }
01342 -postamble {
01343 set val [lindex $args 1]$postamble
01344 set options($opt) $val
01345 set args [lrange $args 2 end]
01346 }
01347 -metaprefix -
01348 -onerror -
01349 -trimlines {
01350 set val [lindex $args 1]
01351 set options($opt) $val
01352 set args [lrange $args 2 end]
01353 }
01354 default {
01355 return -code error "Unknown option: \"$opt\""
01356 }
01357 }
01358 }
01359 return
01360 }
01361
01362 ret ::dsrs::Stitch (type outputfile , type guards) {
01363 variable options
01364 variable inputs
01365 variable input
01366 variable outputs
01367 variable preamble
01368 variable postamble
01369
01370 if {[string equal $input {}]} {
01371 return -code error "No input file defined"
01372 }
01373
01374 if {![info exist inputs($input)]} {
01375 set inputs($input) [get_input $input]
01376 }
01377
01378 set intext $inputs($input)
01379 set otext ""
01380
01381 set c $options(-metaprefix)
01382 set cc $c$c
01383
01384 set pmap [list @output@ $outputfile \
01385 @input@ $input \
01386 @guards@ $guards]
01387
01388 if {[info exists options(-preamble)]} {
01389 set pre $options(-preamble)
01390
01391 if {![string equal $pre ""]} {
01392 append otext [Subst $pre $pmap $cc] \n
01393 }
01394 }
01395
01396 array set o [array get options]
01397 catch {unset o(-preamble)}
01398 catch {unset o(-postamble)}
01399 set opt [array get o]
01400
01401 append otext [eval [linsert $opt 0 docstrip::extract $intext $guards]]
01402
01403 if {[info exists options(-postamble)]} {
01404 set post $options(-postamble)
01405
01406 if {![string equal $post ""]} {
01407 append otext [Subst $post $pmap $cc]
01408 }
01409 }
01410
01411 # Accumulate outputs in memory
01412
01413 append outputs($outputfile) $otext
01414 return
01415 }
01416
01417 ret ::dsrs::Subst (type text , type pmap , type cc) {
01418 return [string trim "$cc [join [split [string map $pmap $text] \n] "\n$cc "]"]
01419 }
01420
01421 ret ::dsrs::Final () {
01422 variable outputs
01423 foreach o [array names outputs] {
01424 puts " = Writing $o ..."
01425
01426 if {[string equal \
01427 docstrip/docstrip.tcl \
01428 [file join [file tail [pwd]] $o]]} {
01429
01430 # We are writing over code required by ourselves.
01431 # For easy recovery in case of problems we save
01432 # the original
01433
01434 puts " *Saving original of code important to docstrip/regen itself*"
01435 write_out $o.bak [get_input $o]
01436 }
01437
01438 write_out $o $outputs($o)
01439 }
01440 }
01441
01442
01443
01444
01445 ret __name () {global package_name ; puts -nonewline $package_name}
01446 ret __version () {global package_version ; puts -nonewline $package_version}
01447 ret __minor () {global package_version ; puts -nonewline [lindex [split $package_version .] 1]}
01448 ret __major () {global package_version ; puts -nonewline [lindex [split $package_version .] 0]}
01449
01450
01451
01452
01453 ret __imodules () {puts [imodules]}
01454 ret __modules () {puts [modules]}
01455 ret __lmodules () {puts [join [modules] \n]}
01456
01457
01458 ret nparray (type a , optional chan =stdout) {
01459 upvar $a packages
01460
01461 set maxl 0
01462 foreach name [lsort [array names packages]] {
01463 if {[string length $name] > $maxl} {
01464 set maxl [string length $name]
01465 }
01466 }
01467 foreach name [lsort [array names packages]] {
01468 foreach v $packages($name) {
01469 puts $chan [format "%-*s %s" $maxl $name $v]
01470 }
01471 }
01472 return
01473 }
01474
01475 ret __packages () {
01476 array set packages {}
01477 foreach {p vm} [ipackages] {
01478 set packages($p) [lindex $vm 0]
01479 }
01480 nparray packages
01481 return
01482 }
01483
01484 ret __provided () {
01485 array set packages [ppackages]
01486 nparray packages
01487 return
01488 }
01489
01490
01491 ret __vcompare () {
01492 global argv
01493 set oldplist [lindex $argv 0]
01494 pkg-compare $oldplist
01495 return
01496 }
01497
01498 ret __rstatus () {
01499 global distribution approved
01500
01501 catch {
01502 set f [file join $distribution .APPROVE]
01503 set f [open $f r]
01504 while {![eof $f]} {
01505 if {[gets $f line] < 0} continue
01506 set line [string trim $line]
01507 if {$line == {}} continue
01508 set approved($line) .
01509 }
01510 close $f
01511 }
01512 pkg-compare [location_PACKAGES]
01513 return
01514 }
01515
01516 ret pkg-compare (type oldplist) {
01517 global approved ; array set approved {}
01518
01519 getpackage struct::set struct/sets.tcl
01520
01521 array set curpkg [ipackages]
01522 array set oldpkg [loadpkglist $oldplist]
01523 array set mod {}
01524 array set changed {}
01525 foreach m [modified-modules] {
01526 set mod($m) .
01527 }
01528
01529 foreach p [array names curpkg] {
01530 set __($p) .
01531 foreach {vlist module} $curpkg($p) break
01532 set curpkg($p) $vlist
01533 set changed($p) [info exists mod($module)]
01534 }
01535 foreach p [array names oldpkg] {set __($p) .}
01536 set unified [lsort [array names __]]
01537 unset __
01538
01539 set maxl 0
01540 foreach name $unified {
01541 if {[string length $name] > $maxl} {
01542 set maxl [string length $name]
01543 }
01544 }
01545
01546 set maxm 0
01547 foreach m [modules] {
01548 if {[string length $m] > $maxm} {
01549 set maxm [string length $m]
01550 }
01551 }
01552
01553 set lastm ""
01554 foreach m [lsort -dict [modules]] {
01555 set packages {}
01556 foreach {p ___} [ppackages $m] {
01557 lappend packages $p
01558 }
01559 foreach name [lsort -dict $packages] {
01560 set skip 0
01561 set suffix ""
01562 set prefix " "
01563 if {![info exists curpkg($name)]} {set curpkg($name) {}}
01564 if {![info exists oldpkg($name)]} {
01565 set oldpkg($name) {}
01566 set suffix " NEW"
01567 set prefix "Nn "
01568 set skip 1
01569 }
01570 if {!$skip} {
01571 # Draw attention to changed packages where version is
01572 # unchanged.
01573
01574 set vequal [struct::set equal $oldpkg($name) $curpkg($name)]
01575
01576 if {$changed($name)} {
01577 if {$vequal} {
01578 # Changed according to ChangeLog, Version is not. ALERT.
01579 set prefix "!! "
01580 set suffix "\t<<< MISMATCH. Version ==, ChangeLog ++"
01581 } else {
01582 # Both changelog and version number indicate a change.
01583 # Small alert, have to classify the order of changes.
01584 set prefix "cv "
01585 set suffix "\t=== Classify changes."
01586 }
01587 } else {
01588 if {$vequal} {
01589 # Versions are unchanged, changelog also indicates no change.
01590 # No particular attention here.
01591 } else {
01592 # Versions changed, but according to changelog nothing in code. ALERT.
01593 set prefix "!! "
01594 set suffix "\t<<< MISMATCH. ChangeLog ==, Version ++"
01595 }
01596 }
01597 if {[info exists approved($name)]} {
01598 set prefix " "
01599 set suffix ""
01600 }
01601 }
01602
01603 # To handle multiple versions we match the found versions up
01604 # by major version. We assume that we have only one version
01605 # per major version. This allows us to detect changes within
01606 # each major version, new major versions, etc.
01607
01608 array set om {} ; foreach v $oldpkg($name) {set om([lindex [split $v .] 0]) $v}
01609 array set cm {} ; foreach v $curpkg($name) {set cm([lindex [split $v .] 0]) $v}
01610
01611 set all [lsort -dict [struct::set union [array names om] [array names cm]]]
01612
01613 sakdebug {
01614 puts @@@@@@@@@@@@@@@@
01615 parray om
01616 parray cm
01617 puts all\ $all
01618 puts @@@@@@@@@@@@@@@@
01619 }
01620
01621 foreach v $all {
01622 if {![string equal $m $lastm]} {
01623 set mdis $m
01624 } else {
01625 set mdis ""
01626 }
01627 set lastm $m
01628
01629 if {[info exists om($v)]} {set ov $om($v)} else {set ov "--"}
01630 if {[info exists cm($v)]} {set cv $cm($v)} else {set cv "--"}
01631
01632 puts stdout ${prefix}[format "%-*s %-*s %-*s %-*s" \
01633 $maxm $mdis $maxl $name 8 $ov 8 $cv]$suffix
01634 }
01635
01636 unset om cm
01637 }
01638 }
01639 return
01640 }
01641
01642 ret checkmod () {
01643 global argv
01644 package require sak::util
01645 return [sak::util::checkModules argv]
01646 }
01647
01648
01649
01650
01651
01652
01653 ret __critcl () {
01654 global argv critcl critclmodules critcldefault critclnotes tcl_platform
01655 if {$tcl_platform(platform) == "windows"} {
01656
01657 # Windows is a bit more complicated. We have to choose an
01658 # interpreter, and a starkit for it, and call both.
01659 #
01660 # We prefer tclkitsh, but try to make do with a tclsh. That
01661 # one will have to have all the necessary packages to support
01662 # starkits. ActiveTcl for example.
01663
01664 set interpreter {}
01665 foreach i {critcl.exe tclkitsh tclsh} {
01666 set interpreter [auto_execok $i]
01667 if {$interpreter != {}} break
01668 }
01669
01670 if {$interpreter == {}} {
01671 return -code error \
01672 "failed to find either tclkitsh.exe or tclsh.exe in path"
01673 }
01674
01675 # The critcl starkit can come out of the environment, or we
01676 # try to locate it using several possible names. We try to
01677 # find it if and only if we did not find a critcl starpack
01678 # before.
01679
01680 if {[file tail $interpreter] == "critcl.exe"} {
01681 set critcl $interpreter
01682 } else {
01683 set kit {}
01684 if {[info exists ::env(CRITCL)]} {
01685 set kit $::env(CRITCL)
01686 } else {
01687 foreach k {critcl.kit critcl} {
01688 set kit [auto_execok $k]
01689 if {$kit != {}} break
01690 }
01691 }
01692
01693 if {$kit == {}} {
01694 return -code error "failed to find critcl.kit or critcl in \
01695 path.\n\
01696 You may wish to set the CRITCL environment variable to the\
01697 location of your critcl(.kit) file."
01698 }
01699 set critcl [concat $interpreter $kit]
01700 }
01701 } else {
01702 # My, isn't it simpler under unix.
01703 set critcl [auto_execok critcl]
01704 }
01705
01706 set flags ""
01707 while {[string match -* [set option [lindex $argv 0]]]} {
01708 # -debug and -clean only work with critcl >= v04
01709 switch -exact -- $option {
01710 -keep { append flags " -keep" }
01711 -debug { append flags " -debug" }
01712 -clean { append flags " -clean" }
01713 -- { set argv [lreplace $argv 0 0]; break }
01714 default { break }
01715 }
01716 set argv [lreplace $argv 0 0]
01717 }
01718
01719 if {$critcl != {}} {
01720 if {[llength $argv] == 0} {
01721 puts stderr "[string repeat - 72]"
01722 puts stderr "Building critcl components."
01723 if {$critclnotes != {}} {
01724 puts stderr $critclnotes
01725 }
01726 puts stderr "[string repeat - 72]"
01727
01728 critcl_module $critcldefault $flags
01729 } else {
01730 foreach m [dealias $argv] {
01731 if {[info exists critclmodules($m)]} {
01732 critcl_module $m $flags
01733 } else {
01734 puts "warning: $m is not a critcl module"
01735 }
01736 }
01737 }
01738 } else {
01739 puts "error: cannot find a critcl to run."
01740 return 1
01741 }
01742 return
01743 }
01744
01745
01746 ret __critcl-modules () {
01747 global critclmodules critcldefault
01748 foreach m [lsort -dict [array names critclmodules]] {
01749 if {$m == $critcldefault} {
01750 puts "$m **"
01751 } else {
01752 puts $m
01753 }
01754 }
01755 return
01756 }
01757
01758 ret critcl_module (type pkg , optional extra ="") {
01759 global critcl distribution critclmodules critcldefault
01760 if {$pkg == $critcldefault} {
01761 set files {}
01762 foreach f $critclmodules($critcldefault) {
01763 lappend files [file join $distribution modules $f]
01764 }
01765 foreach m [array names critclmodules] {
01766 if {$m == $critcldefault} continue
01767 foreach f $critclmodules($m) {
01768 lappend files [file join $distribution modules $f]
01769 }
01770 }
01771 } else {
01772 foreach f $critclmodules($pkg) {
01773 lappend files [file join $distribution modules $f]
01774 }
01775 }
01776 set target [file join $distribution modules]
01777 catch {
01778 puts "$critcl $extra -force -libdir [list $target] -pkg [list $pkg] $files"
01779 eval exec $critcl $extra -force -libdir [list $target] -pkg [list $pkg] $files
01780 } r
01781 puts $r
01782 return
01783 }
01784
01785
01786
01787 ret __bench/edit () {
01788 global argv argv0
01789
01790 set format text
01791 set output {}
01792
01793 while {[string match -* [set option [lindex $argv 0]]]} {
01794 set val [lindex $argv 1]
01795 switch -exact -- $option {
01796 -format {
01797 switch -exact -- $val {
01798 raw - csv - text {}
01799 default {
01800 return -error "Bad format \"$val\", expected text, csv, or raw"
01801 }
01802 }
01803 set format $val
01804 }
01805 -o {set output $val}
01806 -- {
01807 set argv [lrange $argv 1 end]
01808 break
01809 }
01810 default { break }
01811 }
01812 set argv [lrange $argv 2 end]
01813 }
01814
01815 switch -exact -- $format {
01816 raw {}
01817 csv {
01818 getpackage csv csv/csv.tcl
01819 getpackage bench::out::csv bench/bench_wcsv.tcl
01820 }
01821 text {
01822 getpackage report report/report.tcl
01823 getpackage struct::matrix struct/matrix.tcl
01824 getpackage bench::out::text bench/bench_wtext.tcl
01825 }
01826 }
01827
01828 getpackage bench::in bench/bench_read.tcl
01829 getpackage bench bench/bench.tcl
01830
01831 if {[llength $argv] != 3} {
01832 puts "Usage: $argv0 benchdata column newvalue"
01833 }
01834
01835 foreach {in col new} $argv break
01836
01837 _bench_write $output \
01838 [bench::edit \
01839 [bench::in::read $in] \
01840 $col $new] \
01841 {} $format
01842 return
01843 }
01844
01845 ret __bench/del () {
01846 global argv argv0
01847
01848 set format text
01849 set output {}
01850
01851 while {[string match -* [set option [lindex $argv 0]]]} {
01852 set val [lindex $argv 1]
01853 switch -exact -- $option {
01854 -format {
01855 switch -exact -- $val {
01856 raw - csv - text {}
01857 default {
01858 return -error "Bad format \"$val\", expected text, csv, or raw"
01859 }
01860 }
01861 set format $val
01862 }
01863 -o {set output $val}
01864 -- {
01865 set argv [lrange $argv 1 end]
01866 break
01867 }
01868 default { break }
01869 }
01870 set argv [lrange $argv 2 end]
01871 }
01872
01873 switch -exact -- $format {
01874 raw {}
01875 csv {
01876 getpackage csv csv/csv.tcl
01877 getpackage bench::out::csv bench/bench_wcsv.tcl
01878 }
01879 text {
01880 getpackage report report/report.tcl
01881 getpackage struct::matrix struct/matrix.tcl
01882 getpackage bench::out::text bench/bench_wtext.tcl
01883 }
01884 }
01885
01886 getpackage bench::in bench/bench_read.tcl
01887 getpackage bench bench/bench.tcl
01888
01889 if {[llength $argv] < 2} {
01890 puts "Usage: $argv0 benchdata column..."
01891 }
01892
01893 set in [lindex $argv 0]
01894
01895 set data [bench::in::read $in]
01896
01897 foreach c [lrange $argv 1 end] {
01898 set data [bench::del $data $c]
01899 }
01900
01901 _bench_write $output $data {} $format
01902 return
01903 }
01904
01905 ret __bench/show () {
01906 global argv
01907
01908 set format text
01909 set output {}
01910 set norm {}
01911
01912 while {[string match -* [set option [lindex $argv 0]]]} {
01913 set val [lindex $argv 1]
01914 switch -exact -- $option {
01915 -format {
01916 switch -exact -- $val {
01917 raw - csv - text {}
01918 default {
01919 return -error "Bad format \"$val\", expected text, csv, or raw"
01920 }
01921 }
01922 set format $val
01923 }
01924 -o {set output $val}
01925 -norm {set norm $val}
01926 -- {
01927 set argv [lrange $argv 1 end]
01928 break
01929 }
01930 default { break }
01931 }
01932 set argv [lrange $argv 2 end]
01933 }
01934
01935 switch -exact -- $format {
01936 raw {}
01937 csv {
01938 getpackage csv csv/csv.tcl
01939 getpackage bench::out::csv bench/bench_wcsv.tcl
01940 }
01941 text {
01942 getpackage report report/report.tcl
01943 getpackage struct::matrix struct/matrix.tcl
01944 getpackage bench::out::text bench/bench_wtext.tcl
01945 }
01946 }
01947
01948 getpackage bench::in bench/bench_read.tcl
01949
01950 array set DATA {}
01951
01952 foreach path $argv {
01953 array set DATA [bench::in::read $path]
01954 }
01955
01956 _bench_write $output [array get DATA] $norm $format
01957 return
01958 }
01959
01960 ret __bench () {
01961 global argv
01962
01963 # I. Process command line arguments for the
01964 # benchmark commands - Validation, possible
01965 # translation ...
01966
01967 set flags {}
01968 set norm {}
01969 set format text
01970 set verbose warn
01971 set output {}
01972 set paths {}
01973 set interp {}
01974
01975 while {[string match -* [set option [lindex $argv 0]]]} {
01976 set val [lindex $argv 1]
01977 switch -exact -- $option {
01978 -throwerrors {lappend flags -errors $val}
01979 -match -
01980 -rmatch -
01981 -iters -
01982 -threads {lappend flags $option $val}
01983 -o {set output $val}
01984 -norm {set norm $val}
01985 -path {lappend paths $val}
01986 -interp {set interp $val}
01987 -format {
01988 switch -exact -- $val {
01989 raw - csv - text {}
01990 default {
01991 return -error "Bad format \"$val\", expected text, csv, or raw"
01992 }
01993 }
01994 set format $val
01995 }
01996 -verbose {
01997 set verbose info
01998 set argv [lrange $argv 1 end]
01999 continue
02000 }
02001 -debug {
02002 set verbose debug
02003 set argv [lrange $argv 1 end]
02004 continue
02005 }
02006 -- {
02007 set argv [lrange $argv 1 end]
02008 break
02009 }
02010 default { break }
02011 }
02012 set argv [lrange $argv 2 end]
02013 }
02014
02015 switch -exact -- $format {
02016 raw {}
02017 csv {
02018 getpackage csv csv/csv.tcl
02019 getpackage bench::out::csv bench/bench_wcsv.tcl
02020 }
02021 text {
02022 getpackage report report/report.tcl
02023 getpackage struct::matrix struct/matrix.tcl
02024 getpackage bench::out::text bench/bench_wtext.tcl
02025 }
02026 }
02027
02028 # Choose between benchmarking everything, or
02029 # only selected modules.
02030
02031 if {[llength $argv] == 0} {
02032 _bench_all $paths $interp $flags $norm $format $verbose $output
02033 } else {
02034 if {![checkmod]} {return}
02035 _bench_module [dealias $argv] $paths $interp $flags $norm $format $verbose $output
02036 }
02037 return
02038 }
02039
02040 ret _bench_module (type mlist , type paths , type interp , type flags , type norm , type format , type verbose , type output) {
02041 global package_name package_version
02042
02043 puts "Benchmarking $package_name $package_version development"
02044 puts "======================================================"
02045 bench_mod $mlist $paths $interp $flags $norm $format $verbose $output
02046 puts "------------------------------------------------------"
02047 puts ""
02048 return
02049 }
02050
02051 ret _bench_all (type paths , type flags , type interp , type norm , type format , type verbose , type output) {
02052 _bench_module [modules] $paths $interp $flags $norm $format $verbose $output
02053 return
02054 }
02055
02056
02057
02058 ret __validate_v () {
02059 global argv
02060 if {[llength $argv] == 0} {
02061 _validate_all_v
02062 } else {
02063 if {![checkmod]} {return}
02064 foreach m [dealias $argv] {
02065 _validate_module_v $m
02066 }
02067 }
02068 return
02069 }
02070
02071 ret _validate_all_v () {
02072 global package_name package_version
02073 set i 0
02074
02075 puts "Validating $package_name $package_version development"
02076 puts "==================================================="
02077 puts "[incr i]: Consistency of package versions ..."
02078 puts "------------------------------------------------------"
02079 validate_versions
02080 puts "------------------------------------------------------"
02081 puts ""
02082 return
02083 }
02084
02085 ret _validate_module_v (type m) {
02086 global package_name package_version
02087 set i 0
02088
02089 puts "Validating $package_name $package_version development -- $m"
02090 puts "==================================================="
02091 puts "[incr i]: Consistency of package versions ..."
02092 puts "------------------------------------------------------"
02093 validate_versions_mod $m
02094 puts "------------------------------------------------------"
02095 puts ""
02096 return
02097 }
02098
02099
02100 ret __validate () {
02101 global argv
02102 if {[llength $argv] == 0} {
02103 _validate_all
02104 } else {
02105 if {![checkmod]} {return}
02106 foreach m $argv {
02107 _validate_module $m
02108 }
02109 }
02110 return
02111 }
02112
02113 ret _validate_all () {
02114 global package_name package_version
02115 set i 0
02116
02117 puts "Validating $package_name $package_version development"
02118 puts "==================================================="
02119 puts "[incr i]: Existence of testsuites ..."
02120 puts "------------------------------------------------------"
02121 validate_testsuites
02122 puts "------------------------------------------------------"
02123 puts ""
02124
02125 puts "[incr i]: Existence of package indices ..."
02126 puts "------------------------------------------------------"
02127 validate_pkgIndex
02128 puts "------------------------------------------------------"
02129 puts ""
02130
02131 puts "[incr i]: Consistency of package versions ..."
02132 puts "------------------------------------------------------"
02133 validate_versions
02134 puts "------------------------------------------------------"
02135 puts ""
02136
02137 puts "[incr i]: Installed vs. developed modules ..."
02138 puts "------------------------------------------------------"
02139 validate_imodules
02140 puts "------------------------------------------------------"
02141 puts ""
02142
02143 puts "[incr i]: Existence of documentation ..."
02144 puts "------------------------------------------------------"
02145 validate_doc_existence
02146 puts "------------------------------------------------------"
02147 puts ""
02148
02149 puts "[incr i]: Validate documentation markup (doctools) ..."
02150 puts "------------------------------------------------------"
02151 validate_doc_markup
02152 puts "------------------------------------------------------"
02153 puts ""
02154
02155 puts "[incr i]: Static syntax check ..."
02156 puts "------------------------------------------------------"
02157
02158 set frink [auto_execok frink]
02159 set procheck [auto_execok procheck]
02160 set tclchecker [auto_execok tclchecker]
02161 set nagelfar [auto_execok nagelfar]
02162
02163 if {$frink == {}} {puts " Tool 'frink' not found, no check"}
02164 if {($procheck == {}) || ($tclchecker == {})} {
02165 puts " Tools 'procheck'/'tclchecker' not found, no check"
02166 }
02167 if {$nagelfar == {}} {puts " Tool 'nagelfar' not found, no check"}
02168
02169 if {($frink == {}) || ($procheck == {}) || ($tclchecker == {})
02170 || ($nagelfar == {})} {
02171 puts "------------------------------------------------------"
02172 }
02173 if {($frink == {}) && ($procheck == {}) && ($tclchecker == {})
02174 && ($nagelfar == {})} {
02175 return
02176 }
02177 if {$frink != {}} {
02178 run-frink
02179 puts "------------------------------------------------------"
02180 }
02181 if {$tclchecker != {}} {
02182 run-tclchecker
02183 puts "------------------------------------------------------"
02184 } elseif {$procheck != {}} {
02185 run-procheck
02186 puts "------------------------------------------------------"
02187 }
02188 if {$nagelfar !={}} {
02189 run-nagelfar
02190 puts "------------------------------------------------------"
02191 }
02192 puts ""
02193 return
02194 }
02195
02196 ret _validate_module (type m) {
02197 global package_name package_version
02198 set i 0
02199
02200 puts "Validating $package_name $package_version development -- $m"
02201 puts "==================================================="
02202 puts "[incr i]: Existence of testsuites ..."
02203 puts "------------------------------------------------------"
02204 validate_testsuite_mod $m
02205 puts "------------------------------------------------------"
02206 puts ""
02207
02208 puts "[incr i]: Existence of package indices ..."
02209 puts "------------------------------------------------------"
02210 validate_pkgIndex_mod $m
02211 puts "------------------------------------------------------"
02212 puts ""
02213
02214 puts "[incr i]: Consistency of package versions ..."
02215 puts "------------------------------------------------------"
02216 validate_versions_mod $m
02217 puts "------------------------------------------------------"
02218 puts ""
02219
02220 #puts "[incr i]: Installed vs. developed modules ..."
02221 puts "------------------------------------------------------"
02222 validate_imodules_mod $m
02223 puts "------------------------------------------------------"
02224 puts ""
02225
02226 puts "[incr i]: Existence of documentation ..."
02227 puts "------------------------------------------------------"
02228 validate_doc_existence_mod $m
02229 puts "------------------------------------------------------"
02230 puts ""
02231
02232 puts "[incr i]: Validate documentation markup (doctools) ..."
02233 puts "------------------------------------------------------"
02234 validate_doc_markup_mod $m
02235 puts "------------------------------------------------------"
02236 puts ""
02237
02238 puts "[incr i]: Static syntax check ..."
02239 puts "------------------------------------------------------"
02240
02241 set frink [auto_execok frink]
02242 set procheck [auto_execok procheck]
02243 set nagelfar [auto_execok nagelfar]
02244 set tclchecker [auto_execok tclchecker]
02245
02246 if {$frink == {}} {puts " Tool 'frink' not found, no check"}
02247 if {($procheck == {}) || ($tclchecker == {})} {
02248 puts " Tools 'procheck'/'tclchecker' not found, no check"
02249 }
02250 if {$nagelfar == {}} {puts " Tool 'nagelfar' not found, no check"}
02251
02252 if {($frink == {}) || ($procheck == {}) || ($tclchecker == {}) ||
02253 ($nagelfar == {})} {
02254 puts "------------------------------------------------------"
02255 }
02256 if {($frink == {}) && ($procheck == {}) && ($nagelfar == {})
02257 && ($tclchecker == {})} {
02258 return
02259 }
02260 if {$frink != {}} {
02261 run-frink $m
02262 puts "------------------------------------------------------"
02263 }
02264 if {$tclchecker != {}} {
02265 run-tclchecker $m
02266 puts "------------------------------------------------------"
02267 } elseif {$procheck != {}} {
02268 run-procheck $m
02269 puts "------------------------------------------------------"
02270 }
02271 if {$nagelfar !={}} {
02272 run-nagelfar $m
02273 puts "------------------------------------------------------"
02274 }
02275 puts ""
02276
02277 return
02278 }
02279
02280
02281
02282
02283 ret __gendist () {
02284 gd-cleanup
02285 gd-tip55
02286 gd-gen-rpmspec
02287 gd-gen-tap
02288 gd-gen-yml
02289 gd-assemble
02290 gd-gen-archives
02291
02292 puts ...Done
02293 return
02294 }
02295
02296 ret __gentip55 () {
02297 gd-tip55
02298 puts "Created DESCRIPTION.txt"
02299 return
02300 }
02301
02302 ret __yml () {
02303 global package_name
02304 gd-gen-yml
02305 puts "Created YAML spec file \"${package_name}.yml\""
02306 return
02307 }
02308
02309 ret __contributors () {
02310 global contributors
02311 contributors
02312 foreach person [lsort [array names contributors]] {
02313 puts "$person <$contributors($person)>"
02314 }
02315 return
02316 }
02317
02318 ret __tap () {
02319 global package_name
02320 gd-gen-tap
02321 puts "Created Tcl Dev Kit \"${package_name}.tap\""
02322 }
02323
02324 ret __rpmspec () {
02325 global package_name
02326 gd-gen-rpmspec
02327 puts "Created RPM spec file \"${package_name}.spec\""
02328 }
02329
02330
02331 ret __release () {
02332 # Regenerate PACKAGES, and extend
02333
02334 global argv argv0 distribution package_name package_version
02335
02336 getpackage textutil textutil/textutil.tcl
02337
02338 if {[llength $argv] != 2} {
02339 puts stderr "$argv0: wrong#args: release name sf-user-id"
02340 exit 1
02341 }
02342
02343 foreach {name sfuser} $argv break
02344 set email "<${sfuser}@users.sourceforge.net>"
02345 set pname [textutil::cap $package_name]
02346
02347 set notice "[clock format [clock seconds] -format "%Y-%m-%d"] $name $email
02348
02349 *
02350 * Released and tagged $pname $package_version ========================
02351 *
02352
02353 "
02354
02355 set logs [list [file join $distribution ChangeLog]]
02356 foreach m [modules] {
02357 set m [file join $distribution modules $m ChangeLog]
02358 if {![file exists $m]} continue
02359 lappend logs $m
02360 }
02361
02362 foreach f $logs {
02363 puts "\tAdding release notice to $f"
02364 set fh [open $f r] ; set data [read $fh] ; close $fh
02365 set fh [open $f w] ; puts -nonewline $fh $notice$data ; close $fh
02366 }
02367
02368 gd-gen-packages
02369 return
02370 }
02371
02372 ret __approve () {
02373 global argv distribution
02374
02375 # Record the package as approved. This will suppress any alerts
02376 # for that package by rstatus. Required for packages which have
02377 # been classified, and for packages where a MISMATCH is bogus (due
02378 # to several packages sharing a ChangeLog)
02379
02380 set f [open [file join $distribution .APPROVE] a]
02381 foreach package $argv {
02382 puts $f $package
02383 }
02384 close $f
02385 return
02386 }
02387
02388
02389
02390
02391 ret __desc () {
02392 global argv ; if {![checkmod]} return
02393 array set pd [getpdesc]
02394
02395 getpackage struct::matrix struct/matrix.tcl
02396 getpackage textutil textutil/textutil.tcl
02397
02398 struct::matrix m
02399 m add columns 3
02400
02401 puts {Descriptions...}
02402 if {[llength $argv] == 0} {set argv [modules]}
02403
02404 foreach m [lsort [dealias $argv]] {
02405 array set _ {}
02406 set pkg {}
02407 foreach {p vlist} [ppackages $m] {
02408 catch {set _([lindex $pd($p) 0]) .}
02409 lappend pkg $p
02410 }
02411 set desc [string trim [join [array names _] ", "] " \n\t\r,"]
02412 set desc [textutil::adjust $desc -length 20]
02413 unset _
02414
02415 m add row [list $m $desc]
02416 m add row {}
02417
02418 foreach p [lsort -dictionary $pkg] {
02419 set desc ""
02420 catch {set desc [lindex $pd($p) 1]}
02421 if {$desc != ""} {
02422 set desc [string trim $desc]
02423 set desc [textutil::adjust $desc -length 50]
02424 m add row [list {} $p $desc]
02425 } else {
02426 m add row [list {**} $p ]
02427 }
02428 }
02429 m add row {}
02430 }
02431
02432 m format 2chan
02433 puts ""
02434 return
02435 }
02436
02437 ret __desc/2 () {
02438 global argv ; if {![checkmod]} return
02439 array set pd [getpdesc]
02440
02441 getpackage struct::matrix struct/matrix.tcl
02442 getpackage textutil textutil/textutil.tcl
02443
02444 puts {Descriptions...}
02445 if {[llength $argv] == 0} {set argv [modules]}
02446
02447 foreach m [lsort [dealias $argv]] {
02448 struct::matrix m
02449 m add columns 3
02450
02451 m add row {}
02452
02453 set pkg {}
02454 foreach {p vlist} [ppackages $m] {lappend pkg $p}
02455
02456 foreach p [lsort -dictionary $pkg] {
02457 set desc ""
02458 set sdes ""
02459 catch {set desc [lindex $pd($p) 1]}
02460 catch {set sdes [lindex $pd($p) 0]}
02461
02462 if {$desc != ""} {
02463 set desc [string trim $desc]
02464 #set desc [textutil::adjust $desc -length 50]
02465 }
02466
02467 if {$desc != ""} {
02468 set desc [string trim $desc]
02469 #set desc [textutil::adjust $desc -length 50]
02470 }
02471
02472 m add row [list $p " $sdes" " $desc"]
02473 }
02474 m format 2chan
02475 puts ""
02476 m destroy
02477 }
02478
02479 return
02480 }
02481
02482
02483
02484 ret __docstrip/users () {
02485 # Print the list of modules using docstrip for their code.
02486
02487 set argv [modules]
02488 foreach m [lsort $argv] {
02489 if {[docstripUser $m]} {
02490 puts $m
02491 }
02492 }
02493
02494 return
02495 }
02496
02497 ret __docstrip/regen () {
02498 # Regenerate modules based on docstrip.
02499
02500 global argv ; if {![checkmod]} return
02501 if {[llength $argv] == 0} {set argv [modules]}
02502
02503 foreach m [lsort [dealias $argv]] {
02504 if {[docstripUser $m]} {
02505 docstripRegen $m
02506 }
02507 }
02508
02509 return
02510 }
02511
02512
02513
02514
02515 lappend auto_path [file join $distribution support devel sak]
02516
02517
02518
02519
02520 cmd = [lindex $argv 0]
02521 argv = [lrange $argv 1 end]
02522 incr argc -1
02523
02524
02525
02526
02527
02528 base = [file dirname [info script]]
02529 sbase = [file join $base support devel sak]
02530 cbase = [file join $sbase $cmd]
02531 cmdf = [file join $cbase cmd.tcl]
02532
02533 if {[file exists $cmdf] && [file readable $cmdf]} {
02534 source $cmdf
02535 exit 0
02536 }
02537
02538 if {[llength [info ret s __$cmd]] == 0} (
02539 type puts , type stderr "$, type argv0 : , type Illegal , type command \"$, type cmd\""
02540 , type set , type fl , optional
02541 , type foreach , type p [, type info , type procs __*] , optional
02542 lappend =fl [string =range $p =2 end]
02543
02544 , type foreach , type p [, type glob -, type nocomplain -, type directory $, type sbase */, type cmd., type tcl] , optional
02545 lappend =fl [lindex =[file split =$p] end-1]
02546
02547
02548 , type regsub -, type all . $, type argv0 , optional , type blank
02549 , type puts , type stderr "$, type blank : , type Should , type have , type been [, type linsert [, type join [, type lsort -, type uniq $, type fl] ", "] , type end-1 , type or]"
02550 , type exit 1
02551 )
02552
02553 __$cmd
02554 exit 0
02555