Skip to content

Commit

Permalink
Merge pull request #1 from dlesl/nix-lock
Browse files Browse the repository at this point in the history
Add `rebar3 nix lock` command
  • Loading branch information
gleber authored May 9, 2021
2 parents b3be301 + 75b3310 commit e6b2533
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 216 deletions.
3 changes: 1 addition & 2 deletions rebar.config
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
{erl_opts, [debug_info]}.
{deps, [ {hex2nix, {git, "/home/gleber/code/erl/hex2nix/"}}
, {erlware_commons, "1.0.0"}]}.
{deps, []}.
15 changes: 1 addition & 14 deletions rebar.lock
Original file line number Diff line number Diff line change
@@ -1,14 +1 @@
{"1.1.0",
[{<<"cf">>,{pkg,<<"cf">>,<<"0.2.1">>},1},
{<<"erlware_commons">>,{pkg,<<"erlware_commons">>,<<"1.0.0">>},0},
{<<"getopt">>,{pkg,<<"getopt">>,<<"0.8.2">>},1},
{<<"ibrowse">>,{pkg,<<"ibrowse">>,<<"4.4.0">>},1},
{<<"jsx">>,{pkg,<<"jsx">>,<<"2.8.2">>},1}]}.
[
{pkg_hash,[
{<<"cf">>, <<"69D0B1349FD4D7D4DC55B7F407D29D7A840BF9A1EF5AF529F1EBE0CE153FC2AB">>},
{<<"erlware_commons">>, <<"087467DE5833C0BB5B3CCDD387F9E9C1FB816A75B7A709629BF24B5ED3246C51">>},
{<<"getopt">>, <<"B17556DB683000BA50370B16C0619DF1337E7AF7ECBF7D64FBF8D1D6BCE3109B">>},
{<<"ibrowse">>, <<"2D923325EFE0D2CB09B9C6A047B2835A5EDA69D8A47ED6FF8BC03628B764E991">>},
{<<"jsx">>, <<"7ACC7D785B5ABE8A6E9ADBDE926A24E481F29956DD8B4DF49E3E4E7BCC92A018">>}]}
].
[].
86 changes: 6 additions & 80 deletions src/nix_bootstrap.erl
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,12 @@

-export([perform/1]).

-record(data, {version
, registry_only = false
-record(data, { version
, debug_info = false
, compile_ports
, erl_libs
, plugins
, root
, name
, registry_snapshot}).

-define(HEX_REGISTRY_PATH, ".cache/rebar3/hex/default/registry").
}).

perform(Opts) ->
io:format("nix_bootstrap opts: ~p~n", [Opts]),
Expand All @@ -45,48 +40,26 @@ perform(Opts) ->
io:format("nix_bootstrap data: ~p~n", [RequiredData]),
do_the_bootstrap(RequiredData).

%% @doc There are two modes 'registry_only' where the register is
%% created from hex and everything else.
-spec do_the_bootstrap(#data{}) -> ok.
do_the_bootstrap(RequiredData = #data{registry_only = true}) ->
ok = bootstrap_registry(RequiredData);
do_the_bootstrap(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, "registry-only" and "debug-info"
%% dependencies minimal. For now there can be one entry on the
%% command line: "debug-info"
-spec parse_args([proplists:property()]) -> {ok, #data{}}.
parse_args(Opts) ->
RegistryOnly = proplists:get_value(registry_only, Opts),
DebugInfo = proplists:get_value(debug_info, Opts),
{ok, #data{registry_only = RegistryOnly,
debug_info = DebugInfo}}.
{ok, #data{debug_info = DebugInfo}}.

-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),
ok = if_debug_info_add(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) ->
ok = link_app(Path, Target)
end, CopiableFiles).

-spec bootstrap_libs(#data{}) -> ok.
bootstrap_libs(#data{erl_libs = ErlLibs}) ->
io:format("Bootstrapping dependent libraries~n"),
Expand Down Expand Up @@ -151,39 +124,13 @@ fixup_app_name(FileName) ->
[Name, _Version, _Tag] -> 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, #data{}}.
gather_required_data_from_the_environment(ArgData) ->
{ok, ArgData#data{ version = guard_env("version")
, erl_libs = get_env("ERL_LIBS", [])
, plugins = get_env("buildPlugins", [])
, root = code:root_dir()
, name = guard_env("name")
, compile_ports = nix2bool(get_env("compilePorts", ""))
, registry_snapshot = guard_env("HEX_REGISTRY_SNAPSHOT")}}.
}}.

-spec nix2bool(any()) -> boolean().
nix2bool("1") ->
Expand Down Expand Up @@ -237,27 +184,6 @@ add_debug_info(Config) ->
{erl_opts, [debug_info | ExistingOpts]})
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 = add_pc_to_plugins(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 add_pc_to_plugins([term()]) -> [term()].
add_pc_to_plugins(Config) ->
PluginList = case lists:keysearch(plugins, 1, Config) of
{value, {plugins, ExistingPluginList}} -> ExistingPluginList;
_ -> []
end,
lists:keystore(plugins, 1, Config, {plugins, [pc | PluginList]}).

-spec read_rebar_config() -> [term()].
read_rebar_config() ->
case file:consult("rebar.config") of
Expand Down
3 changes: 1 addition & 2 deletions src/rebar3_nix.erl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,5 @@
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) ->
{ok, State1} = rebar3_nix_bootstrap_prv:init(State),
{ok, State2} = rebar3_nix_init_prv:init(State1),
%% {ok, State2} = rebar3_nix_prv:init(State1),
{ok, State2} = rebar3_nix_lock_prv:init(State1),
{ok, State2}.
3 changes: 1 addition & 2 deletions src/rebar3_nix_bootstrap_prv.erl
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ init(State) ->
{ok, rebar_state:add_provider(State, Provider)}.

