Cleaner way to detect if a particular package was installed in apt-get hook

aptdpkg

I have a simple script that applies a patch to a given package, and, since each time said package is upgraded the patch gets overridden, I would really like to automatically apply the patch after every upgrade.

To accomplish this, I created a file in /etc/apt/apt.conf.d/ and added a hook for DPkg::Post-Invoke. As documented by man apt-get, this hook is run by apt-get after installing a package with dpkg. However this hook does not seem to have any information whatsoever about which particular package has been installed, so I cannot know if I have to apply the patch or not. Nothing gets passed to its stdin, nothing gets passed as argument, and the man page says nothing about it.

So to solve this I did the only thing that I could think of: I added another hook for DPkg::Pre-Install-Pkgs, which gets run by apt-get before packages are installed. This hook gets (through stdin) the list of .deb files which are going to be installd by dpkg, so I just check whether any file name matches the name of the package I want to patch, and if so I create a file in /tmp. When my other hook is executed, it first checks for the existence of said file and, if present, applies the patch to the package that has just been installed.

Here's the file I've created in /etc/apt/apt.conf.d/:

DPkg::Pre-Install-Pkgs {
    "while read -r pkg; do case $pkg in *somepkg*) touch /tmp/.patch && exit 0; esac done < /dev/stdin";
};

DPkg::Post-Invoke {
    "[ -f /tmp/.patch ] && /home/marco/scripts/apply_somepkg_patch.sh && rm -f /tmp/.patch; exit 0";
};

To be clear: the apply_somepkg_patch.sh simply edits the contents of a file provided by the package. I want said file to be upgraded and patched each time, I don't want to "lock" it so it doesn't get upgraded.

Now, while this all works just fine, it looks really dirty and somehow wrong to me. Is there any cleaner way to accomplish this? Perhaps only using the DPkg::Post-Invoke hook? Or, in other words, is there a way to know which package got installed in the DPkg::Post-Invoke hook?


EDIT: adding a detailed example of what I'm doing just to be 101% clear, even though I don't think it adds any more information to what I said above.

Suppose somepkg is the package I'm talking about, and somefile is the file installed by such package which I want to patch.

  1. First installation of somepkg, content of somefile:

    some_opt1 = some_value
    some_opt2 = some_value
    some_opt3 = a, b, c, d
    some_opt4 = some_value
    
  2. Apply patch, changing it to:

    some_opt1 = some_value
    some_opt2 = some_value
    some_opt3 = X, Y, Z, d
    some_opt4 = some_value
    
  3. Upgrade of somepkg, contents somefile after upgrade:

    some_opt1 = some_value
    some_opt2 = some_value
    some_opt5 = some_value
    some_opt3 = a, b, c, d
    some_opt6 = some_value
    some_opt4 = some_value
    
  4. Apply patch, changing it to:

    some_opt1 = some_value
    some_opt2 = some_value
    some_opt5 = some_value
    some_opt3 = X, Y, Z, d
    some_opt6 = some_value
    some_opt4 = some_value
    

Now, what's the somepackage, where somefile is, what's inside somefile: this is all completely irrelevant for my question. All you need to know is that I want to dynamically modify the contents of somefile, which is part of somepkg, after getting the upgraded version of the file.

This obviously cannot be done statically: I need a script to read somefile, parse its content and patch it accordingly. Therefore, if I want my script to be automatically ran each time somepkg gets updated, I need to make apt-get run it automatically for me.

Best Answer

There’s no nice way to do this with apt or dpkg hooks of the style you’re currently using. There might be a simple way of handling such patches on upgrades for the specific package and file you’re modifying, but if you want a generic solution, I think the best approach in Debian currently is to use file triggers.

This involves creating a (simple) package which will take care of patching the file on upgrades of the other package (the one containing the file you wish to patch). Your patching package needs to declare its interest in a file trigger; to do so, add a file named debian/triggers) containing the single line

interest /path/to/the/file/to/patch

Then in the package’s postinst (debian/postinst), check if the first argument is triggered, and if it is, run your patching script (or merge that in your postinst). If you want to keep your patching script separate, you could ship it in your patching package to keep things contained.

Once all that’s done, build and install your patching package, and then whenever you upgrade the package you’re modifying, your patching package’s postinst will be called.

Related Question