beam-modules: buildMix -> mixRelease
This commit is contained in:
@@ -1,100 +0,0 @@
|
||||
{ stdenv, writeText, elixir, erlang, hex, lib }:
|
||||
|
||||
{ name
|
||||
, version
|
||||
, src
|
||||
, setupHook ? null
|
||||
, buildInputs ? []
|
||||
, beamDeps ? []
|
||||
, postPatch ? ""
|
||||
, compilePorts ? false
|
||||
, installPhase ? null
|
||||
, buildPhase ? null
|
||||
, configurePhase ? null
|
||||
, meta ? {}
|
||||
, enableDebugInfo ? false
|
||||
, ... }@attrs:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
debugInfoFlag = lib.optionalString (enableDebugInfo || elixir.debugInfo) "--debug-info";
|
||||
|
||||
shell = drv: stdenv.mkDerivation {
|
||||
name = "interactive-shell-${drv.name}";
|
||||
buildInputs = [ drv ];
|
||||
};
|
||||
|
||||
bootstrapper = ./mix-bootstrap;
|
||||
|
||||
pkg = self: stdenv.mkDerivation ( attrs // {
|
||||
name = "${name}-${version}";
|
||||
inherit version;
|
||||
|
||||
dontStrip = true;
|
||||
|
||||
inherit src;
|
||||
|
||||
setupHook = if setupHook == null
|
||||
then writeText "setupHook.sh" ''
|
||||
addToSearchPath ERL_LIBS "$1/lib/erlang/lib"
|
||||
''
|
||||
else setupHook;
|
||||
|
||||
inherit buildInputs;
|
||||
propagatedBuildInputs = [ hex elixir ] ++ beamDeps;
|
||||
|
||||
configurePhase = if configurePhase == null
|
||||
then ''
|
||||
runHook preConfigure
|
||||
${erlang}/bin/escript ${bootstrapper}
|
||||
runHook postConfigure
|
||||
''
|
||||
else configurePhase ;
|
||||
|
||||
|
||||
buildPhase = if buildPhase == null
|
||||
then ''
|
||||
runHook preBuild
|
||||
|
||||
export HEX_OFFLINE=1
|
||||
export HEX_HOME=`pwd`
|
||||
export MIX_ENV=prod
|
||||
export MIX_NO_DEPS=1
|
||||
|
||||
mix compile ${debugInfoFlag} --no-deps-check
|
||||
|
||||
runHook postBuild
|
||||
''
|
||||
else buildPhase;
|
||||
|
||||
installPhase = if installPhase == null
|
||||
then ''
|
||||
runHook preInstall
|
||||
|
||||
MIXENV=prod
|
||||
|
||||
if [ -d "_build/shared" ]; then
|
||||
MIXENV=shared
|
||||
fi
|
||||
|
||||
mkdir -p "$out/lib/erlang/lib/${name}-${version}"
|
||||
for reldir in src ebin priv include; do
|
||||
fd="_build/$MIXENV/lib/${name}/$reldir"
|
||||
[ -d "$fd" ] || continue
|
||||
cp -Hrt "$out/lib/erlang/lib/${name}-${version}" "$fd"
|
||||
success=1
|
||||
done
|
||||
|
||||
runHook postInstall
|
||||
''
|
||||
else installPhase;
|
||||
|
||||
passthru = {
|
||||
packageName = name;
|
||||
env = shell self;
|
||||
inherit beamDeps;
|
||||
};
|
||||
});
|
||||
in fix pkg
|
||||
@@ -33,7 +33,7 @@ let
|
||||
buildHex = callPackage ./build-hex.nix { };
|
||||
buildErlangMk = callPackage ./build-erlang-mk.nix { };
|
||||
fetchMixDeps = callPackage ./fetch-mix-deps.nix { };
|
||||
buildMix = callPackage ./build-mix.nix { };
|
||||
mixRelease = callPackage ./mix-release.nix { };
|
||||
|
||||
# BEAM-based languages.
|
||||
elixir = elixir_1_11;
|
||||
|
||||
@@ -1,34 +1,49 @@
|
||||
{ stdenvNoCC, lib, elixir, hex, rebar, rebar3, cacert, git }:
|
||||
|
||||
{ name, version, sha256, src, mixEnv ? "prod", debug ? false, meta ? { } }:
|
||||
|
||||
stdenvNoCC.mkDerivation ({
|
||||
name = "mix-deps-${name}-${version}";
|
||||
{ pname
|
||||
, version
|
||||
, sha256
|
||||
, src
|
||||
, mixEnv ? "prod"
|
||||
, debug ? false
|
||||
, meta ? { }
|
||||
, ...
|
||||
}@attrs:
|
||||
|
||||
stdenvNoCC.mkDerivation (attrs // {
|
||||
nativeBuildInputs = [ elixir hex cacert git ];
|
||||
|
||||
inherit src;
|
||||
|
||||
MIX_ENV = mixEnv;
|
||||
MIX_DEBUG = if debug then 1 else 0;
|
||||
DEBUG = if debug then 1 else 0; # for rebar3
|
||||
# the api with `mix local.rebar rebar path` makes a copy of the binary
|
||||
MIX_REBAR = "${rebar}/bin/rebar";
|
||||
MIX_REBAR3 = "${rebar3}/bin/rebar3";
|
||||
# there is a persistent download failure with absinthe 1.6.3
|
||||
# those defaults reduce the failure rate
|
||||
HEX_HTTP_CONCURRENCY = 1;
|
||||
HEX_HTTP_TIMEOUT = 120;
|
||||
|
||||
configurePhase = ''
|
||||
configurePhase = attrs.configurePhase or ''
|
||||
runHook preConfigure
|
||||
export HEX_HOME="$TEMPDIR/.hex";
|
||||
export MIX_HOME="$TEMPDIR/.mix";
|
||||
export MIX_DEPS_PATH="$out";
|
||||
export MIX_DEPS_PATH="$TEMPDIR/deps";
|
||||
|
||||
# Rebar
|
||||
mix local.rebar rebar "${rebar}/bin/rebar"
|
||||
mix local.rebar rebar3 "${rebar3}/bin/rebar3"
|
||||
export REBAR_GLOBAL_CONFIG_DIR="$TMPDIR/rebar3"
|
||||
export REBAR_CACHE_DIR="$TMPDIR/rebar3.cache"
|
||||
runHook postConfigure
|
||||
'';
|
||||
|
||||
dontBuild = true;
|
||||
|
||||
installPhase = ''
|
||||
installPhase = attrs.installPhase or ''
|
||||
runHook preInstall
|
||||
mix deps.get --only ${mixEnv}
|
||||
find "$TEMPDIR/deps" -path '*/.git/*' -a ! -name HEAD -exec rm -rf {} +
|
||||
cp -r --no-preserve=mode,ownership,timestamps $TEMPDIR/deps $out
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
outputHashAlgo = "sha256";
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
#!/usr/bin/env escript
|
||||
%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
|
||||
%%! -smp enable
|
||||
%%% ---------------------------------------------------------------------------
|
||||
%%% @doc
|
||||
%%% The purpose of this command is to prepare a mix project so that mix
|
||||
%%% understands that the dependencies are all already installed. If you want a
|
||||
%%% hygienic build on nix then you must run this command before running mix. I
|
||||
%%% suggest that you add a `Makefile` to your project and have the bootstrap
|
||||
%%% command be a dependency of the build commands. See the nix documentation for
|
||||
%%% more information.
|
||||
%%%
|
||||
%%% This command designed to have as few dependencies as possible so that it can
|
||||
%%% be a dependency of root level packages like mix. To that end it does many
|
||||
%%% things in a fairly simplistic way. That is by design.
|
||||
%%%
|
||||
%%% ### Assumptions
|
||||
%%%
|
||||
%%% This command makes the following assumptions:
|
||||
%%%
|
||||
%%% * It is run in a nix-shell or nix-build environment
|
||||
%%% * that all dependencies have been added to the ERL_LIBS
|
||||
%%% Environment Variable
|
||||
|
||||
-record(data, {version
|
||||
, erl_libs
|
||||
, root
|
||||
, name}).
|
||||
-define(LOCAL_HEX_REGISTRY, "registry.ets").
|
||||
|
||||
main(Args) ->
|
||||
{ok, RequiredData} = gather_required_data_from_the_environment(Args),
|
||||
ok = bootstrap_libs(RequiredData).
|
||||
|
||||
%% @doc
|
||||
%% This takes an app name in the standard OTP <name>-<version> format
|
||||
%% and returns just the app name. Why? Because rebar doesn't
|
||||
%% respect OTP conventions in some cases.
|
||||
-spec fixup_app_name(file:name()) -> string().
|
||||
fixup_app_name(Path) ->
|
||||
BaseName = filename:basename(Path),
|
||||
case string:split(BaseName, "-") of
|
||||
[Name, _Version] -> Name;
|
||||
Name -> Name
|
||||
end.
|
||||
|
||||
|
||||
-spec gather_required_data_from_the_environment([string()]) -> {ok, #data{}}.
|
||||
gather_required_data_from_the_environment(_) ->
|
||||
{ok, #data{ version = guard_env("version")
|
||||
, erl_libs = os:getenv("ERL_LIBS", [])
|
||||
, root = code:root_dir()
|
||||
, name = guard_env("name")}}.
|
||||
|
||||
-spec guard_env(string()) -> string().
|
||||
guard_env(Name) ->
|
||||
case os:getenv(Name) of
|
||||
false ->
|
||||
stderr("Expected Environment variable ~s! Are you sure you are "
|
||||
"running in a Nix environment? Either a nix-build, "
|
||||
"nix-shell, etc?~n", [Name]),
|
||||
erlang:halt(1);
|
||||
Variable ->
|
||||
Variable
|
||||
end.
|
||||
|
||||
-spec bootstrap_libs(#data{}) -> ok.
|
||||
bootstrap_libs(#data{erl_libs = ErlLibs}) ->
|
||||
io:format("Bootstrapping dependent libraries~n"),
|
||||
Target = "_build/prod/lib/",
|
||||
Paths = string:tokens(ErlLibs, ":"),
|
||||
CopiableFiles =
|
||||
lists:foldl(fun(Path, Acc) ->
|
||||
gather_directory_contents(Path) ++ Acc
|
||||
end, [], Paths),
|
||||
lists:foreach(fun (Path) ->
|
||||
ok = link_app(Path, Target)
|
||||
end, CopiableFiles).
|
||||
|
||||
-spec gather_directory_contents(string()) -> [{string(), string()}].
|
||||
gather_directory_contents(Path) ->
|
||||
{ok, Names} = file:list_dir(Path),
|
||||
lists:map(fun(AppName) ->
|
||||
{filename:join(Path, AppName), fixup_app_name(AppName)}
|
||||
end, Names).
|
||||
|
||||
%% @doc
|
||||
%% Makes a symlink from the directory pointed at by Path to a
|
||||
%% directory of the same name in Target. So if we had a Path of
|
||||
%% {`foo/bar/baz/bash`, `baz`} and a Target of `faz/foo/foos`, the symlink
|
||||
%% would be `faz/foo/foos/baz`.
|
||||
-spec link_app({string(), string()}, string()) -> ok.
|
||||
link_app({Path, TargetFile}, TargetDir) ->
|
||||
Target = filename:join(TargetDir, TargetFile),
|
||||
ok = make_symlink(Path, Target).
|
||||
|
||||
-spec make_symlink(string(), string()) -> ok.
|
||||
make_symlink(Path, TargetFile) ->
|
||||
file:delete(TargetFile),
|
||||
ok = filelib:ensure_dir(TargetFile),
|
||||
io:format("Making symlink from ~s to ~s~n", [Path, TargetFile]),
|
||||
ok = file:make_symlink(Path, TargetFile).
|
||||
|
||||
%% @doc
|
||||
%% Write the result of the format string out to stderr.
|
||||
-spec stderr(string(), [term()]) -> ok.
|
||||
stderr(FormatStr, Args) ->
|
||||
io:put_chars(standard_error, io_lib:format(FormatStr, Args)).
|
||||
106
pkgs/development/beam-modules/mix-release.nix
Normal file
106
pkgs/development/beam-modules/mix-release.nix
Normal file
@@ -0,0 +1,106 @@
|
||||
{ stdenv, lib, elixir, erlang, findutils, hex, rebar, rebar3, fetchMixDeps, makeWrapper, git }:
|
||||
|
||||
{ pname
|
||||
, version
|
||||
, src
|
||||
, nativeBuildInputs ? [ ]
|
||||
, meta ? { }
|
||||
, enableDebugInfo ? false
|
||||
, mixEnv ? "prod"
|
||||
, compileFlags ? [ ]
|
||||
, mixDeps ? null
|
||||
, ...
|
||||
}@attrs:
|
||||
let
|
||||
overridable = builtins.removeAttrs attrs [ "compileFlags" ];
|
||||
|
||||
in
|
||||
stdenv.mkDerivation (overridable // {
|
||||
nativeBuildInputs = nativeBuildInputs ++ [ erlang hex elixir makeWrapper git ];
|
||||
|
||||
MIX_ENV = mixEnv;
|
||||
MIX_DEBUG = if enableDebugInfo then 1 else 0;
|
||||
HEX_OFFLINE = 1;
|
||||
DEBUG = if enableDebugInfo then 1 else 0; # for Rebar3 compilation
|
||||
# the api with `mix local.rebar rebar path` makes a copy of the binary
|
||||
MIX_REBAR = "${rebar}/bin/rebar";
|
||||
MIX_REBAR3 = "${rebar3}/bin/rebar3";
|
||||
|
||||
postUnpack = ''
|
||||
export HEX_HOME="$TEMPDIR/hex"
|
||||
export MIX_HOME="$TEMPDIR/mix"
|
||||
# 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"
|
||||
|
||||
# Rebar
|
||||
export REBAR_GLOBAL_CONFIG_DIR="$TEMPDIR/rebar3"
|
||||
export REBAR_CACHE_DIR="$TEMPDIR/rebar3.cache"
|
||||
|
||||
${lib.optionalString (mixDeps != null) ''
|
||||
cp --no-preserve=mode -R "${mixDeps}" "$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
|
||||
|
||||
runHook postConfigure
|
||||
'';
|
||||
|
||||
buildPhase = attrs.buildPhase or ''
|
||||
runHook preBuild
|
||||
|
||||
mix compile --no-deps-check ${lib.concatStringsSep " " compileFlags}
|
||||
|
||||
runHook postBuild
|
||||
'';
|
||||
|
||||
|
||||
installPhase = attrs.installPhase or ''
|
||||
runHook preInstall
|
||||
|
||||
mix release --no-deps-check --path "$out"
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
fixupPhase = ''
|
||||
runHook preFixup
|
||||
if [ -e "$out/bin/${pname}.bat" ]; then # absent in special cases, i.e. elixir-ls
|
||||
rm "$out/bin/${pname}.bat" # windows file
|
||||
fi
|
||||
# contains secrets and should not be in the nix store
|
||||
# TODO document how to handle RELEASE_COOKIE
|
||||
# secrets should not be in the nix store.
|
||||
# This is only used for connecting multiple nodes
|
||||
if [ -e $out/releases/COOKIE ]; then # absent in special cases, i.e. elixir-ls
|
||||
rm $out/releases/COOKIE
|
||||
fi
|
||||
# TODO remove the uneeded reference too erlang
|
||||
# one possible way would be
|
||||
# for f in $(${findutils}/bin/find $out -name start); do
|
||||
# substituteInPlace $f \
|
||||
# --replace 'ROOTDIR=${erlang}/lib/erlang' 'ROOTDIR=""'
|
||||
# done
|
||||
# What is left to do is to check that erlang is not required on
|
||||
# the host
|
||||
|
||||
patchShebangs $out
|
||||
runHook postFixup
|
||||
'';
|
||||
# TODO figure out how to do a Fixed Output Derivation and add the output hash
|
||||
# This doesn't play well at the moment with Phoenix projects
|
||||
# for example that have frontend dependencies
|
||||
|
||||
# disallowedReferences = [ erlang ];
|
||||
})
|
||||
Reference in New Issue
Block a user