Make Nix Package Writable During Build Process

I’m currently trying to fix the dita-ot package, where the installation of plugins does not work. Usually, you’d install plugins via dita install <plugin> (e.g., dita install com.here.validate.svrl), but that tries to write to files from the package itself. As Nix store is immutable, it fails.

My updated approach would now be the following:

  1. Let users define a variable plugins that contains a list of all plugins that should be installed when building the package.
  2. During some phase, run dita install <plugins>.
  3. Have a finished derivation that does not need anymore changes.

Sadly, this does not work as I cannot create directories for some reason. Could you give me a hint what the problem here is?

Error Logs

Adding the line $out/share/dita-ot/bin/dita install com.here.validate.svrl to the install phase of the dita-ot package yields following output:

➜  nixpkgs git:(ditaot/FixPluginInstallation) ✗ nix-build -A dita-ot
this derivation will be built:
  /nix/store/mgzaihiqpxmw81gigx81y0hqjiqp2djx-dita-ot-4.2.4.drv
building '/nix/store/mgzaihiqpxmw81gigx81y0hqjiqp2djx-dita-ot-4.2.4.drv'...
Running phase: unpackPhase
unpacking source archive /nix/store/fzbb1p7jaxxxig43g31301kjshql8jl4-source
source root is source
Running phase: patchPhase
Running phase: updateAutotoolsGnuConfigScriptsPhase
Running phase: configurePhase
no configure script, doing nothing
Running phase: buildPhase
no Makefile or custom buildPhase, doing nothing
Running phase: installPhase
Error: Cannot create directory '/nix/store/3fkhsfhqg02kl623mlgfl7yrnhlp6akc-dita-ot-4.2.4/share/dita-ot/plugins/com.here.validate.svrl'.
error: builder for '/nix/store/mgzaihiqpxmw81gigx81y0hqjiqp2djx-dita-ot-4.2.4.drv' failed with exit code 1;
       last 11 log lines:
       > Running phase: unpackPhase
       > unpacking source archive /nix/store/fzbb1p7jaxxxig43g31301kjshql8jl4-source
       > source root is source
       > Running phase: patchPhase
       > Running phase: updateAutotoolsGnuConfigScriptsPhase
       > Running phase: configurePhase
       > no configure script, doing nothing
       > Running phase: buildPhase
       > no Makefile or custom buildPhase, doing nothing
       > Running phase: installPhase
       > Error: Cannot create directory '/nix/store/3fkhsfhqg02kl623mlgfl7yrnhlp6akc-dita-ot-4.2.4/share/dita-ot/plugins/com.here.validate.svrl'.
       For full logs, run 'nix log /nix/store/mgzaihiqpxmw81gigx81y0hqjiqp2djx-dita-ot-4.2.4.drv'.

You cannot create directories in other Nix paths during a build. Path immutability after a build is done is kinda a core principle of Nix and I wouldn’t bet on it being changed. I agree that this model is not an ideal match for such a situation, but there’s a few things you can do:

  1. Invert what you build, instead of passing the main program as dependency into the derivation of the plugin, build the plugin derivations first and pass them into the main derivation where you can install them. This only works if you don’t need the base program while building the plugins.

  2. Have a base program and plugin derivations like you have now, then have a third “program with plugins” derivation that takes all as an input and builds a combined output. This may well require copying the whole base derivation over to make it writable again, so not too good for very large derivations, though optimizing the Nix store will eventually remove redundancies.

  3. If in any way possible, see if the program has options to circumvent the issue, e.g., has a PLUGIN_PATHS or PLUGIN_REGISTRY environment variable so that you can provide your plugins without writing to the base application install location.

2 Likes

Buidling on what polygon says, you can search nixpkgs for something like withPlugins to see how some packages approach this with passthru functions.