milahu / nixpkgs

Nix Packages collection
MIT License
0 stars 0 forks source link

stdenv.mkDerivation: overrideAttrs fails to override derived attributes #34

Closed milahu closed 2 months ago

milahu commented 4 months ago

test.nix

with import <nixpkgs> {};
(stdenv.mkDerivation rec {
  name = "";
  x = "1";
  buildCommand = "echo bash x = $x; echo nix x = ${x}; exit 1";
}).overrideAttrs (oldAttrs: {
  x = "2";
})
nix-build test.nix
bash x = 2
nix x = 1

in practice, this mostly affects the version attribute

with import <nixpkgs> {};
gitea.overrideAttrs (oldAttrs: rec {
  doCheck = false; # waste of time
  version = "1.21.6";
  src = pkgs.fetchurl {
    url = "https://dl.gitea.com/gitea/${version}/gitea-src-${version}.tar.gz";
    hash = "sha256-tixWipiVHugacTzBurdgfiLnKyVDDcqCPlysj2DoWjg=";
  };
})

this will build gitea version 1.21.6 but the gitea webinterface will still show the old version 1.21.4

because gitea/default.nix uses the nix variable version when it should use the bash variable version

nixpkgs/pkgs/applications/version-management/gitea/default.nix

{
  ldflags = [
    "-s"
    "-w"
    "-X main.Version=${version}"
    "-X 'main.Tags=${lib.concatStringsSep " " tags}'"
  ];

the build flag main.Version is used in gitea/main.go

// these flags will be set by the build flags
var (
  Version     = "development" // program version for this build
  Tags        = ""            // the Golang build tags
  MakeVersion = ""            // "make" program version if built with make
)

func init() {
  setting.AppVer = Version

see also

nixos discourse

How to override this derivation?

One possible fix would be changing the interpolation of Nix variable `${src}` to a use of `$src` environment variable. The environment variables are only set by the builder from the attributes passed to `mkDerivation` so your changes would manifest there. The same would have to be done for other variables you would like to tweak like `archive` or `edition`. Alternately, since values are passed as function arguments through `callPackage`, it would be nicer to override them using `override` but that might not be possible when there are two nested `callPackage` calls. Not completely sure about this but would expect `override` to only work for the outer one in `all-packages.nix`.

Hm, that’s what I suspected, that there needs to be an upstream change in nixpkgs to support this.

softmaker-office, freeoffice: make it easy to override versions nixpkgs#96163

→ pass version as function argument through callPackage

nixpkgs manual

https://ryantm.github.io/nixpkgs/using/overrides/#sec-pkg-overrideAttrs

Example usages: ```nix helloBar = pkgs.hello.overrideAttrs (finalAttrs: previousAttrs: { pname = previousAttrs.pname + "-bar"; }); ``` In the above example, "-bar" is appended to the pname attribute, while all other attributes will be retained from the original hello package.

note: "while all other attributes will be retained from the original hello package."

nixos reddit

Is overrideAttrs supposed to work like this?

Let's say I have a simple derivation made using mkDerivation drv1.nix ```nix mkDerivation { # ... a = 69; installPhase = '' echo "${a}" > $out ''; } ``` and I want to customize it using overrideAttrs drv2.nix ``` (import ./drv1.nix).overrideAttrs (final: prev: { a = 420; }) ``` when I build dev2, the result contains "69" but I expected "420".
`overrideAttrs` modifies the attribute set that gets fed into `mkDerivation`. Now, Nix may be a lazy language, but by the time the `overrideAttrs` function was called, the set is already, well, set in place, meaning you have to change `installPhase` directly. FWIW, you can use the `prev` parameter to retrieve the original `installPhase` value for your override. If possible, I'd recommend adding `a` as a parameter at the top of `drv1.nix` (e.g. `{ stdenv, a ? 4, ... }` to give it a default value), and use the `override` function in `drv2.nix` (as well as importing `drv1.nix` using `callPackage`) instead so the rest is cleanly re-evaluated.
3 possible solutions: - use overrideAttrs to override derived attributes - in your example `installPhase` - instead of nix variables, use bash variables - `installPhase = ''echo "$a" > $out'';` - instead of overrideAttrs, use override, and pass the variable as argument to the build function but with bash variables and override: > Hm, that’s what I suspected, that there needs to be an upstream change in nixpkgs to support this. ideally there should be a way to patch the nix source of the original derivation, for example replace `version = "1";` with `version = "2";` and replace `src.hash = "111...";` with `src.hash = "222...";`, and then evaluate the patched nix source, so that all derived attributes use the patched values of `version` and `src.hash`... but i guess this would require IFD (import from derivation), which is "non standard" so realistically, its easier to copy the nix sources from nixpkgs (default.nix and patches), patch the attributes, and use `pkgs.callPackage ./path/to/patched/package { }`. this way, you have a "minimal diff", and you avoid overriding derived attributes with overrideAttrs. you can share such patches packages in [nur-packages](https://github.com/nix-community/NUR)
milahu commented 2 months ago

already solved by finalAttrs

nixpkgs/pkgs/by-name/he/hello/package.nix

{ callPackage
, lib
, stdenv
, fetchurl
, nixos
, testers
, hello
}:

stdenv.mkDerivation (finalAttrs: {
  pname = "hello";
  version = "2.12.1";

  src = fetchurl {
    url = "mirror://gnu/hello/hello-${finalAttrs.version}.tar.gz";
    sha256 = "sha256-jZkUKv2SV28wsM18tCqNxoCZmLxdYH2Idh9RLibH2yA=";
  };