nixpkgs mirror (for testing)
github.com/NixOS/nixpkgs
nix
1{
2 go,
3 cacert,
4 gitMinimal,
5 lib,
6 stdenv,
7}:
8
9lib.extendMkDerivation {
10 constructDrv = stdenv.mkDerivation;
11 excludeDrvArgNames = [
12 "overrideModAttrs"
13 ];
14 extendDrvArgs =
15 finalAttrs:
16 {
17 nativeBuildInputs ? [ ], # Native build inputs used for the derivation.
18 passthru ? { },
19
20 # A function to override the `goModules` derivation.
21 overrideModAttrs ? (finalAttrs: previousAttrs: { }),
22
23 # Directory to the `go.mod` and `go.sum` relative to the `src`.
24 modRoot ? "./",
25
26 # The SRI hash of the vendored dependencies.
27 # If `null`, it means the project either has no external dependencies
28 # or the vendored dependencies are already present in the source tree.
29 vendorHash ? throw (
30 if args ? vendorSha256 then
31 "buildGoModule: Expect vendorHash instead of vendorSha256"
32 else
33 "buildGoModule: vendorHash is missing"
34 ),
35
36 # The go.sum file to track which can cause rebuilds.
37 goSum ? null,
38
39 # Whether to delete the vendor folder supplied with the source.
40 deleteVendor ? false,
41
42 # Whether to fetch (go mod download) and proxy the vendor directory.
43 # This is useful if your code depends on c code and go mod tidy does not
44 # include the needed sources to build or if any dependency has case-insensitive
45 # conflicts which will produce platform dependant `vendorHash` checksums.
46 proxyVendor ? false,
47
48 # We want parallel builds by default.
49 enableParallelBuilding ? true,
50
51 # Do not enable this without good reason
52 # IE: programs coupled with the compiler.
53 allowGoReference ? false,
54
55 # Meta data for the final derivation.
56 meta ? { },
57
58 # Go linker flags.
59 ldflags ? [ ],
60 # Go build flags.
61 GOFLAGS ? [ ],
62
63 # Instead of building binary targets with 'go install', build test binaries with 'go test'.
64 # The binaries found in $out/bin can be executed as go tests outside of the sandbox.
65 # This is mostly useful outside of nixpkgs, for example to build integration/e2e tests
66 # that won't run within the sandbox.
67 buildTestBinaries ? false,
68
69 ...
70 }@args:
71 {
72 inherit
73 modRoot
74 vendorHash
75 deleteVendor
76 proxyVendor
77 goSum
78 ;
79 goModules =
80 if (finalAttrs.vendorHash == null) then
81 ""
82 else
83 (stdenv.mkDerivation {
84 name =
85 let
86 prefix = "${finalAttrs.name or "${finalAttrs.pname}-${finalAttrs.version}"}-";
87
88 # If "goSum" is supplied then it can cause "goModules" to rebuild.
89 # Attach the hash name of the "go.sum" file so we can rebuild when it changes.
90 suffix = lib.optionalString (
91 finalAttrs.goSum != null
92 ) "-${(lib.removeSuffix "-go.sum" (lib.removePrefix "${builtins.storeDir}/" finalAttrs.goSum))}";
93 in
94 "${prefix}go-modules${suffix}";
95
96 nativeBuildInputs = (finalAttrs.nativeBuildInputs or [ ]) ++ [
97 go
98 gitMinimal
99 cacert
100 ];
101
102 inherit (finalAttrs) src modRoot goSum;
103
104 # The following inheritance behavior is not trivial to expect, and some may
105 # argue it's not ideal. Changing it may break vendor hashes in Nixpkgs and
106 # out in the wild. In anycase, it's documented in:
107 # doc/languages-frameworks/go.section.md.
108 prePatch = finalAttrs.prePatch or "";
109 patches = finalAttrs.patches or [ ];
110 patchFlags = finalAttrs.patchFlags or [ ];
111 postPatch = finalAttrs.postPatch or "";
112 preBuild = finalAttrs.preBuild or "";
113 postBuild = finalAttrs.modPostBuild or "";
114 sourceRoot = finalAttrs.sourceRoot or "";
115 setSourceRoot = finalAttrs.setSourceRoot or "";
116 env = finalAttrs.env or { };
117
118 impureEnvVars = lib.fetchers.proxyImpureEnvVars ++ [
119 "GIT_PROXY_COMMAND"
120 "SOCKS_SERVER"
121 "GOPROXY"
122 ];
123
124 configurePhase =
125 args.modConfigurePhase or ''
126 runHook preConfigure
127 export GOCACHE=$TMPDIR/go-cache
128 export GOPATH="$TMPDIR/go"
129 cd "$modRoot"
130 runHook postConfigure
131 '';
132
133 buildPhase =
134 args.modBuildPhase or (
135 ''
136 runHook preBuild
137 ''
138 + lib.optionalString finalAttrs.deleteVendor ''
139 if [ ! -d vendor ]; then
140 echo "vendor folder does not exist, 'deleteVendor' is not needed"
141 exit 10
142 else
143 rm -rf vendor
144 fi
145 ''
146 + ''
147 if [ -d vendor ]; then
148 echo "vendor folder exists, please set 'vendorHash = null;' in your expression"
149 exit 10
150 fi
151
152 export GIT_SSL_CAINFO=$NIX_SSL_CERT_FILE
153 ${
154 if finalAttrs.proxyVendor then
155 ''
156 mkdir -p "$GOPATH/pkg/mod/cache/download"
157 go mod download
158 ''
159 else
160 ''
161 if (( "''${NIX_DEBUG:-0}" >= 1 )); then
162 goModVendorFlags+=(-v)
163 fi
164 go mod vendor "''${goModVendorFlags[@]}"
165 ''
166 }
167
168 mkdir -p vendor
169
170 runHook postBuild
171 ''
172 );
173
174 installPhase =
175 args.modInstallPhase or ''
176 runHook preInstall
177
178 ${
179 if finalAttrs.proxyVendor then
180 ''
181 rm -rf "$GOPATH/pkg/mod/cache/download/sumdb"
182 cp -r --reflink=auto "$GOPATH/pkg/mod/cache/download" $out
183 ''
184 else
185 ''
186 cp -r --reflink=auto vendor $out
187 ''
188 }
189
190 if ! [ "$(ls -A $out)" ]; then
191 echo "vendor folder is empty, please set 'vendorHash = null;' in your expression"
192 exit 10
193 fi
194
195 runHook postInstall
196 '';
197
198 dontFixup = true;
199
200 outputHashMode = "recursive";
201 outputHash = finalAttrs.vendorHash;
202 # Handle empty `vendorHash`; avoid error:
203 # empty hash requires explicit hash algorithm.
204 outputHashAlgo = if finalAttrs.vendorHash == "" then "sha256" else null;
205 # in case an overlay clears passthru by accident, don't fail evaluation
206 }).overrideAttrs
207 (
208 let
209 pos = builtins.unsafeGetAttrPos "passthru" finalAttrs;
210 posString =
211 if pos == null then "unknown" else "${pos.file}:${toString pos.line}:${toString pos.column}";
212 in
213 finalAttrs.passthru.overrideModAttrs
214 or (lib.warn "buildGoModule: ${finalAttrs.name or finalAttrs.pname}: passthru.overrideModAttrs missing after overrideAttrs. Last overridden at ${posString}." overrideModAttrs)
215 );
216
217 nativeBuildInputs = [ go ] ++ nativeBuildInputs;
218
219 env = args.env or { } // {
220 inherit (go) GOOS GOARCH;
221
222 GO111MODULE = "on";
223 GOTOOLCHAIN = "local";
224
225 CGO_ENABLED = args.env.CGO_ENABLED or go.CGO_ENABLED;
226
227 GOFLAGS = toString (
228 GOFLAGS
229 ++
230 lib.warnIf (lib.any (lib.hasPrefix "-mod=") GOFLAGS)
231 "use `proxyVendor` to control Go module/vendor behavior instead of setting `-mod=` in GOFLAGS"
232 (lib.optional (!finalAttrs.proxyVendor) "-mod=vendor")
233 ++
234 lib.warnIf (builtins.elem "-trimpath" GOFLAGS)
235 "`-trimpath` is added by default to GOFLAGS by buildGoModule when allowGoReference isn't set to true"
236 (lib.optional (!finalAttrs.allowGoReference) "-trimpath")
237 );
238 };
239
240 inherit enableParallelBuilding;
241
242 # If not set to an explicit value, set the buildid empty for reproducibility.
243 ldflags = ldflags ++ lib.optional (!lib.any (lib.hasPrefix "-buildid=") ldflags) "-buildid=";
244
245 configurePhase =
246 args.configurePhase or (
247 ''
248 runHook preConfigure
249
250 export GOCACHE=$TMPDIR/go-cache
251 export GOPATH="$TMPDIR/go"
252 export GOPROXY=off
253 export GOSUMDB=off
254 if [ -f "$NIX_CC_FOR_TARGET/nix-support/dynamic-linker" ]; then
255 export GO_LDSO=$(cat $NIX_CC_FOR_TARGET/nix-support/dynamic-linker)
256 fi
257 cd "$modRoot"
258 ''
259 + lib.optionalString (finalAttrs.vendorHash != null) ''
260 ${
261 if finalAttrs.proxyVendor then
262 ''
263 export GOPROXY="file://$goModules"
264 ''
265 else
266 ''
267 rm -rf vendor
268 cp -r --reflink=auto "$goModules" vendor
269 ''
270 }
271 ''
272 + ''
273 runHook postConfigure
274 ''
275 );
276
277 buildPhase =
278 args.buildPhase or (
279 lib.warnIf (builtins.elem "-buildid=" ldflags)
280 "`-buildid=` is set by default as ldflag by buildGoModule"
281 ''
282 runHook preBuild
283
284 exclude='\(/_\|examples\|Godeps\|testdata'
285 if [[ -n "$excludedPackages" ]]; then
286 IFS=' ' read -r -a excludedArr <<<$excludedPackages
287 printf -v excludedAlternates '%s\\|' "''${excludedArr[@]}"
288 excludedAlternates=''${excludedAlternates%\\|} # drop final \| added by printf
289 exclude+='\|'"$excludedAlternates"
290 fi
291 exclude+='\)'
292
293 buildGoDir() {
294 local cmd="$1" dir="$2"
295
296 declare -a flags
297 flags+=(''${tags:+-tags=$(concatStringsSep "," tags)})
298 flags+=(''${ldflags:+-ldflags="''${ldflags[*]}"})
299 flags+=("-p" "$NIX_BUILD_CORES")
300 if (( "''${NIX_DEBUG:-0}" >= 1 )); then
301 flags+=(-x)
302 fi
303
304 if [ "$cmd" = "test" ]; then
305 flags+=(-vet=off)
306 flags+=($checkFlags)
307 fi
308
309 local OUT
310 if ! OUT="$(go $cmd "''${flags[@]}" $dir 2>&1)"; then
311 if ! echo "$OUT" | grep -qE '(no( buildable| non-test)?|build constraints exclude all) Go (source )?files'; then
312 echo "$OUT" >&2
313 return 1
314 fi
315 fi
316 if [ -n "$OUT" ]; then
317 echo "$OUT" >&2
318 fi
319 return 0
320 }
321
322 getGoDirs() {
323 local type;
324 type="$1"
325 if [ -n "$subPackages" ]; then
326 echo "$subPackages" | sed "s,\(^\| \),\1./,g"
327 else
328 find . -type f -name \*$type.go -exec dirname {} \; | grep -v "/vendor/" | sort --unique | grep -v "$exclude"
329 fi
330 }
331
332 if [ -z "$enableParallelBuilding" ]; then
333 export NIX_BUILD_CORES=1
334 fi
335 for pkg in $(getGoDirs ""); do
336 ${
337 if buildTestBinaries then
338 ''
339 echo "Building test binary for $pkg"
340 buildGoDir "test -c -o $GOPATH/bin/" "$pkg"
341 ''
342 else
343 ''
344 echo "Building subPackage $pkg"
345 buildGoDir install "$pkg"
346 ''
347 }
348 done
349 ''
350 + lib.optionalString (stdenv.hostPlatform != stdenv.buildPlatform) ''
351 # normalize cross-compiled builds w.r.t. native builds
352 (
353 dir=$GOPATH/bin/''${GOOS}_''${GOARCH}
354 if [[ -n "$(shopt -s nullglob; echo $dir/*)" ]]; then
355 mv $dir/* $dir/..
356 fi
357 if [[ -d $dir ]]; then
358 rmdir $dir
359 fi
360 )
361 ''
362 + ''
363 runHook postBuild
364 ''
365 );
366
367 doCheck = args.doCheck or (!buildTestBinaries);
368 checkPhase =
369 args.checkPhase or ''
370 runHook preCheck
371 # We do not set trimpath for tests, in case they reference test assets
372 export GOFLAGS=''${GOFLAGS//-trimpath/}
373
374 for pkg in $(getGoDirs test); do
375 buildGoDir test "$pkg"
376 done
377
378 runHook postCheck
379 '';
380
381 installPhase =
382 args.installPhase or ''
383 runHook preInstall
384
385 mkdir -p $out
386 dir="$GOPATH/bin"
387 [ -e "$dir" ] && cp -r $dir $out
388
389 runHook postInstall
390 '';
391
392 strictDeps = true;
393
394 inherit allowGoReference;
395 disallowedReferences = lib.optional (!finalAttrs.allowGoReference) go;
396
397 passthru = {
398 inherit go;
399 # Canonicallize `overrideModAttrs` as an attribute overlay.
400 # `passthru.overrideModAttrs` will be overridden
401 # when users want to override `goModules`.
402 overrideModAttrs = lib.toExtension overrideModAttrs;
403 }
404 // passthru;
405
406 meta = {
407 # Add default meta information.
408 platforms = go.meta.platforms or lib.platforms.all;
409 }
410 // meta;
411 };
412}