Unverified Commit 6f8f61df authored by Adam C. Stephens's avatar Adam C. Stephens Committed by GitHub
Browse files

beamPackages.buildMix: move to fixed point builder and hooks (#475224)

parents 56a4a6f6 9cbc309f
Loading
Loading
Loading
Loading
+66 −136
Original line number Diff line number Diff line
{
  stdenv,
  writeText,
  elixir,
  erlang,
  hex,
  beamCopySourceHook,
  beamModuleInstallHook,
  mixBuildDirHook,
  mixCompileHook,
  mixAppConfigPatchHook,

  lib,
  stdenv,
  writeText,
}:

lib.extendMkDerivation {
  constructDrv = stdenv.mkDerivation;
  excludeDrvArgNames = [
    "mixEnv"
  ];
  extendDrvArgs =
    finalAttrs:
    {
  name,
  version,
  src,
  buildInputs ? [ ],
  nativeBuildInputs ? [ ],
      beamDeps ? [ ],
      mixEnv ? "prod",
      mixTarget ? "host",

      # 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 ? [ ],
  propagatedBuildInputs ? [ ],
  postPatch ? "",
  compilePorts ? false,
  meta ? { },
  enableDebugInfo ? false,
  mixEnv ? "prod",
  mixTarget ? "host",
  removeConfig ? true,
  # A config directory that is considered for all the dependencies of an app, typically in $src/config/
  # This was initially added, as some of Mobilizon's dependencies need to access the config at build time.
  appConfigPath ? null,
      ...
}@attrs:

assert appConfigPath != null -> removeConfig;
    }@args:
    {
      name = "erlang${erlang.version}-${args.name}-${finalAttrs.version}";

      env = {
        ERL_COMPILER_OPTIONS =
          let
  shell =
    drv:
    stdenv.mkDerivation {
      name = "interactive-shell-${drv.name}";
      buildInputs = [ drv ];
    };

  pkg =
    self:
    stdenv.mkDerivation (
      attrs
      // {
        name = "${name}-${version}";
        inherit version src;
            options = erlangCompilerOptions ++ lib.optionals erlangDeterministicBuilds [ "deterministic" ];
          in
          "[${lib.concatStringsSep "," options}]";

        MIX_ENV = mixEnv;
        MIX_TARGET = mixTarget;
@@ -57,103 +52,38 @@ let
        MIX_DEBUG = if enableDebugInfo then 1 else 0;
        HEX_OFFLINE = 1;

        __darwinAllowLocalNetworking = true;

        ERL_COMPILER_OPTIONS =
          let
            options = erlangCompilerOptions ++ lib.optionals erlangDeterministicBuilds [ "deterministic" ];
          in
          "[${lib.concatStringsSep "," options}]";

        LANG = if stdenv.hostPlatform.isLinux then "C.UTF-8" else "C";
        LC_CTYPE = if stdenv.hostPlatform.isLinux then "C.UTF-8" else "UTF-8";

        # 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
        setupHook = attrs.setupHook or writeText "setupHook.sh" ''
      # This is used by package builders such as mixRelease
      setupHook = writeText "setupHook.sh" ''
        addToSearchPath ERL_LIBS "$1/lib/erlang/lib"
      '';

        buildInputs = buildInputs ++ [ ];
        nativeBuildInputs = nativeBuildInputs ++ [
      nativeBuildInputs = (args.nativeBuildInputs or [ ]) ++ [
        elixir
        hex
        ];
        propagatedBuildInputs = propagatedBuildInputs ++ beamDeps;

        configurePhase =
          attrs.configurePhase or ''
            runHook preConfigure

            ${./mix-configure-hook.sh}
            ${lib.optionalString (removeConfig && isNull appConfigPath)
              # By default, we don't want to include whatever config a dependency brings; per
              # https://hexdocs.pm/elixir/main/Config.html, config is application specific.
              ''
                rm -rf config
                mkdir config
              ''
            }
            ${lib.optionalString (!isNull appConfigPath)
              # Some more tightly-coupled dependencies do depend on the config of the application
              # they're being built for.
              ''
                rm -rf config
                cp -r ${appConfigPath} config
              ''
            }

            runHook postConfigure
          '';

        buildPhase =
          attrs.buildPhase or ''
            runHook preBuild
            export HEX_HOME="$TEMPDIR/hex"
            export MIX_HOME="$TEMPDIR/mix"
            mix compile --no-deps-check
            runHook postBuild
          '';

        installPhase =
          attrs.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/${name}-${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/${name}/{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/${name}-${version}" "$reldir"
              fi
            done

            # Copy the source so it can be used by dependent packages. For example,
            # phoenix applications need the source of phoenix and phoenix_html to
            # build javascript and css assets.
            mkdir -p $out/src
            cp -r "$src/." "$out/src"

            runHook postInstall
          '';
        beamCopySourceHook
        beamModuleInstallHook
        mixBuildDirHook
        mixCompileHook
        mixAppConfigPatchHook
      ];

        # stripping does not have any effect on beam files
        # it is however needed for dependencies with NIFs like bcrypt for example
        dontStrip = false;
      propagatedBuildInputs = (args.propagatedBuildInputs or [ ]) ++ beamDeps;

        passthru = {
          packageName = name;
          env = shell self;
      passthru = (args.passthru or { }) // {
        inherit beamDeps;
      };
    };
}
    );
in
lib.fix pkg
+12 −0
Original line number Diff line number Diff line
@@ -11,6 +11,9 @@ let
  callPackageWithScope =
    scope: drv: args:
    lib.callPackageWith scope drv args;
  callPackagesWithScope =
    scope: drv: args:
    lib.callPackagesWith scope drv args;
  mkScope = scope: pkgs // scope;

  packages =
@@ -18,6 +21,7 @@ let
    let
      defaultScope = mkScope self;
      callPackage = drv: args: callPackageWithScope defaultScope drv args;
      callPackages = drv: args: callPackagesWithScope defaultScope drv args;
    in
    rec {
      inherit callPackage erlang;
@@ -95,6 +99,14 @@ let
      # without helper functions buildRebar3 and buildMix.
      hex = callPackage ./hex { };
      webdriver = callPackage ./webdriver { };

      inherit (callPackages ./hooks { })
        beamCopySourceHook
        beamModuleInstallHook
        mixBuildDirHook
        mixCompileHook
        mixAppConfigPatchHook
        ;
    };
in
makeExtensible packages
+16 −0
Original line number Diff line number Diff line
# 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)
+25 −0
Original line number Diff line number Diff line
# 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
+22 −0
Original line number Diff line number Diff line
{ 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-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;
}
Loading