sak.tcl

Go to the documentation of this file.
00001 /* !/bin/sh*/
00002 /*  -*- tcl -*- \*/
00003 exec tclsh "$0" ${1+"$@"}
00004 
00005 /*  --------------------------------------------------------------*/
00006 /*  Perform various checks and operations on the distribution.*/
00007 /*  SAK = Swiss Army Knife.*/
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] ; /*  Get version information.*/
00037 
00038  package = _nv ${package_name}-${package_version}
00039 
00040 catch {eval file delete -force [glob [file rootname [info script]].tmp.*]}
00041 
00042 /*  --------------------------------------------------------------*/
00043 /*  SAK internal debugging support.*/
00044 
00045 /*  Configuration, change as needed*/
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 /*  Internal helper to load packages straight out of the local directory*/
00056 /*  tree. Not something from an installation, possibly incompatible.*/
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 /*  Result: dict (package name --> list of package versions).*/
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 /*  Result: dict (package name => list of (list of package versions, module)).*/
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 /*  Result: dict (package name --> list of package versions).*/
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/*.l] {
00685         set f [open $file r]
00686     foreach l [split [read $f] \n] {
00687         foreach {p sd d} $l break
00688         set _($p) [list $sd $d]
00689     }
00690         close $f
00691     }
00692     file delete -force doc/desc
00693 
00694     return [array get _]
00695 }
00696 
00697 ret  gd-gen-rpmspec () {
00698     global package_version package_name distribution
00699 
00700     set in  [file join $distribution support releases package_rpm.txt]
00701     set out [file join $distribution ${package_name}.spec]
00702 
00703     write_out $out [string map \
00704             [list \
00705                  @PACKAGE_VERSION@ $package_version \
00706                  @PACKAGE_NAME@    $package_name] \
00707             [get_input $in]]
00708     return
00709 }
00710 
00711 ret  gd-gen-yml () {
00712     # YAML is the format used for the FreePAN archive network.
00713     # http://freepan.org/
00714 
00715     global package_version package_name distribution
00716 
00717     set in  [file join $distribution support releases package_yml.txt]
00718     set out [file join $distribution ${package_name}.yml]
00719 
00720     write_out $out [string map \
00721             [list \
00722                  @PACKAGE_VERSION@ $package_version \
00723                  @PACKAGE_NAME@    $package_name] \
00724             [get_input $in]]
00725     return
00726 }
00727 
00728 ret  docfiles () {
00729     global distribution
00730 
00731     getpackage fileutil fileutil/fileutil.tcl
00732 
00733     set res [list]
00734     foreach f [fileutil::findByPattern $distribution -glob *.man] {
00735     # Remove files under SCCS. They are repository, not sources to check.
00736     if {[string match *SCCS* $f]} continue
00737     lappend res [file rootname [file tail $f]].n
00738     }
00739     proc docfiles {} [list return $res]
00740     return $res
00741 }
00742 
00743 ret  gd-tip55 () {
00744     global package_version package_name distribution contributors
00745     contributors
00746 
00747     set in  [file join $distribution support releases package_tip55.txt]
00748     set out [file join $distribution DESCRIPTION.txt]
00749 
00750     set md [string map \
00751         [list \
00752              @PACKAGE_VERSION@ $package_version \
00753              @PACKAGE_NAME@    $package_name] \
00754         [get_input $in]]
00755 
00756     foreach person [lsort [array names contributors]] {
00757         set mail $contributors($person)
00758         regsub {@}  $mail " at " mail
00759         regsub -all {\.} $mail " dot " mail
00760         append md "Contributor: $person <$mail>\n"
00761     }
00762 
00763     write_out $out $md
00764     return
00765 }
00766 
00767 /*  Fill the global array of contributors to the bundle by processing*/
00768 /*  the ChangeLog entries.*/
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 /*  Handle modules using docstrip*/
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 /*  docstrip low level operations for stitching.*/
01265 
01266 namespace ::dsrs {
01267     /*  Standard preamble to preambles*/
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     /*  Standard postamble to postambles*/
01281 
01282     variable postamble {}
01283     append   postamble                           \n
01284     append   postamble                           \n
01285     append   postamble "End of file `@output@'."
01286 
01287     /*  Default values for the options which are relevant to the*/
01288     /*  application itself and thus have to be defined always.*/
01289     /*  They are processed as global options, as part of argv.*/
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 /*  Configuration*/
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 /*  Development*/
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 /*  Critcl stuff*/
01650 /*  -------------------------------------------------------------------------*/
01651 
01652 /*  Build critcl modules. If no args then build the default critcl module.*/
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 /*  Prints a list of all the modules supporting critcl enhancement.*/
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 /*  Release engineering*/
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 /*  Documentation*/
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 /*  Make sak specific packages visible.*/
02514 
02515 lappend auto_path [file join $distribution support devel sak]
02516 
02517 /*  --------------------------------------------------------------*/
02518 /*  Dispatcher to the sak commands.*/
02519 
02520   cmd =   [lindex $argv 0]
02521   argv =  [lrange $argv 1 end]
02522 incr argc -1
02523 
02524 /*  Prefer a command implementation found in the support tree.*/
02525 /*  Then see if the command is implemented here, in this file.*/
02526 /*  At last fail and report possible commands.*/
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 

Generated on 21 Sep 2010 for Gui by  doxygen 1.6.1