diff options
Diffstat (limited to 'src/rebar_prv_install_deps.erl')
-rw-r--r-- | src/rebar_prv_install_deps.erl | 180 |
1 files changed, 103 insertions, 77 deletions
diff --git a/src/rebar_prv_install_deps.erl b/src/rebar_prv_install_deps.erl index ba49532..768d41a 100644 --- a/src/rebar_prv_install_deps.erl +++ b/src/rebar_prv_install_deps.erl @@ -37,7 +37,10 @@ -export([handle_deps/3, handle_deps/4, - handle_deps/5]). + handle_deps/5, + + find_cycles/1, + cull_compile/2]). -export_type([dep/0]). @@ -58,7 +61,7 @@ init(State) -> State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER}, {module, ?MODULE}, - {bare, true}, + {bare, false}, {deps, ?DEPS}, {example, undefined}, {short_desc, ""}, @@ -76,6 +79,10 @@ do(State) -> {Apps, State1} = lists:foldl(fun deps_per_profile/2, {[], State}, lists:reverse(Profiles)), + State2 = rebar_state:update_all_deps(State1, Apps), + CodePaths = [rebar_app_info:ebin_dir(A) || A <- Apps], + State3 = rebar_state:update_code_paths(State2, all_deps, CodePaths), + Source = ProjectApps ++ Apps, case find_cycles(Source) of {cycles, Cycles} -> @@ -84,7 +91,7 @@ do(State) -> {error, Error}; {no_cycle, Sorted} -> ToCompile = cull_compile(Sorted, ProjectApps), - {ok, rebar_state:deps_to_build(State1, ToCompile)} + {ok, rebar_state:deps_to_build(State3, ToCompile)} end catch %% maybe_fetch will maybe_throw an exception to break out of some loops @@ -158,11 +165,7 @@ handle_deps(Profile, State0, Deps, Upgrade, Locks) -> ,lists:ukeysort(2, SrcApps) ,lists:ukeysort(2, Solved)), - State5 = rebar_state:update_all_deps(State4, AllDeps), - CodePaths = [rebar_app_info:ebin_dir(A) || A <- AllDeps], - State6 = rebar_state:update_code_paths(State5, all_deps, CodePaths), - - {ok, AllDeps, State6}. + {ok, AllDeps, State4}. %% =================================================================== %% Internal functions @@ -202,31 +205,40 @@ update_pkg_deps(Profile, Packages, PkgDeps, Graph, Upgrade, Seen, State, Locks) update_pkg_deps(Profile, S, Packages, Upgrade, Seen, State, Locks) end. +pkg_locked({Name, _, _}, Locks) -> + pkg_locked(Name, Locks); pkg_locked({Name, _}, Locks) -> + pkg_locked(Name, Locks); +pkg_locked(Name, Locks) -> false =/= lists:keyfind(Name, 1, Locks). -update_pkg_deps(Profile, Pkgs, Packages, Upgrade, Seen, State, _Locks) -> +update_pkg_deps(Profile, Pkgs, Packages, Upgrade, Seen, State, Locks) -> %% Create app_info record for each pkg dep DepsDir = profile_dep_dir(State, Profile), {Solved, _, State1} = lists:foldl(fun(Pkg, {Acc, SeenAcc, StateAcc}) -> - handle_pkg_dep(Profile, Pkg, Packages, Upgrade, DepsDir, Acc, SeenAcc, StateAcc) + handle_pkg_dep(Profile, Pkg, Packages, Upgrade, DepsDir, Acc, SeenAcc, Locks, StateAcc) end, {[], Seen, State}, Pkgs), {Solved, State1}. -handle_pkg_dep(Profile, Pkg, Packages, Upgrade, DepsDir, Fetched, Seen, State) -> - AppInfo = package_to_app(DepsDir, Packages, Pkg, State), +handle_pkg_dep(Profile, Pkg, Packages, Upgrade, DepsDir, Fetched, Seen, Locks, State) -> + IsLock = pkg_locked(Pkg, Locks), + AppInfo = package_to_app(DepsDir, Packages, Pkg, IsLock, State), + Deps = rebar_app_info:deps(AppInfo), Level = rebar_app_info:dep_level(AppInfo), {NewSeen, NewState} = maybe_lock(Profile, AppInfo, Seen, State, Level), {_, AppInfo1} = maybe_fetch(AppInfo, Profile, Upgrade, Seen, NewState), - {[AppInfo1 | Fetched], NewSeen, NewState}. + {AppInfo2, _, _, _, _} = + handle_dep(NewState, Profile, DepsDir, AppInfo1, Locks, Level), + AppInfo3 = rebar_app_info:deps(AppInfo2, Deps), + {[AppInfo3 | Fetched], NewSeen, NewState}. maybe_lock(Profile, AppInfo, Seen, State, Level) -> + Name = rebar_app_info:name(AppInfo), case rebar_app_info:is_checkout(AppInfo) of false -> case Profile of default -> - Name = rebar_app_info:name(AppInfo), case sets:is_element(Name, Seen) of false -> Locks = rebar_state:lock(State), @@ -241,13 +253,13 @@ maybe_lock(Profile, AppInfo, Seen, State, Level) -> {Seen, State} end; _ -> - {Seen, State} + {sets:add_element(Name, Seen), State} end; true -> - {Seen, State} + {sets:add_element(Name, Seen), State} end. -package_to_app(DepsDir, Packages, {Name, Vsn, Level}, State) -> +package_to_app(DepsDir, Packages, {Name, Vsn, Level}, IsLock, State) -> case dict:find({Name, Vsn}, Packages) of error -> case rebar_packages:check_registry(Name, Vsn, State) of @@ -256,14 +268,13 @@ package_to_app(DepsDir, Packages, {Name, Vsn, Level}, State) -> false -> throw(?PRV_ERROR({missing_package, Name, Vsn})) end; - {ok, P} -> - PkgDeps = [{PkgName, PkgVsn} - || {PkgName,PkgVsn} <- proplists:get_value(<<"deps">>, P, [])], - {ok, AppInfo} = rebar_app_info:new(Name, Vsn), - AppInfo1 = rebar_app_info:deps(AppInfo, PkgDeps), - AppInfo2 = rebar_app_info:dir(AppInfo1, filename:join([DepsDir, Name])), - AppInfo3 = rebar_app_info:dep_level(AppInfo2, Level), - rebar_app_info:source(AppInfo3, {pkg, Name, Vsn}) + {ok, PkgDeps} -> + Source = {pkg, Name, Vsn}, + AppInfo = new_dep(DepsDir, Name, Vsn, Source, IsLock, State), + AppInfo1 = rebar_app_info:dep_level(rebar_app_info:deps(AppInfo, PkgDeps), Level), + BaseDir = rebar_state:get(State, base_dir, []), + AppState1 = rebar_state:set(rebar_app_info:state(AppInfo1), base_dir, BaseDir), + rebar_app_info:state(AppInfo1, AppState1) end. -spec update_src_deps(atom(), non_neg_integer(), list(), list(), list(), rebar_state:t(), boolean(), sets:set(binary()), list()) -> {rebar_state:t(), list(), list(), sets:set(binary())}. @@ -345,7 +356,6 @@ handle_upgrade(AppInfo, Profile, SrcDeps, PkgDeps, SrcApps, Level, State, Locks) {true, AppInfo1} -> handle_dep(AppInfo1, Profile, SrcDeps, PkgDeps, SrcApps, Level, State, Locks); - {false, AppInfo1} -> {[AppInfo1|SrcDeps], PkgDeps, SrcApps, State, Locks} end; @@ -356,7 +366,7 @@ handle_upgrade(AppInfo, Profile, SrcDeps, PkgDeps, SrcApps, Level, State, Locks) handle_dep(AppInfo, Profile, SrcDeps, PkgDeps, SrcApps, Level, State, Locks) -> DepsDir = profile_dep_dir(State, Profile), {AppInfo1, NewSrcDeps, NewPkgDeps, NewLocks, State1} = - handle_dep(State, DepsDir, AppInfo, Locks, Level), + handle_dep(State, Profile, DepsDir, AppInfo, Locks, Level), AppInfo2 = rebar_app_info:dep_level(AppInfo1, Level), {NewSrcDeps ++ SrcDeps ,NewPkgDeps++PkgDeps @@ -364,9 +374,9 @@ handle_dep(AppInfo, Profile, SrcDeps, PkgDeps, SrcApps, Level, State, Locks) -> ,State1 ,NewLocks}. --spec handle_dep(rebar_state:t(), file:filename_all(), rebar_app_info:t(), list(), integer()) -> +-spec handle_dep(rebar_state:t(), atom(), file:filename_all(), rebar_app_info:t(), list(), integer()) -> {rebar_app_info:t(), [rebar_app_info:t()], [pkg_dep()], [integer()]}. -handle_dep(State, DepsDir, AppInfo, Locks, Level) -> +handle_dep(State, Profile, DepsDir, AppInfo, Locks, Level) -> Profiles = rebar_state:current_profiles(State), Name = rebar_app_info:name(AppInfo), @@ -374,22 +384,26 @@ handle_dep(State, DepsDir, AppInfo, Locks, Level) -> S = rebar_app_info:state(AppInfo), S1 = rebar_state:new(S, C, rebar_app_info:dir(AppInfo)), - S2 = rebar_state:apply_profiles(S1, Profiles), - S3 = rebar_state:apply_overrides(S2, Name), - AppInfo1 = rebar_app_info:state(AppInfo, S3), + S2 = rebar_state:apply_overrides(S1, Name), + + S3 = rebar_state:apply_profiles(S2, Profiles), + Plugins = rebar_state:get(S3, plugins, []), + S4 = rebar_state:set(S3, {plugins, Profile}, Plugins), + AppInfo1 = rebar_app_info:state(AppInfo, S4), %% Dep may have plugins to install. Find and install here. - State1 = rebar_plugins:handle_plugins(rebar_state:get(S3, plugins, []), State), + S5 = rebar_plugins:install(S4), + AppInfo2 = rebar_app_info:state(AppInfo1, S5), - Deps = rebar_state:get(S3, deps, []), %% Upgrade lock level to be the level the dep will have in this dep tree + Deps = rebar_state:get(S5, deps, []), NewLocks = [{DepName, Source, LockLevel+Level} || - {DepName, Source, LockLevel} <- rebar_state:get(S3, {locks, default}, [])], - AppInfo2 = rebar_app_info:deps(AppInfo1, rebar_state:deps_names(Deps)), - {SrcDeps, PkgDeps} = parse_deps(DepsDir, Deps, S3, Locks, Level), - {AppInfo2, SrcDeps, PkgDeps, Locks++NewLocks, State1}. + {DepName, Source, LockLevel} <- rebar_state:get(S5, {locks, default}, [])], + AppInfo3 = rebar_app_info:deps(AppInfo2, rebar_state:deps_names(Deps)), + {SrcDeps, PkgDeps} = parse_deps(DepsDir, Deps, S5, Locks, Level+1), + {AppInfo3, SrcDeps, PkgDeps, Locks++NewLocks, State}. --spec maybe_fetch(rebar_app_info:t(), atom(), boolean() | {true, binary(), integer()}, +-spec maybe_fetch(rebar_app_info:t(), atom(), boolean(), sets:set(binary()), rebar_state:t()) -> {boolean(), rebar_app_info:t()}. maybe_fetch(AppInfo, Profile, Upgrade, Seen, State) -> AppDir = ec_cnv:to_list(rebar_app_info:dir(AppInfo)), @@ -405,7 +419,7 @@ maybe_fetch(AppInfo, Profile, Upgrade, Seen, State) -> case fetch_app(AppInfo, AppDir, State) of true -> maybe_symlink_default(State, Profile, AppDir, AppInfo), - {true, update_app_info(AppInfo)}; + {true, update_app_info(AppDir, AppInfo)}; Other -> {Other, AppInfo} end; @@ -432,7 +446,7 @@ maybe_fetch(AppInfo, Profile, Upgrade, Seen, State) -> already_in_default(AppInfo, State) -> Name = ec_cnv:to_list(rebar_app_info:name(AppInfo)), - DefaultAppDir = filename:join([rebar_state:get(State, base_dir), "default", "lib", Name]), + DefaultAppDir = filename:join([rebar_state:get(State, base_dir, []), "default", "lib", Name]), rebar_app_discover:find_app(DefaultAppDir, all). needs_symlinking(State, Profile) -> @@ -477,69 +491,69 @@ parse_deps(DepsDir, Deps, State, Locks, Level) -> end, case lists:keyfind(ec_cnv:to_binary(Name), 1, Locks) of false -> - parse_dep(Dep, Acc, DepsDir, State); + parse_dep(Dep, Acc, DepsDir, false, State); LockedDep -> LockedLevel = element(3, LockedDep), case LockedLevel > Level of true -> - parse_dep(Dep, Acc, DepsDir, State); + parse_dep(Dep, Acc, DepsDir, false, State); false -> - parse_dep(LockedDep, Acc, DepsDir, State) + parse_dep(LockedDep, Acc, DepsDir, true, State) end end end, {[], []}, Deps). -parse_dep({Name, Vsn}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, State) when is_list(Vsn) -> +parse_dep({Name, Vsn}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, IsLock, State) when is_list(Vsn) -> CheckoutsDir = ec_cnv:to_list(rebar_dir:checkouts_dir(State, Name)), case rebar_app_info:discover(CheckoutsDir) of {ok, _App} -> - Dep = new_dep(DepsDir, Name, [], [], State), + Dep = new_dep(DepsDir, Name, [], [], IsLock, State), {[Dep | SrcDepsAcc], PkgDepsAcc}; not_found -> {SrcDepsAcc, [parse_goal(ec_cnv:to_binary(Name) ,ec_cnv:to_binary(Vsn)) | PkgDepsAcc]} end; -parse_dep(Name, {SrcDepsAcc, PkgDepsAcc}, DepsDir, State) when is_atom(Name) -> +parse_dep(Name, {SrcDepsAcc, PkgDepsAcc}, DepsDir, IsLock, State) when is_atom(Name) -> {PkgName, PkgVsn} = get_package(ec_cnv:to_binary(Name), State), CheckoutsDir = ec_cnv:to_list(rebar_dir:checkouts_dir(State, Name)), case rebar_app_info:discover(CheckoutsDir) of {ok, _App} -> - Dep = new_dep(DepsDir, Name, [], [], State), + Dep = new_dep(DepsDir, Name, [], [], IsLock, State), {[Dep | SrcDepsAcc], PkgDepsAcc}; not_found -> {SrcDepsAcc, [{PkgName, PkgVsn} | PkgDepsAcc]} end; -parse_dep({Name, Source}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, State) when is_tuple(Source) -> - Dep = new_dep(DepsDir, Name, [], Source, State), +parse_dep({Name, Source}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, IsLock, State) when is_tuple(Source) -> + Dep = new_dep(DepsDir, Name, [], Source, IsLock, State), {[Dep | SrcDepsAcc], PkgDepsAcc}; -parse_dep({Name, Source}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, State) when is_tuple(Source) -> - Dep = new_dep(DepsDir, Name, [], Source, State), +parse_dep({Name, Source}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, IsLock, State) when is_tuple(Source) -> + Dep = new_dep(DepsDir, Name, [], Source, IsLock, State), {[Dep | SrcDepsAcc], PkgDepsAcc}; -parse_dep({Name, _Vsn, Source}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, State) when is_tuple(Source) -> - Dep = new_dep(DepsDir, Name, [], Source, State), +parse_dep({Name, _Vsn, Source}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, IsLock, State) when is_tuple(Source) -> + Dep = new_dep(DepsDir, Name, [], Source, IsLock, State), {[Dep | SrcDepsAcc], PkgDepsAcc}; -parse_dep({Name, _Vsn, Source, Opts}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, State) when is_tuple(Source) -> +parse_dep({Name, _Vsn, Source, Opts}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, IsLock, State) when is_tuple(Source) -> ?WARN("Dependency option list ~p in ~p is not supported and will be ignored", [Opts, Name]), - Dep = new_dep(DepsDir, Name, [], Source, State), + Dep = new_dep(DepsDir, Name, [], Source, IsLock, State), {[Dep | SrcDepsAcc], PkgDepsAcc}; -parse_dep({_Name, {pkg, Name, Vsn}, Level}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, State) when is_integer(Level) -> +parse_dep({_Name, {pkg, Name, Vsn}, Level}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, IsLock, State) when is_integer(Level) -> CheckoutsDir = ec_cnv:to_list(rebar_dir:checkouts_dir(State, Name)), case rebar_app_info:discover(CheckoutsDir) of {ok, _App} -> - Dep = new_dep(DepsDir, Name, [], [], State), + Dep = new_dep(DepsDir, Name, [], [], IsLock, State), {[Dep | SrcDepsAcc], PkgDepsAcc}; not_found -> {SrcDepsAcc, [{Name, Vsn} | PkgDepsAcc]} end; -parse_dep({Name, Source, Level}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, State) when is_tuple(Source) +parse_dep({Name, Source, Level}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, IsLock, State) when is_tuple(Source) , is_integer(Level) -> - Dep = new_dep(DepsDir, Name, [], Source, State), + Dep = new_dep(DepsDir, Name, [], Source, IsLock, State), {[Dep | SrcDepsAcc], PkgDepsAcc}; -parse_dep(Dep, _, _, _) -> +parse_dep(Dep, _, _, _, _) -> throw(?PRV_ERROR({parse_dep, Dep})). -new_dep(DepsDir, Name, Vsn, Source, State) -> +new_dep(DepsDir, Name, Vsn, Source, IsLock, State) -> CheckoutsDir = ec_cnv:to_list(rebar_dir:checkouts_dir(State, Name)), {ok, Dep} = case rebar_app_info:discover(CheckoutsDir) of {ok, App} -> @@ -560,7 +574,7 @@ new_dep(DepsDir, Name, Vsn, Source, State) -> ParentOverrides = rebar_state:overrides(State), Dep1 = rebar_app_info:state(Dep, rebar_state:overrides(S, ParentOverrides++Overrides)), - rebar_app_info:source(Dep1, Source). + rebar_app_info:is_lock(rebar_app_info:source(Dep1, Source), IsLock). fetch_app(AppInfo, AppDir, State) -> ?INFO("Fetching ~s (~p)", [rebar_app_info:name(AppInfo), rebar_app_info:source(AppInfo)]), @@ -572,8 +586,12 @@ fetch_app(AppInfo, AppDir, State) -> throw(Error) end. -update_app_info(AppInfo) -> - AppDetails = rebar_app_info:app_details(AppInfo), +%% This is called after the dep has been downloaded and unpacked, if it hadn't been already. +%% So this is the first time for newly downloaded apps that its .app/.app.src data can +%% be read in an parsed. +update_app_info(AppDir, AppInfo) -> + {ok, Found} = rebar_app_info:discover(AppDir), + AppDetails = rebar_app_info:app_details(Found), Applications = proplists:get_value(applications, AppDetails, []), IncludedApplications = proplists:get_value(included_applications, AppDetails, []), AppInfo1 = rebar_app_info:applications( @@ -581,22 +599,29 @@ update_app_info(AppInfo) -> IncludedApplications++Applications), rebar_app_info:valid(AppInfo1, false). -maybe_upgrade(AppInfo, AppDir, false, State) -> - Source = rebar_app_info:source(AppInfo), - rebar_fetch:needs_update(AppDir, Source, State); -maybe_upgrade(AppInfo, AppDir, true, State) -> +maybe_upgrade(AppInfo, AppDir, Upgrade, State) -> Source = rebar_app_info:source(AppInfo), - case rebar_fetch:needs_update(AppDir, Source, State) of + case Upgrade orelse rebar_app_info:is_lock(AppInfo) of true -> - ?INFO("Upgrading ~s", [rebar_app_info:name(AppInfo)]), - case rebar_fetch:download_source(AppDir, Source, State) of + case rebar_fetch:needs_update(AppDir, Source, State) of true -> - true; - Error -> - throw(Error) + ?INFO("Upgrading ~s", [rebar_app_info:name(AppInfo)]), + case rebar_fetch:download_source(AppDir, Source, State) of + true -> + true; + Error -> + throw(Error) + end; + false -> + case Upgrade of + true -> + ?INFO("No upgrade needed for ~s", [rebar_app_info:name(AppInfo)]), + false; + false -> + false + end end; false -> - ?INFO("No upgrade needed for ~s", [rebar_app_info:name(AppInfo)]), false end. @@ -632,7 +657,8 @@ warn_skip_pkg({Name, Source}, State) -> not_needs_compile(App) -> not(rebar_app_info:is_checkout(App)) - andalso rebar_app_info:valid(App). + andalso rebar_app_info:valid(App) + andalso rebar_state:has_all_artifacts(rebar_app_info:state(App)) =:= true. get_package(Dep, State) -> case rebar_state:registry(State) of |