Sunday, January 17, 2010

Upgrading with apt-get replaces packages built from source

Sometimes you need to apply your own flavor to some distribution package. With apt this is a dream, as you simply (using the example of grub2):
  1. Instruct to to install all the dependencies needed to rebuild a specific package:
    sudo apt-get build-dep grub2
  2. Fetch, extract and apply distro patches of the source code:
    apt-get source grub2
  3. Make your modifications
  4. Rebuild (from inside the extracted source tree)
    dpkg-buildpackage -j2 -rfakeroot -b
  5. Then install the generated .debs
This is all fine except for when you get to upgrading your packages to newer versions. The package selection policies always see self installed debs as lower priority to those coming from the repositories.

So your package will always be replaced with it's same original distro version. To explain with a more clear example, assume you have linux-image-2.6.31-17-generic installed. You fetch it's source, beat a bug, rebuild and install it, once you upgrade the repositories version of linux-image-2.6.31-17-generic will be installed, making the bug a "zombie".

I had a look around, and it seems that the solutions a float is to either
  1. increase the version of the package so it's higher than the one from the repository, or
  2. to "hold" the package.
The problem with the first approach is that you need to select the version carefully enough, so a legitimate upgrade doesn't go unnoticed. If you were to increase version 1.0 to 1.1, and a version 1.0.1 gets released, you'll miss it, because you're version is still higher.

The problem with the second approach is that you'll never have the package upgraded.

So in both cases you'll probably end up having to monitor for upgrades these package, to ensure you don't miss any. There is also the option of seeing which packages are proposed for the upgrade, and just not do any of those you built yourself unless their versions were increased.

This was inefficient for me, since my list of self-built packages were growing increasingly large, and I had more than one machine to do all this maintenance on.

So I set out on finding a solution. In the process of applying a possible solution I found that it's actually very simple. Halfway through it was already solved.

So here it is:
  1. Create your own repository
  2. Load your packages into the repository
  3. Install them from the repository
  4. Done
That's all there is to it.

So, to give a bit more detailed instructions.
  1. When your done testing your changes and ready to load the package into the repository, build your package with the dpkg-buildpackage command. This is necessary to generate the .changes file.
  2. Setup a .deb repository and import the packages. See this link for instructions.
  3. Add your repository to then end of your /etc/apt/sources.list file.
  4. Install the package
Further, when setting up my repository, I gave a custom name as the repository's "Suite". This way I could more easily pin this repository. Doing this, however, will result in a warning when trying to import the packages using the reprepro utility. You can tell reprepro to ignore the warning and continue, or you can build your packages prepared for this repository.

To do so, when building your package, do the following from inside it's source tree:
  1. Open the 'debian/changelog' file
  2. The first line would read something like:
    gnutls26 (2.8.3-2) unstable; urgency=low
    OR
    grub2 (1.97~beta4-1ubuntu4.1) karmic-security; urgency=low
  3. The part after the package version in parenthesis and before the semi-colon is the target "suite", in these cases 'unstable' and 'karmic-security' respectively.
  4. Change this to whatever your configured 'Suite' value is, and build the package.
Another problem I ran into when trying to import my modified kernel image was a warning:
Cannot put file 'virtio-modules-2.6.31-17-generic-di_2.6.31-17.54_i386.udeb' into component 'main', as it is not listed in UDebComponents!
This was because I didn't include a UDebComponents entry in my repository configuration, which has to be listed AFTER the Components entry. So if you're going to rebuild and import the kernel, you need to have something similar to this in your 'conf/distributions' file:
Components: main non-free contrib
UDebComponents: main
And that's about all there was to it. I suspect it might depend on the order of the repositories as well, so if this doesn't seem to help, try and swap the order your repositories are listed in your sources.list, or try pinning your custom repository with a higher priority.

No comments: