summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/rebar.app.src1
-rw-r--r--src/rebar_fetch.erl3
-rw-r--r--src/rebar_hg_resource.erl121
-rw-r--r--src/rebar_prv_edoc.erl48
4 files changed, 172 insertions, 1 deletions
diff --git a/src/rebar.app.src b/src/rebar.app.src
index 1314ead..e5f21ea 100644
--- a/src/rebar.app.src
+++ b/src/rebar.app.src
@@ -29,6 +29,7 @@
rebar_prv_dialyzer,
rebar_prv_do,
rebar_prv_eunit,
+ rebar_prv_edoc,
rebar_prv_lock,
rebar_prv_install_deps,
rebar_prv_packages,
diff --git a/src/rebar_fetch.erl b/src/rebar_fetch.erl
index 4dfd790..9c427df 100644
--- a/src/rebar_fetch.erl
+++ b/src/rebar_fetch.erl
@@ -17,7 +17,8 @@
-include_lib("providers/include/providers.hrl").
%% map short versions of resources to module names
--define(RESOURCES, [{git, rebar_git_resource}, {pkg, rebar_pkg_resource}]).
+-define(RESOURCES, [{git, rebar_git_resource}, {pkg, rebar_pkg_resource},
+ {hg, rebar_hg_resource}]).
-spec lock_source(file:filename_all(), rebar_resource:resource()) ->
rebar_resource:resource() | {error, string()}.
diff --git a/src/rebar_hg_resource.erl b/src/rebar_hg_resource.erl
new file mode 100644
index 0000000..a0ebb6d
--- /dev/null
+++ b/src/rebar_hg_resource.erl
@@ -0,0 +1,121 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+-module(rebar_hg_resource).
+
+-behaviour(rebar_resource).
+
+-export([lock/2
+ ,download/3
+ ,needs_update/2
+ ,make_vsn/1]).
+
+-include("rebar.hrl").
+
+lock(AppDir, {hg, Url, _}) ->
+ lock(AppDir, {hg, Url});
+lock(AppDir, {hg, Url}) ->
+ Ref = get_ref(AppDir),
+ {hg, Url, {ref, Ref}}.
+
+%% Return `true' if either the hg url or tag/branch/ref is not the same as
+%% the currently checked out repo for the dep
+needs_update(Dir, {hg, Url, {tag, Tag}}) ->
+ Ref = get_ref(Dir),
+ {ClosestTag, Distance} = get_tag_distance(Dir, Ref),
+ ?DEBUG("Comparing hg tag ~s with ref ~s (closest tag is ~s at distance ~s)",
+ [Tag, Ref, ClosestTag, Distance]),
+ not ((Distance =:= "0") andalso (Tag =:= ClosestTag)
+ andalso compare_url(Dir, Url));
+needs_update(Dir, {hg, Url, {branch, Branch}}) ->
+ Ref = get_ref(Dir),
+ BRef = get_branch_ref(Dir, Branch),
+ not ((Ref =:= BRef) andalso compare_url(Dir, Url));
+needs_update(Dir, {hg, Url, "default"}) ->
+ Ref = get_ref(Dir),
+ BRef = get_branch_ref(Dir, "default"),
+ not ((Ref =:= BRef) andalso compare_url(Dir, Url));
+needs_update(Dir, {hg, Url, Ref}) ->
+ LocalRef = get_ref(Dir),
+ TargetRef = case Ref of
+ {ref, Ref1} ->
+ Length = length(LocalRef),
+ if Length >= 7 -> lists:sublist(Ref1, Length);
+ Length < 7 -> Ref1
+ end;
+ Ref1 ->
+ Ref1
+ end,
+ ?DEBUG("Comparing hg ref ~s with ~s", [Ref1, LocalRef]),
+ not ((LocalRef =:= TargetRef) andalso compare_url(Dir, Url)).
+
+download(Dir, {hg, Url}, State) ->
+ ?WARN("WARNING: It is recommended to use {branch, Name}, {tag, Tag} or {ref, Ref}, otherwise updating the dep may not work as expected.", []),
+ download(Dir, {hg, Url, {branch, "default"}}, State);
+download(Dir, {hg, Url, ""}, State) ->
+ ?WARN("WARNING: It is recommended to use {branch, Name}, {tag, Tag} or {ref, Ref}, otherwise updating the dep may not work as expected.", []),
+ download(Dir, {hg, Url, {branch, "default"}}, State);
+download(Dir, {hg, Url, {branch, Branch}}, _State) ->
+ ok = filelib:ensure_dir(Dir),
+ rebar_utils:sh(?FMT("hg clone -q -b ~s ~s ~s",
+ [Branch, Url, filename:basename(Dir)]),
+ [{cd, filename:dirname(Dir)}]);
+download(Dir, {hg, Url, {tag, Tag}}, _State) ->
+ ok = filelib:ensure_dir(Dir),
+ rebar_utils:sh(?FMT("hg clone -q -r ~s ~s ~s",
+ [Tag, Url, filename:basename(Dir)]),
+ [{cd, filename:dirname(Dir)}]);
+download(Dir, {hg, Url, {ref, Ref}}, _State) ->
+ ok = filelib:ensure_dir(Dir),
+ rebar_utils:sh(?FMT("hg clone -q -r ~s ~s ~s",
+ [Ref, Url, filename:basename(Dir)]),
+ [{cd, filename:dirname(Dir)}]);
+download(Dir, {hg, Url, Rev}, _State) ->
+ ok = filelib:ensure_dir(Dir),
+ rebar_utils:sh(?FMT("hg clone -q -r ~s ~s ~s",
+ [Rev, Url, filename:basename(Dir)]),
+ [{cd, filename:dirname(Dir)}]).
+
+make_vsn(Dir) ->
+ BaseHg = "hg -R '" ++ Dir ++ "' ",
+ Ref = get_ref(Dir),
+ Cmd = BaseHg ++ "log --template \"{latesttag}+build.{latesttagdistance}.rev.{node|short}\""
+ " --rev " ++ Ref,
+ RawVsn = string:strip(os:cmd(Cmd), both, $\n),
+ Vsn = case RawVsn of
+ "null+" ++ Rest -> "0.0.0+" ++ Rest;
+ _ -> RawVsn
+ end,
+ {plain, Vsn}.
+
+%%% Internal functions
+
+compare_url(Dir, Url) ->
+ CurrentUrl = string:strip(os:cmd("hg -R '" ++ Dir ++"' paths default"), both, $\n),
+ CurrentUrl1 = string:strip(CurrentUrl, both, $\r),
+ parse_hg_url(CurrentUrl1) =:= parse_hg_url(Url).
+
+get_ref(Dir) ->
+ string:strip(os:cmd("hg -R '" ++ Dir ++ "' --debug id -i"), both, $\n).
+
+get_tag_distance(Dir, Ref) ->
+ Log = string:strip(os:cmd("hg -R '" ++ Dir ++ "' "
+ "log --template \"{latesttag}-{latesttagdistance}\n\" "
+ "--rev " ++ Ref),
+ both, $\n),
+ [Tag, Distance] = re:split(Log, "-([0-9]+)$", [{parts,0}]),
+ {Tag, Distance}.
+
+get_branch_ref(Dir, Branch) ->
+ string:strip(
+ os:cmd("hg -R '" ++ Dir ++ "' log --template \"{node}\n\" --rev " ++ Branch),
+ both, $\n).
+
+parse_hg_url("ssh://" ++ HostPath) ->
+ [Host | Path] = string:tokens(HostPath, "/"),
+ {Host, filename:rootname(filename:join(Path), ".hg")};
+parse_hg_url("http://" ++ HostPath) ->
+ [Host | Path] = string:tokens(HostPath, "/"),
+ {Host, filename:rootname(filename:join(Path), ".hg")};
+parse_hg_url("https://" ++ HostPath) ->
+ [Host | Path] = string:tokens(HostPath, "/"),
+ {Host, filename:rootname(filename:join(Path), ".hg")}.
diff --git a/src/rebar_prv_edoc.erl b/src/rebar_prv_edoc.erl
new file mode 100644
index 0000000..8397e20
--- /dev/null
+++ b/src/rebar_prv_edoc.erl
@@ -0,0 +1,48 @@
+-module(rebar_prv_edoc).
+
+-behaviour(provider).
+
+-export([init/1,
+ do/1,
+ format_error/1]).
+
+-include("rebar.hrl").
+
+-define(PROVIDER, edoc).
+-define(DEPS, [app_discovery]).
+
+%% ===================================================================
+%% Public API
+%% ===================================================================
+
+-spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
+init(State) ->
+ State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER},
+ {module, ?MODULE},
+ {bare, false},
+ {deps, ?DEPS},
+ {example, "rebar edoc"},
+ {short_desc, "Generate documentation using edoc."},
+ {desc, ""},
+ {opts, []}])),
+ {ok, State1}.
+
+-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
+do(State) ->
+ ProjectApps = rebar_state:project_apps(State),
+ EDocOpts = rebar_state:get(State, edoc_opts, []),
+ lists:foreach(fun(AppInfo) ->
+ AppName = ec_cnv:to_list(rebar_app_info:name(AppInfo)),
+ ?INFO("Running edoc for ~s", [AppName]),
+ AppDir = rebar_app_info:dir(AppInfo),
+ ok = edoc:application(list_to_atom(AppName), AppDir, EDocOpts)
+ end, ProjectApps),
+ {ok, State}.
+
+-spec format_error(any()) -> iolist().
+format_error(Reason) ->
+ io_lib:format("~p", [Reason]).
+
+%% ===================================================================
+%% Internal functions
+%% ===================================================================