Lars wonders about debhelper's approach of inserting script fragments into package maintainer scripts.
It's really very interesting to survey debhelper's collection
of fragments, in its autoscripts
directory. Of the 55 fragments,
the mean length is 4.5 lines, and the mode (and also shortest[1])
length is 3 lines.
The 32 scripts that are each three lines follow a very simple pattern:
if [ "$1" = something ] && exists some-script; then
some-script some-parameters
fi
It would be nice to get that down to Lar's more declarative one line approach:
some-script some-parameters $@
In practice though, many of these scripts are not always available, and so the postinst has to test for them before running them. And making them test the postinst's parameters to see if they should do anything makes them less general and less flexible (ie, not able to be run easily by a sysadmin), and so keeping the "$1" test in the postinst is reasonable.
So, I think I've done a pretty good job at keeping debhelper script
fragments short and keeping most of the possibly buggy bits that might need
maintenace out of debhelper. The exceptions tend to be either older
scripts, from a time when I was less careful about doing do, and fragments
of code that I could not pawn off onto some other package, often because
there was no package that owned the issue. (The dh_usrlocal
code
is the best example of that.)
The most promising way to improve things seems to be using dpkg triggers, which is why I was very enthuisiastic when we finally got them, over a year ago. Triggers let many of these hooks into maintainer scripts go away completely. Rather than each package having to test for and call update-menus, menu can simply trigger on the modification of any menu file. Once menu finishes the conversion to using triggers, debhelper can drop those fragments entirely.
Triggers seem likely to be able to eliminate well over 90% of the things we need to put into maintainer scripts, and I hope at least half of debhelper's script fragments can eventually go away thanks to them. The others seem more difficult.
You probably cannot, for example, make a trigger that does something sane when an init script is installed. Debhelper has at least three different fragements that it can put into postinst scripts to handle init scripts, and these only cover the most common three cases (start, don't start, don't restart on upgrade).
Moving even these things into a declarative form has long been a dream of mine. Maybe it could be done with a control file that specifies which of the methods for running the package's init script to use for this package.
But it seems we can't do away with maintainer scripts entirely, no matter how hard we try. That's because maintainer scripts are our only way to deal with other crippling bugs in old versions of a package, and with upgrade issues, and with all the other myriad things that we put custom code in them to deal with. Pity.
[1] Slight oversimplification; two scripts cram the 3-line form in one line for no good reason and are counted as 3-lines above.
You mention that maintainer scripts deal with bugs in old versions, and upgrade issues. How many of those bugs or upgrade issues would actually come up if the packaging format inherently described everything about the package in the first place? If you declaratively describe alternatives, you won't have problems like dangling alternatives or improperly cleaned-up alternatives from old versions, because the alternatives will get handled properly on upgrade, and anything done by the old version will go away. The same goes for symlinks, permissions, hooks, .d directories, triggers, and everything else.
In general, I think the vast majority of the problems with packages that maintainer scripts have to fix come down to this: order shouldn't matter. If I have a system with a given set of versioned packages installed, it should never matter how I got there; I should always have precisely the same system. Upgrades should give the same result as new installations, or even downgrades.
His concern isn't about maintainer scripts in general, it's a concern that dozens or hundreds of packages will need to be rebuilt if there's an bug in one of the snippets that debhelper inserts. The fact that most of the snippets are only 3 lines long, checking for the existance of a script and then farming out work to that script is a very good sign.
Making more snippets like that would help his cause as well. For example, take the dh_usrlocal code. If there's a debhelper-runtime package (e.g. in the base system), that the inserted code could belong to, then dh_usrlocal's code could be replaced by a 3-liner that checks for and calls that script. If there are 3 common ways that debhelper calls initscripts, each one could be pushed into a script in debhelper-runtime, and a 3-liner could be used to call the appropriate script. Not that this is always possible. For example, it appears that prerm-pycentral has 2 paths: one that calls pycentral to do the work, and the other (longer path) that does cleanup when python and pycentral are not available. If pycentral is not available, then chances are that whatever package has the dependency for the 3-liner is also not available.
(I'm not coming to advocate for action, just to clarify his position)
I don't plan to ever make something like a debhelper-runtime package, but if someone wants to take some of the autoscripts that are a bit long due to doing things manually, and create utilities to do those things, I'd gladly make debhelper run those utilities.
There are also some things like the standard conffile removal/rename code that need to stop being copied off the wiki into each package that uses them, and and put into some utilities.
Making something like the alternatives system declarative seems hard to me. That's why debhelper doesn't handle alternatives, because I need a semi-declarative format for a
debian/alternatives
file for adh_alternatives
to work on.Note that triggers implicitly make things declarative. Ie, by including a menu file, a package declares that it has a menu item, and the menu system triggers to update whatever needs updating.