1#!/bin/sh 2# -*- tcl -*- \ 3exec tclsh "$0" ${1+"$@"} 4 5# -------------------------------------------------------------- 6# Perform various checks and operations on the distribution. 7# SAK = Swiss Army Knife. 8 9set distribution [file dirname [info script]] 10lappend auto_path [file join $distribution modules] 11 12set critcldefault {} 13set critclnotes {} 14set dist_excluded {} 15 16proc package_name {text} {global package_name ; set package_name $text} 17proc package_version {text} {global package_version ; set package_version $text} 18proc dist_exclude {path} {global dist_excluded ; lappend dist_excluded $path} 19proc critcl {name files} { 20 global critclmodules 21 set critclmodules($name) $files 22 return 23} 24proc critcl_main {name files} { 25 global critcldefault 26 set critcldefault $name 27 critcl $name $files 28 return 29} 30proc critcl_notes {text} { 31 global critclnotes 32 set critclnotes [string map {{\n } \n} $text] 33 return 34} 35 36source [file join $distribution support installation version.tcl] ; # Get version information. 37 38set package_nv ${package_name}-${package_version} 39 40catch {eval file delete -force [glob [file rootname [info script]].tmp.*]} 41 42# -------------------------------------------------------------- 43# SAK internal debugging support. 44 45# Configuration, change as needed 46set debug 0 47 48if {$debug} { 49 proc sakdebug {script} {uplevel 1 $script ; return} 50} else { 51 proc sakdebug {args} {} 52} 53 54# -------------------------------------------------------------- 55# Internal helper to load packages straight out of the local directory 56# tree. Not something from an installation, possibly incompatible. 57 58proc getpackage {package tclmodule} { 59 global distribution 60 if {[catch {package present $package}]} { 61 set src [file join \ 62 $distribution modules \ 63 $tclmodule] 64 if {[file exists $src]} { 65 uplevel #0 [list source $src] 66 } else { 67 # Fallback 68 package require $package 69 } 70 } 71} 72 73# -------------------------------------------------------------- 74 75proc tclfiles {} { 76 global distribution 77 getpackage fileutil fileutil/fileutil.tcl 78 set fl [fileutil::findByPattern $distribution -glob *.tcl] 79 # Remove files under SCCS. They are repository, not sources to check. 80 set tmp {} 81 foreach f $fl { 82 if {[string match *SCCS* $f]} continue 83 lappend tmp $f 84 } 85 proc tclfiles {} [list return $tmp] 86 return $tmp 87} 88 89proc modtclfiles {modules} { 90 global mfiles guide 91 load_modinfo 92 set mfiles [list] 93 foreach m $modules { 94 eval $guide($m,pkg) $m __dummy__ 95 } 96 return $mfiles 97} 98 99proc modules {} { 100 global distribution 101 set fl [list] 102 foreach f [glob -nocomplain [file join $distribution modules *]] { 103 if {![file isdirectory $f]} {continue} 104 if {[string match CVS [file tail $f]]} {continue} 105 106 if {![file exists [file join $f pkgIndex.tcl]]} {continue} 107 108 lappend fl [file tail $f] 109 } 110 set fl [lsort $fl] 111 proc modules {} [list return $fl] 112 return $fl 113} 114 115proc modules_mod {m} { 116 return [expr {[lsearch -exact [modules] $m] >= 0}] 117} 118 119proc dealias {modules} { 120 set _ {} 121 foreach m $modules { 122 if {[file exists $m]} { 123 set m [file tail $m] 124 } 125 lappend _ $m 126 } 127 return $_ 128} 129 130proc load_modinfo {} { 131 global distribution modules guide 132 source [file join $distribution support installation modules.tcl] ; # Get list of installed modules. 133 source [file join $distribution support installation actions.tcl] ; # Get installer support code. 134 proc load_modinfo {} {} 135 return 136} 137 138proc imodules {} {global modules ; load_modinfo ; return $modules} 139 140proc imodules_mod {m} { 141 global modules 142 load_modinfo 143 return [expr {[lsearch -exact $modules $m] > 0}] 144} 145 146# Result: dict (package name --> list of package versions). 147 148proc loadpkglist {fname} { 149 set f [open $fname r] 150 foreach line [split [read $f] \n] { 151 set line [string trim $line] 152 if {[string match @* $line]} continue 153 if {$line == {}} continue 154 foreach {n v} $line break 155 lappend p($n) $v 156 set p($n) [lsort -uniq -dict $p($n)] 157 } 158 close $f 159 return [array get p] 160} 161 162# Result: dict (package name => list of (list of package versions, module)). 163 164proc ipackages {args} { 165 # Determine indexed packages (ifneeded, pkgIndex.tcl) 166 167 global distribution 168 169 if {[llength $args] == 0} {set args [modules]} 170 171 array set p {} 172 foreach m $args { 173 set f [open [file join $distribution modules $m pkgIndex.tcl] r] 174 foreach line [split [read $f] \n] { 175 if { [regexp {#} $line]} {continue} 176 if {![regexp {ifneeded} $line]} {continue} 177 regsub {^.*ifneeded } $line {} line 178 regsub {([0-9]) \[.*$} $line {\1} line 179 180 foreach {n v} $line break 181 182 if {![info exists p($n)]} { 183 set p($n) [list $v $m] 184 } else { 185 # We have multiple versions of the same package. We 186 # remember all versions. 187 188 foreach {vlist m} $p($n) break 189 lappend vlist $v 190 set p($n) [list [lsort -uniq -dict $vlist] $m] 191 } 192 } 193 close $f 194 } 195 return [array get p] 196} 197 198 199# Result: dict (package name --> list of package versions). 200 201proc ppackages {args} { 202 # Determine provided packages (provide, *.tcl - pkgIndex.tcl) 203 # We cache results for a bit of speed, some stuff uses this 204 # multiple times for the same arguments. 205 206 global ppcache 207 if {[info exists ppcache($args)]} { 208 return $ppcache($args) 209 } 210 211 global p pf currentfile 212 array set p {} 213 214 if {[llength $args] == 0} { 215 set files [tclfiles] 216 } else { 217 set files [modtclfiles $args] 218 } 219 220 getpackage fileutil fileutil/fileutil.tcl 221 set capout [fileutil::tempfile] ; set capcout [open $capout w] 222 set caperr [fileutil::tempfile] ; set capcerr [open $caperr w] 223 224 array set notprovided {} 225 226 foreach f $files { 227 # We ignore package indices and all files not in a module. 228 229 if {[string equal pkgIndex.tcl [file tail $f]]} {continue} 230 if {![regexp modules $f]} {continue} 231 232 # We use two methods to extract the version information from a 233 # module and its packages. First we do a static scan for 234 # appropriate statements. If that did not work out we try to 235 # execute the script in a modified interpreter which lets us 236 # pick up dynamically generated version data (like stored in 237 # variables). If the second method fails as well we give up. 238 239 # Method I. Static scan. 240 241 # We do heuristic scanning of the code to locate suitable 242 # package provide statements. 243 244 set fh [open $f r] 245 246 set currentfile [eval file join [lrange [file split $f] end-1 end]] 247 248 set ok -1 249 foreach line [split [read $fh] \n] { 250 if {[regexp "\#\\s*@sak\\s+notprovided\\s+(\[^\\s\]+)" $line -> nppname]} { 251 sakdebug {puts stderr "PRAGMA notprovided = $nppname"} 252 set notprovided($nppname) . 253 } 254 255 regsub "\#.*$" $line {} line 256 if {![regexp {provide} $line]} {continue} 257 if {![regexp {package} $line]} {continue} 258 259 # Now a stronger check for the actual command 260 if {![regexp {package[ ][ ]*provide} $line]} {continue} 261 262 set xline $line 263 regsub {^.*provide } $line {} line 264 regsub {\].*$} $line {\1} line 265 266 sakdebug {puts stderr __$f\ _________$line} 267 268 foreach {n v} $line break 269 270 # HACK ... 271 # Module 'page', package 'page::gen::peg::cpkg'. 272 # Has a provide statement inside a template codeblock. 273 # Name is placeholder @@. Ignore this specific name. 274 # Better would be to use general static Tcl parsing 275 # to find that the string is a variable value. 276 277 if {[string equal $n @@]} continue 278 279 if {[regexp {^[0-9]+(\.[0-9]+)*$} $v]} { 280 lappend p($n) $v 281 set p($n) [lsort -uniq -dict $p($n)] 282 set pf($n,$v) $currentfile 283 set ok 1 284 285 # We continue the scan. The file may provide several 286 # versions of the same package, or multiple packages. 287 continue 288 } 289 290 # 'package provide foo' are tests. Ignore. 291 if {$v == ""} continue 292 293 # We do not set the state to bad if we found ok provide 294 # statements before, only if nothing was found before. 295 if {$ok < 0} { 296 set ok 0 297 298 # No good version found on the current line. We scan 299 # further through the file and hope for more luck. 300 301 sakdebug {puts stderr @_$f\ _________$xline\t<$n>\t($v)} 302 } 303 } 304 close $fh 305 306 # Method II. Restricted Execution. 307 # We now try to run the code through a safe interpreter 308 # and hope for better luck regarding package information. 309 310 if {$ok == -1} {sakdebug {puts stderr $f\ IGNORE}} 311 if {$ok == 0} { 312 sakdebug {puts -nonewline stderr $f\ EVAL} 313 314 # Source the code into a sub-interpreter. The sub 315 # interpreter overloads 'package provide' so that the 316 # information about new packages goes directly to us. We 317 # also make sure that the sub interpreter doesn't kill us, 318 # and will not get stuck early by trying to load other 319 # files, or when creating procedures in namespaces which 320 # do not exist due to us disabling most of the package 321 # management. 322 323 set fh [open $f r] 324 325 set ip [interp create] 326 327 # Kill control structures. Namespace is required, but we 328 # skip everything related to loading of packages, 329 # i.e. 'command import'. 330 331 $ip eval { 332 rename ::if ::_if_ 333 rename ::namespace ::_namespace_ 334 335 proc ::if {args} {} 336 proc ::namespace {cmd args} { 337 #puts stderr "_nscmd_ $cmd" 338 ::_if_ {[string equal $cmd import]} return 339 #puts stderr "_nsdo_ $cmd $args" 340 return [uplevel 1 [linsert $args 0 ::_namespace_ $cmd]] 341 } 342 } 343 344 # Kill more package stuff, and ensure that unknown 345 # commands are neither loaded nor abort execution. We also 346 # stop anything trying to kill the application at large. 347 348 interp alias $ip package {} xPackage 349 interp alias $ip source {} xNULL 350 interp alias $ip unknown {} xNULL 351 interp alias $ip proc {} xNULL 352 interp alias $ip exit {} xNULL 353 354 # From here on no redefinitions anymore, proc == xNULL !! 355 356 $ip eval {close stdout} ; interp share {} $capcout $ip 357 $ip eval {close stderr} ; interp share {} $capcerr $ip 358 359 if {[catch {$ip eval [read $fh]} msg]} { 360 sakdebug {puts stderr "ERROR in $currentfile:\n$::errorInfo\n"} 361 } 362 363 sakdebug {puts stderr ""} 364 365 close $fh 366 interp delete $ip 367 } 368 } 369 370 close $capcout ; file delete $capout 371 close $capcerr ; file delete $caperr 372 373 # Process the accumulated pragma information, remove all the 374 # packages which exist but not really, in terms of indexing. 375 376 foreach n [array names notprovided] { 377 catch { unset p($n) } 378 array unset pf $n,* 379 } 380 381 set pp [array get p] 382 unset p 383 384 set ppcache($args) $pp 385 return $pp 386} 387 388proc xNULL {args} {} 389proc xPackage {cmd args} { 390 if {[string equal $cmd provide]} { 391 global p pf currentfile 392 foreach {n v} $args break 393 394 # No version specified, this is an inquiry, we ignore these. 395 if {$v == {}} {return} 396 397 sakdebug {puts stderr \tOK\ $n\ =\ $v} 398 399 lappend p($n) $v 400 set p($n) [lsort -uniq -dict $p($n)] 401 set pf($n,$v) $currentfile 402 } 403 return 404} 405 406proc sep {} {puts ~~~~~~~~~~~~~~~~~~~~~~~~} 407 408proc gd-cleanup {} { 409 global package_nv 410 411 puts {Cleaning up...} 412 413 set fl [glob -nocomplain ${package_nv}*] 414 foreach f $fl { 415 puts " Deleting $f ..." 416 catch {file delete -force $f} 417 } 418 return 419} 420 421proc gd-gen-archives {} { 422 global package_name package_nv 423 424 puts {Generating archives...} 425 426 set tar [auto_execok tar] 427 if {$tar != {}} { 428 puts " Gzipped tarball (${package_nv}.tar.gz)..." 429 catch { 430 exec $tar cf - ${package_nv} | gzip --best > ${package_nv}.tar.gz 431 } 432 433 set bzip [auto_execok bzip2] 434 if {$bzip != {}} { 435 puts " Bzipped tarball (${package_nv}.tar.bz2)..." 436 exec tar cf - ${package_nv} | bzip2 > ${package_nv}.tar.bz2 437 } 438 } 439 440 set zip [auto_execok zip] 441 if {$zip != {}} { 442 puts " Zip archive (${package_nv}.zip)..." 443 catch { 444 exec $zip -r ${package_nv}.zip ${package_nv} 445 } 446 } 447 448 set sdx [auto_execok sdx] 449 if {$sdx != {}} { 450 file copy -force [file join ${package_nv} support installation main.tcl] \ 451 [file join ${package_nv} main.tcl] 452 file rename ${package_nv} ${package_name}.vfs 453 454 puts " Starkit (${package_nv}.kit)..." 455 exec sdx wrap ${package_name} 456 file rename ${package_name} ${package_nv}.kit 457 458 if {![file exists tclkit]} { 459 puts " No tclkit present in current working directory, no starpack." 460 } else { 461 puts " Starpack (${package_nv}.exe)..." 462 exec sdx wrap ${package_name} -runtime tclkit 463 file rename ${package_name} ${package_nv}.exe 464 } 465 466 file rename ${package_name}.vfs ${package_nv} 467 } 468 469 puts { Keeping directory for other archive types} 470 471 ## Keep the directory for 'sdx' - kit/pack 472 return 473} 474 475proc xcopyfile {src dest} { 476 # dest can be dir or file 477 global mfiles 478 lappend mfiles $src 479 return 480} 481 482proc xcopy {src dest recurse {pattern *}} { 483 foreach file [glob [file join $src $pattern]] { 484 set base [file tail $file] 485 set sub [file join $dest $base] 486 if {0 == [string compare CVS $base]} {continue} 487 if {[file isdirectory $file]} then { 488 if {$recurse} { 489 xcopy $file $sub $recurse $pattern 490 } 491 } else { 492 xcopyfile $file $sub 493 } 494 } 495} 496 497 498proc xxcopy {src dest recurse {pattern *}} { 499 global package_name 500 501 file mkdir $dest 502 foreach file [glob -nocomplain [file join $src $pattern]] { 503 set base [file tail $file] 504 set sub [file join $dest $base] 505 506 # Exclude CVS, SCCS, ... automatically, and possibly the temp 507 # hierarchy itself too. 508 509 if {0 == [string compare CVS $base]} {continue} 510 if {0 == [string compare SCCS $base]} {continue} 511 if {0 == [string compare BitKeeper $base]} {continue} 512 if {[string match ${package_name}-* $base]} {continue} 513 if {[string match *~ $base]} {continue} 514 515 if {[file isdirectory $file]} then { 516 if {$recurse} { 517 file mkdir $sub 518 xxcopy $file $sub $recurse $pattern 519 } 520 } else { 521 puts -nonewline stdout . ; flush stdout 522 file copy -force $file $sub 523 } 524 } 525} 526 527proc gd-assemble {} { 528 global package_nv distribution dist_excluded 529 530 puts "Assembling distribution in directory '${package_nv}'" 531 532 xxcopy $distribution ${package_nv} 1 533 534 foreach f $dist_excluded { 535 file delete -force [file join $package_nv $f] 536 } 537 puts "" 538 return 539} 540 541proc normalize-version {v} { 542 # Strip everything after the first non-version character, and any 543 # trailing dots left behind by that, to avoid the insertion of bad 544 # version numbers into the generated .tap file. 545 546 regsub {[^0-9.].*$} $v {} v 547 return [string trimright $v .] 548} 549 550proc gd-gen-tap {} { 551 getpackage textutil textutil/textutil.tcl 552 getpackage fileutil fileutil/fileutil.tcl 553 554 global package_name package_version distribution tcl_platform 555 556 set pname [textutil::cap $package_name] 557 558 set modules [imodules] 559 array set pd [getpdesc] 560 set lines [list] 561 # Header 562 lappend lines {format {TclDevKit Project File}} 563 lappend lines {fmtver 2.0} 564 lappend lines {fmttool {TclDevKit TclApp PackageDefinition} 2.5} 565 lappend lines {} 566 lappend lines "## Saved at : [clock format [clock seconds]]" 567 lappend lines "## By : $tcl_platform(user)" 568 lappend lines {##} 569 lappend lines "## Generated by \"[file tail [info script]] tap\"" 570 lappend lines "## of $package_name $package_version" 571 lappend lines {} 572 lappend lines {########} 573 lappend lines {#####} 574 lappend lines {###} 575 lappend lines {##} 576 lappend lines {#} 577 578 # Bundle definition 579 lappend lines {} 580 lappend lines {# ###############} 581 lappend lines {# Complete bundle} 582 lappend lines {} 583 lappend lines [list Package [list $package_name [normalize-version $package_version]]] 584 lappend lines "Base @TAP_DIR@" 585 lappend lines "Platform *" 586 lappend lines "Desc \{$pname: Bundle of all packages\}" 587 lappend lines "Path pkgIndex.tcl" 588 lappend lines "Path [join $modules "\nPath "]" 589 590 set strip [llength [file split $distribution]] 591 incr strip 2 592 593 foreach m $modules { 594 # File set of module ... 595 596 lappend lines {} 597 lappend lines "# #########[::textutil::strRepeat {#} [string length $m]]" ; # {} 598 lappend lines "# Module \"$m\"" 599 set n 0 600 foreach {p vlist} [ppackages $m] { 601 foreach v $vlist { 602 lappend lines "# \[[format %1d [incr n]]\] | \"$p\" ($v)" 603 } 604 } 605 if {$n > 1} { 606 # Multiple packages (*). We create one hidden package to 607 # contain all the files and then have all the true 608 # packages in the module refer to it. 609 # 610 # (*) This can also be one package for which we have 611 # several versions. Or a combination thereof. 612 613 array set _ {} 614 foreach {p vlist} [ppackages $m] { 615 catch {set _([lindex $pd($p) 0]) .} 616 } 617 set desc [string trim [join [array names _] ", "] " \n\t\r,"] 618 if {$desc == ""} {set desc "$pname module"} 619 unset _ 620 621 lappend lines "# -------+" 622 lappend lines {} 623 lappend lines [list Package [list __$m 0.0]] 624 lappend lines "Platform *" 625 lappend lines "Desc \{$desc\}" 626 lappend lines Hidden 627 lappend lines "Base @TAP_DIR@/$m" 628 629 foreach f [lsort -dict [modtclfiles $m]] { 630 lappend lines "Path [fileutil::stripN $f $strip]" 631 } 632 633 # Packages in the module ... 634 foreach {p vlist} [ppackages $m] { 635 # NO DANGER. As we are listing only the packages P for 636 # the module any other version of P in a different 637 # module is _not_ listed here. 638 639 set desc "" 640 catch {set desc [string trim [lindex $pd($p) 1]]} 641 if {$desc == ""} {set desc "$pname package"} 642 643 foreach v $vlist { 644 lappend lines {} 645 lappend lines [list Package [list $p [normalize-version $v]]] 646 lappend lines "See [list __$m]" 647 lappend lines "Platform *" 648 lappend lines "Desc \{$desc\}" 649 } 650 } 651 } else { 652 # A single package in the module. And only one version of 653 # it as well. Otherwise we are in the multi-pkg branch. 654 655 foreach {p vlist} [ppackages $m] break 656 set desc "" 657 catch {set desc [string trim [lindex $pd($p) 1]]} 658 if {$desc == ""} {set desc "$pname package"} 659 660 set v [lindex $vlist 0] 661 662 lappend lines "# -------+" 663 lappend lines {} 664 lappend lines [list Package [list $p [normalize-version $v]]] 665 lappend lines "Platform *" 666 lappend lines "Desc \{$desc\}" 667 lappend lines "Base @TAP_DIR@/$m" 668 669 foreach f [lsort -dict [modtclfiles $m]] { 670 lappend lines "Path [fileutil::stripN $f $strip]" 671 } 672 } 673 lappend lines {} 674 lappend lines {#} 675 lappend lines "# #########[::textutil::strRepeat {#} [string length $m]]" 676 } 677 678 lappend lines {} 679 lappend lines {#} 680 lappend lines {##} 681 lappend lines {###} 682 lappend lines {#####} 683 lappend lines {########} 684 685 # Write definition 686 set f [open [file join $distribution ${package_name}.tap] w] 687 puts $f [join $lines \n] 688 close $f 689 return 690} 691 692proc getpdesc {} { 693 global argv ; if {![checkmod]} return 694 695 package require sak::doc 696 sak::doc::Gen desc l $argv 697 698 array set _ {} 699 foreach file [glob -nocomplain doc/desc/*.l] { 700 set f [open $file r] 701 foreach l [split [read $f] \n] { 702 foreach {p sd d} $l break 703 set _($p) [list $sd $d] 704 } 705 close $f 706 } 707 file delete -force doc/desc 708 709 return [array get _] 710} 711 712proc gd-gen-rpmspec {} { 713 global package_version package_name distribution 714 715 set in [file join $distribution support releases package_rpm.txt] 716 set out [file join $distribution ${package_name}.spec] 717 718 write_out $out [string map \ 719 [list \ 720 @PACKAGE_VERSION@ $package_version \ 721 @PACKAGE_NAME@ $package_name] \ 722 [get_input $in]] 723 return 724} 725 726proc gd-gen-yml {} { 727 # YAML is the format used for the FreePAN archive network. 728 # http://freepan.org/ 729 730 global package_version package_name distribution 731 732 set in [file join $distribution support releases package_yml.txt] 733 set out [file join $distribution ${package_name}.yml] 734 735 write_out $out [string map \ 736 [list \ 737 @PACKAGE_VERSION@ $package_version \ 738 @PACKAGE_NAME@ $package_name] \ 739 [get_input $in]] 740 return 741} 742 743proc docfiles {} { 744 global distribution 745 746 getpackage fileutil fileutil/fileutil.tcl 747 748 set res [list] 749 foreach f [fileutil::findByPattern $distribution -glob *.man] { 750 # Remove files under SCCS. They are repository, not sources to check. 751 if {[string match *SCCS* $f]} continue 752 lappend res [file rootname [file tail $f]].n 753 } 754 proc docfiles {} [list return $res] 755 return $res 756} 757 758proc gd-tip55 {} { 759 global package_version package_name distribution contributors 760 contributors 761 762 set in [file join $distribution support releases package_tip55.txt] 763 set out [file join $distribution DESCRIPTION.txt] 764 765 set md [string map \ 766 [list \ 767 @PACKAGE_VERSION@ $package_version \ 768 @PACKAGE_NAME@ $package_name] \ 769 [get_input $in]] 770 771 foreach person [lsort [array names contributors]] { 772 set mail $contributors($person) 773 regsub {@} $mail " at " mail 774 regsub -all {\.} $mail " dot " mail 775 append md "Contributor: $person <$mail>\n" 776 } 777 778 write_out $out $md 779 return 780} 781 782# Fill the global array of contributors to the bundle by processing 783# the ChangeLog entries. 784# 785proc contributors {} { 786 global distribution contributors 787 if {![info exists contributors] || [array size contributors] == 0} { 788 get_contributors [file join $distribution ChangeLog] 789 790 foreach f [glob -nocomplain [file join $distribution modules *]] { 791 if {![file isdirectory $f]} {continue} 792 if {[string match CVS [file tail $f]]} {continue} 793 if {![file exists [file join $f ChangeLog]]} {continue} 794 get_contributors [file join $f ChangeLog] 795 } 796 } 797} 798 799proc get_contributors {changelog} { 800 global contributors 801 set f [open $changelog r] 802 while {![eof $f]} { 803 gets $f line 804 if {[regexp {^[\d-]+\s+(.*?)<(.*?)>} $line r name mail]} { 805 set name [string trim $name] 806 if {![info exists names($name)]} { 807 set contributors($name) $mail 808 } 809 } 810 } 811 close $f 812} 813 814proc validate_imodules_cmp {imvar dmvar} { 815 upvar $imvar im $dmvar dm 816 817 foreach m [lsort [array names im]] { 818 if {![info exists dm($m)]} { 819 puts " Installed, does not exist: $m" 820 } 821 } 822 foreach m [lsort [array names dm]] { 823 if {![info exists im($m)]} { 824 puts " Missing in installer: $m" 825 } 826 } 827 return 828} 829 830proc validate_imodules {} { 831 foreach m [imodules] {set im($m) .} 832 foreach m [modules] {set dm($m) .} 833 834 validate_imodules_cmp im dm 835 return 836} 837 838proc validate_imodules_mod {m} { 839 array set im {} 840 array set dm {} 841 if {[imodules_mod $m]} {set im($m) .} 842 if {[modules_mod $m]} {set dm($m) .} 843 844 validate_imodules_cmp im dm 845 return 846} 847proc validate_versions_cmp {ipvar ppvar} { 848 global pf 849 getpackage struct::set struct/sets.tcl 850 851 upvar $ipvar ip $ppvar pp 852 set maxl 0 853 foreach name [array names ip] {if {[string length $name] > $maxl} {set maxl [string length $name]}} 854 foreach name [array names pp] {if {[string length $name] > $maxl} {set maxl [string length $name]}} 855 856 foreach p [lsort [array names ip]] { 857 if {![info exists pp($p)]} { 858 puts " Indexed, no provider: $p" 859 } 860 } 861 foreach p [lsort [array names pp]] { 862 if {![info exists ip($p)]} { 863 foreach k [array names pf $p,*] { 864 puts " Provided, not indexed: [format "%-*s | %s" $maxl $p $pf($k)]" 865 } 866 } 867 } 868 foreach p [lsort [array names ip]] { 869 if {![info exists pp($p)]} continue 870 if {[struct::set equal $pp($p) $ip($p)]} continue 871 872 # Compute intersection and set differences. 873 foreach {__ pmi imp} [struct::set intersect3 $pp($p) $ip($p)] break 874 875 puts " Index/provided versions differ: [format "%-*s | %8s | %8s" $maxl $p $imp $pmi]" 876 } 877} 878 879proc validate_versions {} { 880 foreach {p vm} [ipackages] {set ip($p) [lindex $vm 0]} 881 foreach {p vlist} [ppackages] {set pp($p) $vlist} 882 883 validate_versions_cmp ip pp 884 return 885} 886 887proc validate_versions_mod {m} { 888 foreach {p vm} [ipackages $m] {set ip($p) [lindex $vm 0]} 889 foreach {p vlist} [ppackages $m] {set pp($p) $vlist} 890 891 validate_versions_cmp ip pp 892 return 893} 894 895proc validate_testsuite_mod {m} { 896 global distribution 897 if {[llength [glob -nocomplain [file join $distribution modules $m *.test]]] == 0} { 898 puts " Without testsuite : $m" 899 } 900 return 901} 902 903proc bench_mod {mlist paths interp flags norm format verbose output} { 904 global distribution env tcl_platform 905 906 getpackage logger logger/logger.tcl 907 getpackage bench bench/bench.tcl 908 909 ::logger::setlevel $verbose 910 911 set pattern tclsh* 912 if {$interp != {}} { 913 set pattern [file tail $interp] 914 set paths [list [file dirname $interp]] 915 } elseif {![llength $paths]} { 916 # Using the environment PATH is not a good default for 917 # SAK. Use the interpreter running SAK as the default. 918 if 0 { 919 set paths [split $env(PATH) \ 920 [expr {($tcl_platform(platform) == "windows") ? ";" : ":"}]] 921 } 922 set interp [info nameofexecutable] 923 set pattern [file tail $interp] 924 set paths [list [file dirname $interp]] 925 } 926 927 set interps [bench::versions \ 928 [bench::locate $pattern $paths]] 929 930 if {![llength $interps]} { 931 puts "No interpreters found" 932 return 933 } 934 935 if {[llength $flags]} { 936 set cmd [linsert $flags 0 bench::run] 937 } else { 938 set cmd [list bench::run] 939 } 940 941 array set DATA {} 942 943 foreach m $mlist { 944 set files [glob -nocomplain [file join $distribution modules $m *.bench]] 945 if {![llength $files]} { 946 bench::log::warn "No benchmark files found for module \"$m\"" 947 continue 948 } 949 950 set run $cmd 951 lappend run $interps $files 952 array set DATA [eval $run] 953 } 954 955 _bench_write $output [array get DATA] $norm $format 956 return 957} 958 959proc bench_all {flags norm format verbose output} { 960 bench_mod [modules] $flags $norm $format $verbose $output 961 return 962} 963 964 965proc _bench_write {output data norm format} { 966 if {$norm != {}} { 967 getpackage logger logger/logger.tcl 968 getpackage bench bench/bench.tcl 969 970 set data [bench::norm $data $norm] 971 } 972 973 set data [bench::out::$format $data] 974 975 if {$output == {}} { 976 puts $data 977 } else { 978 set output [open $output w] 979 puts $output "# -*- tcl -*- bench/$format" 980 puts $output $data 981 close $output 982 } 983} 984 985proc validate_testsuites {} { 986 foreach m [modules] { 987 validate_testsuite_mod $m 988 } 989 return 990} 991 992proc validate_pkgIndex_mod {m} { 993 global distribution 994 if {[llength [glob -nocomplain [file join $distribution modules $m pkgIndex.tcl]]] == 0} { 995 puts " Without package index : $m" 996 } 997 return 998} 999 1000proc validate_pkgIndex {} { 1001 global distribution 1002 foreach m [modules] { 1003 validate_pkgIndex_mod $m 1004 } 1005 return 1006} 1007 1008proc validate_doc_existence_mod {m} { 1009 global distribution 1010 if {[llength [glob -nocomplain [file join $distribution modules $m {*.[13n]}]]] == 0} { 1011 if {[llength [glob -nocomplain [file join $distribution modules $m {*.man}]]] == 0} { 1012 puts " Without * any ** manpages : $m" 1013 } 1014 } elseif {[llength [glob -nocomplain [file join $distribution modules $m {*.man}]]] == 0} { 1015 puts " Without doctools manpages : $m" 1016 } else { 1017 foreach f [glob -nocomplain [file join $distribution modules $m {*.[13n]}]] { 1018 if {![file exists [file rootname $f].man]} { 1019 puts " no .man equivalent : $f" 1020 } 1021 } 1022 } 1023 return 1024} 1025 1026proc validate_doc_existence {} { 1027 global distribution 1028 foreach m [modules] { 1029 validate_doc_existence_mod $m 1030 } 1031 return 1032} 1033 1034 1035proc validate_doc_markup_mod {m} { 1036 package require sak::doc 1037 sak::doc::Gen null null [list $m] 1038 return 1039} 1040 1041proc validate_doc_markup {} { 1042 package require sak::doc 1043 sak::doc::Gen null null [modules] 1044 return 1045} 1046 1047proc run-frink {args} { 1048 global distribution 1049 1050 set tmp [file rootname [info script]].tmp.[pid] 1051 1052 if {[llength $args] == 0} { 1053 set files [tclfiles] 1054 } else { 1055 set files [lsort -dict [modtclfiles $args]] 1056 } 1057 1058 foreach f $files { 1059 puts "FRINK ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" 1060 puts "$f..." 1061 puts "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" 1062 1063 catch {exec frink 2> $tmp -HJ $f} 1064 set data [get_input $tmp] 1065 if {[string length $data] > 0} { 1066 puts $data 1067 } 1068 } 1069 catch {file delete -force $tmp} 1070 return 1071} 1072 1073proc run-procheck {args} { 1074 global distribution 1075 1076 if {[llength $args] == 0} { 1077 set files [tclfiles] 1078 } else { 1079 set files [lsort -dict [modtclfiles $args]] 1080 } 1081 1082 foreach f $files { 1083 puts "PROCHECK ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" 1084 puts "$f ..." 1085 puts "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" 1086 1087 catch {exec procheck >@ stdout $f} 1088 } 1089 return 1090} 1091 1092proc run-tclchecker {args} { 1093 global distribution 1094 1095 if {[llength $args] == 0} { 1096 set files [tclfiles] 1097 } else { 1098 set files [lsort -dict [modtclfiles $args]] 1099 } 1100 1101 foreach f $files { 1102 puts "TCLCHECKER ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" 1103 puts "$f ..." 1104 puts "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" 1105 1106 catch {exec tclchecker >@ stdout $f} 1107 } 1108 return 1109} 1110 1111proc run-nagelfar {args} { 1112 global distribution 1113 1114 if {[llength $args] == 0} { 1115 set files [tclfiles] 1116 } else { 1117 set files [lsort -dict [modtclfiles $args]] 1118 } 1119 1120 foreach f $files { 1121 puts "NAGELFAR ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" 1122 puts "$f ..." 1123 puts "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" 1124 1125 catch {exec nagelfar >@ stdout $f} 1126 } 1127 return 1128} 1129 1130 1131proc get_input {f} {return [read [set if [open $f r]]][close $if]} 1132 1133proc write_out {f text} { 1134 catch {file delete -force $f} 1135 puts -nonewline [set of [open $f w]] $text 1136 close $of 1137} 1138 1139proc location_PACKAGES {} { 1140 global distribution 1141 return [file join $distribution support releases PACKAGES] 1142} 1143 1144proc gd-gen-packages {} { 1145 global package_version distribution 1146 1147 set P [location_PACKAGES] 1148 file copy -force $P $P.LAST 1149 set f [open $P w] 1150 puts $f "@@ RELEASE $package_version" 1151 puts $f "" 1152 1153 array set packages {} 1154 foreach {p vm} [ipackages] { 1155 set packages($p) [lindex $vm 0] 1156 } 1157 1158 nparray packages $f 1159 close $f 1160} 1161 1162 1163 1164proc modified-modules {} { 1165 global distribution 1166 1167 set mlist [modules] 1168 set modified [list] 1169 1170 foreach m $mlist { 1171 set cl [file join $distribution modules $m ChangeLog] 1172 if {![file exists $cl]} { 1173 lappend modified [list $m no-changelog] 1174 continue 1175 } 1176 # Look for 'Released and tagged' within 1177 # the first four lines of the file. If 1178 # not present assume that the line is 1179 # deeper down, indicatating that the module 1180 # has been modified since the last release. 1181 1182 set f [open $cl r] 1183 set n 0 1184 set mod 1 1185 while {$n < 5} { 1186 gets $f line 1187 incr n 1188 if {[string match -nocase "*Released and tagged*" $line]} { 1189 if {$n <= 4} {set mod 0 ; break} 1190 } 1191 } 1192 if {$mod} { 1193 lappend modified $m 1194 } 1195 close $f 1196 } 1197 1198 return $modified 1199} 1200 1201# -------------------------------------------------------------- 1202# Handle modules using docstrip 1203 1204proc docstripUser {m} { 1205 global distribution 1206 1207 set mdir [file join $distribution modules $m] 1208 1209 if {[llength [glob -nocomplain -dir $mdir *.stitch]]} {return 1} 1210 return 0 1211} 1212 1213proc docstripRegen {m} { 1214 global distribution 1215 puts "$m ..." 1216 1217 getpackage docstrip docstrip/docstrip.tcl 1218 1219 set mdir [file join $distribution modules $m] 1220 1221 foreach sf [glob -nocomplain -dir $mdir *.stitch] { 1222 puts "* [file tail $sf] ..." 1223 1224 set here [pwd] 1225 set fail [catch { 1226 cd [file dirname $sf] 1227 docstripRunStitch [file tail $sf] 1228 } msg] 1229 cd $here 1230 if {$fail} { 1231 puts " [join [split $::errorInfo \n] "\n "]" 1232 } 1233 } 1234 return 1235} 1236 1237proc docstripRunStitch {sf} { 1238 # Run the stitch file in a restricted sandbox ... 1239 1240 set box [restrictedIp { 1241 input ::dsrs::Input 1242 options ::dsrs::Options 1243 stitch ::dsrs::Stitch 1244 reset ::dsrs::Reset 1245 }] 1246 1247 ::dsrs::Init 1248 set fail [catch {interp eval $box [get_input $sf]} msg] 1249 if {$fail} { 1250 puts " [join [split $::errorInfo \n] "\n "]" 1251 } else { 1252 ::dsrs::Final 1253 } 1254 1255 interp delete $box 1256 return 1257} 1258 1259proc emptyIp {} { 1260 set box [interp create] 1261 foreach c [interp eval $box {info commands}] { 1262 if {[string equal $c "rename"]} continue 1263 interp eval $box [list rename $c {}] 1264 } 1265 # Rename command goes last. 1266 interp eval $box [list rename rename {}] 1267 return $box 1268} 1269 1270proc restrictedIp {dict} { 1271 set box [emptyIp] 1272 foreach {cmd localcmd} $dict { 1273 interp alias $box $cmd {} $localcmd 1274 } 1275 return $box 1276} 1277 1278# -------------------------------------------------------------- 1279# docstrip low level operations for stitching. 1280 1281namespace eval ::dsrs { 1282 # Standard preamble to preambles 1283 1284 variable preamble {} 1285 append preamble \n 1286 append preamble "This is the file `@output@'," \n 1287 append preamble "generated with the SAK utility" \n 1288 append preamble "(sak docstrip/regen)." \n 1289 append preamble \n 1290 append preamble "The original source files were:" \n 1291 append preamble \n 1292 append preamble "@input@ (with options: `@guards@')" \n 1293 append preamble \n 1294 1295 # Standard postamble to postambles 1296 1297 variable postamble {} 1298 append postamble \n 1299 append postamble \n 1300 append postamble "End of file `@output@'." 1301 1302 # Default values for the options which are relevant to the 1303 # application itself and thus have to be defined always. 1304 # They are processed as global options, as part of argv. 1305 1306 variable defaults {-metaprefix {%} -preamble {} -postamble {}} 1307 1308 variable options ; array set options {} 1309 variable outputs ; array set outputs {} 1310 variable inputs ; array set inputs {} 1311 variable input {} 1312} 1313 1314proc ::dsrs::Init {} { 1315 variable outputs ; unset outputs ; array set outputs {} 1316 variable inputs ; unset inputs ; array set inputs {} 1317 variable input {} 1318 1319 Reset ; # options 1320 return 1321} 1322 1323proc ::dsrs::Reset {} { 1324 variable defaults 1325 variable options ; unset options ; array set options {} 1326 eval [linsert $defaults 0 Options] 1327 return 1328} 1329 1330proc ::dsrs::Input {sourcefile} { 1331 # Relative to current directory = directory containing the active 1332 # stitch file. 1333 1334 variable input $sourcefile 1335} 1336 1337proc ::dsrs::Options {args} { 1338 variable options 1339 variable preamble 1340 variable postamble 1341 1342 while {[llength $args]} { 1343 set opt [lindex $args 0] 1344 1345 switch -exact -- $opt { 1346 -nopreamble - 1347 -nopostamble { 1348 set o -[string range $opt 3 end] 1349 set options($o) "" 1350 set args [lrange $args 1 end] 1351 } 1352 -preamble { 1353 set val $preamble[lindex $args 1] 1354 set options($opt) $val 1355 set args [lrange $args 2 end] 1356 } 1357 -postamble { 1358 set val [lindex $args 1]$postamble 1359 set options($opt) $val 1360 set args [lrange $args 2 end] 1361 } 1362 -metaprefix - 1363 -onerror - 1364 -trimlines { 1365 set val [lindex $args 1] 1366 set options($opt) $val 1367 set args [lrange $args 2 end] 1368 } 1369 default { 1370 return -code error "Unknown option: \"$opt\"" 1371 } 1372 } 1373 } 1374 return 1375} 1376 1377proc ::dsrs::Stitch {outputfile guards} { 1378 variable options 1379 variable inputs 1380 variable input 1381 variable outputs 1382 variable preamble 1383 variable postamble 1384 1385 if {[string equal $input {}]} { 1386 return -code error "No input file defined" 1387 } 1388 1389 if {![info exist inputs($input)]} { 1390 set inputs($input) [get_input $input] 1391 } 1392 1393 set intext $inputs($input) 1394 set otext "" 1395 1396 set c $options(-metaprefix) 1397 set cc $c$c 1398 1399 set pmap [list @output@ $outputfile \ 1400 @input@ $input \ 1401 @guards@ $guards] 1402 1403 if {[info exists options(-preamble)]} { 1404 set pre $options(-preamble) 1405 1406 if {![string equal $pre ""]} { 1407 append otext [Subst $pre $pmap $cc] \n 1408 } 1409 } 1410 1411 array set o [array get options] 1412 catch {unset o(-preamble)} 1413 catch {unset o(-postamble)} 1414 set opt [array get o] 1415 1416 append otext [eval [linsert $opt 0 docstrip::extract $intext $guards]] 1417 1418 if {[info exists options(-postamble)]} { 1419 set post $options(-postamble) 1420 1421 if {![string equal $post ""]} { 1422 append otext [Subst $post $pmap $cc] 1423 } 1424 } 1425 1426 # Accumulate outputs in memory 1427 1428 append outputs($outputfile) $otext 1429 return 1430} 1431 1432proc ::dsrs::Subst {text pmap cc} { 1433 return [string trim "$cc [join [split [string map $pmap $text] \n] "\n$cc "]"] 1434} 1435 1436proc ::dsrs::Final {} { 1437 variable outputs 1438 foreach o [array names outputs] { 1439 puts " = Writing $o ..." 1440 1441 if {[string equal \ 1442 docstrip/docstrip.tcl \ 1443 [file join [file tail [pwd]] $o]]} { 1444 1445 # We are writing over code required by ourselves. 1446 # For easy recovery in case of problems we save 1447 # the original 1448 1449 puts " *Saving original of code important to docstrip/regen itself*" 1450 write_out $o.bak [get_input $o] 1451 } 1452 1453 write_out $o $outputs($o) 1454 } 1455} 1456 1457# -------------------------------------------------------------- 1458# Configuration 1459 1460proc __name {} {global package_name ; puts -nonewline $package_name} 1461proc __version {} {global package_version ; puts -nonewline $package_version} 1462proc __minor {} {global package_version ; puts -nonewline [lindex [split $package_version .] 1]} 1463proc __major {} {global package_version ; puts -nonewline [lindex [split $package_version .] 0]} 1464 1465# -------------------------------------------------------------- 1466# Development 1467 1468proc __imodules {} {puts [imodules]} 1469proc __modules {} {puts [modules]} 1470proc __lmodules {} {puts [join [modules] \n]} 1471 1472 1473proc nparray {a {chan stdout}} { 1474 upvar $a packages 1475 1476 set maxl 0 1477 foreach name [lsort [array names packages]] { 1478 if {[string length $name] > $maxl} { 1479 set maxl [string length $name] 1480 } 1481 } 1482 foreach name [lsort [array names packages]] { 1483 foreach v $packages($name) { 1484 puts $chan [format "%-*s %s" $maxl $name $v] 1485 } 1486 } 1487 return 1488} 1489 1490proc __packages {} { 1491 array set packages {} 1492 foreach {p vm} [ipackages] { 1493 set packages($p) [lindex $vm 0] 1494 } 1495 nparray packages 1496 return 1497} 1498 1499proc __provided {} { 1500 array set packages [ppackages] 1501 nparray packages 1502 return 1503} 1504 1505 1506proc __vcompare {} { 1507 global argv 1508 set oldplist [lindex $argv 0] 1509 pkg-compare $oldplist 1510 return 1511} 1512 1513proc __rstatus {} { 1514 global distribution approved 1515 1516 catch { 1517 set f [file join $distribution .APPROVE] 1518 set f [open $f r] 1519 while {![eof $f]} { 1520 if {[gets $f line] < 0} continue 1521 set line [string trim $line] 1522 if {$line == {}} continue 1523 set approved($line) . 1524 } 1525 close $f 1526 } 1527 pkg-compare [location_PACKAGES] 1528 return 1529} 1530 1531proc pkg-compare {oldplist} { 1532 global approved ; array set approved {} 1533 1534 getpackage struct::set struct/sets.tcl 1535 1536 array set curpkg [ipackages] 1537 array set oldpkg [loadpkglist $oldplist] 1538 array set mod {} 1539 array set changed {} 1540 foreach m [modified-modules] { 1541 set mod($m) . 1542 } 1543 1544 foreach p [array names curpkg] { 1545 set __($p) . 1546 foreach {vlist module} $curpkg($p) break 1547 set curpkg($p) $vlist 1548 set changed($p) [info exists mod($module)] 1549 } 1550 foreach p [array names oldpkg] {set __($p) .} 1551 set unified [lsort [array names __]] 1552 unset __ 1553 1554 set maxl 0 1555 foreach name $unified { 1556 if {[string length $name] > $maxl} { 1557 set maxl [string length $name] 1558 } 1559 } 1560 1561 set maxm 0 1562 foreach m [modules] { 1563 if {[string length $m] > $maxm} { 1564 set maxm [string length $m] 1565 } 1566 } 1567 1568 set lastm "" 1569 foreach m [lsort -dict [modules]] { 1570 set packages {} 1571 foreach {p ___} [ppackages $m] { 1572 lappend packages $p 1573 } 1574 foreach name [lsort -dict $packages] { 1575 set skip 0 1576 set suffix "" 1577 set prefix " " 1578 if {![info exists curpkg($name)]} {set curpkg($name) {}} 1579 if {![info exists oldpkg($name)]} { 1580 set oldpkg($name) {} 1581 set suffix " NEW" 1582 set prefix "Nn " 1583 set skip 1 1584 } 1585 if {!$skip} { 1586 # Draw attention to changed packages where version is 1587 # unchanged. 1588 1589 set vequal [struct::set equal $oldpkg($name) $curpkg($name)] 1590 1591 if {$changed($name)} { 1592 if {$vequal} { 1593 # Changed according to ChangeLog, Version is not. ALERT. 1594 set prefix "!! " 1595 set suffix "\t<<< MISMATCH. Version ==, ChangeLog ++" 1596 } else { 1597 # Both changelog and version number indicate a change. 1598 # Small alert, have to classify the order of changes. 1599 set prefix "cv " 1600 set suffix "\t=== Classify changes." 1601 } 1602 } else { 1603 if {$vequal} { 1604 # Versions are unchanged, changelog also indicates no change. 1605 # No particular attention here. 1606 } else { 1607 # Versions changed, but according to changelog nothing in code. ALERT. 1608 set prefix "!! " 1609 set suffix "\t<<< MISMATCH. ChangeLog ==, Version ++" 1610 } 1611 } 1612 if {[info exists approved($name)]} { 1613 set prefix " " 1614 set suffix "" 1615 } 1616 } 1617 1618 # To handle multiple versions we match the found versions up 1619 # by major version. We assume that we have only one version 1620 # per major version. This allows us to detect changes within 1621 # each major version, new major versions, etc. 1622 1623 array set om {} ; foreach v $oldpkg($name) {set om([lindex [split $v .] 0]) $v} 1624 array set cm {} ; foreach v $curpkg($name) {set cm([lindex [split $v .] 0]) $v} 1625 1626 set all [lsort -dict [struct::set union [array names om] [array names cm]]] 1627 1628 sakdebug { 1629 puts @@@@@@@@@@@@@@@@ 1630 parray om 1631 parray cm 1632 puts all\ $all 1633 puts @@@@@@@@@@@@@@@@ 1634 } 1635 1636 foreach v $all { 1637 if {![string equal $m $lastm]} { 1638 set mdis $m 1639 } else { 1640 set mdis "" 1641 } 1642 set lastm $m 1643 1644 if {[info exists om($v)]} {set ov $om($v)} else {set ov "--"} 1645 if {[info exists cm($v)]} {set cv $cm($v)} else {set cv "--"} 1646 1647 puts stdout ${prefix}[format "%-*s %-*s %-*s %-*s" \ 1648 $maxm $mdis $maxl $name 8 $ov 8 $cv]$suffix 1649 } 1650 1651 unset om cm 1652 } 1653 } 1654 return 1655} 1656 1657proc checkmod {} { 1658 global argv 1659 package require sak::util 1660 return [sak::util::checkModules argv] 1661} 1662 1663# ------------------------------------------------------------------------- 1664# Critcl stuff 1665# ------------------------------------------------------------------------- 1666 1667# Build critcl modules. If no args then build the default critcl module. 1668proc __critcl {} { 1669 global argv critcl critclmodules critcldefault critclnotes tcl_platform 1670 if {$tcl_platform(platform) == "windows"} { 1671 1672 # Windows is a bit more complicated. We have to choose an 1673 # interpreter, and a starkit for it, and call both. 1674 # 1675 # We prefer tclkitsh, but try to make do with a tclsh. That 1676 # one will have to have all the necessary packages to support 1677 # starkits. ActiveTcl for example. 1678 1679 set interpreter {} 1680 foreach i {critcl.exe tclkitsh tclsh} { 1681 set interpreter [auto_execok $i] 1682 if {$interpreter != {}} break 1683 } 1684 1685 if {$interpreter == {}} { 1686 return -code error \ 1687 "failed to find either tclkitsh.exe or tclsh.exe in path" 1688 } 1689 1690 # The critcl starkit can come out of the environment, or we 1691 # try to locate it using several possible names. We try to 1692 # find it if and only if we did not find a critcl starpack 1693 # before. 1694 1695 if {[file tail $interpreter] == "critcl.exe"} { 1696 set critcl $interpreter 1697 } else { 1698 set kit {} 1699 if {[info exists ::env(CRITCL)]} { 1700 set kit $::env(CRITCL) 1701 } else { 1702 foreach k {critcl.kit critcl} { 1703 set kit [auto_execok $k] 1704 if {$kit != {}} break 1705 } 1706 } 1707 1708 if {$kit == {}} { 1709 return -code error "failed to find critcl.kit or critcl in \ 1710 path.\n\ 1711 You may wish to set the CRITCL environment variable to the\ 1712 location of your critcl(.kit) file." 1713 } 1714 set critcl [concat $interpreter $kit] 1715 } 1716 } else { 1717 # My, isn't it simpler under unix. 1718 set critcl [auto_execok critcl] 1719 } 1720 1721 set flags "" 1722 while {[string match -* [set option [lindex $argv 0]]]} { 1723 # -debug and -clean only work with critcl >= v04 1724 switch -exact -- $option { 1725 -keep { append flags " -keep" } 1726 -debug { append flags " -debug" } 1727 -clean { append flags " -clean" } 1728 -- { set argv [lreplace $argv 0 0]; break } 1729 default { break } 1730 } 1731 set argv [lreplace $argv 0 0] 1732 } 1733 1734 if {$critcl != {}} { 1735 if {[llength $argv] == 0} { 1736 puts stderr "[string repeat - 72]" 1737 puts stderr "Building critcl components." 1738 if {$critclnotes != {}} { 1739 puts stderr $critclnotes 1740 } 1741 puts stderr "[string repeat - 72]" 1742 1743 critcl_module $critcldefault $flags 1744 } else { 1745 foreach m [dealias $argv] { 1746 if {[info exists critclmodules($m)]} { 1747 critcl_module $m $flags 1748 } else { 1749 puts "warning: $m is not a critcl module" 1750 } 1751 } 1752 } 1753 } else { 1754 puts "error: cannot find a critcl to run." 1755 return 1 1756 } 1757 return 1758} 1759 1760# Prints a list of all the modules supporting critcl enhancement. 1761proc __critcl-modules {} { 1762 global critclmodules critcldefault 1763 foreach m [lsort -dict [array names critclmodules]] { 1764 if {$m == $critcldefault} { 1765 puts "$m **" 1766 } else { 1767 puts $m 1768 } 1769 } 1770 return 1771} 1772 1773proc critcl_module {pkg {extra ""}} { 1774 global critcl distribution critclmodules critcldefault 1775 if {$pkg == $critcldefault} { 1776 set files {} 1777 foreach f $critclmodules($critcldefault) { 1778 lappend files [file join $distribution modules $f] 1779 } 1780 foreach m [array names critclmodules] { 1781 if {$m == $critcldefault} continue 1782 foreach f $critclmodules($m) { 1783 lappend files [file join $distribution modules $f] 1784 } 1785 } 1786 } else { 1787 foreach f $critclmodules($pkg) { 1788 lappend files [file join $distribution modules $f] 1789 } 1790 } 1791 set target [file join $distribution modules] 1792 catch { 1793 puts "$critcl $extra -force -libdir [list $target] -pkg [list $pkg] $files" 1794 eval exec $critcl $extra -force -libdir [list $target] -pkg [list $pkg] $files 1795 } r 1796 puts $r 1797 return 1798} 1799 1800# ------------------------------------------------------------------------- 1801 1802proc __bench/edit {} { 1803 global argv argv0 1804 1805 set format text 1806 set output {} 1807 1808 while {[string match -* [set option [lindex $argv 0]]]} { 1809 set val [lindex $argv 1] 1810 switch -exact -- $option { 1811 -format { 1812 switch -exact -- $val { 1813 raw - csv - text {} 1814 default { 1815 return -error "Bad format \"$val\", expected text, csv, or raw" 1816 } 1817 } 1818 set format $val 1819 } 1820 -o {set output $val} 1821 -- { 1822 set argv [lrange $argv 1 end] 1823 break 1824 } 1825 default { break } 1826 } 1827 set argv [lrange $argv 2 end] 1828 } 1829 1830 switch -exact -- $format { 1831 raw {} 1832 csv { 1833 getpackage csv csv/csv.tcl 1834 getpackage bench::out::csv bench/bench_wcsv.tcl 1835 } 1836 text { 1837 getpackage report report/report.tcl 1838 getpackage struct::matrix struct/matrix.tcl 1839 getpackage bench::out::text bench/bench_wtext.tcl 1840 } 1841 } 1842 1843 getpackage bench::in bench/bench_read.tcl 1844 getpackage bench bench/bench.tcl 1845 1846 if {[llength $argv] != 3} { 1847 puts "Usage: $argv0 benchdata column newvalue" 1848 } 1849 1850 foreach {in col new} $argv break 1851 1852 _bench_write $output \ 1853 [bench::edit \ 1854 [bench::in::read $in] \ 1855 $col $new] \ 1856 {} $format 1857 return 1858} 1859 1860proc __bench/del {} { 1861 global argv argv0 1862 1863 set format text 1864 set output {} 1865 1866 while {[string match -* [set option [lindex $argv 0]]]} { 1867 set val [lindex $argv 1] 1868 switch -exact -- $option { 1869 -format { 1870 switch -exact -- $val { 1871 raw - csv - text {} 1872 default { 1873 return -error "Bad format \"$val\", expected text, csv, or raw" 1874 } 1875 } 1876 set format $val 1877 } 1878 -o {set output $val} 1879 -- { 1880 set argv [lrange $argv 1 end] 1881 break 1882 } 1883 default { break } 1884 } 1885 set argv [lrange $argv 2 end] 1886 } 1887 1888 switch -exact -- $format { 1889 raw {} 1890 csv { 1891 getpackage csv csv/csv.tcl 1892 getpackage bench::out::csv bench/bench_wcsv.tcl 1893 } 1894 text { 1895 getpackage report report/report.tcl 1896 getpackage struct::matrix struct/matrix.tcl 1897 getpackage bench::out::text bench/bench_wtext.tcl 1898 } 1899 } 1900 1901 getpackage bench::in bench/bench_read.tcl 1902 getpackage bench bench/bench.tcl 1903 1904 if {[llength $argv] < 2} { 1905 puts "Usage: $argv0 benchdata column..." 1906 } 1907 1908 set in [lindex $argv 0] 1909 1910 set data [bench::in::read $in] 1911 1912 foreach c [lrange $argv 1 end] { 1913 set data [bench::del $data $c] 1914 } 1915 1916 _bench_write $output $data {} $format 1917 return 1918} 1919 1920proc __bench/show {} { 1921 global argv 1922 1923 set format text 1924 set output {} 1925 set norm {} 1926 1927 while {[string match -* [set option [lindex $argv 0]]]} { 1928 set val [lindex $argv 1] 1929 switch -exact -- $option { 1930 -format { 1931 switch -exact -- $val { 1932 raw - csv - text {} 1933 default { 1934 return -error "Bad format \"$val\", expected text, csv, or raw" 1935 } 1936 } 1937 set format $val 1938 } 1939 -o {set output $val} 1940 -norm {set norm $val} 1941 -- { 1942 set argv [lrange $argv 1 end] 1943 break 1944 } 1945 default { break } 1946 } 1947 set argv [lrange $argv 2 end] 1948 } 1949 1950 switch -exact -- $format { 1951 raw {} 1952 csv { 1953 getpackage csv csv/csv.tcl 1954 getpackage bench::out::csv bench/bench_wcsv.tcl 1955 } 1956 text { 1957 getpackage report report/report.tcl 1958 getpackage struct::matrix struct/matrix.tcl 1959 getpackage bench::out::text bench/bench_wtext.tcl 1960 } 1961 } 1962 1963 getpackage bench::in bench/bench_read.tcl 1964 1965 array set DATA {} 1966 1967 foreach path $argv { 1968 array set DATA [bench::in::read $path] 1969 } 1970 1971 _bench_write $output [array get DATA] $norm $format 1972 return 1973} 1974 1975proc __bench {} { 1976 global argv 1977 1978 # I. Process command line arguments for the 1979 # benchmark commands - Validation, possible 1980 # translation ... 1981 1982 set flags {} 1983 set norm {} 1984 set format text 1985 set verbose warn 1986 set output {} 1987 set paths {} 1988 set interp {} 1989 1990 while {[string match -* [set option [lindex $argv 0]]]} { 1991 set val [lindex $argv 1] 1992 switch -exact -- $option { 1993 -throwerrors {lappend flags -errors $val} 1994 -match - 1995 -rmatch - 1996 -iters - 1997 -threads {lappend flags $option $val} 1998 -o {set output $val} 1999 -norm {set norm $val} 2000 -path {lappend paths $val} 2001 -interp {set interp $val} 2002 -format { 2003 switch -exact -- $val { 2004 raw - csv - text {} 2005 default { 2006 return -error "Bad format \"$val\", expected text, csv, or raw" 2007 } 2008 } 2009 set format $val 2010 } 2011 -verbose { 2012 set verbose info 2013 set argv [lrange $argv 1 end] 2014 continue 2015 } 2016 -debug { 2017 set verbose debug 2018 set argv [lrange $argv 1 end] 2019 continue 2020 } 2021 -- { 2022 set argv [lrange $argv 1 end] 2023 break 2024 } 2025 default { break } 2026 } 2027 set argv [lrange $argv 2 end] 2028 } 2029 2030 switch -exact -- $format { 2031 raw {} 2032 csv { 2033 getpackage csv csv/csv.tcl 2034 getpackage bench::out::csv bench/bench_wcsv.tcl 2035 } 2036 text { 2037 getpackage report report/report.tcl 2038 getpackage struct::matrix struct/matrix.tcl 2039 getpackage bench::out::text bench/bench_wtext.tcl 2040 } 2041 } 2042 2043 # Choose between benchmarking everything, or 2044 # only selected modules. 2045 2046 if {[llength $argv] == 0} { 2047 _bench_all $paths $interp $flags $norm $format $verbose $output 2048 } else { 2049 if {![checkmod]} {return} 2050 _bench_module [dealias $argv] $paths $interp $flags $norm $format $verbose $output 2051 } 2052 return 2053} 2054 2055proc _bench_module {mlist paths interp flags norm format verbose output} { 2056 global package_name package_version 2057 2058 puts "Benchmarking $package_name $package_version development" 2059 puts "======================================================" 2060 bench_mod $mlist $paths $interp $flags $norm $format $verbose $output 2061 puts "------------------------------------------------------" 2062 puts "" 2063 return 2064} 2065 2066proc _bench_all {paths flags interp norm format verbose output} { 2067 _bench_module [modules] $paths $interp $flags $norm $format $verbose $output 2068 return 2069} 2070 2071# ------------------------------------------------------------------------- 2072 2073proc __oldvalidate_v {} { 2074 global argv 2075 if {[llength $argv] == 0} { 2076 _validate_all_v 2077 } else { 2078 if {![checkmod]} {return} 2079 foreach m [dealias $argv] { 2080 _validate_module_v $m 2081 } 2082 } 2083 return 2084} 2085 2086proc _validate_all_v {} { 2087 global package_name package_version 2088 set i 0 2089 2090 puts "Validating $package_name $package_version development" 2091 puts "===================================================" 2092 puts "[incr i]: Consistency of package versions ..." 2093 puts "------------------------------------------------------" 2094 validate_versions 2095 puts "------------------------------------------------------" 2096 puts "" 2097 return 2098} 2099 2100proc _validate_module_v {m} { 2101 global package_name package_version 2102 set i 0 2103 2104 puts "Validating $package_name $package_version development -- $m" 2105 puts "===================================================" 2106 puts "[incr i]: Consistency of package versions ..." 2107 puts "------------------------------------------------------" 2108 validate_versions_mod $m 2109 puts "------------------------------------------------------" 2110 puts "" 2111 return 2112} 2113 2114 2115proc __oldvalidate {} { 2116 global argv 2117 if {[llength $argv] == 0} { 2118 _validate_all 2119 } else { 2120 if {![checkmod]} {return} 2121 foreach m $argv { 2122 _validate_module $m 2123 } 2124 } 2125 return 2126} 2127 2128proc _validate_all {} { 2129 global package_name package_version 2130 set i 0 2131 2132 puts "Validating $package_name $package_version development" 2133 puts "===================================================" 2134 puts "[incr i]: Existence of testsuites ..." 2135 puts "------------------------------------------------------" 2136 validate_testsuites 2137 puts "------------------------------------------------------" 2138 puts "" 2139 2140 puts "[incr i]: Existence of package indices ..." 2141 puts "------------------------------------------------------" 2142 validate_pkgIndex 2143 puts "------------------------------------------------------" 2144 puts "" 2145 2146 puts "[incr i]: Consistency of package versions ..." 2147 puts "------------------------------------------------------" 2148 validate_versions 2149 puts "------------------------------------------------------" 2150 puts "" 2151 2152 puts "[incr i]: Installed vs. developed modules ..." 2153 puts "------------------------------------------------------" 2154 validate_imodules 2155 puts "------------------------------------------------------" 2156 puts "" 2157 2158 puts "[incr i]: Existence of documentation ..." 2159 puts "------------------------------------------------------" 2160 validate_doc_existence 2161 puts "------------------------------------------------------" 2162 puts "" 2163 2164 puts "[incr i]: Validate documentation markup (doctools) ..." 2165 puts "------------------------------------------------------" 2166 validate_doc_markup 2167 puts "------------------------------------------------------" 2168 puts "" 2169 2170 puts "[incr i]: Static syntax check ..." 2171 puts "------------------------------------------------------" 2172 2173 set frink [auto_execok frink] 2174 set procheck [auto_execok procheck] 2175 set tclchecker [auto_execok tclchecker] 2176 set nagelfar [auto_execok nagelfar] 2177 2178 if {$frink == {}} {puts " Tool 'frink' not found, no check"} 2179 if {($procheck == {}) || ($tclchecker == {})} { 2180 puts " Tools 'procheck'/'tclchecker' not found, no check" 2181 } 2182 if {$nagelfar == {}} {puts " Tool 'nagelfar' not found, no check"} 2183 2184 if {($frink == {}) || ($procheck == {}) || ($tclchecker == {}) 2185 || ($nagelfar == {})} { 2186 puts "------------------------------------------------------" 2187 } 2188 if {($frink == {}) && ($procheck == {}) && ($tclchecker == {}) 2189 && ($nagelfar == {})} { 2190 return 2191 } 2192 if {$frink != {}} { 2193 run-frink 2194 puts "------------------------------------------------------" 2195 } 2196 if {$tclchecker != {}} { 2197 run-tclchecker 2198 puts "------------------------------------------------------" 2199 } elseif {$procheck != {}} { 2200 run-procheck 2201 puts "------------------------------------------------------" 2202 } 2203 if {$nagelfar !={}} { 2204 run-nagelfar 2205 puts "------------------------------------------------------" 2206 } 2207 puts "" 2208 return 2209} 2210 2211proc _validate_module {m} { 2212 global package_name package_version 2213 set i 0 2214 2215 puts "Validating $package_name $package_version development -- $m" 2216 puts "===================================================" 2217 puts "[incr i]: Existence of testsuites ..." 2218 puts "------------------------------------------------------" 2219 validate_testsuite_mod $m 2220 puts "------------------------------------------------------" 2221 puts "" 2222 2223 puts "[incr i]: Existence of package indices ..." 2224 puts "------------------------------------------------------" 2225 validate_pkgIndex_mod $m 2226 puts "------------------------------------------------------" 2227 puts "" 2228 2229 puts "[incr i]: Consistency of package versions ..." 2230 puts "------------------------------------------------------" 2231 validate_versions_mod $m 2232 puts "------------------------------------------------------" 2233 puts "" 2234 2235 #puts "[incr i]: Installed vs. developed modules ..." 2236 puts "------------------------------------------------------" 2237 validate_imodules_mod $m 2238 puts "------------------------------------------------------" 2239 puts "" 2240 2241 puts "[incr i]: Existence of documentation ..." 2242 puts "------------------------------------------------------" 2243 validate_doc_existence_mod $m 2244 puts "------------------------------------------------------" 2245 puts "" 2246 2247 puts "[incr i]: Validate documentation markup (doctools) ..." 2248 puts "------------------------------------------------------" 2249 validate_doc_markup_mod $m 2250 puts "------------------------------------------------------" 2251 puts "" 2252 2253 puts "[incr i]: Static syntax check ..." 2254 puts "------------------------------------------------------" 2255 2256 set frink [auto_execok frink] 2257 set procheck [auto_execok procheck] 2258 set nagelfar [auto_execok nagelfar] 2259 set tclchecker [auto_execok tclchecker] 2260 2261 if {$frink == {}} {puts " Tool 'frink' not found, no check"} 2262 if {($procheck == {}) || ($tclchecker == {})} { 2263 puts " Tools 'procheck'/'tclchecker' not found, no check" 2264 } 2265 if {$nagelfar == {}} {puts " Tool 'nagelfar' not found, no check"} 2266 2267 if {($frink == {}) || ($procheck == {}) || ($tclchecker == {}) || 2268 ($nagelfar == {})} { 2269 puts "------------------------------------------------------" 2270 } 2271 if {($frink == {}) && ($procheck == {}) && ($nagelfar == {}) 2272 && ($tclchecker == {})} { 2273 return 2274 } 2275 if {$frink != {}} { 2276 run-frink $m 2277 puts "------------------------------------------------------" 2278 } 2279 if {$tclchecker != {}} { 2280 run-tclchecker $m 2281 puts "------------------------------------------------------" 2282 } elseif {$procheck != {}} { 2283 run-procheck $m 2284 puts "------------------------------------------------------" 2285 } 2286 if {$nagelfar !={}} { 2287 run-nagelfar $m 2288 puts "------------------------------------------------------" 2289 } 2290 puts "" 2291 2292 return 2293} 2294 2295# -------------------------------------------------------------- 2296# Release engineering 2297 2298proc __gendist {} { 2299 gd-cleanup 2300 gd-tip55 2301 gd-gen-rpmspec 2302 gd-gen-tap 2303 gd-gen-yml 2304 gd-assemble 2305 gd-gen-archives 2306 2307 puts ...Done 2308 return 2309} 2310 2311proc __gentip55 {} { 2312 gd-tip55 2313 puts "Created DESCRIPTION.txt" 2314 return 2315} 2316 2317proc __yml {} { 2318 global package_name 2319 gd-gen-yml 2320 puts "Created YAML spec file \"${package_name}.yml\"" 2321 return 2322} 2323 2324proc __contributors {} { 2325 global contributors 2326 contributors 2327 foreach person [lsort [array names contributors]] { 2328 puts "$person <$contributors($person)>" 2329 } 2330 return 2331} 2332 2333proc __tap {} { 2334 global package_name 2335 gd-gen-tap 2336 puts "Created Tcl Dev Kit \"${package_name}.tap\"" 2337} 2338 2339proc __rpmspec {} { 2340 global package_name 2341 gd-gen-rpmspec 2342 puts "Created RPM spec file \"${package_name}.spec\"" 2343} 2344 2345 2346proc __release {} { 2347 # Regenerate PACKAGES, and extend 2348 2349 global argv argv0 distribution package_name package_version 2350 2351 getpackage textutil textutil/textutil.tcl 2352 2353 if {[llength $argv] != 2} { 2354 puts stderr "$argv0: wrong#args: release name sf-user-id" 2355 exit 1 2356 } 2357 2358 foreach {name sfuser} $argv break 2359 set email "<${sfuser}@users.sourceforge.net>" 2360 set pname [textutil::cap $package_name] 2361 2362 set notice "[clock format [clock seconds] -format "%Y-%m-%d"] $name $email 2363 2364 * 2365 * Released and tagged $pname $package_version ======================== 2366 * 2367 2368" 2369 2370 set logs [list [file join $distribution ChangeLog]] 2371 foreach m [modules] { 2372 set m [file join $distribution modules $m ChangeLog] 2373 if {![file exists $m]} continue 2374 lappend logs $m 2375 } 2376 2377 foreach f $logs { 2378 puts "\tAdding release notice to $f" 2379 set fh [open $f r] ; set data [read $fh] ; close $fh 2380 set fh [open $f w] ; puts -nonewline $fh $notice$data ; close $fh 2381 } 2382 2383 gd-gen-packages 2384 return 2385} 2386 2387proc __approve {} { 2388 global argv distribution 2389 2390 # Record the package as approved. This will suppress any alerts 2391 # for that package by rstatus. Required for packages which have 2392 # been classified, and for packages where a MISMATCH is bogus (due 2393 # to several packages sharing a ChangeLog) 2394 2395 set f [open [file join $distribution .APPROVE] a] 2396 foreach package $argv { 2397 puts $f $package 2398 } 2399 close $f 2400 return 2401} 2402 2403# -------------------------------------------------------------- 2404# Documentation 2405 2406proc __desc {} { 2407 global argv ; if {![checkmod]} return 2408 array set pd [getpdesc] 2409 2410 getpackage struct::matrix struct/matrix.tcl 2411 getpackage textutil textutil/textutil.tcl 2412 2413 struct::matrix m 2414 m add columns 3 2415 2416 puts {Descriptions...} 2417 if {[llength $argv] == 0} {set argv [modules]} 2418 2419 foreach m [lsort [dealias $argv]] { 2420 array set _ {} 2421 set pkg {} 2422 foreach {p vlist} [ppackages $m] { 2423 catch {set _([lindex $pd($p) 0]) .} 2424 lappend pkg $p 2425 } 2426 set desc [string trim [join [array names _] ", "] " \n\t\r,"] 2427 set desc [textutil::adjust $desc -length 20] 2428 unset _ 2429 2430 m add row [list $m $desc] 2431 m add row {} 2432 2433 foreach p [lsort -dictionary $pkg] { 2434 set desc "" 2435 catch {set desc [lindex $pd($p) 1]} 2436 if {$desc != ""} { 2437 set desc [string trim $desc] 2438 set desc [textutil::adjust $desc -length 50] 2439 m add row [list {} $p $desc] 2440 } else { 2441 m add row [list {**} $p ] 2442 } 2443 } 2444 m add row {} 2445 } 2446 2447 m format 2chan 2448 puts "" 2449 return 2450} 2451 2452proc __desc/2 {} { 2453 global argv ; if {![checkmod]} return 2454 array set pd [getpdesc] 2455 2456 getpackage struct::matrix struct/matrix.tcl 2457 getpackage textutil textutil/textutil.tcl 2458 2459 puts {Descriptions...} 2460 if {[llength $argv] == 0} {set argv [modules]} 2461 2462 foreach m [lsort [dealias $argv]] { 2463 struct::matrix m 2464 m add columns 3 2465 2466 m add row {} 2467 2468 set pkg {} 2469 foreach {p vlist} [ppackages $m] {lappend pkg $p} 2470 2471 foreach p [lsort -dictionary $pkg] { 2472 set desc "" 2473 set sdes "" 2474 catch {set desc [lindex $pd($p) 1]} 2475 catch {set sdes [lindex $pd($p) 0]} 2476 2477 if {$desc != ""} { 2478 set desc [string trim $desc] 2479 #set desc [textutil::adjust $desc -length 50] 2480 } 2481 2482 if {$desc != ""} { 2483 set desc [string trim $desc] 2484 #set desc [textutil::adjust $desc -length 50] 2485 } 2486 2487 m add row [list $p " $sdes" " $desc"] 2488 } 2489 m format 2chan 2490 puts "" 2491 m destroy 2492 } 2493 2494 return 2495} 2496 2497# -------------------------------------------------------------- 2498 2499proc __docstrip/users {} { 2500 # Print the list of modules using docstrip for their code. 2501 2502 set argv [modules] 2503 foreach m [lsort $argv] { 2504 if {[docstripUser $m]} { 2505 puts $m 2506 } 2507 } 2508 2509 return 2510} 2511 2512proc __docstrip/regen {} { 2513 # Regenerate modules based on docstrip. 2514 2515 global argv ; if {![checkmod]} return 2516 if {[llength $argv] == 0} {set argv [modules]} 2517 2518 foreach m [lsort [dealias $argv]] { 2519 if {[docstripUser $m]} { 2520 docstripRegen $m 2521 } 2522 } 2523 2524 return 2525} 2526 2527# -------------------------------------------------------------- 2528## Make sak specific packages visible. 2529 2530lappend auto_path [file join $distribution support devel sak] 2531 2532# -------------------------------------------------------------- 2533## Dispatcher to the sak commands. 2534 2535set cmd [lindex $argv 0] 2536set argv [lrange $argv 1 end] 2537incr argc -1 2538 2539# Prefer a command implementation found in the support tree. 2540# Then see if the command is implemented here, in this file. 2541# At last fail and report possible commands. 2542 2543set base [file dirname [info script]] 2544set sbase [file join $base support devel sak] 2545set cbase [file join $sbase $cmd] 2546set cmdf [file join $cbase cmd.tcl] 2547 2548if {[file exists $cmdf] && [file readable $cmdf]} { 2549 source $cmdf 2550 exit 0 2551} 2552 2553if {[llength [info procs __$cmd]] == 0} { 2554 puts stderr "$argv0 : Illegal command \"$cmd\"" 2555 set fl {} 2556 foreach p [info procs __*] { 2557 lappend fl [string range $p 2 end] 2558 } 2559 foreach p [glob -nocomplain -directory $sbase */cmd.tcl] { 2560 lappend fl [lindex [file split $p] end-1] 2561 } 2562 2563 regsub -all . $argv0 { } blank 2564 puts stderr "$blank : Should have been [linsert [join [lsort -uniq $fl] ", "] end-1 or]" 2565 exit 1 2566} 2567 2568__$cmd 2569exit 0 2570