about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEric Merritt <eric@merritt.tech>2016-04-15 11:06:57 -0700
committerEric Merritt <eric@merritt.tech>2016-04-23 19:03:29 -0700
commit383626b9d7dd56618f0789eefee147a097ada4a4 (patch)
tree9fc59e5d96f9f85bb84fba6f59671d6777f799cb
parent2d6d9682bb8a910f3eb5f0be8d5687c753e9732c (diff)
downloadnixlib-383626b9d7dd56618f0789eefee147a097ada4a4.tar
nixlib-383626b9d7dd56618f0789eefee147a097ada4a4.tar.gz
nixlib-383626b9d7dd56618f0789eefee147a097ada4a4.tar.bz2
nixlib-383626b9d7dd56618f0789eefee147a097ada4a4.tar.lz
nixlib-383626b9d7dd56618f0789eefee147a097ada4a4.tar.xz
nixlib-383626b9d7dd56618f0789eefee147a097ada4a4.tar.zst
nixlib-383626b9d7dd56618f0789eefee147a097ada4a4.zip
move rebar3-nix-bootstrap to rebar3
This moves rebar3-nix-bootstrap from its own repository to rebar3. Its a
single file and this vastly reduces the complexity of making changes.
-rw-r--r--pkgs/development/beam-modules/build-rebar3.nix2
-rw-r--r--pkgs/development/tools/build-managers/rebar3/default.nix10
-rwxr-xr-xpkgs/development/tools/build-managers/rebar3/rebar3-nix-bootstrap256
-rw-r--r--pkgs/development/tools/erlang/rebar3-nix-bootstrap/default.nix24
-rw-r--r--pkgs/top-level/all-packages.nix1
5 files changed, 264 insertions, 29 deletions
diff --git a/pkgs/development/beam-modules/build-rebar3.nix b/pkgs/development/beam-modules/build-rebar3.nix
index 2627ddf99a6b..f13322519fd8 100644
--- a/pkgs/development/beam-modules/build-rebar3.nix
+++ b/pkgs/development/beam-modules/build-rebar3.nix
@@ -48,7 +48,7 @@ let
 
     configurePhase = ''
       runHook preConfigure
-      rebar3-nix-bootstrap
+      ${erlang}/bin/escript ${rebar3.bootstrapper}
       runHook postConfigure
     '';
 
diff --git a/pkgs/development/tools/build-managers/rebar3/default.nix b/pkgs/development/tools/build-managers/rebar3/default.nix
index 057ae59b1445..2b5eee407a44 100644
--- a/pkgs/development/tools/build-managers/rebar3/default.nix
+++ b/pkgs/development/tools/build-managers/rebar3/default.nix
@@ -1,10 +1,12 @@
 { stdenv, writeText, callPackage, fetchurl,
-  fetchHex, erlang, hermeticRebar3 ? true, rebar3-nix-bootstrap,
+  fetchHex, erlang, hermeticRebar3 ? true,
   tree, fetchFromGitHub, hexRegistrySnapshot }:
 
 let
   version = "3.0.0-beta.4";
 
