January 19, 2012

Poor man's rollback

By Andrew Wafaa’s request.

Save the package list:

[email protected]:~> rpm -qa --queryformat="%{name}\n" > 1

Do something… like uninstalling what was cool last week and it is not cool anymore:

[email protected]:~> sudo zypper rm erlang
Loading repository data...
Reading installed packages...
Resolving package dependencies...`

The following packages are going to be REMOVED:  
 erlang rabbitmq-server

2 packages to remove.  
After the operation, 51.3 MiB will be freed.  
Continue? [y/n/?] (y): y  
Removing rabbitmq-server-2.2.0-1.2 [done]  
Removing erlang-R14B-1.2 [done]  
There are some running programs that use files deleted by recent upgrade. You may wish to restart some of them. Run 'zypper ps' to list these programs.

Save the new state:

[email protected]:~> rpm -qa --queryformat="%{name}\n" > 2

Now you need to know that zypper accepts + and - in its input. You can install and uninstall packages in one go:

zypper in -- +pkg1 -pkg2 +pkg3 ...

So we can diff both files:

[email protected]:~> diff -u 1 2
--- 1	2012-01-19 17:23:26.640180000 +0100
+++ 2	2012-01-19 17:24:43.196248000 +0100
@@ -420,7 +420,6 @@
@@ -3561,7 +3560,6 @@

Close to what we need. We remove the context lines by using -u0 and we remove the 3 first lines:

[email protected]:~> diff -u0 1 2 | grep -Ev '^(@@|\+\+|--)'

Now feed zypper with this to get your packages back:

zypper in -- $(diff -u0 2 1 | grep -Ev '^(@@|\+\+|--)' | xargs)

Of course this only will work if you have all repositories. It is also useful to sync packages across computers (like you get a new laptop and need to setup it in a similar way).

openSUSE 12.1 rollback is implemented using btrfs via snapper, plus a zypp plugin that records a snapshot on every commit. It should be possible to write a Poor’s man version by recording the package list on every commit and then performing the above operation to go one or more steps back.