Merge pull request #268619 from tweag/lib-descriptions
[NixPkgs.git] / pkgs / development / beam-modules / mix-release.nix
blobe5b44bc5dcdb076c6b7215d3ff9946e327c84928
1 { stdenv
2 , lib
3 , elixir
4 , erlang
5 , hex
6 , git
7 , rebar
8 , rebar3
9 , fetchMixDeps
10 , findutils
11 , makeWrapper
12 , coreutils
13 , gnused
14 , gnugrep
15 , gawk
16 }@inputs:
18 { pname
19 , version
20 , src
21 , nativeBuildInputs ? [ ]
22 , buildInputs ? [ ]
23 , meta ? { }
24 , enableDebugInfo ? false
25 , mixEnv ? "prod"
26 , compileFlags ? [ ]
28   # Mix dependencies provided as a fixed output derivation
29 , mixFodDeps ? null
31   # Mix dependencies generated by mix2nix
32   #
33   # This assumes each dependency is built by buildMix or buildRebar3. Each
34   # dependency needs to have a setup hook to add the lib path to $ERL_LIBS.
35   # This is how Mix finds dependencies.
36 , mixNixDeps ? { }
38 , elixir ? inputs.elixir
39 , hex ? inputs.hex.override { inherit elixir; }
41   # Remove releases/COOKIE
42   #
43   # People have different views on the nature of cookies. Some believe that they are
44   # secrets, while others believe they are just ids for clustering nodes instead of
45   # secrets.
46   #
47   # If you think cookie is secret, you can set this attr to true, then it will be
48   # removed from nix store. If not, you can set it to false.
49   #
50   # For backward compatibility, it is set to true by default.
51   #
52   # You can always specify a custom cookie by using RELEASE_COOKIE environment
53   # variable, regardless of the value of this attr.
54 , removeCookie ? true
56   # This reduces closure size, but can lead to some hard to understand runtime
57   # errors, so use with caution. See e.g.
58   # https://github.com/whitfin/cachex/issues/205
59   # https://framagit.org/framasoft/mobilizon/-/issues/1169
60 , stripDebug ? false
62 , ...
63 }@attrs:
64 let
65   # Remove non standard attributes that cannot be coerced to strings
66   overridable = builtins.removeAttrs attrs [ "compileFlags" "mixNixDeps" ];
68 assert mixNixDeps != { } -> mixFodDeps == null;
69 assert stripDebug -> !enableDebugInfo;
71 stdenv.mkDerivation (overridable // {
72   nativeBuildInputs = nativeBuildInputs ++
73     # Erlang/Elixir deps
74     [ erlang elixir hex git ] ++
75     # Mix deps
76     (builtins.attrValues mixNixDeps) ++
77     # other compile-time deps
78     [ findutils makeWrapper ];
80   buildInputs = buildInputs;
82   MIX_ENV = mixEnv;
83   MIX_DEBUG = if enableDebugInfo then 1 else 0;
84   HEX_OFFLINE = 1;
86   DEBUG = if enableDebugInfo then 1 else 0; # for Rebar3 compilation
87   # The API with `mix local.rebar rebar path` makes a copy of the binary
88   # some older dependencies still use rebar.
89   MIX_REBAR = "${rebar}/bin/rebar";
90   MIX_REBAR3 = "${rebar3}/bin/rebar3";
92   LC_ALL = "C.UTF-8";
94   postUnpack = ''
95     # Mix and Hex
96     export MIX_HOME="$TEMPDIR/mix"
97     export HEX_HOME="$TEMPDIR/hex"
99     # Rebar
100     export REBAR_GLOBAL_CONFIG_DIR="$TEMPDIR/rebar3"
101     export REBAR_CACHE_DIR="$TEMPDIR/rebar3.cache"
103     ${lib.optionalString (mixFodDeps != null) ''
104       # Compilation of the dependencies will require that the dependency path is
105       # writable, thus a copy to the $TEMPDIR is inevitable here.
106       export MIX_DEPS_PATH="$TEMPDIR/deps"
107       cp --no-preserve=mode -R "${mixFodDeps}" "$MIX_DEPS_PATH"
108     ''}
109   '' + (attrs.postUnpack or "");
111   configurePhase = attrs.configurePhase or ''
112     runHook preConfigure
114     ${./mix-configure-hook.sh}
116     # This is needed for projects that have a specific compile step
117     # the dependency needs to be compiled in order for the task
118     # to be available.
119     #
120     # Phoenix projects for example will need compile.phoenix.
121     mix deps.compile --no-deps-check --skip-umbrella-children
123     # Symlink dependency sources. This is needed for projects that require
124     # access to the source of their dependencies. For example, Phoenix
125     # projects need javascript assets to build asset bundles.
126     ${lib.optionalString (mixNixDeps != { }) ''
127       mkdir -p deps
129       ${lib.concatMapStringsSep "\n" (dep: ''
130         dep_name=$(basename ${dep} | cut -d '-' -f2)
131         dep_path="deps/$dep_name"
132         if [ -d "${dep}/src" ]; then
133           ln -s ${dep}/src $dep_path
134         fi
135       '') (builtins.attrValues mixNixDeps)}
136     ''}
138     # Symlink deps to build root. Similar to above, but allows for mixFodDeps
139     # Phoenix projects to find javascript assets.
140     ${lib.optionalString (mixFodDeps != null) ''
141       ln -s ../deps ./
142     ''}
144     runHook postConfigure
145   '';
147   buildPhase = attrs.buildPhase or ''
148     runHook preBuild
150     mix compile --no-deps-check ${lib.concatStringsSep " " compileFlags}
152     runHook postBuild
153   '';
155   installPhase = attrs.installPhase or ''
156     runHook preInstall
158     mix release --no-deps-check --path "$out"
160     runHook postInstall
161   '';
163   postFixup = ''
164     # Remove files for Microsoft Windows
165     rm -f "$out"/bin/*.bat
167     # Wrap programs in $out/bin with their runtime deps
168     for f in $(find $out/bin/ -type f -executable); do
169       wrapProgram "$f" \
170         --prefix PATH : ${lib.makeBinPath [
171           coreutils
172           gnused
173           gnugrep
174           gawk
175         ]}
176     done
177   '' + lib.optionalString removeCookie ''
178     if [ -e $out/releases/COOKIE ]; then
179       rm $out/releases/COOKIE
180     fi
181   '' + lib.optionalString stripDebug ''
182     # Strip debug symbols to avoid hardreferences to "foreign" closures actually
183     # not needed at runtime, while at the same time reduce size of BEAM files.
184     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
185   '';
187   # TODO: remove erlang references in resulting derivation
188   #
189   # # Step 1 - investigate why the resulting derivation still has references to erlang.
190   #
191   # The reason is that the generated binaries contains erlang reference. Here's a repo to
192   # demonstrate the problem - <https://github.com/plastic-gun/nix-mix-release-unwanted-references>.
193   #
194   #
195   # # Step 2 - remove erlang references from the binaries
196   #
197   # As said in above repo, it's hard to remove erlang references from `.beam` binaries.
198   #
199   # We need more experienced developers to resolve this issue.
200   #
201   #
202   # # Tips
203   #
204   # When resolving this issue, it is convenient to fail the build when erlang is referenced,
205   # which can be achieved by using:
206   #
207   #   disallowedReferences = [ erlang ];
208   #