Diversions allow files from a package pkg-A to be temporarily replaced by files from another package pkg-B. When pkg-B is uninstalled, the files from pkg-A are put back into place.

For example, the vim-tiny package includes a small stub file in /usr/share/vim/doc/help.txt, which is renamed to help.txt.vim-tiny to make room for a fuller version when vim-runtime is installed. When vim-runtime is uninstalled, the help.txt.vim-tiny is renamed back to help.txt.

Diversions are a bit finicky. Consider whether a Conflicts relation or update-alternatives might be a better way to achieve what you are trying to accomplish.

Adding a diversion to a package

See Appendix G in the Debian policy manual.

In preinst, make sure the diversion is added in all cases. If you want to avoid spurious messages on upgrades, you can check for versions known to already include the diversion, or you can explicitly check whether the diversion already exists.

pkg=me
diversion_added_version=1.0.9-1
this_version=3.8-2

if
        test "$1" = install ||
        dpkg --compare-versions "$2" lt "$diversion_added_version" ||
        dpkg --compare-versions "$this_version" lt "$2"
then
        dpkg-divert --package "$pkg" --add --rename \
                --divert "/usr/share/foo.diverted-$pkg" /usr/share/foo
fi

In postrm, remove the diversion if and only if the package is being either removed or downgraded to a version before the diversion was added. On upgrades to a newer version, do nothing: the diversion is the new version’s responsibility now.

pkg=me
diversion_added_version=1.0.9-1
this_version=3.8-2

losing_diversion=n

if test "$1" = failed-upgrade
then
        dpkg --compare-versions "$2" le-nl "$this_version" ||
        # An upgrade from a newer version failed.
        # There is no way for us to know enough to take over from here,
        # so abort the upgrade.
        exit 1
elif dpkg --compare-versions "$2" lt-nl "$diversion_added_version"
then
        losing_diversion=y
fi

case "$1,$losing_diversion" in
remove,*|abort-install,*|disappear,*)
*,y)
        dpkg-divert --package "$pkg" --remove --rename \
                --divert "/usr/share/foo.diverted-$pkg" /usr/share/foo
        ;;
esac

Removing a diversion from a package

In postinst and prerm, remove the diversion. Since failed upgrades can change the version number without configuration succeeding, the last version configured is not a reliable indication of whether the diversion is still around. If you want to avoid spurious messages, you can check for the diversion before removing it.

pkg=me

if dpkg-divert --package "$pkg" --list | grep -F "/usr/share/foo.diverted-$pkg"
then
        dpkg-divert --package "$pkg" --remove --rename \
                --divert "/usr/share/foo.diverted-$pkg" /usr/share/foo
fi

Without perfect foresight, the prerm surely cannot recover from failed attempts to upgrade from a newer version. (Nor can any other package; arguably this is a flaw in policy.) So supporting such downgrades reliably requires a check.

this_version=7.1

if test "$1" = failed-upgrade
then
        dpkg --compare-versions "$2" le "$this_version" ||
        # An upgrade from a newer version failed.
        # There is no way for us to know enough to take over from here,
        # so abort the upgrade.
        exit 1
fi


CategoryDebianDevelopment