Gathering packages' ifneeded scripts

See Tcl RFE 680169 [L1 ].


Sometimes, Tcl package gets loaded after a noticeable (few seconds) delay. This is because the default script for package unknown, tclPkgUnknown, have to look into every subdirectory of each of the directories in the search path for the possible pkgIndex.tcl files. Search path is comprised of the directories mentioned in tcl_pkgPath and auto_path variables. Given they're usually contain a rather crowded directory, such as /usr/lib on a GNU/Linux system, there easily could be a hundred of places where pkgIndex.tcl will be sought.

A pkgIndex.tcl file typically consists of number of package ifneeded commands telling the package loader on how the packages are to be loaded. The execution time of a command is very small; the time spend searching for the index files is usually significantly longer (unless, of course, the information is obtained from the disk cache.)

The obvious way to speed-up the process is to gather every package ifneeded command found in the pkgIndex.tcl files and put them all into a single file to be loaded (via source) into the Tcl at the script start time.

Usage
gather-ifneeded ?directory directory ...?

The directories given on a command line will be appended to the search path before processing.

 #!/bin/sh
 ### gather-ifneeded.tcl  -*- Tcl -*-
 ## The following code is in public domain.

 ## the next line restarts using tclsh \
 exec tclsh8.4 "$0" "$@"

 ### Code:

 ## allow more directories to be added to the search path
 foreach dir $argv {
     if { [ lsearch -exact $::auto_path $dir ] < 0 } {
         lappend ::auto_path $dir
     }
 }

 ## obtain the list of the packages available;
 ## the trick is documented at: https://wiki.tcl-lang.org/9883
 catch { package require foo-bar }
 foreach package [ package names ] {
     foreach version [ package versions $package ] {
         puts [ list  package ifneeded $package $version \
                    [ package ifneeded $package $version ] ]
     }
 }

 ### gather-ifneeded.tcl ends here