diff options
| -rw-r--r-- | src/rebar_core.erl | 3 | ||||
| -rw-r--r-- | src/rebar_deps.erl | 98 | 
2 files changed, 90 insertions, 11 deletions
| diff --git a/src/rebar_core.erl b/src/rebar_core.erl index fcfa62a..863d1d5 100644 --- a/src/rebar_core.erl +++ b/src/rebar_core.erl @@ -172,8 +172,9 @@ skip_or_process_dir1(AppFile, ModuleSet, Config, CurrentCodePath,                           CurrentCodePath, ModuleSet)      end. -process_dir1(Dir, Command, DirSet, Config0, CurrentCodePath, +process_dir1(Dir, Command, DirSet, Config, CurrentCodePath,               {DirModules, ModuleSetFile}) -> +    Config0 = rebar_config:set(Config, command, Command),      %% Get the list of modules for "any dir". This is a catch-all list      %% of modules that are processed in addition to modules associated      %% with this directory type. These any_dir modules are processed diff --git a/src/rebar_deps.erl b/src/rebar_deps.erl index be6283d..82c5061 100644 --- a/src/rebar_deps.erl +++ b/src/rebar_deps.erl @@ -97,8 +97,22 @@ preprocess(Config, _) ->      %% deps-related can be executed on their directories.      NonRawAvailableDeps = [D || D <- AvailableDeps, not D#dep.is_raw], -    %% Return all the available dep directories for process -    {ok, NewConfig, dep_dirs(NonRawAvailableDeps)}. +    case rebar_config:get(Config, command, undefined) of +        'update-deps' -> +            %% Skip ALL of the dep folders, we do this because we don't want +            %% any other calls to preprocess() for update-deps beyond the +            %% toplevel directory. They aren't actually harmful, but they slow +            %% things down unnecessarily. +            NewConfig2 = lists:foldl(fun(D, Acc) -> +                                             rebar_config:set_skip_dir(Acc, D#dep.dir) +                                     end, NewConfig, collect_deps(rebar_utils:get_cwd(),NewConfig)), +            %% Return the empty list, as we don't want anything processed before +            %% us. +            {ok, NewConfig2, []}; +        _ -> +            %% Return all the available dep directories for process +            {ok, NewConfig, dep_dirs(NonRawAvailableDeps)} +    end.  postprocess(Config, _) ->      case rebar_config:get_xconf(Config, ?MODULE, undefined) of @@ -169,17 +183,23 @@ do_check_deps(Config) ->      {ok, save_dep_dirs(Config2, lists:reverse(PulledDeps))}.  'update-deps'(Config, _) -> -    %% Determine what deps are required -    RawDeps = rebar_config:get_local(Config, deps, []), -    {Config1, Deps} = find_deps(Config, read, RawDeps), - -    %% Update each dep -    UpdatedDeps = [update_source(Config1, D) -                   || D <- Deps, D#dep.source =/= undefined], +    {Config2, UpdatedDeps} = update_deps_int(rebar_config:set(Config, depowner, dict:new()), []), +    DepOwners = rebar_config:get(Config2, depowner, dict:new()), + +    %% check for conflicting deps +    [?ERROR("Conflicting dependencies for ~p: ~p~n", [K, +                                                      [{"From: " ++ string:join(dict:fetch(D, +                                                                               DepOwners), +                                                                               ", "), +                                                        {D#dep.vsn_regex, +                                                         D#dep.source}} || D <- V]]) || +           {K, V} <- dict:to_list(lists:foldl(fun(Dep, Acc) -> +                                                      dict:append(Dep#dep.app, Dep, Acc) +                                              end, dict:new(), UpdatedDeps)), length(V) > 1],      %% Add each updated dep to our list of dirs for post-processing. This yields      %% the necessary transitivity of the deps -    {ok, save_dep_dirs(Config1, UpdatedDeps)}. +    {ok, save_dep_dirs(Config, UpdatedDeps)}.  'delete-deps'(Config, _) ->      %% Delete all the available deps in our deps/ directory, if any @@ -566,6 +586,64 @@ update_source1(AppDir, {fossil, _Url, Version}) ->      rebar_utils:sh("fossil pull", [{cd, AppDir}]),      rebar_utils:sh(?FMT("fossil update ~s", [Version]), []). +%% Recursively update deps, this is not done via rebar's usual dep traversal as +%% that is the wrong order (tips are updated before branches). Instead we do a +%% traverse the deps at each level completely before traversing *their* deps. +%% This allows updates to actually propogate down the tree, rather than fail to +%% flow up the tree, which was the previous behaviour. +update_deps_int(Config0, UDD) -> +    %% Determine what deps are required +    ConfDir = filename:basename(rebar_utils:get_cwd()), +    RawDeps = rebar_config:get_local(Config0, deps, []), +    {Config1, Deps} = find_deps(Config0, read, RawDeps), + +    %% Update each dep +    UpdatedDeps = [update_source(Config1, D) +                   || D <- Deps, D#dep.source =/= undefined, not lists:member(D, UDD)], + +    lists:foldl(fun(Dep, {Config, Updated}) -> +                        {true, AppDir} = get_deps_dir(Config, Dep#dep.app), +                        Config2 = case has_vcs_dir(element(1, Dep#dep.source), AppDir) of +                            false -> +                                %% If the dep did not exist (maybe it was added) +                                %% clone it. We'll traverse ITS deps below. and +                                %% clone them if needed. +                                {C1, _D1} = use_source(Config, Dep), +                                C1; +                            true -> +                                Config +                        end, +                        ok = file:set_cwd(AppDir), +                        Config3 = rebar_config:new(Config2), +                        %% track where a dep comes from... +                        Config4 = rebar_config:set(Config3, depowner, +                                                   dict:append(Dep, ConfDir, +                                                               rebar_config:get(Config3, +                                                                                depowner, +                                                                                dict:new()))), + +                        {Config5, Res} = update_deps_int(Config4, Updated), +                        {Config5, lists:umerge(lists:sort(Res), +                                               lists:sort(Updated))} +                end, {Config1, lists:umerge(lists:sort(UpdatedDeps), +                                            lists:sort(UDD))}, UpdatedDeps). + +%% Recursively walk the deps and build a list of them. +collect_deps(Dir, C) -> +    case file:set_cwd(Dir) of +        ok -> +            Config = rebar_config:new(C), +            RawDeps = rebar_config:get_local(Config, deps, []), +            {Config1, Deps} = find_deps(Config, read, RawDeps), + +            lists:flatten(Deps ++ [begin +                                       {true, AppDir} = get_deps_dir(Config1, Dep#dep.app), +                                       collect_deps(AppDir, C) +                                   end || Dep <- Deps]); +        _ -> +            [] +    end. +  %% ===================================================================  %% Source helper functions | 
