diff --git a/pkgs/by-name/mo/mobilizon/package.nix b/pkgs/by-name/mo/mobilizon/package.nix index 83c82c4bc4db..5df63c96cbc9 100644 --- a/pkgs/by-name/mo/mobilizon/package.nix +++ b/pkgs/by-name/mo/mobilizon/package.nix @@ -28,7 +28,6 @@ beamPackages.mixRelease rec { nativeBuildInputs = [ git - cmake ]; mixNixDeps = import ./mix.nix { diff --git a/pkgs/development/beam-modules/default.nix b/pkgs/development/beam-modules/default.nix index ac2536a46c92..686fedb24d6d 100644 --- a/pkgs/development/beam-modules/default.nix +++ b/pkgs/development/beam-modules/default.nix @@ -82,9 +82,14 @@ makeScopeWithSplicing' { inherit (pkgs.callPackages ./hooks { }) beamCopySourceHook beamModuleInstallHook + mixAppConfigPatchHook mixBuildDirHook mixCompileHook - mixAppConfigPatchHook + mixDepsCompileHook + mixEscriptSetupHook + mixFodDepsSetupHook + mixNixDepsSetupHook + mixReleaseSetupHook rebar3CompileHook rebarDevendorPatchHook ; diff --git a/pkgs/development/beam-modules/hooks/beam-copy-source-hook.sh b/pkgs/development/beam-modules/hooks/beam-copy-source-hook.sh index a4ffa9fd1413..bdc5056f553c 100755 --- a/pkgs/development/beam-modules/hooks/beam-copy-source-hook.sh +++ b/pkgs/development/beam-modules/hooks/beam-copy-source-hook.sh @@ -13,4 +13,6 @@ beamCopySourceHook() { echo "Finished beamCopySourceHook" } -postPatchHooks+=(beamCopySourceHook) +if [ -z "${dontBeamCopySource-}" ]; then + postPatchHooks+=(beamCopySourceHook) +fi diff --git a/pkgs/development/beam-modules/hooks/default.nix b/pkgs/development/beam-modules/hooks/default.nix index cb567537f628..495b9532cc5a 100644 --- a/pkgs/development/beam-modules/hooks/default.nix +++ b/pkgs/development/beam-modules/hooks/default.nix @@ -13,6 +13,11 @@ meta.license = lib.licenses.mit; } ./beam-module-install-hook.sh; + mixAppConfigPatchHook = makeSetupHook { + name = "mix-config-patch-hook.sh"; + meta.license = lib.licenses.mit; + } ./mix-app-config-patch-hook.sh; + mixBuildDirHook = makeSetupHook { name = "mix-configure-hook.sh"; meta.license = lib.licenses.mit; @@ -23,10 +28,30 @@ meta.license = lib.licenses.mit; } ./mix-compile-hook.sh; - mixAppConfigPatchHook = makeSetupHook { - name = "mix-config-patch-hook.sh"; + mixDepsCompileHook = makeSetupHook { + name = "mix-deps-compile-hook.sh"; meta.license = lib.licenses.mit; - } ./mix-app-config-patch-hook.sh; + } ./mix-deps-compile-hook.sh; + + mixEscriptSetupHook = makeSetupHook { + name = "mix-escript-setup-hook.sh"; + meta.license = lib.licenses.mit; + } ./mix-escript-setup-hook.sh; + + mixFodDepsSetupHook = makeSetupHook { + name = "mix-fod-deps-setup-hook"; + meta.license = lib.licenses.mit; + } ./mix-fod-deps-setup-hook.sh; + + mixNixDepsSetupHook = makeSetupHook { + name = "mix-nix-deps-setup-hook"; + meta.license = lib.licenses.mit; + } ./mix-nix-deps-setup-hook.sh; + + mixReleaseSetupHook = makeSetupHook { + name = "mix-release-setup-hook.sh"; + meta.license = lib.licenses.mit; + } ./mix-release-setup-hook.sh; rebar3CompileHook = makeSetupHook { name = "rebar3-compile-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 index 1dd80c5e3e76..0537736c5a9e 100644 --- a/pkgs/development/beam-modules/hooks/mix-app-config-patch-hook.sh +++ b/pkgs/development/beam-modules/hooks/mix-app-config-patch-hook.sh @@ -16,4 +16,6 @@ mixAppConfigPatchHook() { echo "Finished mixAppConfigPatchHook" } -prePatchHooks+=(mixAppConfigPatchHook) +if [ -z "${dontMixAppConfigPatch-}" ]; then + prePatchHooks+=(mixAppConfigPatchHook) +fi diff --git a/pkgs/development/beam-modules/hooks/mix-build-dir-hook.sh b/pkgs/development/beam-modules/hooks/mix-build-dir-hook.sh index c353aaeabc4d..46af5755640e 100755 --- a/pkgs/development/beam-modules/hooks/mix-build-dir-hook.sh +++ b/pkgs/development/beam-modules/hooks/mix-build-dir-hook.sh @@ -5,9 +5,13 @@ mixBuildDirHook() { echo "Executing mixBuildDirHook" + local lib dir dest build_dir + mkdir -p _build/"$MIX_BUILD_PREFIX"/lib - while read -r -d ':' lib; do + while IFS= read -r -d ':' lib; do + [ -n "$lib" ] || continue for dir in "$lib"/*; do + [ -d "$dir" ] || continue # 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) diff --git a/pkgs/development/beam-modules/hooks/mix-deps-compile-hook.sh b/pkgs/development/beam-modules/hooks/mix-deps-compile-hook.sh new file mode 100755 index 000000000000..aec8a9e39127 --- /dev/null +++ b/pkgs/development/beam-modules/hooks/mix-deps-compile-hook.sh @@ -0,0 +1,19 @@ +# shellcheck shell=bash +# +# 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. +# +# Phoenix projects for example will need compile.phoenix. + +mixDepsCompileHook() { + echo "Executing mixDepsCompileHook" + + mix deps.compile --no-deps-check --skip-umbrella-children + + echo "Finished mixDepsCompileHook" +} + +if [ -z "${dontMixDepsCompile-}" ]; then + postConfigureHooks+=(mixDepsCompileHook) +fi diff --git a/pkgs/development/beam-modules/hooks/mix-escript-setup-hook.sh b/pkgs/development/beam-modules/hooks/mix-escript-setup-hook.sh new file mode 100644 index 000000000000..f83f483ae93b --- /dev/null +++ b/pkgs/development/beam-modules/hooks/mix-escript-setup-hook.sh @@ -0,0 +1,30 @@ +# shellcheck shell=bash + +mixEscriptBuild() { + echo "Executing mixEscriptBuild" + + mix escript.build --no-deps-check + + echo "Finished mixEscriptBuild" +} + +mixEscriptInstall() { + echo "Executing mixEscriptInstall" + + runHook preInstall + + mkdir -p "$out/bin" + cp "$escriptBinName" "$out/bin" + + runHook postInstall + + echo "Finished mixEscriptInstall" +} + +if [ -z "${dontMixEscriptBuild-}" ]; then + postBuildHooks+=(mixEscriptBuild) +fi + +if [ -z "${dontMixEscriptInstall-}" ] && [ -z "${installPhase-}" ]; then + installPhase=mixEscriptInstall +fi diff --git a/pkgs/development/beam-modules/hooks/mix-fod-deps-setup-hook.sh b/pkgs/development/beam-modules/hooks/mix-fod-deps-setup-hook.sh new file mode 100755 index 000000000000..2c5235050b58 --- /dev/null +++ b/pkgs/development/beam-modules/hooks/mix-fod-deps-setup-hook.sh @@ -0,0 +1,29 @@ +# shellcheck shell=bash + +mixFodDepsPostUnpack() { + echo "Executing mixFodDepsPostUnpack" + + if [ -n "${mixFodDeps-}" ]; then + # Compilation of the dependencies will require that the dependency path is + # writable, thus a copy to the $TEMPDIR is inevitable here. + export MIX_DEPS_PATH="$TEMPDIR/deps" + cp --no-preserve=mode -R "${mixFodDeps}" "$MIX_DEPS_PATH" + fi + + echo "Finished mixFodDepsPostUnpack" +} + +mixFodDepsPostConfigure() { + echo "Executing mixFodDepsPostConfigure" + + if [ -n "${mixFodDeps-}" ]; then + # Symlink deps to build root. Allows for mixFodDeps Phoenix projects to + # find javascript assets. + ln -s "$MIX_DEPS_PATH" ./deps + fi + + echo "Finished mixFodDepsPostConfigure" +} + +postUnpackHooks+=(mixFodDepsPostUnpack) +postConfigureHooks+=(mixFodDepsPostConfigure) diff --git a/pkgs/development/beam-modules/hooks/mix-nix-deps-setup-hook.sh b/pkgs/development/beam-modules/hooks/mix-nix-deps-setup-hook.sh new file mode 100755 index 000000000000..18edca00e514 --- /dev/null +++ b/pkgs/development/beam-modules/hooks/mix-nix-deps-setup-hook.sh @@ -0,0 +1,21 @@ +# shellcheck shell=bash +# +# Symlink dependency sources. This is needed for projects that require +# access to the source of their dependencies. For example, Phoenix +# projects need javascript assets to build asset bundles. + +mixNixDepsPostConfigure() { + echo "Executing mixNixDepsPostConfigure" + + local name + for name in "${!mixNixDeps[@]}"; do + if [ -d "${mixNixDeps[$name]}/src" ]; then + mkdir -p deps + ln -sv "${mixNixDeps[$name]}/src" "deps/$name" + fi + done + + echo "Finished mixNixDepsPostConfigure" +} + +postConfigureHooks+=(mixNixDepsPostConfigure) diff --git a/pkgs/development/beam-modules/hooks/mix-release-setup-hook.sh b/pkgs/development/beam-modules/hooks/mix-release-setup-hook.sh new file mode 100644 index 000000000000..81bd142fcc70 --- /dev/null +++ b/pkgs/development/beam-modules/hooks/mix-release-setup-hook.sh @@ -0,0 +1,91 @@ +# shellcheck shell=bash + +mixReleaseInstallHook() { + echo "Executing mixReleaseInstallHook" + + runHook preInstall + + mix release ${mixReleaseName:+"$mixReleaseName"} --no-deps-check --path "$out" + + runHook postInstall + + echo "Finished mixReleaseInstallHook" +} + +mixReleaseFixupHook() { + echo "Executing mixReleaseFixupHook" + + echo "Removing files for Microsoft Windows" + rm -f "$out"/bin/*.bat + + echo "Wrapping programs in $out/bin with their runtime deps" + find "$out/bin/" -type f -executable | while read f; do + wrapProgram "$f" --prefix PATH : "$mixReleaseRuntimePath" + done + + # shellcheck disable=SC2144 # this will only work for a single erts + if [ -e "$out"/erts-* ]; then + mixReleaseRemoveErlangReferences + fi + + echo "Finished mixReleaseFixupHook" +} + +mixReleaseRemoveErlangReferences() { + # ERTS is included in the release, then erlang is not required as a runtime dependency. + # But, erlang is still referenced in some places. To removed references to erlang, + # following steps are required. + + echo "Removing references to erlang" + + # 1. remove references to erlang from plain text files + for file in $(rg "${erlang}/lib/erlang" "$out" --files-with-matches); do + substituteInPlace "$file" --replace "${erlang}/lib/erlang" "$out" + done + + # 2. remove references to erlang from .beam files + # + # No need to do anything, because it has been handled by "deterministic" option specified + # by ERL_COMPILER_OPTIONS. + + # 3. remove references to erlang from normal binary files + for file in $(rg "${erlang}/lib/erlang" "$out" --files-with-matches --binary --iglob '!*.beam'); do + echo "removing references to erlang in $file" + # use bbe to substitute strings in binary files, because using substituteInPlace + # on binaries will raise errors + bbe -e "s|${erlang}/lib/erlang|$out|" -o "$file".tmp "$file" + rm -f "$file" + mv "$file".tmp "$file" + done + + # References to erlang should be removed from output after above processing. +} + +mixReleaseRemoveCookieHook() { + if [ -e "$out/releases/COOKIE" ]; then + echo "Removing $out/releases/COOKIE" + rm "$out/releases/COOKIE" + fi +} + +mixReleaseStripDebugHook() { + # Strip debug symbols to avoid hardreferences to "foreign" closures actually + # not needed at runtime, while at the same time reduce size of BEAM files. + erl -noinput -eval 'lists:foreach(fun(F) -> io:format("Stripping ~p.~n", [F]), beam_lib:strip(F) end, filelib:wildcard("'"$out"'/**/*.beam"))' -s init stop +} + +if [ -z "${dontMixReleaseFixup-}" ]; then + preFixupHooks+=(mixReleaseFixupHook) +fi + +if [ -n "${removeCookie-1}" ]; then + preFixupHooks+=(mixReleaseRemoveCookieHook) +fi + +if [ -n "${stripDebug-}" ]; then + postFixupHooks+=(mixReleaseStripDebugHook) +fi + +if [ -z "${dontMixReleaseInstall-}" ] && [ -z "${installPhase-}" ]; then + installPhase=mixReleaseInstallHook +fi diff --git a/pkgs/development/beam-modules/hooks/rebar-devendor-patch-hook.sh b/pkgs/development/beam-modules/hooks/rebar-devendor-patch-hook.sh index 032bf9b986fe..e0d1a45cfb84 100644 --- a/pkgs/development/beam-modules/hooks/rebar-devendor-patch-hook.sh +++ b/pkgs/development/beam-modules/hooks/rebar-devendor-patch-hook.sh @@ -10,4 +10,6 @@ rebarDevendorPatchHook() { echo "Finished rebarDevendorPatchHook" } -prePatchHooks+=(rebarDevendorPatchHook) +if [ -z "${dontRebarDevendorPatch-}" ]; then + prePatchHooks+=(rebarDevendorPatchHook) +fi diff --git a/pkgs/development/beam-modules/mix-release.nix b/pkgs/development/beam-modules/mix-release.nix index fcb383936249..dd04c592d30b 100644 --- a/pkgs/development/beam-modules/mix-release.nix +++ b/pkgs/development/beam-modules/mix-release.nix @@ -12,11 +12,18 @@ ripgrep, bbe, makeWrapper, + writableTmpDirAsHomeHook, coreutils, gnused, gnugrep, gawk, mixBuildDirHook, + mixCompileHook, + mixDepsCompileHook, + mixEscriptSetupHook, + mixFodDepsSetupHook, + mixNixDepsSetupHook, + mixReleaseSetupHook, }@inputs: lib.extendMkDerivation { @@ -25,7 +32,6 @@ lib.extendMkDerivation { excludeDrvArgNames = [ "compileFlags" "erlangCompilerOptions" - "mixNixDeps" ]; extendDrvArgs = @@ -41,6 +47,7 @@ lib.extendMkDerivation { mixEnv ? "prod", mixTarget ? "host", compileFlags ? [ ], + mixCompileFlags ? compileFlags, # Build a particular named release. # see https://hexdocs.pm/mix/1.12/Mix.Tasks.Release.html#content mixReleaseName ? "", @@ -106,20 +113,22 @@ lib.extendMkDerivation { erlang elixir hex - git - mixBuildDirHook - ] - ++ - # Mix deps - (builtins.attrValues mixNixDeps) - ++ - # other compile-time deps - [ - findutils - ripgrep + bbe + findutils + git makeWrapper - ]; + ripgrep + writableTmpDirAsHomeHook + + mixBuildDirHook + mixCompileHook + mixDepsCompileHook + ] + ++ lib.optionals (escriptBinName != null) [ mixEscriptSetupHook ] + ++ lib.optionals (escriptBinName == null) [ mixReleaseSetupHook ] + ++ lib.optionals (mixFodDeps != null) [ mixFodDepsSetupHook ] + ++ lib.optionals (mixNixDeps != { }) ([ mixNixDepsSetupHook ] ++ (builtins.attrValues mixNixDeps)); buildInputs = [ bashNonInteractive @@ -158,147 +167,13 @@ lib.extendMkDerivation { } // (attrs.env or { }); - postUnpack = '' - # Mix and Hex - export MIX_HOME="$TEMPDIR/mix" - export HEX_HOME="$TEMPDIR/hex" + inherit erlang; - # Rebar - export REBAR_GLOBAL_CONFIG_DIR="$TEMPDIR/rebar3" - export REBAR_CACHE_DIR="$TEMPDIR/rebar3.cache" - - ${lib.optionalString (mixFodDeps != null) '' - # Compilation of the dependencies will require that the dependency path is - # writable, thus a copy to the $TEMPDIR is inevitable here. - export MIX_DEPS_PATH="$TEMPDIR/deps" - cp --no-preserve=mode -R "${mixFodDeps}" "$MIX_DEPS_PATH" - ''} - '' - + (attrs.postUnpack or ""); - - configurePhase = - attrs.configurePhase or '' - runHook preConfigure - - # 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. - # - # Phoenix projects for example will need compile.phoenix. - mix deps.compile --no-deps-check --skip-umbrella-children - - # Symlink dependency sources. This is needed for projects that require - # access to the source of their dependencies. For example, Phoenix - # projects need javascript assets to build asset bundles. - ${lib.optionalString (mixNixDeps != { }) '' - mkdir -p deps - - ${lib.concatMapAttrsStringSep "\n" (name: dep: '' - dep_path="deps/${name}" - if [ -d "${dep}/src" ]; then - ln -sv ${dep}/src $dep_path - fi - '') mixNixDeps} - ''} - - # Symlink deps to build root. Similar to above, but allows for mixFodDeps - # Phoenix projects to find javascript assets. - ${lib.optionalString (mixFodDeps != null) '' - ln -s "$MIX_DEPS_PATH" ./deps - ''} - - runHook postConfigure - ''; - - buildPhase = - attrs.buildPhase or '' - runHook preBuild - - mix compile --no-deps-check ${lib.concatStringsSep " " compileFlags} - - ${lib.optionalString (escriptBinName != null) '' - mix escript.build --no-deps-check - ''} - - runHook postBuild - ''; - - installPhase = - attrs.installPhase or '' - runHook preInstall - - ${ - if (escriptBinName != null) then - '' - mkdir -p $out/bin - cp ${escriptBinName} $out/bin - '' - else - '' - mix release ${mixReleaseName} --no-deps-check --path "$out" - '' - } - - runHook postInstall - ''; - - postFixup = '' - echo "removing files for Microsoft Windows" - rm -f "$out"/bin/*.bat - - echo "wrapping programs in $out/bin with their runtime deps" - for f in $(find $out/bin/ -type f -executable); do - wrapProgram "$f" \ - --prefix PATH : ${ - lib.makeBinPath [ - coreutils - gnused - gnugrep - gawk - ] - } - done - '' - + lib.optionalString removeCookie '' - if [ -e $out/releases/COOKIE ]; then - echo "removing $out/releases/COOKIE" - rm $out/releases/COOKIE - fi - '' - + '' - if [ -e $out/erts-* ]; then - # ERTS is included in the release, then erlang is not required as a runtime dependency. - # But, erlang is still referenced in some places. To removed references to erlang, - # following steps are required. - - # 1. remove references to erlang from plain text files - for file in $(rg "${erlang}/lib/erlang" "$out" --files-with-matches); do - echo "removing references to erlang in $file" - substituteInPlace "$file" --replace "${erlang}/lib/erlang" "$out" - done - - # 2. remove references to erlang from .beam files - # - # No need to do anything, because it has been handled by "deterministic" option specified - # by ERL_COMPILER_OPTIONS. - - # 3. remove references to erlang from normal binary files - for file in $(rg "${erlang}/lib/erlang" "$out" --files-with-matches --binary --iglob '!*.beam'); do - echo "removing references to erlang in $file" - # use bbe to substitute strings in binary files, because using substituteInPlace - # on binaries will raise errors - bbe -e "s|${erlang}/lib/erlang|$out|" -o "$file".tmp "$file" - rm -f "$file" - mv "$file".tmp "$file" - done - - # References to erlang should be removed from output after above processing. - fi - '' - + lib.optionalString stripDebug '' - # Strip debug symbols to avoid hardreferences to "foreign" closures actually - # not needed at runtime, while at the same time reduce size of BEAM files. - erl -noinput -eval 'lists:foreach(fun(F) -> io:format("Stripping ~p.~n", [F]), beam_lib:strip(F) end, filelib:wildcard("'"$out"'/**/*.beam"))' -s init stop - ''; + mixReleaseRuntimePath = lib.makeBinPath [ + coreutils + gnused + gnugrep + gawk + ]; }; }