summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Smith <dizzyd@dizzyd.com>2009-12-30 20:03:27 -0700
committerDave Smith <dizzyd@dizzyd.com>2009-12-30 20:03:27 -0700
commit5cd5870f320540c616cb39cc89d8002f3c8c518a (patch)
tree0123ef7f46be5d16a8a9144b4a3bc6b1f302365c
parent1fe4d13e255818cfa092915e035520dee02db830 (diff)
Got basic retrieval of deps from hg sorta working; minor refactoring of rebar_utils:sh interface
-rw-r--r--src/rebar_deps.erl139
-rw-r--r--src/rebar_utils.erl22
2 files changed, 143 insertions, 18 deletions
diff --git a/src/rebar_deps.erl b/src/rebar_deps.erl
index 7335d58..02a34d6 100644
--- a/src/rebar_deps.erl
+++ b/src/rebar_deps.erl
@@ -37,8 +37,14 @@ preprocess(Config, _) ->
DepsDir = rebar_config:get(Config, deps_dir, "deps"),
%% Process the list of deps from the configuration
- Dirs = process_deps(rebar_config:get(Config, deps, []), [], DepsDir),
- {ok, Config, Dirs}.
+ case catch(process_deps(rebar_config:get(Config, deps, []), [], DepsDir)) of
+ Dirs when is_list(Dirs) ->
+ %% Filter out deps from config so sub-dirs don't wind up trying to d/l deps again
+ Config2 = rebar_config:delete(Config, deps),
+ {ok, Config2, Dirs};
+ {'EXIT', Reason} ->
+ ?ABORT("Error while processing dependencies: ~p\n", [Reason])
+ end.
%% ===================================================================
@@ -48,13 +54,130 @@ preprocess(Config, _) ->
process_deps([], Acc, _Dir) ->
Acc;
process_deps([App | Rest], Acc, Dir) when is_atom(App) ->
+ require_app(App, ".*"),
+ process_deps(Rest, Acc, Dir);
+process_deps([{App, VsnRegex} | Rest], Acc, Dir) when is_atom(App) ->
+ require_app(App, VsnRegex),
+ process_deps(Rest, Acc, Dir);
+process_deps([{App, VsnRegex, Source} | Rest], Acc, Dir) ->
+ ?DEBUG("Process deps: ~p\n", [Rest]),
+ case is_app_available(App, VsnRegex) of
+ true ->
+ process_deps(Rest, Acc, Dir);
+ false ->
+ %% App may not be on the code path, or the version that is doesn't
+ %% match our regex. Either way, we want to pull our revision into
+ %% the deps dir and try to use that
+ require_source_engine(Source),
+ AppDir = filename:join(Dir, App),
+ use_source(AppDir, App, VsnRegex, Source),
+ process_deps(Rest, [AppDir | Acc], Dir)
+ end;
+process_deps([Other | _Rest], _Acc, _Dir) ->
+ ?ABORT("Invalid dependency specification ~p in ~s\n",
+ [Other, rebar_utils:get_cwd()]).
+
+
+
+require_app(App, VsnRegex) ->
+ case is_app_available(App, VsnRegex) of
+ true ->
+ ok;
+ false ->
+ %% The requested app is not available on the code path
+ ?ABORT("~s: Dependency ~s-~s not available.\n",
+ [rebar_utils:get_cwd(), App, VsnRegex])
+ end.
+
+require_source_engine(Source) ->
+ case source_engine_avail(Source) of
+ true ->
+ ok;
+ false ->
+ ?ABORT("No command line interface available to process ~p\n", [Source])
+ end.
+
+
+is_app_available(App, VsnRegex) ->
case code:lib_dir(App) of
{error, bad_name} ->
- %% The requested app is not available on the code path
- ?ABORT("~s: Dependency ~s not available.\n",
- [rebar_utils:get_cwd(), App]);
+ false;
Path ->
- ?INFO("Dependency ~s -> ~s\n", [App, Path])
- end,
- process_deps(Rest, Acc, Dir).
+ is_app_available(App, VsnRegex, Path)
+ end.
+
+is_app_available(App, VsnRegex, Path) ->
+ case rebar_app_utils:is_app_dir(Path) of
+ {true, AppFile} ->
+ case rebar_app_utils:load_app_file(AppFile) of
+ {ok, App, AppData} ->
+ {vsn, Vsn} = lists:keyfind(vsn, 1, AppData),
+ ?INFO("Looking for ~s-~s ; found ~s-~s at ~s\n",
+ [App, VsnRegex, App, Vsn, Path]),
+ case re:run(Vsn, VsnRegex, [{capture, none}]) of
+ match ->
+ true;
+ nomatch ->
+ ?WARN("~s has version ~p; requested regex was ~s\n",
+ [AppFile, Vsn, VsnRegex]),
+ false
+ end;
+ {ok, OtherApp, _} ->
+ ?WARN("~s has application id ~p; expected ~p\n", [AppFile, OtherApp, App]),
+ false;
+ {error, Reason} ->
+ ?ABORT("Failed to parse ~s: ~p\n", [AppFile, Reason])
+ end;
+ false ->
+ ?WARN("Expected ~s to be an app dir (containing ebin/*.app), but no .app found.\n",
+ [Path]),
+ false
+ end.
+
+use_source(AppDir, App, VsnRegex, Source) ->
+ use_source(AppDir, App, VsnRegex, Source, 3).
+
+use_source(_AppDir, _App, _VsnRegex, Source, 0) ->
+ ?ABORT("Failed to acquire source from ~p after 3 tries.\n", [Source]);
+use_source(AppDir, App, VsnRegex, Source, Count) ->
+ case filelib:is_dir(AppDir) of
+ true ->
+ %% Already downloaded -- verify the versioning matches up with our regex
+ case is_app_available(App, VsnRegex, AppDir) of
+ true ->
+ %% Available version matches up -- we're good to go; add the
+ %% app dir to our code path
+ code:add_patha(filename:join(AppDir, ebin)),
+ ok;
+ false ->
+ %% The app that was downloaded doesn't match up (or had
+ %% errors or something). For the time being, abort.
+ ?ABORT("Dependency dir ~s does not satisfy version regex ~s.\n",
+ [AppDir, VsnRegex])
+ end;
+ false ->
+ download_source(AppDir, Source),
+ use_source(AppDir, App, VsnRegex, Source, Count-1)
+ end.
+
+download_source(AppDir, {hg, Url, Rev}) ->
+ ok = filelib:ensure_dir(AppDir),
+ Cmd = ?FMT("hg clone -u ~s ~s", [Rev, Url]),
+ rebar_utils:sh(Cmd, [], filename:dirname(AppDir)).
+
+
+%% ===================================================================
+%% Source helper functions
+%% ===================================================================
+source_engine_avail({hg, _, _}) ->
+ Res = os:cmd("which hg"),
+ ?DEBUG("which hg = ~p\n", [Res]),
+ case Res of
+ [] ->
+ false;
+ _ ->
+ true
+ end;
+source_engine_avail(_) ->
+ false.
diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl
index 902feab..d780419 100644
--- a/src/rebar_utils.erl
+++ b/src/rebar_utils.erl
@@ -27,7 +27,7 @@
-export([get_cwd/0,
is_arch/1,
get_os/0,
- sh/2,
+ sh/2, sh/3,
sh_failfast/2,
now_str/0]).
@@ -62,20 +62,22 @@ get_os() ->
sh(Command, Env) ->
+ sh(Command, Env, get_cwd()).
+
+sh(Command, Env, Dir) ->
?INFO("sh: ~s\n~p\n", [Command, Env]),
- Port = open_port({spawn, Command}, [{env, Env}, exit_status, {line, 16384},
+ Port = open_port({spawn, Command}, [{cd, Dir}, {env, Env}, exit_status, {line, 16384},
use_stdio, stderr_to_stdout]),
- sh_loop(Port).
-
-sh_failfast(Command, Env) ->
- case sh(Command, Env) of
+ case sh_loop(Port) of
ok ->
ok;
{error, Rc} ->
- ?ERROR("~s failed with error: ~w\n", [Command, Rc]),
- ?FAIL
+ ?ABORT("~s failed with error: ~w\n", [Command, Rc])
end.
+sh_failfast(Command, Env) ->
+ sh(Command, Env).
+
now_str() ->
{{Year, Month, Day}, {Hour, Minute, Second}} = calendar:local_time(),
lists:flatten(io_lib:format("~4b/~2..0b/~2..0b ~2..0b:~2..0b:~2..0b",
@@ -95,10 +97,10 @@ match_first([{Regex, MatchValue} | Rest], Val) ->
match_first(Rest, Val)
end.
-sh_loop(Port) ->
+sh_loop(Port) ->
receive
{Port, {data, {_, Line}}} ->
- ?INFO("> ~s\n", [Line]),
+ ?CONSOLE("~s\n", [Line]),
sh_loop(Port);
{Port, {exit_status, 0}} ->
ok;