Ian Jackson <ijack...@chiark.greenend.org.uk> writes:

> 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.

A general issue is that the current approach was designed with incorrect
assumptions, so any of the corner cases (and not so corner cases) that
we'd thought through carefully when it was established might now (and
are likely now to) be broken.

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.

That was a surprise, and means we have to come up with an approach
that's sound given what actually *is* promised, and at least as far as
dependencies go, it sounds like the only place you can (nearly
always(?)) count on your dependencies is "postinst configure" (and from
the triggers docs, I'd thought now maybe also "postinst triggered").

> 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.

Hmm, what kind of "less good state"?

> 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.

Oh, of course -- that's how the entire current policy is designed.  It
was set up to make as few assumptions as possible about what an emacs
flavor or add-on might need to do to configure or clean itself up, while
also providing an inter-add-on dependency respecting install/removal
process.

...but now that we have a lot more experience with add-ons, it could be
that we don't actually need such a general mechanism, and if so, that's
a possibility worth keeping in mind, in case it allows simpler
solutions.

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.

> 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.

The bigger issue I'd have imagined is that the state of B is not known
at that point?

> 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.

Particularly if (as may well be the case now for most flavors and
add-ons), the packages still "work fine" in the interim.  Say if the
install/remove process really was just recompilation, and the preinsts
could adequately clean everything up, then in that arrangement, the
worst you might get is some extraneous per-user compilation artifacts if
a user were to run an emacs flavor before all the recompilations were
finished.

> 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.

> 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.)

I think retriggering might be necessary for the "goes last"
approach(es).


Overall, of course, I'd like to understand the facilities we currently
have available, and exactly what they promise while reasoning about
solutions.

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?


More concretely, and for any who haven't seen it, included below is one
tentative idea we had been considering as a possible way to use triggers
to fix the current issues.

Don't take the specific details too seriously yet, and I would love to
find out that we/I'm just over-complicating things somehow.  (If it
actually is a sensible approach, I do have some of the code sketched
out, and it also has some bits in common with the current
policy/implementation.)


# 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).

We currently assume that "postinst triggered" invocations are as likely
to have the package dependencies configured as "postinst configure".
Some testing has suggested that's the case (e.g. invocations were
ordered with respect to dependencies), but if that's not generally true,
then this approach may not be suitable.  This arrangement has the
advantage of letting the packaging infrastructure handle the dependency
ordering as compared to the current implementation where we try to parse
dpkg deps output, tsort any add-ons found, etc.

# 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.

Have a "configured" state file for each add-on that exists whenever the
package has been successfully (postinst) configured.  It may or may not
be installed for every flavor yet.  It may also not exist if the add-on
is out of date with respect to its dependencies.

Have a per-flavor "installed" state file for for each add-on that's
touched whenever that add-on is successfully installed for the given
flavor.  i.e. if it doesn't exist or is stale relative to the flavor's
corresponding state file, then we need to reinstall for that flavor.

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.

Whenever an add-on changes, remove the configured files for all reverse
dependency add-ons, and trigger emacsen-common-add-on-assess-rebuild.

Each add on and flavor package must include the relevant (empty)
emacsen-common state directories.

# Background:

https://people.debian.org/~srivasta/MaintainerScripts.html#sec-6
https://www.debian.org/doc/debian-policy/ch-maintainerscripts.html#summary-of-ways-maintainer-scripts-are-called

Thanks
-- 
Rob Browning
rlb @defaultvalue.org and @debian.org
GPG as of 2011-07-10 E6A9 DA3C C9FD 1FF8 C676 D2C4 C0F0 39E9 ED1B 597A
GPG as of 2002-11-03 14DD 432F AE39 534D B592 F9A0 25C8 D377 8C7E 73A4

Reply via email to