see Don Porter's 2001 Tcl Conference presentation
http://math.nist.gov/~DPorter/tcltk/oscon/
= Fullfilling the Promise of package unknown =
Don Porter http://math.nist.go v/~ DP orter/tcltk/
Mathematical & Computational Sciences Division Information Technology Laboratory National Institute of Standards and Technology Gaithersburg, Maryland
== Introduction ==
=== What color is a Tk button? ===
Naive answer: Grey.
pack [button .b -text Example]
True answer: What ever color you want.
pack [button .b -text Example -bg red]
Grey is merely the default.
=== How does Tcl find and load packages? ===
Naive answer: Uses $::auto path as a search path... Looks for pkgIndex.tcl files created by pkg_mkIndex, source's them, etc. ...
True answer: However you choose!
Why don't people know this? Why don't people use this?
== Outline Mini-tutorial on package ==
Define provide script and index script
Three parties involved in package management
Defacto interface: tclPkgUnknown - Features and Limitations
Propose: New customization hook package fsindex - Sysadmin control over how packages are installed
== Tutorial: What is a package? ==
A package starts as a collection of related Tcl commands, namespaces, and/or variables grouped together as a single unit.
Grouping simplifies loading and introspection.
Collection becomes a package by calling package provide
namespace eval :: { package provide hw 1.0 namespace eval hw { namespace export hello; variable Who world proc hello {} { variable Who; puts "Hello, $Who!" } } }
Load package into interp: eval provide script
== Tutorial: Loading packages ==
Evaluation of provide script must call Tcl_PkgProvide()
Simplest possible provide scripts:
set pscript1 {package provide hw 1.0} set pscript2 {package provide hw 2.0}
Exactly one version of each package per interp:
namespace eval :: $pscript1 namespace eval :: $pscript2 -> conflicting versions provided for package "hw": 1.0, then 2.0
== Tutorial: Package version selection ==
Authors register provide scripts with package ifneeded
package ifneeded hw 1.0 {package provide hw 1.0} package ifneeded hw 1.1 {package provide hw 1.1} package ifneeded hw 2.0 {package provide hw 2.0}
Users call package require to select and eval one registered provide script
package require hw 1 -> 1.1
Explains how provide scripts are evaluated.
How are package ifneeded commands evaluated?
== Tutorial: Index scripts ==
Authors provide an 'index script' for each package
Index script includes package ifneeded - Just as provide script includes package provide
Simplest possible index script:
set iscript {package ifneeded hw 1.0 {package provide hw 1.0}}
User needs evaluation of index script
eval $iscript
Mechanism? package unknown !
== Tutorial: package unknown ==
User calls package require
package require $package $requiredVersion
When no registered provide script will satisfy the requirement, package require evaluates:
namespace eval :: [package unknown] [list $package $requiredVersion]
package unknown returns command to be used for finding and evaluating index scripts.
package unknown -> tclPkgUnknown
== Promise of package unknown ==
Why not call tclPkgUnknown directly? - package unknown enables customization
package unknown ?command?
User can select any command for finding and evaluating index scripts.
proc falseWitness {p v args} { package ifneeded $p $v [list package provide $p $v] } package unknown falseWitness
Opens up many possibilities...for the user .
== But What About the Sysadmin? ==
== provide Script of Installed Package ==
An installed package has its provide script in a file.
$ cat /usr/lib/hw1.0/hw.tcl -> package provide hw 1.0
Scripts registered with package ifneeded refer to files
package ifneeded hw 1.0 {source /usr/lib/hw1.0/hw.tcl} package ifneeded foo 2.0 {load /usr/lib/foo2.0/../libfoo2.0.so}
But the sysadmin, not the author, decides the installation directory for the package!
== Index Script of Installed Package ==
The provide script needs to know the installation directory. - Unknown to the author who would write provide script.
Index script has job of registering provide script.
Give index script job of creating provide script too!
package ifneeded hw 1.0 [list source [file join $dir hw.tcl]] package ifneeded foo 2.0 [list load [file join $dir .. libfoo2.0.so]]
Interface requirement: index script evaluated incontext where $dir is the installation directory.
== How does tclPkgUnknown work? ==
Called with arguments '$package' and '$requiredVersion'
Treats $::auto_path as an input
Evaluates the pkgIndex.tcl files
== tclPkgUnknown Limitations ==
Ignores arguments telling what to search for
Errors in index scripts of all installed packages reported. Even in packages that are never used
Keeps no map to be more selective.
== tclPkgUnknown Limitations ==
Shares $::auto_path with the auto-loader
Only one pkgIndex.tcl file per directory.
No installed package introspection.
So why not use package unknown to replace tclPkgUnknown with something
better?
== Unfulfilled Promise of package unknown ==
Can package unknown allow sysadmins to customize the way in which packages are installed on their systems?
Not alone.
== package unknown :Half the Battle ==
package unknown only solves half the problem.
No customizable interface for storing index scripts
Once packages are installed as tclPkgUnknown expects, no other retrieval routine can do better.
== The Missing Half ==
Need another customization hook in package
Allow sysadmins to customize package installation conventions on their filesystems.
... like [package unknown]
Preserve an unchanging interface to authors writing package installation routines.
... like [package require]
== Proposal: package fsindex ==
The customizable interface to the collection ofi ndex scripts stored in the filesystem.
Customization just like package unknown
package fsindex ?command?
package fsindex with no arguments -Returns the command that manages index scripts on the filesystem
package fsindex $command - Registers $command as the command that manages index scripts on the filesystem
Responsibility of sysadmin to register package fsindex command matching package installation convention ofthe filesystem.
== package fsindex Interface ==
For each installed package, the command registered with package fsindex must keep track of
provides access to this information through an interface of several subcommands.
namespace eval :: { [package fsindex] $subcommand $args }
For simplicity, assume package fsindex foo.
== package fsindex satisfy ==
Implements the package unknown function.
foo satisfy $package $version
* Finds all index scripts for all versions of package $package that might satisfy the $version requirement * Limit search to search path set by foo searchpath * Evaluate all found index scripts in search path order, set $dir
New default package unknown
proc default {args} { uplevel 1 [package fsindex] satisfy $args } package unknown default
== package fsindex searchpath ==
Limit packages searched by installation directory.
Three forms:
Generalizes setting of $::auto path
== package fsindex insert ==
Add new index script tothe system
foo insert $p $v $d $indexScript
Part of package installation
Called after files of version $v of package $p have been installed into installation directory $d
Registers its $indexScript
Generalization of part of pkg_mkIndex
== package fsindex delete ==
Remove index script from the system
foo delete $p $v $d
Part of package uninstallation
Called after files of version $v of package $p have been removed from installation directory $d
Generalization of deleting pkgIndex.tcl file
== Increased Promise: Introspection ==
What packages are installed, where?
foo names foo versions $p foo directories $p $v
provides what users want from package names
Can use with foo searchpath to carefully limit search to just the directories needed.
== Package Providing the Proposed Interface ==
Coming Soon: the package fsidb
Simple implementation of the package fsindex interface
Collection of index scripts and installation directories associated with packages kept as simple Tcl array read in from a single file.
== Migration Steps ==
Add package fsindex
Wrap (parts of) package fsindex interface around existing tclPkgUnknown .
Initialize package unknown with default that uses package fsindex toquery installed packages.
Migrate package installation scripts to use new installation interface - Installer packages and tools?
Still one hook missing to allow use of fsidb, etc. ...
== Customized Tcl Initialization for Sysadmins ==
Installed packages available for any Tcl interp -tclsh -wish -embedded interps
Index scripts are stored how they're stored.
Could "hack" the init.tcl file
...or init.tcl could explicitly eval a system customization file. (Feature Request 219375. Patch 403526.)
== Summary ==
A straightforward extension of package offers