Make plugins package available to other NixOS package (Keepass)

I’m wondering if there is a way to link plugins from one to another/consuming NixOS package without the need to rebuild this other package.

I like to extend keepass with plugins. For this question let’s assume I want to use the existing package keepass-keepasshttp (plugin) to extend the functionality of keepass.

What I already know:

  1. NixOS uses fixed paths to link dependencies (Nix pills ch 6 &7). Therefore it seems to be unavoidable to rebuild/recompile keepass every time an addon should be added or removed.
  2. The keepass package implemented a patch, which supports those plugins to be included/linked at build-time
  3. Four years ago someone on github suggested using overrides to accomplish no. 1+2.
  4. Last year someone else on reddit suggested the use of overlays instead of override
  5. Solution mentioned in in no. 4 ist working for me so far. But keepass has to be rebuild/recompiled into a new nixos package derivation. This is an example code:
nixpkgs.overlays = [
    (self: super: {
      keepass = super.keepass.override {
          plugins = [ self.keepass-keepasshttp ];

Possible solutions?
On stackoverflow someone suggested using symlinkJoin in conjunction with a wrapper.
As far as I understand the idea behind is to modify the base package (keepass). Thus only a (smaller) customized package containing the selection of plugins must be build on the target system, leaving the keepass package untouched. (maybe I misunderstood that part??)
Pidgin has implemented the symlinkJoin - but frankly I don’t understand what magic is happening there, yet.

Any other ideas to solve that case?
Or could anyone give me some hints how to implement that symlinkJoin/wrapper thing in my keepass example?

If I understand correctly, you’re interested in having a KeePass package with plugins, that doesn’t require rebuilding KeePass from source.

The difficulty here is that the plugins are added in KeePass’s main derivation as part of the postInstall phase:

nixpkgs/default.nix at 770ecb1d3134a7b0e4469eb790836bd837c9f675 · NixOS/nixpkgs · GitHub

So any modifications to the plugins list changes the inputs of the derivation and requires a rebuild.

To work around this, you might be able to setup a wrapper derivation that includes the base KeePass package, and prefixes the PATH variable with the module paths. Something like this might work:

{ pkgs ? import <nixpkgs> {} }:
with pkgs;
stdenv.mkDerivation rec {
  name = "wrappedKeePass";
  plugins = [ keepass-keepasshttp ];
  binPaths = lib.concatStrings (lib.intersperse ":" (map (x: x + "/bin") plugins));
  buildInputs = [ makeWrapper ];

  phases = "wrapPhase";
  wrapPhase = ''
    mkdir -p $out/bin
    ln -s ${keepass}/bin/keepass $out/bin/keepass
    wrapProgram $out/bin/keepass \
      --prefix PATH : "$binPaths"

Thanks for providing an example. Now I understand the approach. :+1:

I digged a bit deeper into the nixos keepass package. And I found something which gives me a headache. :bowing_man:

Now the situation is:

  • nix uses fixed pathes for every package derivation; any change to the package results in a new derivation path
  • keepass also uses fixed pathes, which has to be defined at compile time

Therefore even using a wrapper causes the need to recompile keepass. Because every added/removed plugin changes the path of the wrapper derivation.

With my limited knowledge of the nix eco system, I see no way to solve this problem. :dizzy_face:

I got a hint that I could make use of /run/current-system/... as static plugin path. I’ll have a try on this.

I see now that my example won’t work – the keepass source is being patched to load plugins from the defined plugin paths. Good luck with the static plugin path approach.