From d1972278b5292faefe31e2f81ef57cd06598b387 Mon Sep 17 00:00:00 2001 From: "Adam C. Stephens" Date: Mon, 29 Dec 2025 13:21:40 -0500 Subject: [PATCH] beamPackages.buildMix: move phases to hooks --- pkgs/development/beam-modules/build-mix.nix | 106 ++++++------------ pkgs/development/beam-modules/default.nix | 6 +- .../hooks/beam-copy-source-hook.sh | 16 +++ .../hooks/beam-module-install-hook.sh | 25 +++++ .../beam-modules/hooks/default.nix | 24 +++- .../hooks/mix-app-config-patch-hook.sh | 19 ++++ .../beam-modules/hooks/mix-build-dir-hook.sh | 26 +++++ .../beam-modules/hooks/mix-compile-hook.sh | 20 ++++ .../beam-modules/hooks/mix-configure-hook.sh | 34 ------ .../beam-modules/mix-configure-hook.sh | 5 + pkgs/development/beam-modules/mix-release.nix | 2 - pkgs/servers/mobilizon/default.nix | 1 + 12 files changed, 169 insertions(+), 115 deletions(-) create mode 100755 pkgs/development/beam-modules/hooks/beam-copy-source-hook.sh create mode 100644 pkgs/development/beam-modules/hooks/beam-module-install-hook.sh create mode 100644 pkgs/development/beam-modules/hooks/mix-app-config-patch-hook.sh create mode 100755 pkgs/development/beam-modules/hooks/mix-build-dir-hook.sh create mode 100755 pkgs/development/beam-modules/hooks/mix-compile-hook.sh delete mode 100755 pkgs/development/beam-modules/hooks/mix-configure-hook.sh create mode 100755 pkgs/development/beam-modules/mix-configure-hook.sh diff --git a/pkgs/development/beam-modules/build-mix.nix b/pkgs/development/beam-modules/build-mix.nix index d867648abdfb..52c0ce1ad1f8 100644 --- a/pkgs/development/beam-modules/build-mix.nix +++ b/pkgs/development/beam-modules/build-mix.nix @@ -2,8 +2,13 @@ elixir, erlang, hex, + beamCopySourceHook, + beamModuleInstallHook, + mixBuildDirHook, + mixCompileHook, + mixAppConfigPatchHook, + lib, - mixConfigureHook, stdenv, writeText, }: @@ -16,42 +21,46 @@ lib.extendMkDerivation { extendDrvArgs = finalAttrs: { - nativeBuildInputs ? [ ], - propagatedBuildInputs ? [ ], - passthru ? { }, + beamDeps ? [ ], mixEnv ? "prod", mixTarget ? "host", - enableDebugInfo ? false, - # A handful of libraries require compile time configuration + + # Allow passing compile time config instead of an empty config appConfigPath ? null, + + enableDebugInfo ? false, erlangCompilerOptions ? [ ], # Deterministic Erlang builds remove full system paths from debug information # among other things to keep builds more reproducible. See their docs for more: # https://www.erlang.org/doc/man/compile erlangDeterministicBuilds ? true, - beamDeps ? [ ], ... }@args: { - name = "erlang-${erlang.version}-${args.name}-${finalAttrs.version}"; + name = "erlang${erlang.version}-${args.name}-${finalAttrs.version}"; env = { - MIX_ENV = mixEnv; - MIX_TARGET = mixTarget; - MIX_BUILD_PREFIX = (if mixTarget == "host" then "" else "${mixTarget}_") + "${mixEnv}"; - MIX_DEBUG = if enableDebugInfo then 1 else 0; - HEX_OFFLINE = 1; ERL_COMPILER_OPTIONS = let options = erlangCompilerOptions ++ lib.optionals erlangDeterministicBuilds [ "deterministic" ]; in "[${lib.concatStringsSep "," options}]"; + MIX_ENV = mixEnv; + MIX_TARGET = mixTarget; + MIX_BUILD_PREFIX = (if mixTarget == "host" then "" else "${mixTarget}_") + "${mixEnv}"; + MIX_DEBUG = if enableDebugInfo then 1 else 0; + HEX_OFFLINE = 1; + LANG = if stdenv.hostPlatform.isLinux then "C.UTF-8" else "C"; LC_CTYPE = if stdenv.hostPlatform.isLinux then "C.UTF-8" else "UTF-8"; - __darwinAllowLocalNetworking = true; + + # some hooks need name-version, but we've overridden name above for the nix package + beamModuleName = args.name; }; + __darwinAllowLocalNetworking = true; + # add to ERL_LIBS so other modules can find at runtime. # http://erlang.org/doc/man/code.html#code-path # Mix also searches the code path when compiling with the --no-deps-check flag @@ -60,70 +69,21 @@ lib.extendMkDerivation { addToSearchPath ERL_LIBS "$1/lib/erlang/lib" ''; - nativeBuildInputs = nativeBuildInputs ++ [ + nativeBuildInputs = (args.nativeBuildInputs or [ ]) ++ [ elixir hex - mixConfigureHook + + beamCopySourceHook + beamModuleInstallHook + mixBuildDirHook + mixCompileHook + mixAppConfigPatchHook ]; - propagatedBuildInputs = propagatedBuildInputs ++ beamDeps; - # We don't want to include whatever config a dependency brings; per - # https://hexdocs.pm/elixir/main/Config.html, config is application specific. - patchPhase = - args.patchPhase or ( - '' - runHook prePatch + propagatedBuildInputs = (args.propagatedBuildInputs or [ ]) ++ beamDeps; - rm -rf config - '' - + lib.optionalString (!isNull appConfigPath) '' - cp -r ${appConfigPath} config - '' - + '' - runHook postPatch - '' - ); - - buildPhase = - args.buildPhase or '' - runHook preBuild - - export HEX_HOME="$TEMPDIR/hex" - export MIX_HOME="$TEMPDIR/mix" - mix compile --no-deps-check - - runHook postBuild - ''; - - installPhase = - args.installPhase or '' - runHook preInstall - - # This uses the install path convention established by nixpkgs maintainers - # for all beam packages. Changing this will break compatibility with other - # builder functions like buildRebar3 and buildErlangMk. - mkdir -p "$out/lib/erlang/lib/${finalAttrs.name}-${finalAttrs.version}-${args.version}" - - # Some packages like db_connection will use _build/shared instead of - # honoring the $MIX_ENV variable. - for reldir in _build/{$MIX_BUILD_PREFIX,shared}/lib/${finalAttrs.name}-${finalAttrs.version}/{src,ebin,priv,include} ; do - if test -d $reldir ; then - # Some builds produce symlinks (eg: phoenix priv dircetory). They must - # be followed with -H flag. - cp -Hrt "$out/lib/erlang/lib/${finalAttrs.name}-${finalAttrs.version}" "$reldir" - fi - done - - runHook postInstall - ''; - - # stripping does not have any effect on beam files - # it is however needed for dependencies with NIFs like bcrypt for example - dontStrip = args.dontStrip or false; - - passthru = { + passthru = (args.passthru or { }) // { inherit beamDeps; - } - // passthru; + }; }; } diff --git a/pkgs/development/beam-modules/default.nix b/pkgs/development/beam-modules/default.nix index 4102f0a60031..0fec22df3458 100644 --- a/pkgs/development/beam-modules/default.nix +++ b/pkgs/development/beam-modules/default.nix @@ -101,7 +101,11 @@ let webdriver = callPackage ./webdriver { }; inherit (callPackages ./hooks { }) - mixConfigureHook + beamCopySourceHook + beamModuleInstallHook + mixBuildDirHook + mixCompileHook + mixAppConfigPatchHook ; }; in diff --git a/pkgs/development/beam-modules/hooks/beam-copy-source-hook.sh b/pkgs/development/beam-modules/hooks/beam-copy-source-hook.sh new file mode 100755 index 000000000000..a4ffa9fd1413 --- /dev/null +++ b/pkgs/development/beam-modules/hooks/beam-copy-source-hook.sh @@ -0,0 +1,16 @@ +# shellcheck shell=bash +# +# Copy the source so it can be used by mix projects to assemble `deps` +# do this before building to avoid build artifacts but after patching +# to include any user modifications to the source + +beamCopySourceHook() { + echo "Executing beamCopySourceHook" + + mkdir -p "$out/src" + cp -r "." "$out/src" + + echo "Finished beamCopySourceHook" +} + +postPatchHooks+=(beamCopySourceHook) diff --git a/pkgs/development/beam-modules/hooks/beam-module-install-hook.sh b/pkgs/development/beam-modules/hooks/beam-module-install-hook.sh new file mode 100644 index 000000000000..6591f4bb70f7 --- /dev/null +++ b/pkgs/development/beam-modules/hooks/beam-module-install-hook.sh @@ -0,0 +1,25 @@ +# shellcheck shell=bash +# +# This uses the install path convention established by nixpkgs maintainers +# for all beam packages. Changing this will break compatibility with other +# builder functions like buildRebar3 and buildErlangMk. + +beamModuleInstallHook() { + echo "Executing beamModuleInstallHook" + + mkdir -p "$out/lib/erlang/lib/${beamModuleName}-${version}" + + for reldir in _build/{$MIX_BUILD_PREFIX,shared}/lib/${beamModuleName}/{src,ebin,priv,include}; do + if test -d "$reldir"; then + # Some builds produce symlinks (eg: phoenix priv directory). They must + # be followed with -H flag. + cp -vHrt "$out/lib/erlang/lib/${beamModuleName}-${version}" "$reldir" + fi + done + + echo "Finished beamModuleInstallHook" +} + +if [ -z "${dontBeamModuleInstall-}" ] && [ -z "${installPhase-}" ]; then + installPhase=beamModuleInstallHook +fi diff --git a/pkgs/development/beam-modules/hooks/default.nix b/pkgs/development/beam-modules/hooks/default.nix index 9bf74f5dbbb3..000363c9d150 100644 --- a/pkgs/development/beam-modules/hooks/default.nix +++ b/pkgs/development/beam-modules/hooks/default.nix @@ -1,8 +1,22 @@ +{ makeSetupHook }: { - makeSetupHook, -}: -{ - mixConfigureHook = makeSetupHook { + beamCopySourceHook = makeSetupHook { + name = "beam-copy-source-hook.sh"; + } ./beam-copy-source-hook.sh; + + beamModuleInstallHook = makeSetupHook { + name = "beam-module-install-hook.sh"; + } ./beam-module-install-hook.sh; + + mixBuildDirHook = makeSetupHook { name = "mix-configure-hook.sh"; - } ./mix-configure-hook.sh; + } ./mix-build-dir-hook.sh; + + mixCompileHook = makeSetupHook { + name = "mix-compile-hook.sh"; + } ./mix-compile-hook.sh; + + mixAppConfigPatchHook = makeSetupHook { + name = "mix-config-patch-hook.sh"; + } ./mix-app-config-patch-hook.sh; } diff --git a/pkgs/development/beam-modules/hooks/mix-app-config-patch-hook.sh b/pkgs/development/beam-modules/hooks/mix-app-config-patch-hook.sh new file mode 100644 index 000000000000..e2153db58b4c --- /dev/null +++ b/pkgs/development/beam-modules/hooks/mix-app-config-patch-hook.sh @@ -0,0 +1,19 @@ +# shellcheck shell=bash +# +# We don't want to include whatever config a dependency brings; per +# https://hexdocs.pm/elixir/main/Config.html, config is application specific. + +mixAppConfigPatchHook() { + echo "Executing mixAppConfigPatchHook" + + rm -rvf config + + # But we still need a way to provide config for deps that need compile time config + if [ ! -z "${appConfigPath}" ]; then + ln -sf "${appConfigPath}" config + fi + + echo "Finished mixAppConfigPatchHook" +} + +prePatchHooks+=(mixAppConfigPatchHook) diff --git a/pkgs/development/beam-modules/hooks/mix-build-dir-hook.sh b/pkgs/development/beam-modules/hooks/mix-build-dir-hook.sh new file mode 100755 index 000000000000..c353aaeabc4d --- /dev/null +++ b/pkgs/development/beam-modules/hooks/mix-build-dir-hook.sh @@ -0,0 +1,26 @@ +# shellcheck shell=bash +# +# Symlink all dependencies found in ERL_LIBS since Elixir does not honor ERL_LIBS + +mixBuildDirHook() { + echo "Executing mixBuildDirHook" + + mkdir -p _build/"$MIX_BUILD_PREFIX"/lib + while read -r -d ':' lib; do + for dir in "$lib"/*; do + # Strip version number for directory name if it exists, so naming of + # all libs matches what mix's expectation. + dest=$(basename "$dir" | cut -d '-' -f1) + build_dir="_build/$MIX_BUILD_PREFIX/lib/$dest" + + # Symlink libs to _build so that mix can find them when compiling. + # This is what allows mix to compile the package without searching + # for dependencies over the network. + ln -sv "$dir" "$build_dir" + done + done <<<"$ERL_LIBS:" + + echo "Finished mixBuildDirHook" +} + +preConfigureHooks+=(mixBuildDirHook) diff --git a/pkgs/development/beam-modules/hooks/mix-compile-hook.sh b/pkgs/development/beam-modules/hooks/mix-compile-hook.sh new file mode 100755 index 000000000000..19b27c8a94f8 --- /dev/null +++ b/pkgs/development/beam-modules/hooks/mix-compile-hook.sh @@ -0,0 +1,20 @@ +# shellcheck shell=bash + +mixCompileHook() { + echo "Executing mixCompileHook" + + runHook preBuild + + local flagsArray=() + concatTo flagsArray mixCompileFlags + + mix compile --no-deps-check "${flagsArray[@]}" + + runHook postBuild + + echo "Finished mixCompileHook" +} + +if [ -z "${dontMixCompile-}" ] && [ -z "${buildPhase-}" ]; then + buildPhase=mixCompileHook +fi diff --git a/pkgs/development/beam-modules/hooks/mix-configure-hook.sh b/pkgs/development/beam-modules/hooks/mix-configure-hook.sh deleted file mode 100755 index 56851bc9fb9d..000000000000 --- a/pkgs/development/beam-modules/hooks/mix-configure-hook.sh +++ /dev/null @@ -1,34 +0,0 @@ -# shellcheck shell=bash -mixConfigureHook() { - echo "Executing mixConfigureHook" - - runHook preConfigure - - # Copy the source so it can be used by mix projects - # do this before building to avoid build artifacts but after patching - # to include any modifications - mkdir -p "$out/src" - cp -r "." "$out/src" - - # Symlink all dependencies found in ERL_LIBS since Elixir does not honor ERL_LIBS - mkdir -p _build/"$MIX_BUILD_PREFIX"/lib - while read -r -d ':' lib; do - for dir in "$lib"/*; do - # Strip version number for directory name if it exists, so naming of - # all libs matches what mix's expectation. - dest=$(basename "$dir" | cut -d '-' -f1) - build_dir="_build/$MIX_BUILD_PREFIX/lib/$dest" - ((MIX_DEBUG == 1)) && echo "Linking $dir to $build_dir" - # Symlink libs to _build so that mix can find them when compiling. - # This is what allows mix to compile the package without searching - # for dependencies over the network. - ln -s "$dir" "$build_dir" - done - done <<<"$ERL_LIBS:" - - runHook postConfigure -} - -if [ -z "${dontCargoConfigure-}" ] && [ -z "${configurePhase-}" ]; then - configurePhase=mixConfigureHook -fi diff --git a/pkgs/development/beam-modules/mix-configure-hook.sh b/pkgs/development/beam-modules/mix-configure-hook.sh new file mode 100755 index 000000000000..80a395b8a6a0 --- /dev/null +++ b/pkgs/development/beam-modules/mix-configure-hook.sh @@ -0,0 +1,5 @@ +# Added 2026-02-12 for external users +echo "mix-configure-hook.sh has been removed and is now a setup hook. + Add 'beamPackages.mixBuildDirHook' to 'nativeBuildInputs' instead. +" >&2 +exit 1 diff --git a/pkgs/development/beam-modules/mix-release.nix b/pkgs/development/beam-modules/mix-release.nix index 27a318085710..7204c03bf567 100644 --- a/pkgs/development/beam-modules/mix-release.nix +++ b/pkgs/development/beam-modules/mix-release.nix @@ -171,8 +171,6 @@ stdenv.mkDerivation ( attrs.configurePhase or '' runHook preConfigure - ${./mix-configure-hook.sh} - # This is needed for projects that have a specific compile step # the dependency needs to be compiled in order for the task # to be available. diff --git a/pkgs/servers/mobilizon/default.nix b/pkgs/servers/mobilizon/default.nix index c6fe27b0bbfc..3785f84246df 100644 --- a/pkgs/servers/mobilizon/default.nix +++ b/pkgs/servers/mobilizon/default.nix @@ -146,6 +146,7 @@ mixRelease rec { ${lib.getExe nixfmt} pkgs/servers/mobilizon/mix.nix ''; elixirPackage = beamPackages.elixir; + inherit mixNixDeps; }; meta = {