Holiday planning by Debian packages
Today I am facing a rather difficult decision. Should I travel to Lauterbrunnen for a week of BASE jumping or should I stay with my friends in Sweden for the last weekend of skydiving this season (with the obligatory party), and try out my brand new wingsuit? Facing this decision, I did what any rational human being would do: I decided to ask the aptitude
package manager for help in making this decision.
Setting up a local Debian repository
If you already have a local debian repository, you can skip this, otherwise it's useful to set one up. Install a web server of your choice (I happened to be running lighttpd already) and then install, for example, reprepro
. I am not going to elaborate on this, here:s a guide that may be useful: Local Debian Repository.
Creating a debian project
A very simple debian project consists of a debian
debian directory with the 3 files "control
", "rules
" and "changelog
", so let's create this.
bjorn@terra:~/src/$ mkdir -p decision-example/debian bjorn@terra:~/src/$ cd decision-example bjorn@terra:~/src/decision-example$ touch debian/control bjorn@terra:~/src/decision-example$ cat debian/rules # create this #!/usr/bin/make -f %: dh $@ bjorn@terra:~/src/decision-example$ chmod +x debian/rules bjorn@terra:~/src/decision-example$ cat debian/changelog # create this decision-example (0.0.0) unstable; urgency=low * Initial release. (Closes: #XXXXXX) -- Björn EdströmSat, 20 Oct 2012 11:37:03 +0200
While optional, I am also going to create the "compat
" file because it will supress a bunch of warnings when building the package.
bjorn@terra:~/src/decision-example$ cat debian/compat # create this 7
The interesting file is the control
file, which specifies one or more debian packages to be built. Just to get this out of the way, we are going to add a source package on top, and a single package representing the decision to go skydiving (this package is called gryttjom becayse my home dropzone is a place called Gryttjom which is north of Stockholm in Sweden):
Source: decision-example Section: devel Priority: optional Maintainer: Root Key Build-Depends: debhelper (>= 7) Standards-Version: 3.8.4 Package: decision-gryttjom Architecture: amd64 Description: Go to gryttjom
Having set this up, we can now build our package(s)
bjorn@terra:~/src/decision-example$ debuild -d -us -uc
Essentially that means to build binary (non-source), ignore dependencies when building, and not signing the package. If successful this will create a bunch of files in the parent directory.
Let's publish this package to our debian repository:
bjorn@terra:~/src$ dput -f -u decision decision-example_0.0.0_amd64.changes Uploading to decision (via local to localhost): Successfully uploaded packages. bjorn@terra:~/src$ sudo /usr/bin/reprepro -b /var/www/debian processincoming decision Exporting indices...
Given that you have configured your /etc/apt/sources correctly that package will now be available after an aptitude update
:
bjorn@terra:~$ aptitude search decision p decision-gryttjom - Go to gryttjom
Because we are going to create a bunch of packages from now on, let us create a build script:
bjorn@terra:~/src$ cat ./decision-example/publish.sh #/bin/bash sudo rm -r /var/www/debian/{pool,db,dists} # lazy way to delete previous, only do this if you don't have other packages dput -f -u decision decision-example_0.0.0_amd64.changes sudo /usr/bin/reprepro -b /var/www/debian processincoming decision sudo aptitude update
Decisions and dependencies
Aptitude, which is a package manager for debian, has a rather advanced dependency resolver. Specifically, you can use the keywords "Depends", "Conflicts", "Suggests", "Enhances", "Recommends" and a bunch of other to specify relations between packages. This is what we are going to use to make our decision.
On one level, we can specify our problem as "go to gryttjom or go to the alps". So let's create two packages for each option.
Package: decision-gryttjom Provides: decision-root Priority: standard Conflicts: decision-alps Architecture: amd64 Description: Go to gryttjom Package: decision-alps Provides: decision-root Priority: standard Conflicts: decision-gryttjom Architecture: amd64 Description: Stay in the alps
Let us build these packages (debuild step) and publish (using the build script). Now we have:
bjorn@terra:~$ aptitude search decision p decision-alps - Stay in the alps p decision-gryttjom - Go to gryttjom v decision-root -
We have now codified a decision problem as shown:
bjorn@terra:~$ sudo aptitude install decision-root ... "decision-root" is a virtual package provided by: decision-gryttjom decision-alps You must choose one to install. bjorn@terra:~$ sudo aptitude install --schedule-only decision-gryttjom decision-alps bjorn@terra:~$ sudo aptitude install # we scheduled above and execute here to avoid installing the default ... The following packages are BROKEN: decision-alps decision-gryttjom 0 packages upgraded, 2 newly installed, 0 to remove and 1 not upgraded. Need to get 1,966B of archives. After unpacking 57.3kB will be used. The following packages have unmet dependencies: decision-alps: Conflicts: decision-gryttjom but 0.0.0 is to be installed. decision-gryttjom: Conflicts: decision-alps but 0.0.0 is to be installed. The following actions will resolve these dependencies: Keep the following packages at their current version: decision-alps [Not Installed] Score is 117 Accept this solution? [Y/n/q/?] n The following actions will resolve these dependencies: Keep the following packages at their current version: decision-gryttjom [Not Installed] Score is 117 Accept this solution? [Y/n/q/?]
What we have done is we have created two packages and a root "virtual" package and specified a relationship between them. Using the excellent debtree
utility we can visualize this as follows:
bjorn@terra:~/src$ debtree -R -S decision-alps | dot -T png > decision-example/img/debtree1.png
Above is the dependency graph centered on the decision to go to the Alps. The root decision shows the two options: alps or gryttjom, while the red arrow shows a conflict.
Adding data points, additional decisions
The decision I am making is heavily influenced by weather forecasts. Furthermore, if I go to the Alps I a have the option to either stay in Lauterbrunnen or travel to Mt Brento in Italy to meet up with a friend. So lets create some data points and sub decisions:
Package: decision-gryttjom Provides: decision-root Priority: standard Conflicts: decision-alps Architecture: amd64 Description: Go to gryttjom Package: decision-alps Provides: decision-root Priority: standard Conflicts: decision-gryttjom Suggests: decision-alps-brento, data-good-weather-alps Architecture: amd64 Description: Stay in the alps Package: decision-alps-brento Depends: decision-alps Architecture: amd64 Description: Go to brento Package: data-good-weather-alps Architecture: amd64 Enhances: decision-alps Description: Good weather in the alps Package: data-bad-weather-gryttjom Architecture: amd64 Enhances: decision-alps Recommends: decision-alps Description: Bad weather at home
Here I have basically set up a bunch of hints or indications that if the weather forecast for Sweden looks bad then that leans towards going to the Alps. Building and publishing gives us:
bjorn@terra:~$ aptitude search decision p decision-alps - Stay in the alps p decision-alps-brento - Go to brento p decision-gryttjom - Go to gryttjom v decision-root - bjorn@terra:~$ aptitude search ^data- | egrep 'alps|gryttjom' p data-bad-weather-gryttjom - Bad weather at home p data-good-weather-alps - Good weather in the alps
Now, let's say the forecast says it seems to be bad weather in Sweden. Let's see what aptitude
says:
bjorn@terra:~$ sudo aptitude install --schedule-only decision-gryttjom decision-alps data-bad-weather-gryttjom bjorn@terra:~$ sudo aptitude install ... The following packages are BROKEN: decision-alps decision-gryttjom The following NEW packages will be installed: data-bad-weather-gryttjom 0 packages upgraded, 3 newly installed, 0 to remove and 1 not upgraded. Need to get 3,010B of archives. After unpacking 86.0kB will be used. The following packages have unmet dependencies: decision-alps: Conflicts: decision-gryttjom but 0.0.0 is to be installed. decision-gryttjom: Conflicts: decision-alps but 0.0.0 is to be installed. The following actions will resolve these dependencies: Keep the following packages at their current version: decision-gryttjom [Not Installed] Score is 117 Accept this solution? [Y/n/q/?] n The following actions will resolve these dependencies: Keep the following packages at their current version: decision-alps [Not Installed] Leave the following dependencies unresolved: data-bad-weather-gryttjom recommends decision-alps Score is -83
As can be seen, given the simple dependencies we have set up shows that aptitude
prefers BASE jumping if the weather is bad in Sweden.
Conclusion
To not make this article too long and tedious, I will stop here and not add more data points. However, by using Debian packaging "Suggest", "Ehances" and "Recommends" on some other data points (cost/travel overhead of getting to Brento, if my cold develops further, how much money I have etc) you can actually get something useful. As the number of data points increase it is not immediately obvious (as it is in the example above) what to do, and aptitude actually gives some suggestions.
Of course, I do not recommend anyone to base their life on what a Linux package manager says, and for that reason this article is a little bit tounge-in-cheek, and I realize this article is also the result of some procrastination on my part. However, actually formalizing the data points and relations between decisions helped me out, and when I have the data points I have formalized (travel costs, weather forecasts etc) will give aptitude a spin and hear it out.
Cheers,
Björn