[[!template id=project

title="Undo support for pkgsrc"

contact="""
[tech-pkg](mailto:tech-pkg@NetBSD.org)
"""

category="pkgsrc"
difficulty="medium"

description="""
If one embarks on a set of package updates and it doesn't work out too
well, it is nice to be able to roll back to a previous state.
This entails two things: first, reverting the set of installed
packages to what it was at some chosen prior time, and second,
reverting changes to configuration, saved application state, and other
such material that might be needed to restore to a fully working setup.

This project is about the first part, wihch is relatively tractable.
The second part is Hard(TM), but it's pointless to even speculate
about it until we can handle the first part, which we currently can't.
Also, in many cases the first part is perfectly sufficient to recover
from a problem.

Ultimately the goal would be to be able to do something like
   pkgin --revert yesterday
but there are a number of intermediate steps to that to provide the
infrastructure; after that adding the support to pkgin (or whatever
else) should be straightforward.

The first thing we need is a machine-readable log somewhere of
package installs and deinstalls.
Any time a package is installed or removed, pkg_install adds a record
to this log.
It also has to be possible to trim the log so it doesn't grow without
bound -- it might be interesting to keep the full history of all
package manipulations over ten years, but for many people that's just
a waste of disk space.
Adding code to pkg_install to do this should be straightforward; the
chief issues are

* choosing the format
* deciding where to keep the data

both of which require some measure of community consensus.

Preferably, the file should be text-based so it can be manipulated by
hand if needed.
If not, there ought to be some way to recover it if it gets corrupted.
Either way the file format needs to be versioned and extensible to
allow for future changes.

The file format should probably have a way to enter snapshots of the
package state in addition to change records; otherwise computing the
state at a particular point requires scanning the entire file.
Note that this is very similar to deltas in version control systems
and there's a fair amount of prior art.

Note that we can already almost do this using
/var/backups/work/pkgs.current,v; but it only updates once a day and
the format has assorted drawbacks for automated use.

The next thing needed is a tool (maybe part of pkg_info, maybe not)
to read this log and both (a) report the installed package state as of
a particular point in time, and (b) print the differences between then
and now, or between then and some other point in time.

Given these two things it becomes possible to manually revert your
installed packages to an older state by replacing newer packages with
older packages.
There are then two further things to do:

Arrange a mechanism to keep the .tgz files for old packages on file.

With packages one builds oneself, this can already be done by having
them accumulate in /usr/pkgsrc/packages; however, that has certain
disadvantages, most notably that old packages have to be pruned by
hand.
Also, for downloaded binary packages no comparable scheme exists yet.

Provide a way to compute the set of packages to alter, install, or
remove to switch to a different state.
This is somewhat different from, but very similar to, the update
computations that tools like pkgin and pkg_rolling-replace do, so it
probably makes sense to implement this in one or more of those tools
rather than in pkg_install; but perhaps not.

There are some remaining issues, some of which aren't easily solved
without strengthening other things in pkgsrc.
The most notable one is: what about package options? If I rebuild a
package with different options, it's still the "same" package (same
name, same version) and even if I record the options in the log,
there's no good way to distinguish the before and after binary packages.

"""
]]