summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/rebar3.erl10
-rw-r--r--src/rebar_packages.erl40
-rw-r--r--src/rebar_plugins.erl13
-rw-r--r--src/rebar_prv_shell.erl16
-rw-r--r--src/rebar_prv_update.erl122
-rw-r--r--src/rebar_state.erl24
6 files changed, 189 insertions, 36 deletions
diff --git a/src/rebar3.erl b/src/rebar3.erl
index 879378e..10eccfd 100644
--- a/src/rebar3.erl
+++ b/src/rebar3.erl
@@ -126,14 +126,16 @@ run_aux(State, RawArgs) ->
{ok, Providers} = application:get_env(rebar, providers),
%% Providers can modify profiles stored in opts, so set default after initializing providers
State5 = rebar_state:create_logic_providers(Providers, State4),
- State6 = rebar_plugins:top_level_install(State5),
- State7 = rebar_state:default(State6, rebar_state:opts(State6)),
+ %% Initializing project_plugins which can override default providers
+ State6 = rebar_plugins:project_plugins_install(State5),
+ State7 = rebar_plugins:top_level_install(State6),
+ State8 = rebar_state:default(State7, rebar_state:opts(State7)),
{Task, Args} = parse_args(RawArgs),
- State8 = rebar_state:code_paths(State7, default, code:get_path()),
+ State9 = rebar_state:code_paths(State8, default, code:get_path()),
- rebar_core:init_command(rebar_state:command_args(State8, Args), Task).
+ rebar_core:init_command(rebar_state:command_args(State9, Args), Task).
init_config() ->
%% Initialize logging system
diff --git a/src/rebar_packages.erl b/src/rebar_packages.erl
index c56009e..b5e0923 100644
--- a/src/rebar_packages.erl
+++ b/src/rebar_packages.erl
@@ -7,7 +7,9 @@
,registry_dir/1
,package_dir/1
,registry_checksum/2
+ ,find_highest_matching/6
,find_highest_matching/4
+ ,find_all/3
,verify_table/1
,format_error/1]).
@@ -139,16 +141,26 @@ registry_checksum({pkg, Name, Vsn}, State) ->
%% `~> 2.0` | `>= 2.0.0 and < 3.0.0`
%% `~> 2.1` | `>= 2.1.0 and < 3.0.0`
find_highest_matching(Dep, Constraint, Table, State) ->
+ find_highest_matching(undefined, undefined, Dep, Constraint, Table, State).
+
+find_highest_matching(Pkg, PkgVsn, Dep, Constraint, Table, State) ->
+ try find_all(Dep, Table, State) of
+ {ok, [Vsn]} ->
+ handle_single_vsn(Pkg, PkgVsn, Dep, Vsn, Constraint);
+ {ok, [HeadVsn | VsnTail]} ->
+ {ok, handle_vsns(Constraint, HeadVsn, VsnTail)}
+ catch
+ error:badarg ->
+ none
+ end.
+
+find_all(Dep, Table, State) ->
?MODULE:verify_table(State),
try ets:lookup_element(Table, Dep, 2) of
- [[HeadVsn | VsnTail]] ->
- {ok, handle_vsns(Constraint, HeadVsn, VsnTail)};
- [[Vsn]] ->
- handle_single_vsn(Dep, Vsn, Constraint);
- [Vsn] ->
- handle_single_vsn(Dep, Vsn, Constraint);
- [HeadVsn | VsnTail] ->
- {ok, handle_vsns(Constraint, HeadVsn, VsnTail)}
+ [Vsns] when is_list(Vsns)->
+ {ok, Vsns};
+ Vsns ->
+ {ok, Vsns}
catch
error:badarg ->
none
@@ -165,13 +177,19 @@ handle_vsns(Constraint, HeadVsn, VsnTail) ->
end
end, HeadVsn, VsnTail).
-handle_single_vsn(Dep, Vsn, Constraint) ->
+handle_single_vsn(Pkg, PkgVsn, Dep, Vsn, Constraint) ->
case ec_semver:pes(Vsn, Constraint) of
true ->
{ok, Vsn};
false ->
- ?WARN("Only existing version of ~s is ~s which does not match constraint ~~> ~s. "
- "Using anyway, but it is not guaranteed to work.", [Dep, Vsn, Constraint]),
+ case {Pkg, PkgVsn} of
+ {undefined, undefined} ->
+ ?WARN("Only existing version of ~s is ~s which does not match constraint ~~> ~s. "
+ "Using anyway, but it is not guaranteed to work.", [Dep, Vsn, Constraint]);
+ _ ->
+ ?WARN("[~s:~s] Only existing version of ~s is ~s which does not match constraint ~~> ~s. "
+ "Using anyway, but it is not guaranteed to work.", [Pkg, PkgVsn, Dep, Vsn, Constraint])
+ end,
{ok, Vsn}
end.
diff --git a/src/rebar_plugins.erl b/src/rebar_plugins.erl
index 3c33498..68ba6da 100644
--- a/src/rebar_plugins.erl
+++ b/src/rebar_plugins.erl
@@ -3,7 +3,8 @@
-module(rebar_plugins).
--export([top_level_install/1
+-export([project_plugins_install/1
+ ,top_level_install/1
,project_apps_install/1
,install/2
,handle_plugins/3
@@ -15,6 +16,16 @@
%% Public API
%% ===================================================================
+-spec project_plugins_install(rebar_state:t()) -> rebar_state:t().
+project_plugins_install(State) ->
+ Profiles = rebar_state:current_profiles(State),
+ State1 = rebar_state:allow_provider_overrides(State, true),
+ State2 = lists:foldl(fun(Profile, StateAcc) ->
+ Plugins = rebar_state:get(State, {project_plugins, Profile}, []),
+ handle_plugins(Profile, Plugins, StateAcc)
+ end, State1, Profiles),
+ rebar_state:allow_provider_overrides(State2, false).
+
-spec top_level_install(rebar_state:t()) -> rebar_state:t().
top_level_install(State) ->
Profiles = rebar_state:current_profiles(State),
diff --git a/src/rebar_prv_shell.erl b/src/rebar_prv_shell.erl
index ea759fc..430d1e8 100644
--- a/src/rebar_prv_shell.erl
+++ b/src/rebar_prv_shell.erl
@@ -64,6 +64,8 @@ init(State) ->
"Gives a long name to the node."},
{sname, undefined, "sname", atom,
"Gives a short name to the node."},
+ {setcookie, undefined, "setcookie", atom,
+ "Sets the cookie if the node is distributed."},
{script_file, undefined, "script", string,
"Path to an escript file to run before "
"starting the project apps. Defaults to "
@@ -258,9 +260,11 @@ setup_name(State) ->
{undefined, undefined} ->
ok;
{Name, undefined} ->
- check_epmd(net_kernel:start([Name, longnames]));
+ check_epmd(net_kernel:start([Name, longnames])),
+ setup_cookie(Opts);
{undefined, SName} ->
- check_epmd(net_kernel:start([SName, shortnames]));
+ check_epmd(net_kernel:start([SName, shortnames])),
+ setup_cookie(Opts);
{_, _} ->
?ABORT("Cannot have both short and long node names defined", [])
end.
@@ -271,6 +275,14 @@ check_epmd({error,{{shutdown, {_,net_kernel,{'EXIT',nodistribution}}},_}}) ->
check_epmd(_) ->
ok.
+setup_cookie(Opts) ->
+ case {node(), proplists:get_value(setcookie, Opts, nocookie)} of
+ {'nonode@nohost', _} -> nocookie;
+ {_, nocookie} -> nocookie;
+ {Node, Name} -> erlang:set_cookie(Node, Name)
+ end.
+
+
find_apps_to_boot(State) ->
%% Try the shell_apps option
case first_value([fun find_apps_option/1,
diff --git a/src/rebar_prv_update.erl b/src/rebar_prv_update.erl
index 0e3b9a0..5e1e253 100644
--- a/src/rebar_prv_update.erl
+++ b/src/rebar_prv_update.erl
@@ -11,6 +11,10 @@
-export([hex_to_index/1]).
+-ifdef(TEST).
+-export([cmp_/6, cmpl_/6, valid_vsn/1]).
+-endif.
+
-include("rebar.hrl").
-include_lib("providers/include/providers.hrl").
@@ -99,7 +103,7 @@ hex_to_index(State) ->
ets:foldl(fun({{Pkg, PkgVsn}, [Deps, Checksum, BuildTools | _]}, _) when is_list(BuildTools) ->
case lists:any(fun is_supported/1, BuildTools) of
true ->
- DepsList = update_deps_list(Deps, Registry, State),
+ DepsList = update_deps_list(Pkg, PkgVsn, Deps, Registry, State),
ets:insert(?PACKAGE_TABLE, {{Pkg, PkgVsn}, DepsList, Checksum});
false ->
true
@@ -137,20 +141,114 @@ hex_to_index(State) ->
fail
end.
-update_deps_list(Deps, HexRegistry, State) ->
+update_deps_list(Pkg, PkgVsn, Deps, HexRegistry, State) ->
lists:foldl(fun([Dep, DepVsn, false, _AppName | _], DepsListAcc) ->
- case DepVsn of
- <<"~> ", Vsn/binary>> ->
- case rebar_packages:find_highest_matching(Dep, Vsn, HexRegistry, State) of
- {ok, HighestDepVsn} ->
- [{Dep, HighestDepVsn} | DepsListAcc];
- none ->
- ?WARN("Missing registry entry for package ~s. Try to fix with `rebar3 update`", [Dep]),
- DepsListAcc
- end;
- Vsn ->
+ Dep1 = {Pkg, PkgVsn, Dep},
+ case {valid_vsn(DepVsn), DepVsn} of
+ %% Those are all not perfectly implemented!
+ %% and doubled since spaces seem not to be
+ %% enforced
+ {false, Vsn} ->
+ ?WARN("[~s:~s], Bad dependency version for ~s: ~s.",
+ [Pkg, PkgVsn, Dep, Vsn]),
+ DepsListAcc;
+ {_, <<"~>", Vsn/binary>>} ->
+ highest_matching(Dep1, rm_ws(Vsn), HexRegistry,
+ State, DepsListAcc);
+ {_, <<">=", Vsn/binary>>} ->
+ cmp(Dep1, rm_ws(Vsn), HexRegistry, State,
+ DepsListAcc, fun ec_semver:gte/2);
+ {_, <<">", Vsn/binary>>} ->
+ cmp(Dep1, rm_ws(Vsn), HexRegistry, State,
+ DepsListAcc, fun ec_semver:gt/2);
+ {_, <<"<=", Vsn/binary>>} ->
+ cmpl(Dep1, rm_ws(Vsn), HexRegistry, State,
+ DepsListAcc, fun ec_semver:lte/2);
+ {_, <<"<", Vsn/binary>>} ->
+ cmpl(Dep1, rm_ws(Vsn), HexRegistry, State,
+ DepsListAcc, fun ec_semver:lt/2);
+ {_, <<"==", Vsn/binary>>} ->
+ [{Dep, Vsn} | DepsListAcc];
+ {_, Vsn} ->
[{Dep, Vsn} | DepsListAcc]
end;
([_Dep, _DepVsn, true, _AppName | _], DepsListAcc) ->
DepsListAcc
end, [], Deps).
+
+rm_ws(<<" ", R/binary>>) ->
+ rm_ws(R);
+rm_ws(R) ->
+ R.
+
+valid_vsn(Vsn) ->
+ %% Regepx from https://github.com/sindresorhus/semver-regex/blob/master/index.js
+ SemVerRegExp = "v?(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(\\.(0|[1-9][0-9]*))?"
+ "(-[0-9a-z-]+(\\.[0-9a-z-]+)*)?(\\+[0-9a-z-]+(\\.[0-9a-z-]+)*)?",
+ SupportedVersions = "^(>=?|<=?|~>|==)?\\s*" ++ SemVerRegExp ++ "$",
+ re:run(Vsn, SupportedVersions) =/= nomatch.
+
+highest_matching({Pkg, PkgVsn, Dep}, Vsn, HexRegistry, State, DepsListAcc) ->
+ case rebar_packages:find_highest_matching(Pkg, PkgVsn, Dep, Vsn, HexRegistry, State) of
+ {ok, HighestDepVsn} ->
+ [{Dep, HighestDepVsn} | DepsListAcc];
+ none ->
+ ?WARN("[~s:~s] Missing registry entry for package ~s. Try to fix with `rebar3 update`",
+ [Pkg, PkgVsn, Dep]),
+ DepsListAcc
+ end.
+
+cmp({_Pkg, _PkgVsn, Dep} = Dep1, Vsn, HexRegistry, State, DepsListAcc, CmpFun) ->
+ {ok, Vsns} = rebar_packages:find_all(Dep, HexRegistry, State),
+ cmp_(undefined, Vsn, Vsns, DepsListAcc, Dep1, CmpFun).
+
+
+cmp_(undefined, _MinVsn, [], DepsListAcc, {Pkg, PkgVsn, Dep}, _CmpFun) ->
+ ?WARN("[~s:~s] Missing registry entry for package ~s. Try to fix with `rebar3 update`",
+ [Pkg, PkgVsn, Dep]),
+ DepsListAcc;
+cmp_(HighestDepVsn, _MinVsn, [], DepsListAcc, {_Pkg, _PkgVsn, Dep}, _CmpFun) ->
+ [{Dep, HighestDepVsn} | DepsListAcc];
+
+cmp_(BestMatch, MinVsn, [Vsn | R], DepsListAcc, Dep, CmpFun) ->
+ case CmpFun(Vsn, MinVsn) of
+ true ->
+ cmp_(Vsn, Vsn, R, DepsListAcc, Dep, CmpFun);
+ false ->
+ cmp_(BestMatch, MinVsn, R, DepsListAcc, Dep, CmpFun)
+ end.
+
+%% We need to treat this differently since we want a version that is LOWER but
+%% the higest possible one.
+cmpl({_Pkg, _PkgVsn, Dep} = Dep1, Vsn, HexRegistry, State, DepsListAcc, CmpFun) ->
+ {ok, Vsns} = rebar_packages:find_all(Dep, HexRegistry, State),
+ cmpl_(undefined, Vsn, Vsns, DepsListAcc, Dep1, CmpFun).
+
+cmpl_(undefined, _MaxVsn, [], DepsListAcc, {Pkg, PkgVsn, Dep}, _CmpFun) ->
+ ?WARN("[~s:~s] Missing registry entry for package ~s. Try to fix with `rebar3 update`",
+ [Pkg, PkgVsn, Dep]),
+ DepsListAcc;
+
+cmpl_(HighestDepVsn, _MaxVsn, [], DepsListAcc, {_Pkg, _PkgVsn, Dep}, _CmpFun) ->
+ [{Dep, HighestDepVsn} | DepsListAcc];
+
+cmpl_(undefined, MaxVsn, [Vsn | R], DepsListAcc, Dep, CmpFun) ->
+ case CmpFun(Vsn, MaxVsn) of
+ true ->
+ cmpl_(Vsn, MaxVsn, R, DepsListAcc, Dep, CmpFun);
+ false ->
+ cmpl_(undefined, MaxVsn, R, DepsListAcc, Dep, CmpFun)
+ end;
+
+cmpl_(BestMatch, MaxVsn, [Vsn | R], DepsListAcc, Dep, CmpFun) ->
+ case CmpFun(Vsn, MaxVsn) of
+ true ->
+ case ec_semver:gte(Vsn, BestMatch) of
+ true ->
+ cmpl_(Vsn, MaxVsn, R, DepsListAcc, Dep, CmpFun);
+ false ->
+ cmpl_(BestMatch, MaxVsn, R, DepsListAcc, Dep, CmpFun)
+ end;
+ false ->
+ cmpl_(BestMatch, MaxVsn, R, DepsListAcc, Dep, CmpFun)
+ end.
diff --git a/src/rebar_state.erl b/src/rebar_state.erl
index 5ec2aef..30eff2f 100644
--- a/src/rebar_state.erl
+++ b/src/rebar_state.erl
@@ -36,9 +36,10 @@
deps_names/1,
-
resources/1, resources/2, add_resource/2,
- providers/1, providers/2, add_provider/2]).
+ providers/1, providers/2, add_provider/2,
+ allow_provider_overrides/1, allow_provider_overrides/2
+ ]).
-include("rebar.hrl").
-include_lib("providers/include/providers.hrl").
@@ -63,7 +64,8 @@
all_deps = [] :: [rebar_app_info:t()],
resources = [],
- providers = []}).
+ providers = [],
+ allow_provider_overrides = false :: boolean()}).
-export_type([t/0]).
@@ -103,7 +105,8 @@ new(ParentState, Config, Dir) ->
new(ParentState, Config, Deps, Dir) ->
Opts = ParentState#state_t.opts,
Plugins = proplists:get_value(plugins, Config, []),
- Terms = Deps++[{{plugins, default}, Plugins} | Config],
+ ProjectPlugins = proplists:get_value(project_plugins, Config, []),
+ Terms = Deps++[{{project_plugins, default}, ProjectPlugins}, {{plugins, default}, Plugins} | Config],
true = rebar_config:verify_config_format(Terms),
LocalOpts = dict:from_list(Terms),
@@ -136,7 +139,8 @@ base_state() ->
base_opts(Config) ->
Deps = proplists:get_value(deps, Config, []),
Plugins = proplists:get_value(plugins, Config, []),
- Terms = [{{deps, default}, Deps}, {{plugins, default}, Plugins} | Config],
+ ProjectPlugins = proplists:get_value(project_plugins, Config, []),
+ Terms = [{{deps, default}, Deps}, {{plugins, default}, Plugins}, {{project_plugins, default}, ProjectPlugins} | Config],
true = rebar_config:verify_config_format(Terms),
dict:from_list(Terms).
@@ -368,8 +372,16 @@ providers(#state_t{providers=Providers}) ->
providers(State, NewProviders) ->
State#state_t{providers=NewProviders}.
+allow_provider_overrides(#state_t{allow_provider_overrides=Allow}) ->
+ Allow.
+
+allow_provider_overrides(State, Allow) ->
+ State#state_t{allow_provider_overrides=Allow}.
+
-spec add_provider(t(), providers:t()) -> t().
-add_provider(State=#state_t{providers=Providers}, Provider) ->
+add_provider(State=#state_t{providers=Providers, allow_provider_overrides=true}, Provider) ->
+ State#state_t{providers=[Provider | Providers]};
+add_provider(State=#state_t{providers=Providers, allow_provider_overrides=false}, Provider) ->
Name = providers:impl(Provider),
Namespace = providers:namespace(Provider),
Module = providers:module(Provider),