If this works is greatly dependent on how the package expression is written. Let’s take xournal for example, which uses the most common method of referring to the desktopItem
using recursive attribute set.
This is actually the same issue that occurs with any overriding of attribute from recursive attribute sets as discussed in https://discourse.nixos.org/t/avoid-rec-expresions-in-nixpkgs/8293/4: Nix is a functional language and values in Nix are immutable – when you create a recursive attribute set, the references to its items refer to the original attribute set. Even when you create a new set replacing the value that is referenced:
nix-repl> ex = rec { a = "foo"; b = "${a}bar"; }
nix-repl> ex
{ a = "foo"; b = "foobar"; }
nix-repl> ex // { a = "baz"; }
{ a = "baz"; b = "foobar"; }
Since overrideAttrs
internally does just this for the attribute set passed to stdenv.mkDerivation
, the postInstall
in the new attrset will keep referring to the old desktopItem
.
One way to fix that would be just replacing the old references alongside attribute path in the postInstall
(mypackage.overrideAttrs (oldAttrs: rec {
desktopItem = oldAttrs.desktopItem // { # ← this parts still does not actually work
exec = "/my_exec";
terminal = "true";
};
postInstall = builtins.replaceStrings [ "${oldAttrs.desktopItem}" ] [ "${desktopItem}" ] oldAttrs.postInstall;
}));
There is however another issue. oldAttrs.desktopItem
is not just an attribute set that when changed a new desktop item is created. It is a derivation created by makeDesktopItem
function. And just creating a new attribute with changed exec
attribute will not propagate the change into a new derivation.
Unfortunately, looking at makeDesktopItem
source it does not seem to be easily overridable. As far as I can tell, there is only overrideAttrs
function from the derivation created by runCommandLocal
(or rather stdenv.mkDerivation
called by the trivial builder). This means you will have to resort to the following monstrosity:
(mypackage.overrideAttrs (oldAttrs: rec {
desktopItem = oldAttrs.desktopItem.overrideAttrs (desktopAttrs: {
buildCommand =
let
oldExec = builtins.match ".*(\nExec=[^\n]+\n).*" desktopAttrs.buildCommand;
oldTerminal = builtins.match ".*(\nTerminal=[^\n]+\n).*" desktopAttrs.buildCommand;
matches = oldExec ++ oldTerminal;
replacements = [ "\nExec=/my_exec\n" "\nTerminal=true\n" ];
in
assert oldExec != null && oldTerminal != null;
builtins.replaceStrings matches replacements desktopAttrs.buildCommand;
});
postInstall = builtins.replaceStrings [ "${oldAttrs.desktopItem}" ] [ "${desktopItem}" ] oldAttrs.postInstall;
}))
Note that there is a bug in builtins.replaceStrings
that keeps the original desktop file in the string, which will cause it to be built as a dependency of your overridden mypackage
, even though it is necessary. But that is pretty small concern so I did not bother getting around it here.