Customizing a package installation in a system?

I’m just getting started with NixOS, and I have a question about declaratively customizing a package installation/configuration.

For an extremely simple example, let’s say I’m installing the package cowsay to my system, but I also wanted to add some custom ASCII pictures to it.

So far I have installed the package by adding this to my configuration.nix:

environment.systemPackages = with pkgs; [
    cowsay
  ];

I believe the package itself is defined here:

It fetches a tarball that contains the source code and also some default ASCII pictures. Let’s say I wanted to add some of my own.

This could maybe be accomplished by writing a custom (builder?) script that extracts the tarball and then copies some custom cow pictures from my own directory into the extracted source directory, and then performs the build as usual. Another way to do it would be maybe to override the “installPhase” definition to add custom cow files there.

The question is: is there a way to make this happen just by editing my own configuration.nix file, or do I have to somehow fork the actual package? In other words, can I just override that “installPhase” string (defined in cowsay/default.nix) from inside my own configuration.nix, and if possible, how to do it? If it’s not possible, then what is the recommended way to do this kind of a customization?

(Obviously there are better use cases for this kind of thing, I’m using cowsay just to provide an example. One other use case would be overriding the default global config files of a program.)

Thanks

You can use the overrideAttrs:

environment.systemPackages = with pkgs; [
    (cowsay.overrideAttrs (oldAttrs: {
        installPhase = ''
           # put your code here
        '';
     })
  ];

see the manual about overrideAttrs and I recommand to read about the standard build phases

1 Like

Thanks for your help. I have now managed to do something like this:

(cowsay.overrideAttrs (old: rec {
  installPhase = old.installPhase + ''
    echo "${(import ./companion-cube.cow)}" > $out/share/cows/companion-cube.cow
  '';
}))

This solution “kind of” works, assuming that I have a ‘companion-cube.cow’ (containing the contents of the file wrapped into a multi-line nix string) next to my configuration.nix.

At least the resulting file does appear where it should.

But it’s still a bad solution and doesn’t really work, because for example dollar $ characters get stripped away unless they’re escaped etc.

That means the remaining question is, how do I properly add the file to the build directory?

You might want to consider using fetchpatch to do this, and hosting the file yourself if it’s not already available.

If you wanted to still read the file into memory, using builtins.readFile would be a better solution. It would not require you to wrap it in Nix syntax and escape anything properly.

But cp ${./companion-cube.cow} $out/share/cows/companion-cube.cow would be even better

2 Likes