我想要一种限制可以加载到tcl中的包的方法。 我不能只是从路径中删除它们,因为它有一些应该加载的包。
有没有办法处理这个问题而不将包分成不同的目录?
另外,有没有办法为每个正在加载的包添加跟踪?所以我可以看到哪些包装已加载?
由于
答案 0 :(得分:2)
Tcl分几个阶段加载包,这些都以合理的细节here进行描述:
如果你要求一个它还不知道的包,它会调用在package unknown
注册的处理程序来搜索包索引文件的包路径(包含路径位的各种来源) (pkgIndex.tcl
)提供可以加载的包的描述符。这些描述符是调用package ifneeded
以给脚本调用以加载特定包名称的特定版本的文件。如果在加载后仍然不知道包,则会收到错误消息。
大多数pkgIndex.tcl
脚本非常简单,但它们往往是在程序包安装过程中动态生成的。但是有几个小问题;它们在全局上下文中不进行评估,而是在一个范围内定义一个本地dir
变量,该变量表示包含pkgIndex.tcl
脚本的目录的名称,并且它们是总是假设在所有平台上都是UTF-8编码(我建议只使用其中的ASCII字符,因为脚本完全由程序员控制,因此很容易做到,因为脚本完全受编程控制)。
如果您要求提供 知道的包,因为包已经加载或者存在描述符,它会检查匹配的版本号以及是否该包不是实际加载的,它评估在全局上下文中通过package ifneeded
提供的脚本来实际加载包。这通常是source
Tcl脚本和/或load
DLL。有些软件包比这更复杂,但通常不会在描述符脚本本身中加入过多的复杂性:复杂的东西进入它们加载的代码中,这可能与软件包需要它一样复杂。
现在,还有另一个package
子命令对您有用,package forget
,这使得Tcl忘记了包描述符以及是否加载了包。 如果实际加载了,它不会忘记包的实现,但如果你可以在第二阶段之前忘记描述符,则拒绝Tcl解释器加载包的能力。如果你有一个允许的软件包名称和版本的白名单,你需要做的就是拦截package unknown
处理程序,委托给旧的实现,然后在返回之前删除你不想要的任何东西。幸运的是,未知的包处理程序系统被设计为可以这样拦截。
# These packages are to not be version-checked
set builtins {zlib TclOO tcl::tommath Tcl}
# These are the external packages we want to support filtering; THIS IS A WHITELIST!
set whitelist {
Thread {2.8.1}
yaml {0.3.1}
http {2.8.11}
}
proc filterPackages {wrappedCall args} {
# Do the delegation first
uplevel 1 [list {*}$wrappedCall {*}$args]
# Now filter out anything unexpected
global builtins whitelist
foreach p [package names] {
# Check if this is a package we should just tolerate first
if {$p in $builtins} continue
set scripts {}
foreach v [package versions $p] {
if {[dict exists $whitelist $p] && $v in [dict get $whitelist $p]} {
# This is a version we want to keep
lappend scripts [list \
package ifneeded $p $v [package ifneeded $p $v]]
# Everything else is going to be forgotten in a few moments
}
}
# Forget all those package descriptors...
package forget $p
# ...but put back the ones we want.
foreach s $scripts { eval $s }
}
}
# Now install our filter
package unknown [list filterPackages [package unknown]]
只要在脚本的早期安装此过滤器,在完成任何package require
命令之前(真实内置的小列表除外),您将拥有一个只能package require
的系统你想要允许的包。