opts() ->
[ {registry_only, $r, "registry_only", {boolean, false}, "bootstrap registry only"}
, {debug_info, $d, "debug_info", {boolean, false}, "enable debug info"}
[ {debug_info, $d, "debug_info", {boolean, false}, "enable debug info"}
].

-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
Expand Down
1 change: 0 additions & 1 deletion src/rebar3_nix_env_prv.erl

This file was deleted.

81 changes: 0 additions & 81 deletions src/rebar3_nix_init_prv.erl

This file was deleted.

93 changes: 93 additions & 0 deletions src/rebar3_nix_lock_prv.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
-module(rebar3_nix_lock_prv).

-export([init/1, do/1, format_error/1]).

-define(NIX_DEPS, "# Generated by rebar3_nix
{ fetchHex, fetchFromGitHub }:
{~s
}
").

-define(FETCH_HEX, "
~s = fetchHex {
pkg = \"~s\";
version = \"~s\";
sha256 = \"~s\";
};").

-define(FETCH_GIT, "
~s = fetchGit {
url = \"~s\";
rev = \"~s\";
};").

-define(FETCH_FROM_GITHUB, "
~s = fetchFromGitHub {
owner = \"~s\";
repo = \"~s\";
rev = \"~s\";
sha256 = \"~s\";
};").

-spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) ->
Provider = providers:create([
{namespace, nix},
{name, lock},
{module, ?MODULE},
{bare, true},
{deps, [{default, lock}]},
{example, "rebar3 nix lock -o rebar-deps.nix"},
{opts, [{out, $o, "out", {string, "rebar-deps.nix"}, "Output file."}]},
{short_desc, "Export rebar3 dependencies for nix"},
{desc, "Export rebar3 dependencies for nix"}
]),
{ok, rebar_state:add_provider(State, Provider)}.

-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
Lock = rebar_state:lock(State),
Deps = [to_nix(rebar_app_info:name(AppInfo), rebar_app_info:source(AppInfo))
|| AppInfo <- Lock],
Drv = io_lib:format(?NIX_DEPS, [Deps]),
ok = file:write_file(out_path(State), Drv),
{ok, State}.

out_path(State) ->
{Args, _} = rebar_state:command_parsed_args(State),
proplists:get_value(out, Args).

-spec format_error(any()) -> iolist().
format_error(Reason) ->
io_lib:format("~p", [Reason]).

to_nix(Name, {pkg, PkgName, Vsn, _OldHash, Hash, _Repo}) ->
io_lib:format(?FETCH_HEX, [Name, PkgName, Vsn, to_sri(Hash)]);
to_nix(Name, {git, Url, {ref, Ref}}) ->
case string:prefix(string:lowercase(Url), "https://github.com/") of
nomatch ->
io_lib:format(?FETCH_GIT, [Name, Url, Ref]);
Path ->
[Owner, Repo0] = string:split(Path, "/", trailing),
Repo = re:replace(Repo0, "\\.git$", "", [{return, list}]),
Prefetch = ["nix-prefetch-url --unpack https://github.com/",
Owner, "/", Repo, "/tarball/", Ref, " 2>/dev/null"],
Hash = case string:trim(os:cmd(Prefetch)) of
[] ->
rebar_api:abort(
"prefetch failed, make sure nix-prefetch-url is on your PATH",
[]);
Hash0 ->
Hash0
end,
io_lib:format(?FETCH_FROM_GITHUB, [Name, Owner, Repo, Ref, Hash])
end;
to_nix(Name, Other) ->
rebar_api:abort("rebar3_nix: unsupported dependency type ~p for ~s~n", [Other, Name]),
undefined.

to_sri(Sha256) when is_list(Sha256) ->
to_sri(list_to_binary(Sha256));
to_sri(<<Sha256Base16:64/binary>>) ->
Sha256 = binary_to_integer(Sha256Base16, 16),
["sha256-", base64:encode(<<Sha256:32/big-unsigned-integer-unit:8>>)].
34 changes: 0 additions & 34 deletions src/rebar3_nix_prv.erl

This file was deleted.

0 comments on commit e6b2533

Please sign in to comment.