The -r
option to
%preun
,
%postun
,
%triggerun
,
and
%triggerpostun
scripts
indicates that the package's required resources must be present when
running the script.
Although that seems to be a natural requirement, doing so may require
significant extra disk space when upgrading packages.
Therefore, LPMtool bends the rules a little bit and ignores the package's
required resources when running uninstallation scripts, by default.
The -r
must be explicitly specified in order for LPMtool to
do everything by the book.
This also includes some other package's
%triggerun
and
%triggerpostun
that are triggered by this
subpackage.
This chapter explains the problem with taking into account a package's required resources, when running uninstallation script. This chapter uses an example of two related packages: the main package, and a subpackage which requires some resources from the main package.
It is common to have subpackage that requires resources from the main package. Consider a package called “gizmo” and a subpackage called “gizmo-server”. Subpackages typically have a listed dependency on the main package. Therefore the existing package “gizmo-server” version 1 requires the existing package “gizmo” version 1.
Let's see what happens during an update of these packages to the next version. The new packages are “gizmo” version 2, and “gizmo-server” version 2, which requires “gizmo” 2.
LPMtool begins the update process by creating two transactions:
Upgrade “gizmo” version 1 to “gizmo” version 2.
Upgrade “gizmo-server” version 1 to “gizmo-server” version 2.
Each upgrade transaction consists of two steps: install the new package, then uninstall the old package. Therefore, the two transactions are:
Install “gizmo 2”. Uninstall “gizmo 1”.
Install “gizmo-server 2”. Uninstall “gizmo-server 1”.
LPMtool will normally choose the order of transactions that preserves all existing requirements and dependencies at each step of the process. LPMtool now needs to choose the order in which these two transactions will be processed. LPMtool computes the transaction order by considering the dependencies of all the involved packages:
Version 2 of the “gizmo-server” subpackage requires version 2 of “gizmo”, therefore the main package has to be upgraded first. Otherwise, if “gizmo-server” subpackage is upgraded first, at the end of the first transaction there's going to be a version 2 of the subpackage installed together with version 1 of the main package, but the subpackage needs version 2 of the main package, which is not installed yet.
Therefore, the first transaction needs to be processed first, to upgrade the main package before the subpackage. Although this is a natural observation, it is important to understand the technical requirements that make it necessary.
The first transaction upgrades the main package from version 1 to version 2. After processing the first transaction, version 2 of the main “gizmo” package will be installed, but version 1 of the “gizmo-devel” subpackage will still be present. Version 1 of “gizmo-devel” isn't removed yet; it's only scheduled for uninstallation by the second transaction. However, version 1 of “gizmo-devel” requires version 1 of the main “gizmo” package. Therefore “gizmo-devel” must be uninstalled before uninstalling the main “gizmo” package. When package “X” requires package “Y”, and both packages are slated for uninstallation, LPMtool must remove package “X” first. Even though package “Y” gets removed immediately after “X”, that's not good enough.
Therefore, the second transaction needs to be processed first, according to this dependency.
When LPMtool encounters such a circular dependency - two transactions that mutually require each other to occur first - LPMtool solves the circular dependency by merging both transaction into a single transaction:
Install “gizmo 2”. Install “gizmo-server 2”. Uninstall “gizmo-server 1”. Uninstall “gizmo 1”.
When more than two transaction are mutually dependent on each other, they are also merged together into a single transaction.
Naturally, if the “gizmo” and “gizmo-server” packages contain 5Mb worth of data in each package, only 5Mb of extra disk space is required to upgrade both packages in two separate transactions:
Install the newer version of the first package, using up the extra 5Mb of disk space.
Uninstall the older version of the first package, freeing up 5Mb of disk space used by the older version.
Install the newer version of the second package, using up the extra 5Mb of disk space.
Uninstall the older version of the second package, freeing up 5Mb of disk space used by the older version.
Merging both transactions will now require an extra 10Mb of disk space instead of five, because both new packages now get installed before the old packages get removed.
The amount of disk space required to upgrade an arbitrary
list of packages can be
estimated by the following formula:
N
-O
+L
, where:
N
Total estimated disk space used by the new packages.
O
Total estimated disk space used by the old packages.
L
Total estimated disk space used by the new packages in the largest transaction, disk space-wise.
Nearly all subpackages require the main application package to be installed first. It's not unusual for large applications to have four, five, or even more subpackages. If LPMtool were to follow the dependency rules strictly, every upgrade of the main package and all of its subpackags would have to be done as a single, merged, mega-transaction. Therefore, LPMtool bends the rules a little bit in order to avoid having to merge all transactions into one big mega-transaction that requires a large chunk of disk space.
Therefore, dependencies of a package that's slated for uninstallation will only
be considered if there's an uninstallation script with the -r
option.
If an uninstallation script wasn't provided, the only thing LPMtool will do is
remove a bunch of files.
Since nothing
gets executed before or after the fact,
it should be fairly safe to remove
the files.
The default bending of the dependency rules should be
sufficient to break the circular dependency in nearly all cases,
causing LPMtool to upgrade the main package and subpackages as separate,
smaller transaction.
There's an exception to the exception.
LPMtool will consider all dependencies, without considering the presence or
absence of uninstallation scripts, when LPMtool is invoked only to remove
packages (the -e
option to lpm).
Therefore, when packages are removed completely (as opposed to updating or
installing packages), the subpackages will always be uninstalled first.
There are some extremely marginal situation where bending the dependency
rules in this fashion will end up breaking something.
To force LPMtool to properly consider all dependencies, specify an empty
%postun
or %preun
script, and
give the -r
option:
%postun -r :
Before doing that, however, examine closely the requirements of all involved packages. Chances are that LPMtool does not pick up some requirement automatically, and it should be explicitly added using the “Requires:” header.