summaryrefslogtreecommitdiffstats
path: root/pkgs/development/beam-modules/rebar3-release.nix
blob: d37986990040bca89e79936954c19d1cd3169b55 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
{
  stdenv,
  erlang,
  rebar3WithPlugins,
  openssl,
  lib,
}:

{
  pname,
  version,
  src,
  beamDeps ? [ ],
  buildPlugins ? [ ],
  checkouts ? null,
  releaseType,
  buildInputs ? [ ],
  setupHook ? null,
  profile ? "default",
  installPhase ? null,
  buildPhase ? null,
  configurePhase ? null,
  meta ? { },
  ...
}@attrs:

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

  customPhases = lib.filterAttrs (_: v: v != null) {
    inherit
      setupHook
      configurePhase
      buildPhase
      installPhase
      ;
  };

  # When using the `beamDeps` argument, it is important that we use
  # `rebar3WithPlugins` here even when there are no plugins. The vanilla
  # `rebar3` package is an escript archive with bundled dependencies which can
  # interfere with those in the app we are trying to build. `rebar3WithPlugins`
  # doesn't have this issue since it puts its own deps last on the code path.
  rebar3 = rebar3WithPlugins {
    plugins = buildPlugins;
  };

  pkg =
    assert beamDeps != [ ] -> checkouts == null;
    self:
    stdenv.mkDerivation (
      attrs
      // {

        inherit version pname;

        nativeBuildInputs = (attrs.nativeBuildInputs or [ ]) ++ [
          erlang
          rebar3
        ];

        buildInputs = buildInputs ++ [ openssl ] ++ beamDeps;

        __structuredAttrs = true;
        strictDeps = true;

        # ensure we strip any native binaries (eg. NIFs, ports)
        stripDebugList = lib.optional (releaseType == "release") "rel";

        inherit src;

        env = (attrs.env or { }) // {
          REBAR_IGNORE_DEPS = beamDeps != [ ];
        };

        configurePhase = ''
          runHook preConfigure
          ${lib.optionalString (checkouts != null) "cp --no-preserve=all -R ${checkouts}/_checkouts ."}
          runHook postConfigure
        '';

        buildPhase = ''
          runHook preBuild
          HOME=. DEBUG=1 rebar3 as ${profile} ${if releaseType == "escript" then "escriptize" else "release"}
          runHook postBuild
        '';

        installPhase = ''
          runHook preInstall
          dir=${if releaseType == "escript" then "bin" else "rel"}
          mkdir -p "$out/$dir" "$out/bin"
          cp -R --preserve=mode "_build/${profile}/$dir" "$out"
          ${lib.optionalString (
            releaseType == "release"
          ) "find $out/rel/*/bin -type f -executable -exec ln -s -t $out/bin {} \\;"}
          runHook postInstall
        '';

        # Release will generate a binary which will cause a read null byte failure, see #261354
        postInstall = lib.optionalString (releaseType == "escript") ''
          for dir in $out/rel/*/erts-*; do
            echo "ERTS found in $dir - removing references to erlang to reduce closure size"
            for f in $dir/bin/{erl,start}; do
              substituteInPlace "$f" --replace "${erlang}/lib/erlang" "''${dir/\/erts-*/}"
            done
          done
        '';

        meta = {
          inherit (erlang.meta) platforms;
        }
        // meta;

        passthru = (
          {
            packageName = pname;
            env = shell self;
          }
          // (if attrs ? passthru then attrs.passthru else { })
        );
      }
      // customPhases
    );
in
lib.fix pkg