nixos-config/lib/builders/hugo-build-site/default.nix

254 lines
8.0 KiB
Nix
Raw Permalink Normal View History

# Copyright (c) 2003-2024 Eelco Dolstra and the Nixpkgs/NixOS contributors
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2025-01-12 09:57:14 +00:00
{ hugo, go, cacert, git, lib, stdenv, }:
# A modified Go builder for generating a website with Hugo. Since it relies on
# Hugo modules (which is basically wrapper around Go modules), this can be used
# for Hugo projects that heavily uses them.
#
# Take note, this doesn't work for Hugo projects with remote resources
# right in the content since Hugo allows network access when generating
# the website.
2025-01-12 09:57:14 +00:00
{ name ? "${args'.pname}-${args'.version}",
2025-01-12 09:57:14 +00:00
nativeBuildInputs ? [ ], passthru ? { },
2025-01-12 09:57:14 +00:00
# A function to override the goModules derivation
overrideModAttrs ? (_oldAttrs: { }),
2025-01-12 09:57:14 +00:00
# path to go.mod and go.sum directory
modRoot ? "./",
2025-01-12 09:57:14 +00:00
# vendorHash is the SRI hash of the vendored dependencies
#
# if vendorHash is null, then we won't fetch any dependencies and
# rely on the vendor folder within the source.
vendorHash ? throw (if args' ? vendorSha256 then
"buildHugoSite: Expect vendorHash instead of vendorSha256"
else
"buildHugoSite: vendorHash is missing"),
2025-01-12 09:57:14 +00:00
# Whether to delete the vendor folder supplied with the source.
deleteVendor ? false,
2025-01-12 09:57:14 +00:00
# Whether to fetch (go mod download) and proxy the vendor directory.
# This is useful if your code depends on c code and go mod tidy does not
# include the needed sources to build or if any dependency has case-insensitive
# conflicts which will produce platform dependant `vendorHash` checksums.
proxyVendor ? false,
2025-01-12 09:57:14 +00:00
# We want parallel builds by default
enableParallelBuilding ? true,
2025-01-12 09:57:14 +00:00
# Do not enable this without good reason
# IE: programs coupled with the compiler
allowGoReference ? false,
2025-01-12 09:57:14 +00:00
CGO_ENABLED ? go.CGO_ENABLED,
2025-01-12 09:57:14 +00:00
meta ? { },
2025-01-12 09:57:14 +00:00
ldflags ? [ ],
2025-01-12 09:57:14 +00:00
GOFLAGS ? [ ],
2025-01-12 09:57:14 +00:00
... }@args':
let
2025-01-12 09:57:14 +00:00
args = removeAttrs args' [ "overrideModAttrs" "vendorSha256" "vendorHash" ];
GO111MODULE = "on";
GOTOOLCHAIN = "local";
2025-01-12 09:57:14 +00:00
hugoModules = if (vendorHash == null) then
""
else
(stdenv.mkDerivation {
name = "${name}-hugo-modules";
2025-01-12 09:57:14 +00:00
nativeBuildInputs = (args.nativeBuildInputs or [ ])
++ [ hugo go git cacert ];
2025-01-12 09:57:14 +00:00
inherit (args) src;
inherit (go) GOOS GOARCH;
inherit GO111MODULE GOTOOLCHAIN;
# The following inheritence behavior is not trivial to expect, and some may
# argue it's not ideal. Changing it may break vendor hashes in Nixpkgs and
# out in the wild. In anycase, it's documented in:
# doc/languages-frameworks/go.section.md
prePatch = args.prePatch or "";
patches = args.patches or [ ];
patchFlags = args.patchFlags or [ ];
postPatch = args.postPatch or "";
preBuild = args.preBuild or "";
postBuild = args.modPostBuild or "";
sourceRoot = args.sourceRoot or "";
setSourceRoot = args.setSourceRoot or "";
env = args.env or { };
impureEnvVars = lib.fetchers.proxyImpureEnvVars
++ [ "GIT_PROXY_COMMAND" "SOCKS_SERVER" "GOPROXY" ];
configurePhase = args.modConfigurePhase or ''
runHook preConfigure
export GOCACHE=$TMPDIR/go-cache
export GOPATH="$TMPDIR/go"
cd "${modRoot}"
runHook postConfigure
'';
buildPhase = args.modBuildPhase or (''
runHook preBuild
'' + lib.optionalString deleteVendor ''
if [ ! -d _vendor ]; then
echo "_vendor folder does not exist, 'deleteVendor' is not needed"
exit 10
else
rm -rf _vendor
fi
'' + ''
if [ -d _vendor ]; then
echo "_vendor folder exists, please set 'vendorHash = null;' in your expression"
exit 10
fi
${if proxyVendor then ''
mkdir -p "''${GOPATH}/pkg/mod/cache/download"
hugo mod vendor
'' else ''
if (( "''${NIX_DEBUG:-0}" >= 1 )); then
hugoModVendorFlags+=(-v)
fi
hugo mod vendor "''${hugoModVendorFlags[@]}"
''}
mkdir -p _vendor
runHook postBuild
'');
installPhase = args.modInstallPhase or ''
runHook preInstall
${if proxyVendor then ''
rm -rf "''${GOPATH}/pkg/mod/cache/download/sumdb"
cp -r --reflink=auto "''${GOPATH}/pkg/mod/cache/download" $out
'' else ''
cp -r --reflink=auto _vendor $out
''}
if ! [ "$(ls -A $out)" ]; then
echo "_vendor folder is empty, please set 'vendorHash = null;' in your expression"
exit 10
fi
runHook postInstall
'';
dontFixup = true;
outputHashMode = "recursive";
outputHash = vendorHash;
# Handle empty vendorHash; avoid
# error: empty hash requires explicit hash algorithm
outputHashAlgo = if vendorHash == "" then "sha256" else null;
}).overrideAttrs overrideModAttrs;
package = stdenv.mkDerivation (args // {
nativeBuildInputs = [ hugo git go ] ++ nativeBuildInputs;
inherit (go) GOOS GOARCH;
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.optional (!proxyVendor) "-mod=vendor")
++ lib.warnIf (builtins.elem "-trimpath" GOFLAGS)
"`-trimpath` is added by default to GOFLAGS by buildHugoSite when allowGoReference isn't set to true"
(lib.optional (!allowGoReference) "-trimpath");
inherit CGO_ENABLED enableParallelBuilding GO111MODULE GOTOOLCHAIN;
# If not set to an explicit value, set the buildid empty for reproducibility.
ldflags = ldflags
++ lib.optional (!lib.any (lib.hasPrefix "-buildid=") ldflags)
"-buildid=";
configurePhase = args.configurePhase or (''
runHook preConfigure
export GOCACHE=$TMPDIR/go-cache
export GOPATH="$TMPDIR/go"
export GOPROXY=off
export GOSUMDB=off
cd "$modRoot"
'' + lib.optionalString (vendorHash != null) ''
${if proxyVendor then ''
export GOPROXY=file://${hugoModules}
'' else ''
rm -rf _vendor
cp -r --reflink=auto ${hugoModules} _vendor
''}
'' + ''
# currently pie is only enabled by default in pkgsMusl
# this will respect the `hardening{Disable,Enable}` flags if set
if [[ $NIX_HARDENING_ENABLE =~ "pie" ]]; then
export GOFLAGS="-buildmode=pie $GOFLAGS"
fi
runHook postConfigure
'');
buildPhase = args.buildPhase or ''
runHook preBuild
hugo "''${buildFlags[@]}" --destination public
runHook postBuild
'';
doCheck = args.doCheck or true;
checkPhase = args.checkPhase or ''
runHook preCheck
runHook postCheck
'';
installPhase = args.installPhase or ''
runHook preInstall
mkdir -p $out
cp -r public/* $out
runHook postInstall
'';
strictDeps = true;
disallowedReferences = lib.optional (!allowGoReference) go;
passthru = passthru // { inherit go hugo hugoModules vendorHash; };
meta = {
# Add default meta information
platforms = go.meta.platforms or lib.platforms.all;
} // meta;
});
in package