nh2
nh2

Reputation: 25645

In nixpkgs, how do I override files of a package without recompilation?

For a nixpkgs package that takes long to build, how can I make some simple file changes without incurring a full rebuild?

Example usages:

Upvotes: 4

Views: 3868

Answers (1)

nh2
nh2

Reputation: 25645

Create a new derivation that copies or symlinks all the files of the original package over (e.g. using cp), and then modify the files as desired.

Here is a fully commented example:

# This snippet shows how to override a nix package by copying all of the
# files of an already-built package, and then modifying some of them,
# thus avoiding a full rebuild.
#
# Example usage:
#
# Build the package:
#     nix-build --no-out-link change-file-after-build-example.nix
# See our replacement worked:
#     $ $(nix-build --no-out-link change-file-after-build-example.nix)/share/git/contrib/fast-import/git-import.sh
#     USAGE: git-import branch import-message
{
  pkgs ? import <nixpkgs> {},
  lib ? pkgs.lib,
}:
let
  originalPackage = pkgs.git;

  # We use `overrideAttrs` instead of defining a new `mkDerivation` to keep
  # the original package's `output`, `passthru`, and so on.
  myOverriddenGitPackage = originalPackage.overrideAttrs (old: {
    name = "git-overridden";

    # Using `buildCommand` replaces the original packages build phases.
    buildCommand = ''
      set -euo pipefail

      ${
        # Copy original files, for each split-output (`out`, `dev` etc.).
        # E.g. `${package.dev}` to `$dev`, and so on. If none, just "out".
        # Symlink all files from the original package to here (`cp -rs`),
        # to save disk space.
        # We could alternatiively also copy (`cp -a --no-preserve=mode`).
        lib.concatStringsSep "\n"
          (map
            (outputName:
              ''
                echo "Copying output ${outputName}"
                set -x
                cp -rs --no-preserve=mode "${originalPackage.${outputName}}" "''$${outputName}"
                set +x
              ''
            )
            (old.outputs or ["out"])
          )
      }

      # Example change:
      # Change `usage:` to `USAGE:` in a shell script.
      # Make the file to be not a symlink by full copying using `install` first.
      # This also makes it writable (files in the nix store have `chmod -w`).
      install -v "${originalPackage}"/share/git/contrib/fast-import/git-import.sh "$out"/share/git/contrib/fast-import/git-import.sh
      sed -i -e 's/usage:/USAGE:/g' "$out"/share/git/contrib/fast-import/git-import.sh
    '';

  });
in
  myOverriddenGitPackage

Upvotes: 4

Related Questions