Quicklisp library bundles
Overview
Quicklisp library bundles are self-contained sets of systems that are exported from Quicklisp and loadable without involving Quicklisp. A library bundle has a directory structure that includes software archives, an index file, and a Lisp file that can be loaded to configure ASDF to understand how to load systems from the bundle. It also includes a directory, initially empty, that works like the local-projects mechanism, whereby any system in the bundle's local-projects directory takes precedence over other systems in the bundle.
Bundling works only for systems available through Quicklisp. It cannot find and bundle external ASDF systems and their sources.
Creating a bundle
Bundles are created with
the QL:BUNDLE-SYSTEMS
function.
* (ql:bundle-systems '("vecto" "zpb-exif") :to "my-bundle/") => #P"/Users/xach/my-bundle/bundle.lisp", #<QL-BUNDLE:BUNDLE 6 releases, 10 systems>
When creating a bundle for systems foo, bar, and baz, the directory structure looks like so:
- bundle.lisp
- system-index.txt
- software/
- foo/
- source code for foo
- bar/
- source code for bar
- baz/
- source code for baz
- foo/
- local-projects/
- initially empty
- bundled-local-projects/
- 0000/
- local projects code
- 0001/
- more local projects code
- 0000/
The "bundled-local-projects/" subdirectory appears only if the include-local-projects argument to bundle-systems is true
Loading a bundle
In the following descriptions, loading a bundle refers to loading the bundle.lisp file created for a bundle.
When a bundle is loaded, the systems in the bundle are visible to
ASDF and can be found
via (asdf:find-system system-name)
and
loaded
with (asdf:load-system system-name)
. Loading
a bundle does not load all the bundle's systems —
it just makes them available for later loading via ASDF.
By default, loading bundle.lisp will make the bundle's systems
load before any other systems known to ASDF. This is done
via ASDF's asdf:*system-definition-search-functions*
mechanism, which controls how ASDF finds systems.
Neither Quicklisp nor ASDF are required to load a bundle. ASDF
will be loaded on demand
via CL:REQUIRE
,
and Quicklisp is not needed for loading the bundled system.
Available systems
A newly-created bundle provides the systems indexed by its system-index.txt file.
It also includes a directory, local-projects, into which files and directories may be placed. Any file in the local-projects directory tree matching "*.asd" is added as a loadable system. These systems take precedence over systems in the system index file; if a system named "foo" is available both in the index and the local-projects directory, the local-projects version is loaded.
If two system files in the local-projects directory tree have the
same system name, the one with the shortest pathname
namestring takes precedence. When the two pathnames have the same
length, the one with the lesser (as determined
by CL:STRING<
) pathname takes precedence.
Loading more than one bundle
When more than one bundle is loaded, the systems of the most recently loaded bundle take precedence.
Reloading a bundle
A bundle can be loaded any number of times; each time it is loaded, its systems move to the front of the precedence list.
Overwriting a bundle
When given a to argument that points to an existing
bundle, BUNDLE-SYSTEMS
will delete and recreate the software directory, and overwrite
bundle.lisp and system-index.txt. The local-projects directory and
any other files in to are left unchanged.
When passed :overwrite
nil
, BUNDLE-SYSTEMS
will signal a continuable
error of
type QL-BUNDLE:BUNDLE-DIRECTORY-EXISTS
.
Detecting updates
When looking up a system, the bundle system search code checks the timestamp of system-index.txt file and the local-projects directory. If either has an updated filesystem timestamp, the index is reloaded or the directory is re-scanned before continuing with the system lookup.
This allows the automatic detection of simple changes to a bundle's contents. If this automatic detection fails to pick up an expected change, the bundle itself can simply be reloaded to force an update.
Disabling bundles
Bundles are implemented by adding a symbol named
"QL-BUNDLE-SEARCHER" to
ASDF's ASDF:*SYSTEM-DEFINITION-SEARCH-FUNCTIONS*
list. To disable all bundles, that symbol can be removed from the
list. Loading another bundle will re-initialize the bundle system
from scratch.
Interface
[Function]
ql:bundle-systems
system-names
&key
to
overwrite
include-local-projects
=>
bundle-loader-pathname,
bundle-object
Creates a system bundle for system-names in the directory to.
For each system named by system-names, and each system required by those systems, recursively, unpacks the release archive in the
software/
subdirectory of to.If any system is not available via Quicklisp, signals an error of type
QL-BUNDLE:SYSTEM-NOT-FOUND
If overwrite is true (the default) and to already exists, deletes its
software/
subdirectory before unpacking.If overwrite is false and to already exists, signals a continuable error of type
QL-BUNDLE:BUNDLE-ALREADY-EXISTS
.If include-local-projects is true, each directory in ql:*local-project-directories is copied into "bundled-local-projects/" subdirectory of the bundle. Each local project directory is assigned a number in sequence from 0, and copied into a subdirectory named after that number. The number is used to avoid clashing references to local projects, which may have arbitrary names on the filesystem.
Returns the pathname to the bundle loader file as its primary value, and the bundle object itself as the secondary value.
The bundle object can be used with
QL-DIST:PROVIDED-SYSTEMS
andQL-DIST:PROVIDED-RELEASES
to get an exact list of its contents.
[Condition]
ql-bundle:bundle-directory-exists
This condition is signaled when
QL:BUNDLE-SYSTEMS
is given:overwrite nil
and the to argument refers to a directory that already exists.The directory in question can be accessed with the
QL-BUNDLE:BUNDLE-DIRECTORY-EXISTS-DIRECTORY
function.
[Condition]
ql-bundle:system-not-found
This condition is signaled when
QL:BUNDLE-SYSTEMS
is given a system name that is not available via Quicklisp.The system name in question can be accessed with the
QL-BUNDLE:SYSTEM-NOT-FOUND-SYSTEM
function.