Steve and I have been discussing a general overhaul of the package
system which is necessary to solve some of the problems that have
shown up over the past. Examples are Didier's gripes, Valdis's
comments, the ps-print mess, different tracks of Gnus
etc. etc. etc. which the current system does not handle gracefully.
Here's the rough draft for a new package system design. I tried hard
to address all reasonable issues posted over the past. I'd appreciate
if people, before yelling at me because of problem X I've forgotten,
would first ask me how to solve problem X in this framework. Chances
are fair that I'll have an answer.
Let me know what you think.
This is from scratch. Forget the current layout, forget about the
current handling of auto-autoloads etc. etc. etc.
A package is a collection of files constituting an extension to
XEmacs that may be optionally installed or uninstalled as a unit. A
package has the following properties:
- a name (a symbol)
- a description
- a version (a string "<major>.<minor>")
- an author version (a string, free format)
- a maintainer (a string)
- a predicate indicating whether it can run in a given incarnation of
Emacs
- a list of package specifications (see below) which must be satisfied
for the package to be able to compile
- a list of package specifications (see below) which must be satisfied
for the package to run
(I did not worry about things like checksums, as I'm not an expert on
that stuff, but they are supposed to be in there as well.)
The following constraint must hold:
Two different author versions of a package must have different
versions as well.
A package is distributed as a directory hierarchy; all files belonging
to one package live under that directory, no other files do. The name
of the directory uniquely identifies the name of the package as well
as its version. Apart from that property, the name of the direcory is
completely free-format.
The layout of a package is essentially as before. The subdirectory
names recognized by XEmacs are the following:
etc
info
lib-src
lisp
man
Moreover, it contains a file specifying the above attributes.
An extension of the old package-info would do nicely.
A package drops into a *package hierarchy* which is just a directory
containing package directories. A package hierarchy has the
following properties:
- a predicate indicating whether its packages can run in a given
incarnation of Emacs
Installation happens simply via dropping a package into a package
hierarchy, uninstallation happens via removing its directory. There
are no associated database files which must be held consistent.
From within the package system, specific packages can be identified
via *package specifications*.
Here is the syntax for package specifications:
<package-specification> -> <package-name>
| (<package-name> <package-property>?)
<package-property> -> (version <version>)
| (at-least-version <version>)
| (at-most-version <version>)
| (and <package-property>*)
| (or <package-property>*)
| (not <package-property>)
<version> -> <string-literal>
<package-name> -> <symbol>
The semantics is mostly obvious, hopefully. Do note that the mantissa
of version numbers is interpreted in a way different from that of
floating point numbers, but rather in the way common in the software
world. I.e., "1.10" denotes a later version than "1.2". Moreover, if
several packages match a package specification, the specification
identifies the one with the latest version.
Examples for package specifications:
gnus
(gnus (at-least-version "1.12"))
(efs (and (at-least-version "1.12")
(at-most-version "1.15)))
(gnus (not (version "0.84")))
API:
These are all necessarily macros because they deal with package
specifications. However, they transliterate trivially into function
calls such that their definitions will not have to change ever. Maybe
even the underlying functional interface can be exposed.
(package-present-p <package-specification>)
This tests if a package matching the specification exists. It has no
side effects.
(use-package <package-specification>)
This indicates a preference for a package matching the specification
to XEmacs. This means that, in the future, no other packages with the
same name may be used in the running XEmacs. It also has the
side-effect of making the package's autoloads available.
(require-package-feature <symbol> <package-specification>)
This is like `require', except that it doesn't require quoting and is
relative to a package specification where the feature must reside.
(provide-package-feature <symbol> <package-name>)
Like `provide', only relative to a given package.
(locate-package-directory <exp> <package-specification>)
(locate-package-library <exp> <package-specification> &optional ...)
(find-package-library <exp> <package-specification> &optional ...)
(load-package-library <exp> <package-specification>)
(locate-package-data-directory <package-specification>)
(locate-package-data-file <exp> <package-specification>)
(locate-package-executable-directory <package-specification>)
(locate-package-executable <exp> <package-specification>)
(locate-package-info-directory <package-specification>)
(locate-package-info-file <exp> <package-specification>)
These are all like the equivalent existing functions, except that they
are relative to a given package specification.
The existing functions continue to exist, but change their behavior:
Nothing related to packages shows up in the relevant ...-path and
...-directory-list variables. (I.e., package lisp subdirectories do
not end up in `load-path.) However, the relevant functions which used
to search in them still go through the package directories as a last
resort.