omniosorg / pkg5

Image Packaging System
https://omnios.org/
Other
12 stars 56 forks source link

new depend action type that installs only on update for splitting up packages #455

Open jclulow opened 1 year ago

jclulow commented 1 year ago

Consider a large package that has many loosely related drivers:

We'd like to be able to take the derelict driver out into a new package, pkg:/driver/derelict, while leaving the others alone for now. The end result should look like:

Distributions generally have a metapackage that contain a list of driver packages that are relevant to the install media or system they are producing; ideally this need not be all drivers. As part of building new illumos packages, a distribution could include (if they wish!) a depend type=require action in their metapackages and the driver would then be explicitly included in media. Because pkg:/barge does not depend on the new pkg:/driver/derelict, new distribution releases are able to exclude the driver in question if it is not relevant to them, thus reducing the size of the software in their base install.

Unfortunately, this falls down for updating existing systems. If you had pkg:/barge@1.0 previously, you would have had (and could have been depending upon!) the driver derelict shipped in that package. Once your system updates to pkg:/barge@1.1, that driver is no longer in that package, and will be removed from the disk! If you needed that driver to boot, your system would not boot any longer.

The classical strategy for dealing with this is to make the old package, which is being split up, depend on the new package; i.e.,

This is regrettable, because it is not possible, then, to install barge without getting derelict, thus ultimately defeating the point of splitting up the packages in the first place.

Another option is to split up barge even more completely and turn the old package into a meta-package itself; e.g.,

Distribution meta-packages would then be altered not to install pkg:/barge at all, and instead install the subset of the new packages which are relevant. End users could ultimately uninstall pkg:/barge at their leisure, provided they don't uninstall whichever of the drivers are useful to them, and also don't use the relatively recent pkg autoremove functionality which uninstalls packages that were not themselves explicitly marked as manually installed by the operator.

This is not ideal, though, for all cases; e.g., if you're trying to remove portions of a package that is itself a legitimate package that needs to continue to exist; e.g., /system/kernel.

What I think would be neat instead is a new action type: depend type=upgrade which would, when put on the package pkg:/barge:

This would afford us a one-time installation of pkg:/driver/derelict, on upgrade of pkg:/barge across the transition where it was split out, that would not keep bringing it back from the dead if the user decided themselves to uninstall it.

citrus-it commented 1 year ago

I know this doesn't quite do you what you need in terms of how it would be done in a change to illumos-gate, but one way that you can already do this, is using the origin dependency type. I think this is the cleanest solution but it needs an interim update.

For example:

pkg:/barge@1.0
    driver flotsam
    driver jetsam
    driver lagan
    driver derelict

pkg:/barge@1.1
    driver flotsam
    driver jetsam
    driver lagan
    depend type=require fmri=driver/derelict

pkg:/driver/derelict@1.1
    driver derelict

pkg:/barge@1.2
    driver flotsam
    driver jetsam
    driver lagan
    depend fmri=barge@1.1 type=origin

The nub of this is that we aren't allowed to update to barge@1.2 except from barge@1.1, which will have installed derelict for us. It doesn't help with flagging the package as manually installed, but that's pretty standard for packages that deliver drivers, although with no dependencies we do have to think about the impact of autoremove.

I was surprised that there's nothing in the test suite for this, so I added a test based on this example in https://github.com/omniosorg/pkg5/pull/456 and it passes:

% pfexec ./run.py -o TestPkgApiInstall.test_origin_depend

Tests in progress:
        0       7013    api.t_pkg_api_install.py TestPkgApiInstall
Estimated time remaining 4 seconds

Finished api.t_pkg_api_install.py TestPkgApiInstall in process 0
Total test classes:1 Finished test classes:1 Running tests:0
Total tests:1 Tests run:1 Errors:0 Failures:0 Skips:0

Another way to address this may be to extend the pkg.additional- attributes, to allow a few more options than just to update or uninstall. And yet another way could be if we added new dependency type of reverse-conditional, leading to something like:

depend fmri=derelict type=reverse-conditional predicate=barge@1.1

That is, install derelict if barge@1.0 is not installed. Once we're on barge@1.1, the predicate would no longer be true.