This moves rebar3-nix-bootstrap from its own repository to rebar3. Its a single file and this vastly reduces the complexity of making changes.wip/yesman
parent
2d6d9682bb
commit
383626b9d7
@ -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)). |
@ -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 ]; |
||||
}; |
||||
} |
Loading…
Reference in new issue