Date: Tue, 31 Oct 2000 23:59:47 -0800 From: Tim Kientzle <kientzle@acm.org> To: "Daniel C. Sobral" <dcs@newsguy.com> Cc: Patrick Bihan-Faou <patrick@rageagainst.com>, libh@FreeBSD.ORG Subject: Making the Packages System Better Message-ID: <39FFCD73.7364C2BF@acm.org> References: <39DCC860.B04F7D50@acm.org> <20001006155542.A29218@cichlids.cichlids.com> <39F3CDD7.15B889E7@acm.org> <20001023190412.B507@cichlids.cichlids.com> <39F47E98.4BB647AA@acm.org> <20001023202244.B10374@cichlids.cichlids.com> <39F48F4A.38D458C2@acm.org> <39FCF244.5A8C8E59@newsguy.com> <39FDC12E.304B0011@acm.org> <39FE2406.150CA3B1@newsguy.com> <00cb01c042f1$1a347190$040aa8c0@local.mindstep.com> <39FE562C.714DBE7C@newsguy.com>
next in thread | previous in thread | raw e-mail | index | archive | help
"Daniel C. Sobral" wrote:
> Somehow I dislike PATHs, MANPATHs and LIBPATHs with 40 or 50 entries, I
> dislike a /usr that won't fit in one screen, I dislike having programs
> all over the place, I dislike having to edit /etc every time I want to
> make a new program available, and I specially dislike having to instruct
> users in setting up their accounts to be able to use a new program .
The following is an outline of an approach to package management
that addresses all of these concerns, does not require a package
database, and involves minimal automation. Just to make things clear,
I'm specifically talking about pre-compiled packages such as would
be downloaded from the FreeBSD website or installed from a CD-ROM.
1) Each package resides in it's own private directory.
E.g., "foo" version 3.4 resides in /usr/packages/foo-3.4/
From here on, I'll refer to /usr/packages/foo-3.4/ as PREFIX.
2) Certain directories within PREFIX have special meaning.
PREFIX/bin - user binaries
PREFIX/lib - programming libraries
PREFIX/man - man pages
PREFIX/include - C/C++ include files
PREFIX/rc.d - boot-time startup scripts
<others may be required>
Directories not on this list have no special meaning and
can be used however the package wants to use them.
3) Special link directories are created for those recognized
directories:
/usr/packages/bin contains symlinks to /usr/packages/*/bin/*
/usr/packages/lib contains symlinks to /usr/packages/*/lib/*
/usr/pacakges/man/... tree contains symlinks to corresponding files
in /usr/packages/*/man/...
/usr/packages/include contains symlinks to
/usr/packages/*/include/*
... etc ...
Only recognized directories have their contents symlinked.
For example, PREFIX/private is never symlinked, nor is
PREFIX/libexec or PREFIX/libdata or any other directory not on
a particular list. This is an important point.
Several important things to note here:
* User paths, MANPATH, LIBPATH, etc, do not ever need to be augmented
when new directories are added, since those paths will all use the
link directories.
* Package installation/deinstallation/upgrading are pretty
trivial. The only significant automation needed is to
build/maintain the link dirs.
* Tentative upgrades are fairly simple: /usr/packages/foo-3.5/ can
be installed without first removing /usr/packages/foo-3.4/
(A little intelligence in building the link directories
obviously helps here, but nothing unreasonable.) In comparison,
supporting tentative upgrades with the current approach requires
the ability to archive all updated files individually and restore
them for a rollback. (Question: do you correctly handle files
that existed in the previous version but not the new version?)
* Rolling back an incomplete install is trivial: just delete the
directory.
With the current system, rolling back an incomplete install
requires that you make copies of any overwritten or altered files
and keep track of each file that does get installed. A crashed
incomplete install is an ugly mess with the current defaults.
* No temporary directory is needed, since a new directory
is created for each package. If the package name isn't known in
advance, you can create a temporary directory in /usr/packages
and just rename it when the final name is known. Similarly,
package archive creation is much simplified (no need to fake
a directory heirarchy).
* Some packages will obviously have to touch files outside of
their directory; this could be handled in several ways, the easiest
is to have an "install" script in the PREFIX dir and execute it
after unpacking.
* Dependency handling is very efficient, even with networked installs.
You can pull down a package and unpack it directly into it's PREFIX
dir, then test dependencies and recursively install those
dependencies.
By executing the "install" script and updating link directories as
the recursion unwinds, you ensure that the visible parts of the
installation are done in the correct order without requiring any
temporary storage and without ever having to pause a download in
progress. In contrast, the current system requires you to either
stop the current download to handle the dependency or have multiple
pending installs sitting in temporary directories requiring additional
disk space. (This is admittedly a subtle point. ;-)
* The symlink directories should only contain symlinks and
never contain actual files. Otherwise, you run into some
confusing maintenance issues. (Learn from database design:
don't mix derived data and primary data.)
* Packages should be compiled directly for their specific PREFIX.
Files outside of the "special" directories do not get symlinked.
Among other things, this avoids a lot of filename conflicts.
(Two different spelling packages that have a "dictionary" file
in PREFIX/private/dictionary won't conflict since that file
doesn't need to be symlinked.)
The basic principle: packages should keep their guts to themselves.
In essence, the symlink directories are just how a package
publicizes it's public interfaces.
* This does not require any changes to the existing "ports"
collection as long as all ports are PREFIX-aware. They
can just be compiled with package-specific PREFIXes.
* The symlink dirs should probably build shadows of any
directories. E.g., /usr/packages/tcl-8.0/lib/tcl/xxxx
should result in a real dir /usr/packages/lib/tcl/
with symlinks to corresponding files. That allows several
tcl packages to have files within .../lib/tcl/
* Often, you need no special utilities at all with this scheme.
For example, a list of installed packages: ls /usr/packages
Building/maintaining the link directories is a pretty simple
exercise in walking a directory heirarchy that can be cribbed
from any number of sources. As a crude first cut, you can simply:
cd /usr/packages/bin && ln -s ../*/bin/* .
But that rapidly runs into argument-length limits. Besides,
it's much faster to compare the existing symlinks to the
desired symlinks and only alter the ones that have changed
(delete symlinks that point to deleted packages or add new
symlinks). Updating all of the symlink directories shouldn't
take more than a second or two. I have Perl code that does
most of this if you're interested (although it could be improved
by adding full shadow-dir support).
In short, I'd argue that this approach is significantly simpler
than the current package tools: it doesn't require a database;
it makes it easy to provide such advanced features as
rollback, recovering failed installs and tentative upgrades.
I'm fairly confident that tools to support this approach would
be much simpler than overhauling the existing tools to provide
such features. However, note that such tools would not work
with the current /usr/local tarpit, since they rely heavily on
the assumption that each package goes into its very own directory.
If you must support the /usr/local tarpit, then you've got some
ugly coding ahead.
Comments?
- Tim Kientzle
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-libh" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?39FFCD73.7364C2BF>
