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