buildGoModule: fix overrideAttrs overriding
Fix overriding of vendorHash and various attributes via the fixed point attribute support of stdenv.mkDerivation. Pass as derivation attributes goModules, modRoot, vendorHash, deleteVendor, and proxyVendor. Move goModules and vendorHash out of passthru. Co-authored-by: Doron Behar <doron.behar@gmail.com>
This commit is contained in:
parent
010277de84
commit
eed069a5bc
@ -62,6 +62,65 @@ The following is an example expression using `buildGoModule`:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Obtaining and overriding `vendorHash` for `buildGoModule` {#buildGoModule-vendorHash}
|
||||||
|
|
||||||
|
We can use `nix-prefetch` to obtain the actual hash. The following command gets the value of `vendorHash` for package `pet`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cd path/to/nixpkgs
|
||||||
|
nix-prefetch -E "{ sha256 }: ((import ./. { }).my-package.overrideAttrs { vendorHash = sha256; }).goModules"
|
||||||
|
```
|
||||||
|
|
||||||
|
To obtain the hash without external tools, set `vendorHash = lib.fakeHash;` and run the build. ([more details here](#sec-source-hashes)).
|
||||||
|
|
||||||
|
`vendorHash` can be overridden with `overrideAttrs`. Override the above example like this:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
pet_0_4_0 = pet.overrideAttrs (
|
||||||
|
finalAttrs: previousAttrs: {
|
||||||
|
version = "0.4.0";
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
inherit (previousAttrs.src) owner repo;
|
||||||
|
rev = "v${finalAttrs.version}";
|
||||||
|
hash = "sha256-gVTpzmXekQxGMucDKskGi+e+34nJwwsXwvQTjRO6Gdg=";
|
||||||
|
};
|
||||||
|
vendorHash = "sha256-dUvp7FEW09V0xMuhewPGw3TuAic/sD7xyXEYviZ2Ivs=";
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Overriding `goModules` (#buildGoModule-goModules-override)
|
||||||
|
|
||||||
|
Overriding `<pkg>.goModules` by calling `goModules.overrideAttrs` is unsupported. Still, it is possible to override the `vendorHash` (`goModules`'s `outputHash`) and the `pre`/`post` hooks for both the build and patch phases of the primary and `goModules` derivation. Alternatively, the primary derivation provides an overridable `passthru.overrideModAttrs` function to store the attribute overlay implicitly taken by `goModules.overrideAttrs`. Here's an example usage of `overrideModAttrs`:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
pet-overridden = pet.overrideAttrs (
|
||||||
|
finalAttrs: previousAttrs: {
|
||||||
|
passthru = previousAttrs.passthru // {
|
||||||
|
# If the original package has an `overrideModAttrs` attribute set, you'd
|
||||||
|
# want to extend it, and not replace it. Hence we use
|
||||||
|
# `lib.composeExtensions`. If you are sure the `overrideModAttrs` of the
|
||||||
|
# original package trivially does nothing, you can safely replace it
|
||||||
|
# with your own by not using `lib.composeExtensions`.
|
||||||
|
overrideModAttrs = lib.composeExtensions previousAttrs.passthru.overrideModAttrs (
|
||||||
|
finalModAttrs: previousModAttrs: {
|
||||||
|
# goModules-specific overriding goes here
|
||||||
|
postBuild = ''
|
||||||
|
# Here you have access to the `vendor` directory.
|
||||||
|
substituteInPlace vendor/github.com/example/repo/file.go \
|
||||||
|
--replace-fail "panic(err)" ""
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## `buildGoPackage` (legacy) {#ssec-go-legacy}
|
## `buildGoPackage` (legacy) {#ssec-go-legacy}
|
||||||
|
|
||||||
The function `buildGoPackage` builds legacy Go programs, not supporting Go modules.
|
The function `buildGoPackage` builds legacy Go programs, not supporting Go modules.
|
||||||
|
@ -272,6 +272,10 @@
|
|||||||
[buildRustPackage: Compiling Rust applications with Cargo](https://nixos.org/manual/nixpkgs/unstable/#compiling-rust-applications-with-cargo)
|
[buildRustPackage: Compiling Rust applications with Cargo](https://nixos.org/manual/nixpkgs/unstable/#compiling-rust-applications-with-cargo)
|
||||||
for more information.
|
for more information.
|
||||||
|
|
||||||
|
- The `vendorHash` of Go packages built with `buildGoModule` can now be overridden with `overrideAttrs`.
|
||||||
|
`goModules`, `modRoot`, `vendorHash`, `deleteVendor`, and `proxyVendor` are now passed as derivation attributes.
|
||||||
|
`goModules` and `vendorHash` are no longer placed t under `passthru`.
|
||||||
|
|
||||||
- `hareHook` has been added as the language framework for Hare. From now on, it,
|
- `hareHook` has been added as the language framework for Hare. From now on, it,
|
||||||
not the `hare` package, should be added to `nativeBuildInputs` when building
|
not the `hare` package, should be added to `nativeBuildInputs` when building
|
||||||
Hare programs.
|
Hare programs.
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
, patches ? [ ]
|
, patches ? [ ]
|
||||||
|
|
||||||
# A function to override the goModules derivation
|
# A function to override the goModules derivation
|
||||||
, overrideModAttrs ? (_oldAttrs: { })
|
, overrideModAttrs ? (finalAttrs: previousAttrs: { })
|
||||||
|
|
||||||
# path to go.mod and go.sum directory
|
# path to go.mod and go.sum directory
|
||||||
, modRoot ? "./"
|
, modRoot ? "./"
|
||||||
@ -58,18 +58,38 @@
|
|||||||
assert goPackagePath != "" -> throw "`goPackagePath` is not needed with `buildGoModule`";
|
assert goPackagePath != "" -> throw "`goPackagePath` is not needed with `buildGoModule`";
|
||||||
|
|
||||||
let
|
let
|
||||||
args = removeAttrs args' [ "overrideModAttrs" "vendorSha256" "vendorHash" ];
|
args = removeAttrs args' [ "overrideModAttrs" "vendorSha256" ];
|
||||||
|
|
||||||
GO111MODULE = "on";
|
GO111MODULE = "on";
|
||||||
GOTOOLCHAIN = "local";
|
GOTOOLCHAIN = "local";
|
||||||
|
|
||||||
goModules = if (vendorHash == null) then "" else
|
toExtension =
|
||||||
|
overlay0:
|
||||||
|
if lib.isFunction overlay0 then
|
||||||
|
final: prev:
|
||||||
|
if lib.isFunction (overlay0 prev) then
|
||||||
|
# `overlay0` is `final: prev: { ... }`
|
||||||
|
overlay0 final prev
|
||||||
|
else
|
||||||
|
# `overlay0` is `prev: { ... }`
|
||||||
|
overlay0 prev
|
||||||
|
else
|
||||||
|
# `overlay0` is `{ ... }`
|
||||||
|
final: prev: overlay0;
|
||||||
|
|
||||||
|
in
|
||||||
|
(stdenv.mkDerivation (finalAttrs:
|
||||||
|
args
|
||||||
|
// {
|
||||||
|
|
||||||
|
inherit modRoot vendorHash deleteVendor proxyVendor;
|
||||||
|
goModules = if (finalAttrs.vendorHash == null) then "" else
|
||||||
(stdenv.mkDerivation {
|
(stdenv.mkDerivation {
|
||||||
name = "${name}-go-modules";
|
name = "${finalAttrs.name or "${finalAttrs.pname}-${finalAttrs.version}"}-go-modules";
|
||||||
|
|
||||||
nativeBuildInputs = (args.nativeBuildInputs or [ ]) ++ [ go git cacert ];
|
nativeBuildInputs = (finalAttrs.nativeBuildInputs or [ ]) ++ [ go git cacert ];
|
||||||
|
|
||||||
inherit (args) src;
|
inherit (finalAttrs) src modRoot;
|
||||||
inherit (go) GOOS GOARCH;
|
inherit (go) GOOS GOARCH;
|
||||||
inherit GO111MODULE GOTOOLCHAIN;
|
inherit GO111MODULE GOTOOLCHAIN;
|
||||||
|
|
||||||
@ -77,15 +97,15 @@ let
|
|||||||
# argue it's not ideal. Changing it may break vendor hashes in Nixpkgs and
|
# argue it's not ideal. Changing it may break vendor hashes in Nixpkgs and
|
||||||
# out in the wild. In anycase, it's documented in:
|
# out in the wild. In anycase, it's documented in:
|
||||||
# doc/languages-frameworks/go.section.md
|
# doc/languages-frameworks/go.section.md
|
||||||
prePatch = args.prePatch or "";
|
prePatch = finalAttrs.prePatch or "";
|
||||||
patches = args.patches or [ ];
|
patches = finalAttrs.patches or [ ];
|
||||||
patchFlags = args.patchFlags or [ ];
|
patchFlags = finalAttrs.patchFlags or [ ];
|
||||||
postPatch = args.postPatch or "";
|
postPatch = finalAttrs.postPatch or "";
|
||||||
preBuild = args.preBuild or "";
|
preBuild = finalAttrs.preBuild or "";
|
||||||
postBuild = args.modPostBuild or "";
|
postBuild = finalAttrs.modPostBuild or "";
|
||||||
sourceRoot = args.sourceRoot or "";
|
sourceRoot = finalAttrs.sourceRoot or "";
|
||||||
setSourceRoot = args.setSourceRoot or "";
|
setSourceRoot = finalAttrs.setSourceRoot or "";
|
||||||
env = args.env or { };
|
env = finalAttrs.env or { };
|
||||||
|
|
||||||
impureEnvVars = lib.fetchers.proxyImpureEnvVars ++ [
|
impureEnvVars = lib.fetchers.proxyImpureEnvVars ++ [
|
||||||
"GIT_PROXY_COMMAND"
|
"GIT_PROXY_COMMAND"
|
||||||
@ -97,13 +117,13 @@ let
|
|||||||
runHook preConfigure
|
runHook preConfigure
|
||||||
export GOCACHE=$TMPDIR/go-cache
|
export GOCACHE=$TMPDIR/go-cache
|
||||||
export GOPATH="$TMPDIR/go"
|
export GOPATH="$TMPDIR/go"
|
||||||
cd "${modRoot}"
|
cd "$modRoot"
|
||||||
runHook postConfigure
|
runHook postConfigure
|
||||||
'';
|
'';
|
||||||
|
|
||||||
buildPhase = args.modBuildPhase or (''
|
buildPhase = args.modBuildPhase or (''
|
||||||
runHook preBuild
|
runHook preBuild
|
||||||
'' + lib.optionalString deleteVendor ''
|
'' + lib.optionalString finalAttrs.deleteVendor ''
|
||||||
if [ ! -d vendor ]; then
|
if [ ! -d vendor ]; then
|
||||||
echo "vendor folder does not exist, 'deleteVendor' is not needed"
|
echo "vendor folder does not exist, 'deleteVendor' is not needed"
|
||||||
exit 10
|
exit 10
|
||||||
@ -116,7 +136,7 @@ let
|
|||||||
exit 10
|
exit 10
|
||||||
fi
|
fi
|
||||||
|
|
||||||
${if proxyVendor then ''
|
${if finalAttrs.proxyVendor then ''
|
||||||
mkdir -p "''${GOPATH}/pkg/mod/cache/download"
|
mkdir -p "''${GOPATH}/pkg/mod/cache/download"
|
||||||
go mod download
|
go mod download
|
||||||
'' else ''
|
'' else ''
|
||||||
@ -134,7 +154,7 @@ let
|
|||||||
installPhase = args.modInstallPhase or ''
|
installPhase = args.modInstallPhase or ''
|
||||||
runHook preInstall
|
runHook preInstall
|
||||||
|
|
||||||
${if proxyVendor then ''
|
${if finalAttrs.proxyVendor then ''
|
||||||
rm -rf "''${GOPATH}/pkg/mod/cache/download/sumdb"
|
rm -rf "''${GOPATH}/pkg/mod/cache/download/sumdb"
|
||||||
cp -r --reflink=auto "''${GOPATH}/pkg/mod/cache/download" $out
|
cp -r --reflink=auto "''${GOPATH}/pkg/mod/cache/download" $out
|
||||||
'' else ''
|
'' else ''
|
||||||
@ -152,20 +172,19 @@ let
|
|||||||
dontFixup = true;
|
dontFixup = true;
|
||||||
|
|
||||||
outputHashMode = "recursive";
|
outputHashMode = "recursive";
|
||||||
outputHash = vendorHash;
|
outputHash = finalAttrs.vendorHash;
|
||||||
# Handle empty vendorHash; avoid
|
# Handle empty vendorHash; avoid
|
||||||
# error: empty hash requires explicit hash algorithm
|
# error: empty hash requires explicit hash algorithm
|
||||||
outputHashAlgo = if vendorHash == "" then "sha256" else null;
|
outputHashAlgo = if finalAttrs.vendorHash == "" then "sha256" else null;
|
||||||
}).overrideAttrs overrideModAttrs;
|
}).overrideAttrs finalAttrs.passthru.overrideModAttrs;
|
||||||
|
|
||||||
package = stdenv.mkDerivation (args // {
|
|
||||||
nativeBuildInputs = [ go ] ++ nativeBuildInputs;
|
nativeBuildInputs = [ go ] ++ nativeBuildInputs;
|
||||||
|
|
||||||
inherit (go) GOOS GOARCH;
|
inherit (go) GOOS GOARCH;
|
||||||
|
|
||||||
GOFLAGS = GOFLAGS
|
GOFLAGS = GOFLAGS
|
||||||
++ lib.warnIf (lib.any (lib.hasPrefix "-mod=") GOFLAGS) "use `proxyVendor` to control Go module/vendor behavior instead of setting `-mod=` in GOFLAGS"
|
++ lib.warnIf (lib.any (lib.hasPrefix "-mod=") GOFLAGS) "use `proxyVendor` to control Go module/vendor behavior instead of setting `-mod=` in GOFLAGS"
|
||||||
(lib.optional (!proxyVendor) "-mod=vendor")
|
(lib.optional (!finalAttrs.proxyVendor) "-mod=vendor")
|
||||||
++ lib.warnIf (builtins.elem "-trimpath" GOFLAGS) "`-trimpath` is added by default to GOFLAGS by buildGoModule when allowGoReference isn't set to true"
|
++ lib.warnIf (builtins.elem "-trimpath" GOFLAGS) "`-trimpath` is added by default to GOFLAGS by buildGoModule when allowGoReference isn't set to true"
|
||||||
(lib.optional (!allowGoReference) "-trimpath");
|
(lib.optional (!allowGoReference) "-trimpath");
|
||||||
inherit CGO_ENABLED enableParallelBuilding GO111MODULE GOTOOLCHAIN;
|
inherit CGO_ENABLED enableParallelBuilding GO111MODULE GOTOOLCHAIN;
|
||||||
@ -181,12 +200,12 @@ let
|
|||||||
export GOPROXY=off
|
export GOPROXY=off
|
||||||
export GOSUMDB=off
|
export GOSUMDB=off
|
||||||
cd "$modRoot"
|
cd "$modRoot"
|
||||||
'' + lib.optionalString (vendorHash != null) ''
|
'' + lib.optionalString (finalAttrs.vendorHash != null) ''
|
||||||
${if proxyVendor then ''
|
${if finalAttrs.proxyVendor then ''
|
||||||
export GOPROXY=file://${goModules}
|
export GOPROXY="file://$goModules"
|
||||||
'' else ''
|
'' else ''
|
||||||
rm -rf vendor
|
rm -rf vendor
|
||||||
cp -r --reflink=auto ${goModules} vendor
|
cp -r --reflink=auto "$goModules" vendor
|
||||||
''}
|
''}
|
||||||
'' + ''
|
'' + ''
|
||||||
|
|
||||||
@ -307,12 +326,17 @@ let
|
|||||||
|
|
||||||
disallowedReferences = lib.optional (!allowGoReference) go;
|
disallowedReferences = lib.optional (!allowGoReference) go;
|
||||||
|
|
||||||
passthru = { inherit go goModules vendorHash; } // passthru;
|
passthru = {
|
||||||
|
inherit go;
|
||||||
|
# Canonicallize `overrideModAttrs` as an attribute overlay.
|
||||||
|
# `passthru.overrideModAttrs` will be overridden
|
||||||
|
# when users want to override `goModules`.
|
||||||
|
overrideModAttrs = toExtension overrideModAttrs;
|
||||||
|
} // passthru;
|
||||||
|
|
||||||
meta = {
|
meta = {
|
||||||
# Add default meta information
|
# Add default meta information
|
||||||
platforms = go.meta.platforms or lib.platforms.all;
|
platforms = go.meta.platforms or lib.platforms.all;
|
||||||
} // meta;
|
} // meta;
|
||||||
});
|
}
|
||||||
in
|
))
|
||||||
package
|
|
||||||
|
@ -27,6 +27,38 @@ let
|
|||||||
expr = ((stdenvNoCC.mkDerivation { pname = "hello-no-final-attrs"; }).overrideAttrs { pname = "hello-no-final-attrs-overridden"; }).pname == "hello-no-final-attrs-overridden";
|
expr = ((stdenvNoCC.mkDerivation { pname = "hello-no-final-attrs"; }).overrideAttrs { pname = "hello-no-final-attrs-overridden"; }).pname == "hello-no-final-attrs-overridden";
|
||||||
expected = true;
|
expected = true;
|
||||||
};
|
};
|
||||||
|
buildGoModule-overrideAttrs = {
|
||||||
|
expr = lib.all (
|
||||||
|
attrPath:
|
||||||
|
let
|
||||||
|
attrPathPretty = lib.concatStringsSep "." attrPath;
|
||||||
|
valueNative = lib.getAttrFromPath attrPath pet_0_4_0;
|
||||||
|
valueOverridden = lib.getAttrFromPath attrPath pet_0_4_0-overridden;
|
||||||
|
in
|
||||||
|
lib.warnIfNot
|
||||||
|
(valueNative == valueOverridden)
|
||||||
|
"pet_0_4_0.${attrPathPretty} (${valueNative}) does not equal pet_0_4_0-overridden.${attrPathPretty} (${valueOverridden})"
|
||||||
|
true
|
||||||
|
) [
|
||||||
|
[ "drvPath" ]
|
||||||
|
[ "name" ]
|
||||||
|
[ "pname" ]
|
||||||
|
[ "version" ]
|
||||||
|
[ "vendorHash" ]
|
||||||
|
[ "goModules" "drvPath" ]
|
||||||
|
[ "goModules" "name" ]
|
||||||
|
[ "goModules" "outputHash" ]
|
||||||
|
];
|
||||||
|
expected = true;
|
||||||
|
};
|
||||||
|
buildGoModule-goModules-overrideAttrs = {
|
||||||
|
expr = pet-foo.goModules.FOO == "foo";
|
||||||
|
expected = true;
|
||||||
|
};
|
||||||
|
buildGoModule-goModules-overrideAttrs-vendored = {
|
||||||
|
expr = lib.isString pet-vendored.drvPath;
|
||||||
|
expected = true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
addEntangled = origOverrideAttrs: f:
|
addEntangled = origOverrideAttrs: f:
|
||||||
@ -51,6 +83,74 @@ let
|
|||||||
overrides1 = example.overrideAttrs (_: super: { pname = "a-better-${super.pname}"; });
|
overrides1 = example.overrideAttrs (_: super: { pname = "a-better-${super.pname}"; });
|
||||||
|
|
||||||
repeatedOverrides = overrides1.overrideAttrs (_: super: { pname = "${super.pname}-with-blackjack"; });
|
repeatedOverrides = overrides1.overrideAttrs (_: super: { pname = "${super.pname}-with-blackjack"; });
|
||||||
|
|
||||||
|
pet_0_3_4 = pkgs.buildGoModule rec {
|
||||||
|
pname = "pet";
|
||||||
|
version = "0.3.4";
|
||||||
|
|
||||||
|
src = pkgs.fetchFromGitHub {
|
||||||
|
owner = "knqyf263";
|
||||||
|
repo = "pet";
|
||||||
|
rev = "v${version}";
|
||||||
|
hash = "sha256-Gjw1dRrgM8D3G7v6WIM2+50r4HmTXvx0Xxme2fH9TlQ=";
|
||||||
|
};
|
||||||
|
|
||||||
|
vendorHash = "sha256-ciBIR+a1oaYH+H1PcC8cD8ncfJczk1IiJ8iYNM+R6aA=";
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
description = "Simple command-line snippet manager, written in Go";
|
||||||
|
homepage = "https://github.com/knqyf263/pet";
|
||||||
|
license = lib.licenses.mit;
|
||||||
|
maintainers = with lib.maintainers; [ kalbasit ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
pet_0_4_0 = pkgs.buildGoModule rec {
|
||||||
|
pname = "pet";
|
||||||
|
version = "0.4.0";
|
||||||
|
|
||||||
|
src = pkgs.fetchFromGitHub {
|
||||||
|
owner = "knqyf263";
|
||||||
|
repo = "pet";
|
||||||
|
rev = "v${version}";
|
||||||
|
hash = "sha256-gVTpzmXekQxGMucDKskGi+e+34nJwwsXwvQTjRO6Gdg=";
|
||||||
|
};
|
||||||
|
|
||||||
|
vendorHash = "sha256-dUvp7FEW09V0xMuhewPGw3TuAic/sD7xyXEYviZ2Ivs=";
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
description = "Simple command-line snippet manager, written in Go";
|
||||||
|
homepage = "https://github.com/knqyf263/pet";
|
||||||
|
license = lib.licenses.mit;
|
||||||
|
maintainers = with lib.maintainers; [ kalbasit ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
pet_0_4_0-overridden = pet_0_3_4.overrideAttrs (finalAttrs: previousAttrs: {
|
||||||
|
version = "0.4.0";
|
||||||
|
|
||||||
|
src = pkgs.fetchFromGitHub {
|
||||||
|
inherit (previousAttrs.src) owner repo;
|
||||||
|
rev = "v${finalAttrs.version}";
|
||||||
|
hash = "sha256-gVTpzmXekQxGMucDKskGi+e+34nJwwsXwvQTjRO6Gdg=";
|
||||||
|
};
|
||||||
|
|
||||||
|
vendorHash = "sha256-dUvp7FEW09V0xMuhewPGw3TuAic/sD7xyXEYviZ2Ivs=";
|
||||||
|
});
|
||||||
|
|
||||||
|
pet-foo = pet_0_3_4.overrideAttrs (
|
||||||
|
finalAttrs: previousAttrs: {
|
||||||
|
passthru = previousAttrs.passthru // {
|
||||||
|
overrideModAttrs = lib.composeExtensions previousAttrs.passthru.overrideModAttrs (
|
||||||
|
finalModAttrs: previousModAttrs: {
|
||||||
|
FOO = "foo";
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
pet-vendored = pet-foo.overrideAttrs { vendorHash = null; };
|
||||||
in
|
in
|
||||||
|
|
||||||
stdenvNoCC.mkDerivation {
|
stdenvNoCC.mkDerivation {
|
||||||
|
Loading…
Reference in New Issue
Block a user