如何限制tcl加载的包?

时间:2018-03-11 10:12:19

标签: tcl

我想要一种限制可以加载到tcl中的包的方法。 我不能只是从路径中删除它们,因为它有一些应该加载的包。

有没有办法处理这个问题而不将包分成不同的目录?

另外,有没有办法为每个正在加载的包添加跟踪?所以我可以看到哪些包装已加载?

由于

1 个答案:

答案 0 :(得分:2)

Tcl分几个阶段加载包,这些都以合理的细节here进行描述:

  1. 如果你要求一个它还不知道的包,它会调用在package unknown注册的处理程序来搜索包索引文件的包路径(包含路径位的各种来源) (pkgIndex.tcl)提供可以加载的包的描述符。这些描述符是调用package ifneeded以给脚本调用以加载特定包名称的特定版本的文件。如果在加载后仍然不知道包,则会收到错误消息。

    大多数pkgIndex.tcl脚本非常简单,但它们往往是在程序包安装过程中动态生成的。但是有几个小问题;它们在全局上下文中进行评估,而是在一个范围内定义一个本地dir变量,该变量表示包含pkgIndex.tcl脚本的目录的名称,并且它们是总是假设在所有平台上都是UTF-8编码(我建议只使用其中的ASCII字符,因为脚本完全由程序员控制,因此很容易做到,因为脚本完全受编程控制)。

  2. 如果您要求提供 知道的包,因为包已经加载或者存在描述符,它会检查匹配的版本号以及是否该包不是实际加载的,它评估在全局上下文中通过package ifneeded提供的脚本来实际加载包。这通常是source Tcl脚本和/或load DLL。有些软件包比这更复杂,但通常不会在描述符脚本本身中加入过多的复杂性:复杂的东西进入它们加载的代码中,这可能与软件包需要它一样复杂。

  3. 现在,还有另一个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的系统你想要允许的包。