Postinstall or hook?

Hi! I’m new to nixos, and just switched from Manjaro to NixOs.
With Arch based linux, we can hook after the installation of a package. I used this to execute some bash scripts.
I want to do the same things after a package was updated or installed. How I can do that with nixos ? And how to get the path of a package with bash ?

On NixOS, you are not mutating the system when “installing” stuff. When you run nixos-rebuild switch, it builds a completely new system derivation, adds it as a new generation to the system profile, and then finally activate it. The new derivation has no knowledge about previous generations so hooks for package installation do not really make sense.

The activation is carried out by a script that is part of the new system derivation and you can insert actions to it with system.activationScripts NixOS option.


Can you elaborate a little on what these scripts are doing?

Ok, thanks for your answer.
system.activationScripts is called after each nixos-rebuild. I just want to call my script after a package update or install. Is there an alternative to ? Maybe with a patch ?

My scripts simply copy-paste some files inside some applications. Example: I copy some html and js files and inject them in Vivaldi web browser to tweak the UI.

Maybe I can fork this default.nix file for installing vivaldi and add my changes to copy-paste my files ?
Is it a good alternative to do that ?

(vivaldi.overrideAttrs (previousAttrs: {
  postInstall = (previousAttrs.postInstall or "") + ''

This is exactly what I was looking for. Thanks !
Just missing one more closed parenthesis at the end.

How do you access to an user directories in the postInstall script ?
I tried this, but without success (error No such file or dir)

(unstablePkgs.vivaldi.overrideAttrs (previousAttrs: {
      postInstall = (previousAttrs.postInstall or "") + ''
        echo "test vivaldi"
        echo "${config.users.users.manu.home}"
        ls ${config.users.users.manu.home}/.nixos
        # sh ${config.users.users.manu.home}/.nixos/

I can see the result of echo “${config.users.users.manu.home}” : /home/manu
But can’t do ls. It seems that the user home is not mounted during the build process.

the simple answer is you can’t, if you want to directly modify a package you do it like above with overrideAttrs if you have files that are essentially config files then you would use the nixos module system which by default doesn’t support managing a users home, but there is GitHub - nix-community/home-manager: Manage a user environment using Nix [maintainer=@rycee] which can do that for you.

${builtins.path { path = "${config.users.users.manu.home}/.nixos/"; } }

Note that the file/dir will be copied to the nix store.

(There are some other ways, but I think builtins.path is the most future-proof one.)

1 Like

It works with Vivaldi ! I will do the same things for other tweaks.
Thanks a lot @Artturin, you saved my day :slight_smile:

If you are modifying the vivaldi package, you should include the script in the same directory tree like the NixOS configuration rather than a random location in your home directory. That way you can easily include it in the same version control repository.

You can refer to it using a path literal, which, when interpolated, will be resolved to a path visible to the builder:

  postInstall = (previousAttrs.postInstall or "") + ''
    sh ${./}

If you want to modify package files then overriding attributes as suggested above is correct. Just keep in mind that the semantics is quite different from pacman’s package scriptspostInstall hook of generic builder in Nixpkgs does not run when the package is installed to your system but rather when the package is built. If you are familiar with Arch’s PKGBUILD system, it would be like if you inserted custom shell snippet to run at the end of a package’s package() function (with similar limitations to what paths are visible/writeable).