+  bootstrapper = ./rebar3-nix-bootstrap;
+
   # TODO: all these below probably should go into nixpkgs.erlangModules.sources.*
   # {erlware_commons,     "0.16.0"},
   erlware_commons = fetchHex {
@@ -83,16 +85,18 @@ stdenv.mkDerivation {
     sha256 = "0px66scjdia9aaa5z36qzxb848r56m0k98g0bxw065a2narsh4xy";
   };
 
+  inherit bootstrapper;
+
   patches = if hermeticRebar3 == true
   then  [ ./hermetic-bootstrap.patch ./hermetic-rebar3.patch ]
   else [];
 
   buildInputs = [ erlang tree  ];
-  propagatedBuildInputs = [ hexRegistrySnapshot rebar3-nix-bootstrap ];
+  propagatedBuildInputs = [ hexRegistrySnapshot ];
 
   postPatch = ''
     echo postPatch
-    rebar3-nix-bootstrap registry-only
+    ${erlang}/bin/escript ${bootstrapper} registry-only
     echo "$ERL_LIBS"
     mkdir -p _build/default/lib/
     mkdir -p _build/default/plugins
diff --git a/pkgs/development/tools/build-managers/rebar3/rebar3-nix-bootstrap b/pkgs/development/tools/build-managers/rebar3/rebar3-nix-bootstrap
new file mode 100755
index 000000000000..d75d69f054d6
--- /dev/null
+++ b/pkgs/development/tools/build-managers/rebar3/rebar3-nix-bootstrap
@@ -0,0 +1,256 @@
+#!/usr/bin/env escript
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%%! -smp enable
+%%% ---------------------------------------------------------------------------
+%%% @doc
+%%% The purpose of this command is to prepare a rebar3 project so that
+%%% rebar3 understands that the dependencies are all already
+%%% installed. If you want a hygienic build on nix then you must run
+%%% this command before running rebar3. 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 rebar3. 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
+              , registry_only = false
+              , compile_ports
+              , erl_libs
+              , plugins
+              , root
+              , name
+              , registry_snapshot}).
+
+-define(HEX_REGISTRY_PATH, ".cache/rebar3/hex/default/registry").
+
+main(Args) ->
+    {ok, ArgData} = parse_args(Args),
+    {ok, RequiredData} = gather_required_data_from_the_environment(ArgData),
+    do(RequiredData).
+
+%% @doc
+%% This actually runs the command. There are two modes 'register_only'
+%% where the register is created from hex and everything else.
+-spec do(#data{}) -> ok.
+do(RequiredData = #data{registry_only = true}) ->
+    ok = bootstrap_registry(RequiredData);
+do(RequiredData) ->
+    ok = bootstrap_registry(RequiredData),
+    ok = bootstrap_configs(RequiredData),
+    ok = bootstrap_plugins(RequiredData),
+    ok = bootstrap_libs(RequiredData).
+
+%% @doc
+%% Argument parsing is super simple only because we want to keep the
+%% dependencies minimal. For now there can be two entries on the
+%% command line, "register-only" and "compile-ports"
+-spec parse_args([string()]) -> #data{}.
+parse_args(Args) ->
+    {ok, #data{registry_only = lists:member("registry-only", Args)}}.
+
+-spec bootstrap_configs(#data{}) -> ok.
+bootstrap_configs(RequiredData)->
+    io:format("Boostrapping app and rebar configurations~n"),
+    ok = if_single_app_project_update_app_src_version(RequiredData),
+    ok = if_compile_ports_add_pc_plugin(RequiredData).
+
+-spec bootstrap_plugins(#data{}) -> ok.
+bootstrap_plugins(#data{plugins = Plugins}) ->
+    io:format("Bootstrapping rebar3 plugins~n"),
+    Target = "_build/default/plugins/",
+    Paths = string:tokens(Plugins, " "),
+    CopiableFiles =
+        lists:foldl(fun(Path, Acc) ->
+                            gather_dependency(Path) ++ Acc
+                    end, [], Paths),
+    lists:foreach(fun (Path) ->
+                          link_app(Path, Target)
+                  end, CopiableFiles).
+
+-spec bootstrap_libs(#data{}) -> ok.
+bootstrap_libs(#data{erl_libs = ErlLibs}) ->
+    io:format("Bootstrapping dependent librariesXXXX~n"),
+    Target = "_build/default/lib/",
+    Paths = string:tokens(ErlLibs, ":"),
+    CopiableFiles =
+        lists:foldl(fun(Path, Acc) ->
+                            gather_directory_contents(Path) ++ Acc
+                    end, [], Paths),
+    lists:foreach(fun (Path) ->
+                          link_app(Path, Target)
+                  end, CopiableFiles).
+
+-spec gather_dependency(string()) -> [{string(), string()}].
+gather_dependency(Path) ->
+    FullLibrary = filename:join(Path, "lib/erlang/lib/"),
+    case filelib:is_dir(FullLibrary) of
+        true ->
+            gather_directory_contents(FullLibrary);
+        false ->
+            [raw_hex(Path)]
+    end.
+
+-spec raw_hex(string()) -> {string(), string()}.
+raw_hex(Path) ->
+    [_, Name] = re:split(Path, "-hex-source-"),
+    {Path, erlang:binary_to_list(Name)}.
+
+-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),
+    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
+%% This takes an app name in the standard OTP <name>-<version> format
+%% and returns just the app name. Why? because rebar is doesn't
+%% respect OTP conventions in some cases.
+-spec fixup_app_name(string()) -> string().
+fixup_app_name(FileName) ->
+    case string:tokens(FileName, "-") of
+        [Name] -> Name;
+        [Name, _Version] -> Name
+    end.
+
+-spec bootstrap_registry(#data{}) -> ok.
+bootstrap_registry(#data{registry_snapshot = RegistrySnapshot}) ->
+    io:format("Bootstrapping Hex Registry for Rebar~n"),
+    make_sure_registry_snapshot_exists(RegistrySnapshot),
+    filelib:ensure_dir(?HEX_REGISTRY_PATH),
+    ok = case filelib:is_file(?HEX_REGISTRY_PATH) of
+             true ->
+                 file:delete(?HEX_REGISTRY_PATH);
+             false ->
+                 ok
+         end,
+    ok = file:make_symlink(RegistrySnapshot,
+                           ?HEX_REGISTRY_PATH).
+
+-spec make_sure_registry_snapshot_exists(string()) -> ok.
+make_sure_registry_snapshot_exists(RegistrySnapshot) ->
+    case filelib:is_file(RegistrySnapshot) of
+        true ->
+            ok;
+        false ->
+            stderr("Registry snapshot (~s) does not exist!", [RegistrySnapshot]),
+            erlang:halt(1)
+    end.
+
+-spec gather_required_data_from_the_environment(#data{}) -> {ok, map()}.
+gather_required_data_from_the_environment(ArgData) ->
+    {ok, ArgData#data{ version = guard_env("version")
+                     , erl_libs = os:getenv("ERL_LIBS", [])
+                     , plugins = os:getenv("buildPlugins", [])
+                     , root = code:root_dir()
+                     , name = guard_env("name")
+                     , compile_ports = nix2bool(os:getenv("compilePorts", ""))
+                     , registry_snapshot = guard_env("HEX_REGISTRY_SNAPSHOT")}}.
+
+-spec nix2bool(any()) -> boolean().
+nix2bool("1") ->
+    true;
+nix2bool("") ->
+    false.
+
+-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.
+
+%% @doc
+%% If the compile ports flag is set, rewrite the rebar config to
+%% include the 'pc' plugin.
+-spec if_compile_ports_add_pc_plugin(#data{}) -> ok.
+if_compile_ports_add_pc_plugin(#data{compile_ports = true}) ->
+    ConfigTerms = update_config(read_rebar_config()),
+    Text = lists:map(fun(Term) -> io_lib:format("~tp.~n", [Term]) end,
+                     ConfigTerms),
+    file:write_file("rebar.config", Text);
+if_compile_ports_add_pc_plugin(_) ->
+    ok.
+
+-spec update_config([term()]) -> [term()].
+update_config(Config) ->
+    case lists:keysearch(plugins, 1, Config) of
+        {ok, {plugins, PluginList}} ->
+            lists:keystore(plugins, 1, Config, {plugins, [Config | PluginList]});
+        _ ->
+            [{plugins, [pc]} | Config]
+    end.
+
+-spec read_rebar_config() -> [term()].
+read_rebar_config() ->
+    case file:consult("rebar.config") of
+        {ok, Terms} ->
+            Terms;
+        _ ->
+            stderr("Unable to read rebar config!", []),
+            erlang:halt(1)
+    end.
+
+
+-spec if_single_app_project_update_app_src_version(#data{}) -> ok.
+if_single_app_project_update_app_src_version(#data{name = Name,
+                                                   version = Version}) ->
+    case app_src_exists(Name) of
+        {true, SrcFile} ->
+            update_app_src_with_version(SrcFile, Version);
+        {false, _} ->
+            ok
+    end.
+
+-spec update_app_src_with_version(string(), string()) -> ok.
+update_app_src_with_version(SrcFile, Version) ->
+    {ok, [{application, Name, Details}]} = file:consult(SrcFile),
+    NewDetails = lists:keyreplace(vsn, 1, Details, {vsn, Version}),
+    file:write_file(SrcFile, io_lib:fwrite("~p.\n", [{application, Name, NewDetails}])).
+
+-spec app_src_exists(string()) -> boolean().
+app_src_exists(Name) ->
+    FileName = filename:join("src",
+                             lists:concat([Name, ".app.src"])),
+    {filelib:is_file(FileName), FileName}.
+
+
+%% @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)).
diff --git a/pkgs/development/tools/erlang/rebar3-nix-bootstrap/default.nix b/pkgs/development/tools/erlang/rebar3-nix-bootstrap/default.nix
deleted file mode 100644
index ed38d573abf1..000000000000
--- a/pkgs/development/tools/erlang/rebar3-nix-bootstrap/default.nix
+++ /dev/null
@@ -1,24 +0,0 @@
-{stdenv, fetchFromGitHub, erlang }:
-
-stdenv.mkDerivation rec {
-    name = "rebar3-nix-bootstrap";
-    version = "0.0.3";
-
-    src = fetchFromGitHub {
-        owner = "erlang-nix";
-        repo = "rebar3-nix-bootstrap";
-        rev = "${version}";
-        sha256 = "01yyaz104jj3mxx8k10q3rwpn2rh13q1ja5r0iq37qyjmg8xflhq";
-    };
-
-    buildInputs = [ erlang ];
-
-    installFlags = "PREFIX=$(out)";
-
-    meta = {
-      description = "Shim command to help bootstrap a rebar3 project on Nix";
-      license = stdenv.lib.licenses.asl20;
-      homepage = "https://github.com/erlang-nix/rebar3-nix-bootstrap";
-      maintainers = with stdenv.lib.maintainers; [ ericbmerritt ];
-    };
-}
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index 02a1721ab178..3b0f9db8f167 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -5311,7 +5311,6 @@ in
   rebar = callPackage ../development/tools/build-managers/rebar { };
   rebar3-open = callPackage ../development/tools/build-managers/rebar3 { hermeticRebar3 = false; };
   rebar3 = callPackage ../development/tools/build-managers/rebar3 { hermeticRebar3 = true; };
-  rebar3-nix-bootstrap = callPackage ../development/tools/erlang/rebar3-nix-bootstrap { };
   hexRegistrySnapshot = callPackage ../development/beam-modules/hex-registry-snapshot.nix { };
   fetchHex = callPackage ../development/beam-modules/fetch-hex.nix { };