Hey, Sean mentioned your discussion about triggers, and I ended up first thinking that it might mean triggers wouldn't work for our purposes, but
now I'm not so sure, and wondered if you might have time to discuss that
a bit. (However, if you don't have time for this right now, no
worries.)
What led us to the current attempt to rework emacsen-common / emacs
policy is the realization that dpkg doesn't actually promise much about
the state of a package's dependencies during maintainer script
invocations, outside of "postinst configure",
One thing I wondered about was this triggers.txt statement:
Packages in t-awaited and t-pending demand satisfaction of their
dependencies just like packages in installed.
Does that mean that all of the dependencies of a package in one of those states should be past their postinst configure, or something else?
So one of the options I've been considering is to switch to triggers
(and dropping the attempt to promise that once an add-on's postinst
configure finishes it's "ready").
Given (A) above, I was pondering the possibility of having some
idempotent "rebuild" trigger that would (assuming we can) just examine
what add-ons and flavors are ready (i.e. successfully past their
postinat configures), and rebuild any combinations that are stale[2].
Both flavors and add-ons would trigger "rebuild".
Of course there are many variants of the idea, depending on what exactly
our existing semantics allow.
[2] One option might be to just do nothing in the trigger until it is
invoked when the entire add-on tree is past all of the add-on
postinst configures, and then rebuild everything that needs it --
i.e. instead of trying to rebuild stale add-ons in any *subtrees*
that are ready during intermediate trigger invocations.
I'm not sure why that's a problem for emacs addons. In this scheme
you only need to run *compilation* of some addon during that addon's postinst, and the postinst of the emacs flavour. In each case you can
do processing only of packages that are `configured`, plus this one.
The cleanup tasks don't seem like they'd need much in the way of
working dependencies.
However, note that dpkg does *not* bring packages out of `installed`
just because their dependencies regress to less good states, provided
the dependency isn't actually removed.
ISTM that you ought to aim to promise that once an add-on is in state `installed` it is ready (subject to the caveat above). That would
mean any things that invoke the addon, and Depend on it, will work
properly.
Let's consider three packages: emacsen package E (of some flavour);
addon packages A and B where B uses features from A.
When we reinstall A we need to rebuild both it and B.
We could achive this by doing it in A's postinst but in a large run
it'll probably have to done again later, eg if emacsen are being
updated too.
Realistically, E must be interested in A, so that A gets rebuilt. (We
don't want to do this the other way around, because that would cause
an emacs to be considered not-`installed` simply because some addon
hadn't been compiled.)
If we update E, E's postinst will need to rebuild both A and B. So
E's postinst needs to be able to do a topological sort of the addons,
so that it can compile them in the right order.
Given that E's postinst can do the sort, it can reliably recompile everything.
dpkg tries to defer trigger processing. And you mustn't "defer work"
and return success from a trigger processing postinst invocation,
since you might never be called again. (I guess you could manually
retrigger but this seems fraught and also unnecessary.)
As an example related to the failures that precipitated all this, the
current emacs policy requires all add-ons to depend on emacsen-common,
and for them to call its commands at various points to handle installs/rebuilds and removals. i.e. emacsen-common is the
library/subsystem that handles all the dependency ordering, etc.
But that's just wrong if you can't assume much about the state (or even availability) of emacsen-common from those maintainer scripts, i.e. when
we designed all this, I would never have guessed that even if you depend
on emacsen-common, it might not actually be ready (or even unpacked)
from say your prerm.
It's also perhaps worth noting that we don't actually care about
triggers per se. I'd just started looking at them when among other
things, I wondered if they might be able to eliminate the need for our
own (currently a bit sketchy) dependency ordering.
Realistically, E must be interested in A, so that A gets rebuilt. (We don't want to do this the other way around, because that would cause
an emacs to be considered not-`installed` simply because some addon
hadn't been compiled.)
Without having thought about it carefully -- that might be OK...
i.e. it might be fine if the whole system (add-ons and flavors) comes
out of "up to date" for a bit, as long as it re-converges eventually.
If we update E, E's postinst will need to rebuild both A and B. So
E's postinst needs to be able to do a topological sort of the addons,
so that it can compile them in the right order.
Given that E's postinst can do the sort, it can reliably recompile everything.
But from E's postinst, we have no idea what state the add-ons are in?
And if so, and we had to be "completely conservative", the most we could
do is rebuild any dependency graph sub-trees we could find where the
add-ons were past their "postinst configure"s ... and then we'd have to ensure we get to the rest later somehow.
One correct solution might involve some command we know will always "run last" in any given apt/dpkg run, and I'd wondered if triggers might be
able to support that.
I think I have a better handle on what dpkg promises with respect to dependency states from maintscript invocations, i.e. generally, not
much, in the limiting case, outside "postinst configure" (and now maybe "postinst triggered"). There it's likely, and as likely as it'll ever
be, that your deps will be configured -- elsewhere, not so much.
I'd also like to understand what we might be able to count on with
respect to triggers. For example, is it plausible to put them in
roughly the same class as "postinst configure" with respect to the dependencies will be available/configured there?
# Overview:
The general approach is to maintain relevant state files in /var/lib/emacsen-common/..., to manipulate those to reflect changes, and
to then trigger all the add-ons to re-evaluate the state to accommodate changes (in some cases, an add-on will decide there's nothing to do).
# Approach:
Have an "installed" state file for each emacs flavor that's touched
whenever that flavor is changed and only exists if the last postinst configure/triggered for that flavor was successful, i.e. it indicates
whether add-ons should consider that flavor when building.
Whenever a flavor changes, trigger emacsen-common-add-on-assess-rebuild
All add-ons will be sensitive to that trigger, and will use the
installed state files to reinstall for the relevant flavors.
According to https://www.debian.org/doc/debian-policy/ch-maintainerscripts.html the dependencies will have previously been configured and not removed.
I'm not sure what state you found they were in but I would bet against
there being a dpkg bug in this area.
Can't you look in the filesystem? I would do this by having E's
postinst look in /usr for what things to compile. It doesn't need to
know the dpkg status.
I don't think this is the right approach. Instead, recompile
everything that is physically present. This ought to work right for
anything that's not "half-installed", and in that case it can (and
should be) fixed by reinstalling the half-installed package's .deb.
In the meantime E's trigger run can fail. (But "half-installed" is
very rare.)
The trigger system arranges that the hook you provide will run *again*
if it didn't run last. Ie, it must tolerate being run not-last, but
if anything *else* happens to trigger it after that, it will run
again.
I think this is the only reasonably plausible semantics (and it's
sufficient for your purposes).
You want to be very careful with any separate state you maintain.
That can make things significantly more complicated. By recording
state separately, you introduce the possibility of bugs where the separately-recorded information is wrong (ie, doesn't reflect the real
state of the system).
(This doesn't prevent you from putting the code for the compilation
framework into a common package; the flavour's postinst can call it.)
The trigger system works better when central packages are interested
and leaf packages do the triggering. This proposal inverts that.
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 429 |
Nodes: | 16 (2 / 14) |
Uptime: | 115:48:57 |
Calls: | 9,056 |
Calls today: | 3 |
Files: | 13,395 |
Messages: | 6,016,442 |