diff options
-rw-r--r-- | src/rebar_digraph.erl | 77 | ||||
-rw-r--r-- | src/rebar_erlc_compiler.erl | 71 | ||||
-rw-r--r-- | src/rebar_packages.erl | 21 | ||||
-rw-r--r-- | src/rebar_prv_install_deps.erl | 16 | ||||
-rw-r--r-- | src/rebar_resource.erl | 8 | ||||
-rw-r--r-- | src/rebar_state.erl | 4 |
6 files changed, 113 insertions, 84 deletions
diff --git a/src/rebar_digraph.erl b/src/rebar_digraph.erl index decc542..1198530 100644 --- a/src/rebar_digraph.erl +++ b/src/rebar_digraph.erl @@ -1,86 +1,28 @@ -module(rebar_digraph). --export([check_graph/2 - ,restore_graph/1 - ,store_graph/3 +-export([restore_graph/1 ,solve/2 - ,subgraph/2]). + ,subgraph/2 + ,format_error/1]). -include("rebar.hrl"). -check_graph(_File, #graph{vsn=?GRAPH_VSN}) -> - ok; -check_graph(File, #graph{vsn=Vsn}) -> - ?ABORT("~s file version is incompatible. expected: ~b got: ~b", - [File, ?GRAPH_VSN, Vsn]); -check_graph(File, _) -> - ?ABORT("~s file is invalid. Please delete before next run.", - [File]). - restore_graph({Vs, Es}) -> - G = digraph:new(), + Graph = digraph:new(), lists:foreach(fun({V, LastUpdated}) -> - digraph:add_vertex(G, V, LastUpdated) + digraph:add_vertex(Graph, V, LastUpdated) end, Vs), lists:foreach(fun({V1, V2}) -> - digraph:add_edge(G, V1, V2) + digraph:add_edge(Graph, V1, V2) end, Es), - G; -restore_graph(File) -> - G = digraph:new(), - case file:read_file(File) of - {ok, Data} -> - try binary_to_term(Data) of - G -> - %% ok = check_erlcinfo(Config, Graph), - #graph{info=Graph} = G, - {Vs, Es} = Graph, - lists:foreach( - fun({V, LastUpdated}) -> - digraph:add_vertex(G, V, LastUpdated) - end, Vs), - lists:foreach( - fun({V1, V2}) -> - digraph:add_edge(G, V1, V2) - end, Es) - catch - error:badarg -> - ?ERROR( - "Failed (binary_to_term) to restore rebar info file." - " Discard file.", []), - ok - end; - _Err -> - ok - end, - G. - -store_graph(_G, _File, _Modified = false) -> - ok; -store_graph(G, File, _Modified) -> - Vs = lists:map( - fun(V) -> - digraph:vertex(G, V) - end, digraph:vertices(G)), - Es = lists:flatmap( - fun({V, _}) -> - lists:map( - fun(E) -> - {_, V1, V2, _} = digraph:edge(G, E), - {V1, V2} - end, digraph:out_edges(G, V)) - end, Vs), - - ok = filelib:ensure_dir(File), - Data = term_to_binary(#graph{info={Vs, Es}}, [{compressed, 9}]), - file:write_file(File, Data). + Graph. solve(Graph, Vertices) -> solve(Graph, Vertices, dict:new()). solve(_Graph, [], Solution) -> {_, Vertices} = lists:unzip(dict:to_list(Solution)), - Vertices; + {ok, Vertices}; solve(Graph, Vertices, Solution) -> {NV, NS} = lists:foldl(fun(V, {NewVertices, SolutionAcc}) -> @@ -99,3 +41,6 @@ solve(Graph, Vertices, Solution) -> subgraph(Graph, Vertices) -> digraph_utils:subgraph(Graph, Vertices). + +format_error(no_solution) -> + io_lib:format("No solution for packages found.", []). diff --git a/src/rebar_erlc_compiler.erl b/src/rebar_erlc_compiler.erl index 5e7787c..71ee780 100644 --- a/src/rebar_erlc_compiler.erl +++ b/src/rebar_erlc_compiler.erl @@ -38,6 +38,14 @@ -define(ERLCINFO_VSN, 1). -define(ERLCINFO_FILE, "erlcinfo"). +-type erlc_info_v() :: {digraph:vertex(), term()} | 'false'. +-type erlc_info_e() :: {digraph:vertex(), digraph:vertex()}. +-type erlc_info() :: {list(erlc_info_v()), list(erlc_info_e())}. +-record(erlcinfo, + { + vsn = ?ERLCINFO_VSN :: pos_integer(), + info = {[], []} :: erlc_info() + }). -define(RE_PREFIX, "^[^._]"). @@ -392,11 +400,20 @@ needs_compile(Source, Target, Parents) -> lists:any(fun(I) -> TargetLastMod < filelib:last_modified(I) end, [Source] ++ Parents). +check_erlcinfo(_Config, #erlcinfo{vsn=?ERLCINFO_VSN}) -> + ok; +check_erlcinfo(Config, #erlcinfo{vsn=Vsn}) -> + ?ABORT("~s file version is incompatible. expected: ~b got: ~b", + [erlcinfo_file(Config), ?ERLCINFO_VSN, Vsn]); +check_erlcinfo(Config, _) -> + ?ABORT("~s file is invalid. Please delete before next run.", + [erlcinfo_file(Config)]). + erlcinfo_file(_Config) -> filename:join([rebar_utils:get_cwd(), ?CONFIG_DIR, ?ERLCINFO_FILE]). init_erlcinfo(Config, Erls) -> - G = rebar_digraph:restore_graph(erlcinfo_file(Config)), + G = restore_erlcinfo(Config), %% Get a unique list of dirs based on the source files' locations. %% This is used for finding files in sub dirs of the configured %% src_dirs. For example, src/sub_dir/foo.erl. @@ -408,7 +425,7 @@ init_erlcinfo(Config, Erls) -> Updates = [update_erlcinfo(G, Erl, include_path(Erl, Config) ++ Dirs) || Erl <- Erls], Modified = lists:member(modified, Updates), - ok = rebar_digraph:store_graph(G, erlcinfo_file(Config), Modified), + ok = store_erlcinfo(G, Config, Modified), G. update_erlcinfo(G, Source, Dirs) -> @@ -445,6 +462,56 @@ modify_erlcinfo(G, Source, Dirs) -> digraph:add_edge(G, Source, Incl) end, AbsIncls). +restore_erlcinfo(Config) -> + File = erlcinfo_file(Config), + G = digraph:new(), + case file:read_file(File) of + {ok, Data} -> + try binary_to_term(Data) of + Erlcinfo -> + ok = check_erlcinfo(Config, Erlcinfo), + #erlcinfo{info=ErlcInfo} = Erlcinfo, + {Vs, Es} = ErlcInfo, + lists:foreach( + fun({V, LastUpdated}) -> + digraph:add_vertex(G, V, LastUpdated) + end, Vs), + lists:foreach( + fun({V1, V2}) -> + digraph:add_edge(G, V1, V2) + end, Es) + catch + error:badarg -> + ?ERROR( + "Failed (binary_to_term) to restore rebar info file." + " Discard file.", []), + ok + end; + _Err -> + ok + end, + G. + +store_erlcinfo(_G, _Config, _Modified = false) -> + ok; +store_erlcinfo(G, Config, _Modified) -> + Vs = lists:map( + fun(V) -> + digraph:vertex(G, V) + end, digraph:vertices(G)), + Es = lists:flatmap( + fun({V, _}) -> + lists:map( + fun(E) -> + {_, V1, V2, _} = digraph:edge(G, E), + {V1, V2} + end, digraph:out_edges(G, V)) + end, Vs), + File = erlcinfo_file(Config), + ok = filelib:ensure_dir(File), + Data = term_to_binary(#erlcinfo{info={Vs, Es}}, [{compressed, 9}]), + file:write_file(File, Data). + %% NOTE: If, for example, one of the entries in Files, refers to %% gen_server.erl, that entry will be dropped. It is dropped because %% such an entry usually refers to the beam file, and we don't pass a diff --git a/src/rebar_packages.erl b/src/rebar_packages.erl index 7334365..7308611 100644 --- a/src/rebar_packages.erl +++ b/src/rebar_packages.erl @@ -2,9 +2,26 @@ -export([get_packages/1]). +-export_type([constraint/0]). + -include("rebar.hrl"). --spec get_packages(rebar_state:t()) -> {rebar_dict(), rlx_depsolver:t()}. +-type pkg_name() :: string() | binary() | atom(). + +-type vsn() :: 'NO_VSN' + | ec_semver:semver(). + +-type constraint_op() :: + '=' | gte | '>=' | lte | '<=' + | gt | '>' | lt | '<' | pes | '~>' | between. + +-type constraint() :: pkg_name() + | {pkg_name(), vsn()} + | {pkg_name(), vsn(), constraint_op()} + | {pkg_name(), vsn(), vsn(), between}. + + +-spec get_packages(rebar_state:t()) -> {rebar_dict(), rebar_digraph()}. get_packages(State) -> Home = rebar_utils:home_dir(), RebarDir = rebar_state:get(State, global_rebar_dir, filename:join(Home, ?CONFIG_DIR)), @@ -17,7 +34,7 @@ get_packages(State) -> {Dict, rebar_digraph:restore_graph(Graph)} catch _:_ -> - ?ERROR("Bad packages index, try to fix with `rebar update`~n", []), + ?ERROR("Bad packages index, try to fix with `rebar update`", []), {dict:new(), digraph:new()} end; false -> diff --git a/src/rebar_prv_install_deps.erl b/src/rebar_prv_install_deps.erl index 7e41429..81bc71f 100644 --- a/src/rebar_prv_install_deps.erl +++ b/src/rebar_prv_install_deps.erl @@ -131,10 +131,12 @@ handle_deps(State, Deps, Update) -> PkgDeps1 -> %% Find pkg deps needed S = case rebar_digraph:solve(Graph, PkgDeps1) of + {ok, []} -> + throw({rebar_digraph, no_solution}); {ok, Solution} -> Solution; - Reason -> - throw({error, {rlx_depsolver, Reason}}) + [] -> + throw({rebar_digraph, no_solution}) end, %% Create app_info record for each pkg dep @@ -156,19 +158,17 @@ handle_deps(State, Deps, Update) -> %% Internal functions %% =================================================================== -package_to_app(DepsDir, Packages, Pkg={_, Vsn}) -> - Name = ec_cnv:to_binary(rlx_depsolver:dep_pkg(Pkg)), - FmtVsn = iolist_to_binary(rlx_depsolver:format_version(Vsn)), - case dict:find({Name, FmtVsn}, Packages) of +package_to_app(DepsDir, Packages, {Name, Vsn}) -> + case dict:find({Name, Vsn}, Packages) of error -> []; {ok, P} -> PkgDeps = proplists:get_value(<<"deps">>, P, []), Link = proplists:get_value(<<"link">>, P, ""), - {ok, AppInfo} = rebar_app_info:new(Name, FmtVsn), + {ok, AppInfo} = rebar_app_info:new(Name, Vsn), AppInfo1 = rebar_app_info:deps(AppInfo, PkgDeps), AppInfo2 = rebar_app_info:dir(AppInfo1, get_deps_dir(DepsDir, Name)), - [rebar_app_info:source(AppInfo2, {pkg, Name, FmtVsn, Link})] + [rebar_app_info:source(AppInfo2, {pkg, Name, Vsn, Link})] end. -spec update_src_deps(integer(), rebar_state:t(), boolean(), sets:set(binary())) -> diff --git a/src/rebar_resource.erl b/src/rebar_resource.erl index 5babff7..ee7d2d3 100644 --- a/src/rebar_resource.erl +++ b/src/rebar_resource.erl @@ -4,10 +4,10 @@ -export([]). --export_types([resource/0 - ,type/0 - ,location/0 - ,ref/0]). +-export_type([resource/0 + ,type/0 + ,location/0 + ,ref/0]). -type resource() :: {type(), location(), ref()}. -type type() :: atom(). diff --git a/src/rebar_state.erl b/src/rebar_state.erl index f39251d..7ed29fa 100644 --- a/src/rebar_state.erl +++ b/src/rebar_state.erl @@ -28,7 +28,7 @@ src_deps = [], src_apps = [], - pkg_deps = [] :: [rlx_depsolver:constraint()], + pkg_deps = [] :: [rebar_packages:constraint()], project_apps = [], providers = []}). @@ -103,7 +103,7 @@ deps_names(State) -> ec_cnv:to_binary(Dep) end, Deps). --spec pkg_deps(t()) -> [rlx_depsolver:constraint()]. +-spec pkg_deps(t()) -> [rebar_packages:constraint()]. pkg_deps(#state_t{pkg_deps=PkgDeps}) -> PkgDeps. |