diff --git a/rebar.config.script b/rebar.config.script index 07feb95d..fb7cfb00 100644 --- a/rebar.config.script +++ b/rebar.config.script @@ -2,9 +2,8 @@ %% ex: ts=4 sw=4 ft=erlang et %% TODO: Change temporary retest fork back to dizzyd/retest after merge -%% ExtraDeps = [{retest, ".*", {git, "git://github.com/dizzyd/retest.git"}}], -ExtraDeps = [{retest, ".*", - {git, "git://github.com/tuncer/retest.git", "next"}}], +%% ExtraDeps = [{retest, ".*", {git, "git://github.com/tuncer/retest.git", "next"}}], +ExtraDeps = [{retest, ".*", {git, "git://github.com/dizzyd/retest.git"}}], case os:getenv("REBAR_EXTRA_DEPS") of false -> diff --git a/src/rebar_deps.erl b/src/rebar_deps.erl index 5e697094..5208578c 100644 --- a/src/rebar_deps.erl +++ b/src/rebar_deps.erl @@ -478,13 +478,74 @@ use_source(Config, Dep, Count) -> "with reason:~n~p.\n", [Dep#dep.dir, Reason]) end; false -> - ?CONSOLE("Pulling ~p from ~p\n", [Dep#dep.app, Dep#dep.source]), - require_source_engine(Dep#dep.source), - {true, TargetDir} = get_deps_dir(Config, Dep#dep.app), - download_source(TargetDir, Dep#dep.source), - use_source(Config, Dep#dep { dir = TargetDir }, Count-1) + DepDir = case is_local_source(Dep) of + true -> + %% Repo source is a local directory, skip local cache + ?CONSOLE("Pulling ~p from ~p\n", [Dep#dep.app, Dep#dep.source]), + require_source_engine(Dep#dep.source), + {true, TargetDir} = get_deps_dir(Config, Dep#dep.app), + download_source(TargetDir, Dep#dep.source), + TargetDir; + false -> + CacheTargetDir = ensure_local_cache(Config, Dep), + {true, TargetDir} = get_deps_dir(Config, Dep#dep.app), + ok = filelib:ensure_dir(TargetDir), + rebar_file_utils:cp_r([CacheTargetDir], TargetDir), + TargetDir + end, + use_source(Config, Dep#dep { dir = DepDir }, Count-1) + end. + +local_cache_base_dir(Dep) -> + {ok, [[Home]]} = init:get_argument(home), + CacheBaseDir = filename:join([Home, ".rebar", "cache", Dep#dep.app]), + filelib:ensure_dir(CacheBaseDir++"/"), + CacheBaseDir. + +local_cache_target_dir(Dep) -> + CacheBaseDir = local_cache_base_dir(Dep), + VersionDirs = case Dep#dep.source of + {_,_,{B,Version}} when is_atom(B) -> [atom_to_list(B), Version]; + {_,_,{B,Version}} -> [B, Version]; + {_,_,Version} -> [Version]; + {_,_} -> ["master"] + end, + filename:join([CacheBaseDir]++VersionDirs). + +%% the hallmarks of a local file +maybe_local_dir(".") -> true; +maybe_local_dir("/") -> true; +maybe_local_dir("\\") -> true; +maybe_local_dir(_) -> false. + +is_local_source(Dep) -> + case Dep#dep.source of + {_,Local,_} when is_list(Local) -> + maybe_local_dir(string:substr(Local, 1, 1)); + {_,Local} when is_list(Local) -> + maybe_local_dir(string:substr(Local, 1, 1)); + _ -> false end. +ensure_local_cache(Config, Dep) -> + ?CONSOLE("Checking local cache for ~p from ~p\n", [Dep#dep.app, Dep#dep.source]), + CacheTargetDir = local_cache_target_dir(Dep), + case filelib:is_dir(CacheTargetDir) of + true -> + %% Attempting to update always, and catch timeouts. After N + %% timeouts, set source as 'unreachable' and just carry on + %% In the future, version branches by most recent commit, + %% and compare against remote HEAD + require_source_engine(Dep#dep.source), + update_source(Config, Dep, CacheTargetDir); + false -> + ?CONSOLE("Pulling ~p from ~p into local cache\n", [Dep#dep.app, Dep#dep.source]), + require_source_engine(Dep#dep.source), + ?CONSOLE("CacheTargetDir: ~p\n", [CacheTargetDir]), + download_source(CacheTargetDir, Dep#dep.source) + end, + CacheTargetDir. + download_source(AppDir, {hg, Url, Rev}) -> ok = filelib:ensure_dir(AppDir), rebar_utils:sh(?FMT("hg clone -U ~s ~s", [Url, filename:basename(AppDir)]), @@ -536,11 +597,14 @@ download_source(AppDir, {fossil, Url, Version}) -> []). update_source(Config, Dep) -> + {true, AppDir} = get_deps_dir(Config, Dep#dep.app), + update_source(Config, Dep, AppDir). + +update_source(_Config, Dep, AppDir) -> %% It's possible when updating a source, that a given dep does not have a %% VCS directory, such as when a source archive is built of a project, with %% all deps already downloaded/included. So, verify that the necessary VCS %% directory exists before attempting to do the update. - {true, AppDir} = get_deps_dir(Config, Dep#dep.app), case has_vcs_dir(element(1, Dep#dep.source), AppDir) of true -> ?CONSOLE("Updating ~p from ~p\n", [Dep#dep.app, Dep#dep.source]),