|
| 1 | +{ |
| 2 | + go, |
| 3 | + cacert, |
| 4 | + git, |
| 5 | + lib, |
| 6 | + stdenv, |
| 7 | +}: { |
| 8 | + name ? "${args'.pname}-${args'.version}", |
| 9 | + src, |
| 10 | + buildInputs ? [], |
| 11 | + nativeBuildInputs ? [], |
| 12 | + passthru ? {}, |
| 13 | + patches ? [], |
| 14 | + # Go linker flags, passed to go via -ldflags |
| 15 | + ldflags ? [], |
| 16 | + # Go tags, passed to go via -tag |
| 17 | + tags ? [], |
| 18 | + # A function to override the go-modules derivation |
| 19 | + overrideModAttrs ? (_oldAttrs: {}), |
| 20 | + # path to go.mod and go.sum directory |
| 21 | + modRoot ? "./", |
| 22 | + # vendorHash is the SRI hash of the vendored dependencies |
| 23 | + # |
| 24 | + # if vendorHash is null, then we won't fetch any dependencies and |
| 25 | + # rely on the vendor folder within the source. |
| 26 | + vendorHash ? "_unset", |
| 27 | + # same as vendorHash, but outputHashAlgo is hardcoded to sha256 |
| 28 | + # so regular base32 sha256 hashes work |
| 29 | + vendorSha256 ? "_unset", |
| 30 | + # Whether to delete the vendor folder supplied with the source. |
| 31 | + deleteVendor ? false, |
| 32 | + # Whether to fetch (go mod download) and proxy the vendor directory. |
| 33 | + # This is useful if your code depends on c code and go mod tidy does not |
| 34 | + # include the needed sources to build or if any dependency has case-insensitive |
| 35 | + # conflicts which will produce platform dependant `vendorHash` checksums. |
| 36 | + proxyVendor ? false, |
| 37 | + # We want parallel builds by default |
| 38 | + enableParallelBuilding ? true, |
| 39 | + # Do not enable this without good reason |
| 40 | + # IE: programs coupled with the compiler |
| 41 | + allowGoReference ? false, |
| 42 | + CGO_ENABLED ? go.CGO_ENABLED, |
| 43 | + meta ? {}, |
| 44 | + # Not needed with buildGoModule |
| 45 | + goPackagePath ? "", |
| 46 | + # needed for buildFlags{,Array} warning |
| 47 | + buildFlags ? "", |
| 48 | + buildFlagsArray ? "", |
| 49 | + ... |
| 50 | +} @ args': |
| 51 | +with builtins; |
| 52 | +assert goPackagePath != "" -> throw "`goPackagePath` is not needed with `buildGoModule`"; |
| 53 | +assert (vendorSha256 == "_unset" && vendorHash == "_unset") -> throw "either `vendorHash` or `vendorSha256` is required"; |
| 54 | +assert (vendorSha256 != "_unset" && vendorHash != "_unset") -> throw "both `vendorHash` and `vendorSha256` set. only one can be set."; let |
| 55 | + hasAnyVendorHash = (vendorSha256 != null && vendorSha256 != "_unset") || (vendorHash != null && vendorHash != "_unset"); |
| 56 | + vendorHashType = |
| 57 | + if hasAnyVendorHash |
| 58 | + then |
| 59 | + if vendorSha256 != null && vendorSha256 != "_unset" |
| 60 | + then "sha256" |
| 61 | + else "sri" |
| 62 | + else null; |
| 63 | + |
| 64 | + args = removeAttrs args' ["overrideModAttrs" "vendorSha256" "vendorHash"]; |
| 65 | + |
| 66 | + go-modules = |
| 67 | + if hasAnyVendorHash |
| 68 | + then |
| 69 | + stdenv.mkDerivation (let |
| 70 | + modArgs = { |
| 71 | + name = "${name}-go-modules"; |
| 72 | + |
| 73 | + nativeBuildInputs = (args.nativeBuildInputs or []) ++ [go git cacert]; |
| 74 | + |
| 75 | + inherit (args) src; |
| 76 | + inherit (go) GOOS GOARCH; |
| 77 | + |
| 78 | + prePatch = args.prePatch or ""; |
| 79 | + patches = args.patches or []; |
| 80 | + patchFlags = args.patchFlags or []; |
| 81 | + postPatch = args.postPatch or ""; |
| 82 | + preBuild = args.preBuild or ""; |
| 83 | + postBuild = args.postBuild or ""; |
| 84 | + sourceRoot = args.sourceRoot or ""; |
| 85 | + |
| 86 | + GO111MODULE = "on"; |
| 87 | + |
| 88 | + impureEnvVars = |
| 89 | + lib.fetchers.proxyImpureEnvVars |
| 90 | + ++ [ |
| 91 | + "GIT_PROXY_COMMAND" |
| 92 | + "SOCKS_SERVER" |
| 93 | + "GOPROXY" |
| 94 | + ]; |
| 95 | + |
| 96 | + configurePhase = |
| 97 | + args.modConfigurePhase |
| 98 | + or '' |
| 99 | + runHook preConfigure |
| 100 | + export GOCACHE=$TMPDIR/go-cache |
| 101 | + export GOPATH="$TMPDIR/go" |
| 102 | + cd "${modRoot}" |
| 103 | + runHook postConfigure |
| 104 | + ''; |
| 105 | + |
| 106 | + buildPhase = |
| 107 | + args.modBuildPhase |
| 108 | + or '' |
| 109 | + runHook preBuild |
| 110 | + '' |
| 111 | + + lib.optionalString (deleteVendor == true) '' |
| 112 | + if [ ! -d vendor ]; then |
| 113 | + echo "vendor folder does not exist, 'deleteVendor' is not needed" |
| 114 | + exit 10 |
| 115 | + else |
| 116 | + rm -rf vendor |
| 117 | + fi |
| 118 | + '' |
| 119 | + + '' |
| 120 | + if [ -d vendor ]; then |
| 121 | + echo "vendor folder exists, please set 'vendorHash = null;' or 'vendorSha256 = null;' in your expression" |
| 122 | + exit 10 |
| 123 | + fi |
| 124 | +
|
| 125 | + ${ |
| 126 | + if proxyVendor |
| 127 | + then '' |
| 128 | + mkdir -p "''${GOPATH}/pkg/mod/cache/download" |
| 129 | + go mod download |
| 130 | + '' |
| 131 | + else '' |
| 132 | + if (( "''${NIX_DEBUG:-0}" >= 1 )); then |
| 133 | + goModVendorFlags+=(-v) |
| 134 | + fi |
| 135 | + go mod vendor "''${goModVendorFlags[@]}" |
| 136 | + '' |
| 137 | + } |
| 138 | +
|
| 139 | + mkdir -p vendor |
| 140 | +
|
| 141 | + runHook postBuild |
| 142 | + ''; |
| 143 | + |
| 144 | + installPhase = |
| 145 | + args.modInstallPhase |
| 146 | + or '' |
| 147 | + runHook preInstall |
| 148 | +
|
| 149 | + ${ |
| 150 | + if proxyVendor |
| 151 | + then '' |
| 152 | + rm -rf "''${GOPATH}/pkg/mod/cache/download/sumdb" |
| 153 | + cp -r --reflink=auto "''${GOPATH}/pkg/mod/cache/download/"* $out |
| 154 | + '' |
| 155 | + else '' |
| 156 | + cp -r --reflink=auto vendor $out |
| 157 | + '' |
| 158 | + } |
| 159 | +
|
| 160 | + if ! [ "$(ls -A $out)" ]; then |
| 161 | + echo "vendor folder is empty, please set 'vendorHash = null;' or 'vendorSha256 = null;' in your expression" |
| 162 | + exit 10 |
| 163 | + fi |
| 164 | +
|
| 165 | + runHook postInstall |
| 166 | + ''; |
| 167 | + |
| 168 | + dontFixup = true; |
| 169 | + }; |
| 170 | + in |
| 171 | + modArgs |
| 172 | + // ( |
| 173 | + { |
| 174 | + outputHashMode = "recursive"; |
| 175 | + } |
| 176 | + // ( |
| 177 | + if (vendorHashType == "sha256") |
| 178 | + then { |
| 179 | + outputHashAlgo = "sha256"; |
| 180 | + outputHash = vendorSha256; |
| 181 | + } |
| 182 | + else { |
| 183 | + outputHash = vendorHash; |
| 184 | + } |
| 185 | + ) |
| 186 | + // (lib.optionalAttrs (vendorHashType == "sri" && vendorHash == "") { |
| 187 | + outputHashAlgo = "sha256"; |
| 188 | + }) |
| 189 | + ) |
| 190 | + // overrideModAttrs modArgs) |
| 191 | + else ""; |
| 192 | + |
| 193 | + package = stdenv.mkDerivation (args |
| 194 | + // { |
| 195 | + nativeBuildInputs = [go] ++ nativeBuildInputs; |
| 196 | + |
| 197 | + inherit (go) GOOS GOARCH; |
| 198 | + |
| 199 | + GO111MODULE = "on"; |
| 200 | + GOFLAGS = lib.optionals (!proxyVendor) ["-mod=vendor"] ++ lib.optionals (!allowGoReference) ["-trimpath"]; |
| 201 | + inherit CGO_ENABLED; |
| 202 | + |
| 203 | + configurePhase = |
| 204 | + args.configurePhase |
| 205 | + or '' |
| 206 | + runHook preConfigure |
| 207 | +
|
| 208 | + export GOCACHE=$TMPDIR/go-cache |
| 209 | + export GOPATH="$TMPDIR/go" |
| 210 | + export GOPROXY=off |
| 211 | + export GOSUMDB=off |
| 212 | + cd "$modRoot" |
| 213 | + '' |
| 214 | + + lib.optionalString hasAnyVendorHash '' |
| 215 | + ${ |
| 216 | + if proxyVendor |
| 217 | + then '' |
| 218 | + export GOPROXY=file://${go-modules} |
| 219 | + '' |
| 220 | + else '' |
| 221 | + rm -rf vendor |
| 222 | + cp -r --reflink=auto ${go-modules} vendor |
| 223 | + '' |
| 224 | + } |
| 225 | + '' |
| 226 | + + '' |
| 227 | +
|
| 228 | + # currently pie is only enabled by default in pkgsMusl |
| 229 | + # this will respect the `hardening{Disable,Enable}` flags if set |
| 230 | + if [[ $NIX_HARDENING_ENABLE =~ "pie" ]]; then |
| 231 | + export GOFLAGS="-buildmode=pie $GOFLAGS" |
| 232 | + fi |
| 233 | +
|
| 234 | + runHook postConfigure |
| 235 | + ''; |
| 236 | + |
| 237 | + buildPhase = |
| 238 | + args.buildPhase |
| 239 | + or '' |
| 240 | + runHook preBuild |
| 241 | +
|
| 242 | + exclude='\(/_\|examples\|Godeps\|testdata' |
| 243 | + if [[ -n "$excludedPackages" ]]; then |
| 244 | + IFS=' ' read -r -a excludedArr <<<$excludedPackages |
| 245 | + printf -v excludedAlternates '%s\\|' "''${excludedArr[@]}" |
| 246 | + excludedAlternates=''${excludedAlternates%\\|} # drop final \| added by printf |
| 247 | + exclude+='\|'"$excludedAlternates" |
| 248 | + fi |
| 249 | + exclude+='\)' |
| 250 | +
|
| 251 | + buildGoDir() { |
| 252 | + local cmd="$1" dir="$2" |
| 253 | +
|
| 254 | + . $TMPDIR/buildFlagsArray |
| 255 | +
|
| 256 | + declare -a flags |
| 257 | + flags+=($buildFlags "''${buildFlagsArray[@]}") |
| 258 | + flags+=(''${tags:+-tags=${lib.concatStringsSep "," tags}}) |
| 259 | + flags+=(''${ldflags:+-ldflags="$ldflags"}) |
| 260 | + flags+=("-p" "$NIX_BUILD_CORES") |
| 261 | +
|
| 262 | + if [ "$cmd" = "test" ]; then |
| 263 | + flags+=(-vet=off) |
| 264 | + flags+=($checkFlags) |
| 265 | + fi |
| 266 | +
|
| 267 | + local OUT |
| 268 | + if ! OUT="$(go $cmd "''${flags[@]}" $dir 2>&1)"; then |
| 269 | + if ! echo "$OUT" | grep -qE '(no( buildable| non-test)?|build constraints exclude all) Go (source )?files'; then |
| 270 | + echo "$OUT" >&2 |
| 271 | + return 1 |
| 272 | + fi |
| 273 | + fi |
| 274 | + if [ -n "$OUT" ]; then |
| 275 | + echo "$OUT" >&2 |
| 276 | + fi |
| 277 | + return 0 |
| 278 | + } |
| 279 | +
|
| 280 | + getGoDirs() { |
| 281 | + local type; |
| 282 | + type="$1" |
| 283 | + if [ -n "$subPackages" ]; then |
| 284 | + echo "$subPackages" | sed "s,\(^\| \),\1./,g" |
| 285 | + else |
| 286 | + find . -type f -name \*$type.go -exec dirname {} \; | grep -v "/vendor/" | sort --unique | grep -v "$exclude" |
| 287 | + fi |
| 288 | + } |
| 289 | +
|
| 290 | + if (( "''${NIX_DEBUG:-0}" >= 1 )); then |
| 291 | + buildFlagsArray+=(-x) |
| 292 | + fi |
| 293 | +
|
| 294 | + if [ ''${#buildFlagsArray[@]} -ne 0 ]; then |
| 295 | + declare -p buildFlagsArray > $TMPDIR/buildFlagsArray |
| 296 | + else |
| 297 | + touch $TMPDIR/buildFlagsArray |
| 298 | + fi |
| 299 | + if [ -z "$enableParallelBuilding" ]; then |
| 300 | + export NIX_BUILD_CORES=1 |
| 301 | + fi |
| 302 | + for pkg in $(getGoDirs ""); do |
| 303 | + echo "Building subPackage $pkg" |
| 304 | + buildGoDir install "$pkg" |
| 305 | + done |
| 306 | + '' |
| 307 | + + lib.optionalString (stdenv.hostPlatform != stdenv.buildPlatform) '' |
| 308 | + # normalize cross-compiled builds w.r.t. native builds |
| 309 | + ( |
| 310 | + dir=$GOPATH/bin/${go.GOOS}_${go.GOARCH} |
| 311 | + if [[ -n "$(shopt -s nullglob; echo $dir/*)" ]]; then |
| 312 | + mv $dir/* $dir/.. |
| 313 | + fi |
| 314 | + if [[ -d $dir ]]; then |
| 315 | + rmdir $dir |
| 316 | + fi |
| 317 | + ) |
| 318 | + '' |
| 319 | + + '' |
| 320 | + runHook postBuild |
| 321 | + ''; |
| 322 | + |
| 323 | + doCheck = args.doCheck or true; |
| 324 | + checkPhase = |
| 325 | + args.checkPhase |
| 326 | + or '' |
| 327 | + runHook preCheck |
| 328 | + # We do not set trimpath for tests, in case they reference test assets |
| 329 | + export GOFLAGS=''${GOFLAGS//-trimpath/} |
| 330 | +
|
| 331 | + for pkg in $(getGoDirs test); do |
| 332 | + buildGoDir test "$pkg" |
| 333 | + done |
| 334 | +
|
| 335 | + runHook postCheck |
| 336 | + ''; |
| 337 | + |
| 338 | + installPhase = |
| 339 | + args.installPhase |
| 340 | + or '' |
| 341 | + runHook preInstall |
| 342 | +
|
| 343 | + mkdir -p $out |
| 344 | + dir="$GOPATH/bin" |
| 345 | + [ -e "$dir" ] && cp -r $dir $out |
| 346 | +
|
| 347 | + runHook postInstall |
| 348 | + ''; |
| 349 | + |
| 350 | + strictDeps = true; |
| 351 | + |
| 352 | + disallowedReferences = lib.optional (!allowGoReference) go; |
| 353 | + |
| 354 | + passthru = passthru // {inherit go go-modules vendorSha256 vendorHash;}; |
| 355 | + |
| 356 | + enableParallelBuilding = enableParallelBuilding; |
| 357 | + |
| 358 | + meta = |
| 359 | + { |
| 360 | + # Add default meta information |
| 361 | + platforms = go.meta.platforms or lib.platforms.all; |
| 362 | + } |
| 363 | + // meta; |
| 364 | + }); |
| 365 | +in |
| 366 | + lib.warnIf (buildFlags != "" || buildFlagsArray != "") |
| 367 | + "Use the `ldflags` and/or `tags` attributes instead of `buildFlags`/`buildFlagsArray`" |
| 368 | + package |
0 commit comments