|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace eval tcl::Pkg {} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc tcl::Pkg::CompareExtension {fileName {ext {}}} { |
|
global tcl_platform |
|
if {$ext eq ""} {set ext [info sharedlibextension]} |
|
if {$tcl_platform(platform) eq "windows"} { |
|
return [string equal -nocase [file extension $fileName] $ext] |
|
} else { |
|
|
|
|
|
set root $fileName |
|
while {1} { |
|
set currExt [file extension $root] |
|
if {$currExt eq $ext} { |
|
return 1 |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if {![string is integer -strict [string range $currExt 1 end]]} { |
|
return 0 |
|
} |
|
set root [file rootname $root] |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc pkg_mkIndex {args} { |
|
set usage {"pkg_mkIndex ?-direct? ?-lazy? ?-load pattern? ?-verbose? ?--? dir ?pattern ...?"} |
|
|
|
set argCount [llength $args] |
|
if {$argCount < 1} { |
|
return -code error "wrong # args: should be\n$usage" |
|
} |
|
|
|
set more "" |
|
set direct 1 |
|
set doVerbose 0 |
|
set loadPat "" |
|
for {set idx 0} {$idx < $argCount} {incr idx} { |
|
set flag [lindex $args $idx] |
|
switch -glob -- $flag { |
|
-- { |
|
|
|
incr idx |
|
break |
|
} |
|
-verbose { |
|
set doVerbose 1 |
|
} |
|
-lazy { |
|
set direct 0 |
|
append more " -lazy" |
|
} |
|
-direct { |
|
append more " -direct" |
|
} |
|
-load { |
|
incr idx |
|
set loadPat [lindex $args $idx] |
|
append more " -load $loadPat" |
|
} |
|
-* { |
|
return -code error "unknown flag $flag: should be\n$usage" |
|
} |
|
default { |
|
|
|
break |
|
} |
|
} |
|
} |
|
|
|
set dir [lindex $args $idx] |
|
set patternList [lrange $args [expr {$idx + 1}] end] |
|
if {![llength $patternList]} { |
|
set patternList [list "*.tcl" "*[info sharedlibextension]"] |
|
} |
|
|
|
try { |
|
set fileList [glob -directory $dir -tails -types {r f} -- \ |
|
{*}$patternList] |
|
} on error {msg opt} { |
|
return -options $opt $msg |
|
} |
|
foreach file $fileList { |
|
|
|
|
|
|
|
|
|
|
|
if {$file eq "pkgIndex.tcl"} { |
|
continue |
|
} |
|
|
|
set c [interp create] |
|
|
|
|
|
|
|
|
|
if {$loadPat ne ""} { |
|
if {$doVerbose} { |
|
tclLog "currently loaded packages: '[info loaded]'" |
|
tclLog "trying to load all packages matching $loadPat" |
|
} |
|
if {![llength [info loaded]]} { |
|
tclLog "warning: no packages are currently loaded, nothing" |
|
tclLog "can possibly match '$loadPat'" |
|
} |
|
} |
|
foreach pkg [info loaded] { |
|
if {![string match -nocase $loadPat [lindex $pkg 1]]} { |
|
continue |
|
} |
|
if {$doVerbose} { |
|
tclLog "package [lindex $pkg 1] matches '$loadPat'" |
|
} |
|
try { |
|
load [lindex $pkg 0] [lindex $pkg 1] $c |
|
} on error err { |
|
if {$doVerbose} { |
|
tclLog "warning: load [lindex $pkg 0]\ |
|
[lindex $pkg 1]\nfailed with: $err" |
|
} |
|
} on ok {} { |
|
if {$doVerbose} { |
|
tclLog "loaded [lindex $pkg 0] [lindex $pkg 1]" |
|
} |
|
} |
|
if {[lindex $pkg 1] eq "Tk"} { |
|
|
|
$c eval [list wm withdraw .] |
|
} |
|
} |
|
|
|
$c eval { |
|
|
|
|
|
|
|
rename package __package_orig |
|
proc package {what args} { |
|
switch -- $what { |
|
require { |
|
return |
|
} |
|
default { |
|
__package_orig $what {*}$args |
|
} |
|
} |
|
} |
|
proc tclPkgUnknown args {} |
|
package unknown tclPkgUnknown |
|
|
|
|
|
|
|
|
|
proc unknown {args} {} |
|
|
|
|
|
|
|
proc auto_import {args} {} |
|
|
|
|
|
|
|
|
|
|
|
namespace eval ::tcl { |
|
variable dir |
|
variable file |
|
variable direct |
|
variable x |
|
variable debug |
|
variable type |
|
variable namespaces |
|
variable packages |
|
variable origCmds |
|
variable newCmds |
|
variable newPkgs {} |
|
} |
|
} |
|
|
|
$c eval [list set ::tcl::dir $dir] |
|
$c eval [list set ::tcl::file $file] |
|
$c eval [list set ::tcl::direct $direct] |
|
|
|
|
|
|
|
|
|
|
|
foreach p {::tcl::Pkg::CompareExtension} { |
|
$c eval [list namespace eval [namespace qualifiers $p] {}] |
|
$c eval [list proc $p [info args $p] [info body $p]] |
|
} |
|
|
|
try { |
|
$c eval { |
|
set ::tcl::debug "loading or sourcing" |
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::GetAllNamespaces {{root ::}} { |
|
set list $root |
|
foreach ns [namespace children $root] { |
|
lappend list {*}[::tcl::GetAllNamespaces $ns] |
|
} |
|
return $list |
|
} |
|
|
|
|
|
|
|
foreach ::tcl::x [::tcl::GetAllNamespaces] { |
|
set ::tcl::namespaces($::tcl::x) 1 |
|
} |
|
foreach ::tcl::x [package names] { |
|
if {[package provide $::tcl::x] ne ""} { |
|
set ::tcl::packages($::tcl::x) 1 |
|
} |
|
} |
|
set ::tcl::origCmds [info commands] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if {[::tcl::Pkg::CompareExtension $::tcl::file [info sharedlibextension]]} { |
|
|
|
|
|
|
|
|
|
|
|
set ::tcl::debug loading |
|
load [file join $::tcl::dir $::tcl::file] |
|
set ::tcl::type load |
|
} else { |
|
set ::tcl::debug sourcing |
|
source [file join $::tcl::dir $::tcl::file] |
|
set ::tcl::type source |
|
} |
|
|
|
|
|
|
|
|
|
|
|
if {!$::tcl::direct} { |
|
|
|
|
|
|
|
foreach ::tcl::x [::tcl::GetAllNamespaces] { |
|
if {![info exists ::tcl::namespaces($::tcl::x)]} { |
|
namespace import -force ${::tcl::x}::* |
|
} |
|
|
|
|
|
|
|
foreach ::tcl::x [info commands] { |
|
set ::tcl::newCmds($::tcl::x) 1 |
|
} |
|
foreach ::tcl::x $::tcl::origCmds { |
|
unset -nocomplain ::tcl::newCmds($::tcl::x) |
|
} |
|
foreach ::tcl::x [array names ::tcl::newCmds] { |
|
|
|
|
|
set ::tcl::abs [namespace origin $::tcl::x] |
|
|
|
|
|
|
|
|
|
|
|
set ::tcl::abs \ |
|
[lindex [auto_qualify $::tcl::abs ::] 0] |
|
|
|
if {$::tcl::x ne $::tcl::abs} { |
|
|
|
|
|
set ::tcl::newCmds($::tcl::abs) 1 |
|
unset ::tcl::newCmds($::tcl::x) |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
foreach ::tcl::x [package names] { |
|
if {[package provide $::tcl::x] ne "" |
|
&& ![info exists ::tcl::packages($::tcl::x)]} { |
|
lappend ::tcl::newPkgs \ |
|
[list $::tcl::x [package provide $::tcl::x]] |
|
} |
|
} |
|
} |
|
} on error msg { |
|
set what [$c eval set ::tcl::debug] |
|
if {$doVerbose} { |
|
tclLog "warning: error while $what $file: $msg" |
|
} |
|
} on ok {} { |
|
set what [$c eval set ::tcl::debug] |
|
if {$doVerbose} { |
|
tclLog "successful $what of $file" |
|
} |
|
set type [$c eval set ::tcl::type] |
|
set cmds [lsort [$c eval array names ::tcl::newCmds]] |
|
set pkgs [$c eval set ::tcl::newPkgs] |
|
if {$doVerbose} { |
|
if {!$direct} { |
|
tclLog "commands provided were $cmds" |
|
} |
|
tclLog "packages provided were $pkgs" |
|
} |
|
if {[llength $pkgs] > 1} { |
|
tclLog "warning: \"$file\" provides more than one package ($pkgs)" |
|
} |
|
foreach pkg $pkgs { |
|
|
|
lappend files($pkg) [list $file $type $cmds] |
|
} |
|
|
|
if {$doVerbose} { |
|
tclLog "processed $file" |
|
} |
|
} |
|
interp delete $c |
|
} |
|
|
|
append index "# Tcl package index file, version 1.1\n" |
|
append index "# This file is generated by the \"pkg_mkIndex$more\" command\n" |
|
append index "# and sourced either when an application starts up or\n" |
|
append index "# by a \"package unknown\" script. It invokes the\n" |
|
append index "# \"package ifneeded\" command to set up package-related\n" |
|
append index "# information so that packages will be loaded automatically\n" |
|
append index "# in response to \"package require\" commands. When this\n" |
|
append index "# script is sourced, the variable \$dir must contain the\n" |
|
append index "# full path name of this file's directory.\n" |
|
|
|
foreach pkg [lsort [array names files]] { |
|
set cmd {} |
|
lassign $pkg name version |
|
lappend cmd ::tcl::Pkg::Create -name $name -version $version |
|
foreach spec [lsort -index 0 $files($pkg)] { |
|
foreach {file type procs} $spec { |
|
if {$direct} { |
|
set procs {} |
|
} |
|
lappend cmd "-$type" [list $file $procs] |
|
} |
|
} |
|
append index "\n[eval $cmd]" |
|
} |
|
|
|
set f [open [file join $dir pkgIndex.tcl] w] |
|
puts $f $index |
|
close $f |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc tclPkgSetup {dir pkg version files} { |
|
global auto_index |
|
|
|
package provide $pkg $version |
|
foreach fileInfo $files { |
|
set f [lindex $fileInfo 0] |
|
set type [lindex $fileInfo 1] |
|
foreach cmd [lindex $fileInfo 2] { |
|
if {$type eq "load"} { |
|
set auto_index($cmd) [list load [file join $dir $f] $pkg] |
|
} else { |
|
set auto_index($cmd) [list source [file join $dir $f]] |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc tclPkgUnknown {name args} { |
|
global auto_path env |
|
|
|
if {![info exists auto_path]} { |
|
return |
|
} |
|
|
|
|
|
set old_path [set use_path $auto_path] |
|
while {[llength $use_path]} { |
|
set dir [lindex $use_path end] |
|
|
|
|
|
if {[info exists tclSeenPath($dir)]} { |
|
set use_path [lrange $use_path 0 end-1] |
|
continue |
|
} |
|
set tclSeenPath($dir) 1 |
|
|
|
|
|
|
|
|
|
catch { |
|
foreach file [glob -directory $dir -join -nocomplain \ |
|
* pkgIndex.tcl] { |
|
set dir [file dirname $file] |
|
if {![info exists procdDirs($dir)]} { |
|
try { |
|
source $file |
|
} trap {POSIX EACCES} {} { |
|
|
|
continue |
|
} on error msg { |
|
tclLog "error reading package index file $file: $msg" |
|
} on ok {} { |
|
set procdDirs($dir) 1 |
|
} |
|
} |
|
} |
|
} |
|
set dir [lindex $use_path end] |
|
if {![info exists procdDirs($dir)]} { |
|
set file [file join $dir pkgIndex.tcl] |
|
|
|
if {([interp issafe] || [file exists $file])} { |
|
try { |
|
source $file |
|
} trap {POSIX EACCES} {} { |
|
|
|
continue |
|
} on error msg { |
|
tclLog "error reading package index file $file: $msg" |
|
} on ok {} { |
|
set procdDirs($dir) 1 |
|
} |
|
} |
|
} |
|
|
|
set use_path [lrange $use_path 0 end-1] |
|
|
|
|
|
|
|
|
|
|
|
|
|
set index 0 |
|
if {[llength $old_path] == [llength $auto_path]} { |
|
foreach dir $auto_path old $old_path { |
|
if {$dir ne $old} { |
|
|
|
break |
|
} |
|
incr index |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
foreach dir [lrange $auto_path $index end] { |
|
if {![info exists tclSeenPath($dir)] && ($dir ni $use_path)} { |
|
lappend use_path $dir |
|
} |
|
} |
|
set old_path $auto_path |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc tcl::MacOSXPkgUnknown {original name args} { |
|
|
|
uplevel 1 $original [linsert $args 0 $name] |
|
|
|
|
|
global auto_path |
|
|
|
if {![info exists auto_path]} { |
|
return |
|
} |
|
|
|
|
|
set old_path [set use_path $auto_path] |
|
while {[llength $use_path]} { |
|
set dir [lindex $use_path end] |
|
|
|
|
|
if {[info exists tclSeenPath($dir)]} { |
|
set use_path [lrange $use_path 0 end-1] |
|
continue |
|
} |
|
set tclSeenPath($dir) 1 |
|
|
|
|
|
foreach file [glob -directory $dir -join -nocomplain \ |
|
* Resources Scripts pkgIndex.tcl] { |
|
set dir [file dirname $file] |
|
if {![info exists procdDirs($dir)]} { |
|
try { |
|
source $file |
|
} trap {POSIX EACCES} {} { |
|
|
|
continue |
|
} on error msg { |
|
tclLog "error reading package index file $file: $msg" |
|
} on ok {} { |
|
set procdDirs($dir) 1 |
|
} |
|
} |
|
} |
|
set use_path [lrange $use_path 0 end-1] |
|
|
|
|
|
|
|
|
|
|
|
|
|
set index 0 |
|
if {[llength $old_path] == [llength $auto_path]} { |
|
foreach dir $auto_path old $old_path { |
|
if {$dir ne $old} { |
|
|
|
break |
|
} |
|
incr index |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
foreach dir [lrange $auto_path $index end] { |
|
if {![info exists tclSeenPath($dir)] && ($dir ni $use_path)} { |
|
lappend use_path $dir |
|
} |
|
} |
|
set old_path $auto_path |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
proc ::tcl::Pkg::Create {args} { |
|
append err(usage) "[lindex [info level 0] 0] " |
|
append err(usage) "-name packageName -version packageVersion" |
|
append err(usage) "?-load {filename ?{procs}?}? ... " |
|
append err(usage) "?-source {filename ?{procs}?}? ..." |
|
|
|
set err(wrongNumArgs) "wrong # args: should be \"$err(usage)\"" |
|
set err(valueMissing) "value for \"%s\" missing: should be \"$err(usage)\"" |
|
set err(unknownOpt) "unknown option \"%s\": should be \"$err(usage)\"" |
|
set err(noLoadOrSource) "at least one of -load and -source must be given" |
|
|
|
|
|
set len [llength $args] |
|
if {$len < 6} { |
|
error $err(wrongNumArgs) |
|
} |
|
|
|
|
|
array set opts {-name {} -version {} -source {} -load {}} |
|
|
|
|
|
for {set i 0} {$i < $len} {incr i} { |
|
set flag [lindex $args $i] |
|
incr i |
|
switch -glob -- $flag { |
|
"-name" - |
|
"-version" { |
|
if {$i >= $len} { |
|
error [format $err(valueMissing) $flag] |
|
} |
|
set opts($flag) [lindex $args $i] |
|
} |
|
"-source" - |
|
"-load" { |
|
if {$i >= $len} { |
|
error [format $err(valueMissing) $flag] |
|
} |
|
lappend opts($flag) [lindex $args $i] |
|
} |
|
default { |
|
error [format $err(unknownOpt) [lindex $args $i]] |
|
} |
|
} |
|
} |
|
|
|
|
|
if {![llength $opts(-name)]} { |
|
error [format $err(valueMissing) "-name"] |
|
} |
|
if {![llength $opts(-version)]} { |
|
error [format $err(valueMissing) "-version"] |
|
} |
|
|
|
if {!([llength $opts(-source)] || [llength $opts(-load)])} { |
|
error $err(noLoadOrSource) |
|
} |
|
|
|
|
|
set cmdline "package ifneeded $opts(-name) $opts(-version) " |
|
|
|
set cmdList {} |
|
set lazyFileList {} |
|
|
|
|
|
foreach key {load source} { |
|
foreach filespec $opts(-$key) { |
|
lassign $filespec filename proclist |
|
|
|
if { [llength $proclist] == 0 } { |
|
set cmd "\[list $key \[file join \$dir [list $filename]\]\]" |
|
lappend cmdList $cmd |
|
} else { |
|
lappend lazyFileList [list $filename $key $proclist] |
|
} |
|
} |
|
} |
|
|
|
if {[llength $lazyFileList]} { |
|
lappend cmdList "\[list tclPkgSetup \$dir $opts(-name)\ |
|
$opts(-version) [list $lazyFileList]\]" |
|
} |
|
append cmdline [join $cmdList "\\n"] |
|
return $cmdline |
|
} |
|
|
|
interp alias {} ::pkg::create {} ::tcl::Pkg::Create |
|
|