summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/rebar3.erl4
-rw-r--r--src/rebar_app_info.erl2
-rw-r--r--src/rebar_fetch.erl304
-rw-r--r--src/rebar_git_resource.erl146
-rw-r--r--src/rebar_hooks.erl24
-rw-r--r--src/rebar_pkg_resource.erl32
-rw-r--r--src/rebar_prv_clean.erl48
-rw-r--r--src/rebar_prv_compile.erl34
-rw-r--r--src/rebar_prv_install_deps.erl137
-rw-r--r--src/rebar_prv_tar.erl4
-rw-r--r--src/rebar_prv_upgrade.erl11
-rw-r--r--src/rebar_resource.erl43
-rw-r--r--src/rebar_topo.erl2
-rw-r--r--src/rebar_utils.erl28
14 files changed, 493 insertions, 326 deletions
diff --git a/src/rebar3.erl b/src/rebar3.erl
index 22c08ca..e5d82f9 100644
--- a/src/rebar3.erl
+++ b/src/rebar3.erl
@@ -49,10 +49,12 @@ main(Args) ->
ok;
rebar_abort ->
rebar_utils:delayed_halt(1);
+ {error, rebar_abort} ->
+ rebar_utils:delayed_halt(1);
{error, {Module, Reason}} ->
?ERROR(Module:format_error(Reason, []), []),
rebar_utils:delayed_halt(1);
- {error, Error} ->
+ {error, Error} when is_list(Error) ->
?ERROR(Error++"~n", []),
rebar_utils:delayed_halt(1);
Error ->
diff --git a/src/rebar_app_info.erl b/src/rebar_app_info.erl
index 7a33811..47dfcad 100644
--- a/src/rebar_app_info.erl
+++ b/src/rebar_app_info.erl
@@ -38,7 +38,7 @@
original_vsn :: binary() | string() | undefined,
app_details=[] :: list(),
deps=[] :: list(),
- dep_level :: integer(),
+ dep_level=0 :: integer(),
dir :: file:name(),
source :: string() | tuple() | undefined,
valid :: boolean()}).
diff --git a/src/rebar_fetch.erl b/src/rebar_fetch.erl
index 0a90848..a7ae446 100644
--- a/src/rebar_fetch.erl
+++ b/src/rebar_fetch.erl
@@ -7,256 +7,78 @@
%% -------------------------------------------------------------------
-module(rebar_fetch).
--export([new/4,
- lock_source/2,
+-export([lock_source/2,
download_source/2,
- update_source1/2,
- source_engine_avail/1,
- source_engine_avail/2,
- has_vcs_dir/2,
- print_source/1,
- format_source/2]).
+ needs_update/2]).
-include("rebar.hrl").
--record(p4_settings, {
- client=undefined,
- transport="tcp4:perforce:1666",
- username,
- password
- }).
-
-new(Dir, App, Vsn, Source) ->
- NewSource = lock_source(Dir, Source),
- {App, Vsn, NewSource}.
-
-init_p4_settings(Basename) ->
- #p4_settings{client =
- case inet:gethostname() of
- {ok,HostName} ->
- HostName ++ "-"
- ++ os:getenv("USER") ++ "-"
- ++ Basename
- ++ "-Rebar-automated-download"
- end}.
-
-lock_source(AppDir, {git, Url, _}) ->
- Ref = string:strip(os:cmd("git --git-dir='" ++ AppDir ++ "/.git' rev-parse --verify HEAD"), both, $\n),
- {git, Url, Ref};
-lock_source(_AppDir, Source) ->
- Source.
+%% map short versions of resources to module names
+-define(RESOURCES, [{git, rebar_git_resource}, {pkg, rebar_pkg_resource}]).
+
+-spec lock_source(file:filename_all(), rebar_resource:resource()) ->
+ rebar_resource:resource() | {error, string()}.
+lock_source(AppDir, Source) ->
+ case get_resource_type(Source) of
+ {error, _}=Error ->
+ Error;
+ Module ->
+ Module:lock(AppDir, Source)
+ end.
+-spec download_source(file:filename_all(), rebar_resource:resource()) -> true | {error, any()}.
download_source(AppDir, Source) ->
- TmpDir = ec_file:insecure_mkdtemp(),
- AppDir1 = ec_cnv:to_list(AppDir),
- ec_file:mkdir_p(AppDir1),
- case download_source_tmp(TmpDir, Source) of
- {ok, _} ->
- ok = ec_file:copy(TmpDir, filename:absname(AppDir1), [recursive]);
- {tarball, File} ->
- ok = erl_tar:extract(File, [{cwd, TmpDir}
- ,compressed]),
- BaseName = filename:basename(AppDir1),
- [FromDir] = filelib:wildcard(filename:join(TmpDir, BaseName++"-*")),
- ec_file:copy(FromDir, AppDir1, [recursive])
+ case get_resource_type(Source) of
+ {error, _}=Error ->
+ Error;
+ Module ->
+ TmpDir = ec_file:insecure_mkdtemp(),
+ AppDir1 = ec_cnv:to_list(AppDir),
+ ec_file:mkdir_p(AppDir1),
+ case Module:download(TmpDir, Source) of
+ {ok, _} ->
+ code:del_path(filename:absname(filename:join(AppDir1, "ebin"))),
+ ec_file:remove(filename:absname(AppDir1), [recursive]),
+ ok = ec_file:copy(TmpDir, filename:absname(AppDir1), [recursive]),
+ true;
+ {tarball, File} ->
+ ok = erl_tar:extract(File, [{cwd, TmpDir}
+ ,compressed]),
+ BaseName = filename:basename(AppDir1),
+ [FromDir] = filelib:wildcard(filename:join(TmpDir, BaseName++"-*")),
+ code:del_path(filename:absname(filename:join(AppDir1, "ebin"))),
+ ec_file:remove(filename:absname(AppDir1), [recursive]),
+ ok = ec_file:copy(FromDir, filename:absname(AppDir1), [recursive]),
+ true
+ end
end.
-download_source_tmp(TmpDir, {p4, Url}) ->
- download_source_tmp(TmpDir, {p4, Url, "#head"});
-download_source_tmp(TmpDir, {p4, Url, Rev}) ->
- download_source_tmp(TmpDir, {p4, Url, Rev, init_p4_settings(filename:basename(TmpDir))});
-download_source_tmp(TmpDir, {p4, Url, _Rev, Settings}) ->
- ok = filelib:ensure_dir(TmpDir),
- rebar_utils:sh_send("p4 client -i",
- ?FMT("Client: ~s~n"
- ++"Description: generated by Rebar~n"
- ++"Root: ~s~n"
- ++"View:~n"
- ++" ~s/... //~s/...~n",
- [Settings#p4_settings.client,
- TmpDir,
- Url,
- Settings#p4_settings.client]),
- []),
- rebar_utils:sh(?FMT("p4 -c ~s sync -f", [Settings#p4_settings.client]), []);
-download_source_tmp(TmpDir, {hg, Url, Rev}) ->
- ok = filelib:ensure_dir(TmpDir),
- rebar_utils:sh(?FMT("hg clone -U ~s ~s", [Url, filename:basename(TmpDir)]),
- [{cd, filename:dirname(TmpDir)}]),
- rebar_utils:sh(?FMT("hg update ~s", [Rev]), [{cd, TmpDir}]);
-download_source_tmp(TmpDir, {git, Url}) ->
- download_source_tmp(TmpDir, {git, Url, {branch, "HEAD"}});
-download_source_tmp(TmpDir, {git, Url, ""}) ->
- download_source_tmp(TmpDir, {git, Url, {branch, "HEAD"}});
-download_source_tmp(TmpDir, {git, Url, {branch, Branch}}) ->
- ok = filelib:ensure_dir(TmpDir),
- rebar_utils:sh(?FMT("git clone -n ~s ~s", [Url, filename:basename(TmpDir)]),
- [{cd, filename:dirname(TmpDir)}]),
- rebar_utils:sh(?FMT("git checkout -q origin/~s", [Branch]), [{cd, TmpDir}]);
-download_source_tmp(TmpDir, {git, Url, {tag, Tag}}) ->
- ok = filelib:ensure_dir(TmpDir),
- rebar_utils:sh(?FMT("git clone -n ~s ~s", [Url, filename:basename(TmpDir)]),
- [{cd, filename:dirname(TmpDir)}]),
- rebar_utils:sh(?FMT("git checkout -q ~s", [Tag]), [{cd, TmpDir}]);
-download_source_tmp(TmpDir, {git, Url, Rev}) ->
- ok = filelib:ensure_dir(TmpDir),
- rebar_utils:sh(?FMT("git clone -n ~s ~s", [Url, filename:basename(TmpDir)]),
- [{cd, filename:dirname(TmpDir)}]),
- rebar_utils:sh(?FMT("git checkout -q ~s", [Rev]), [{cd, TmpDir}]);
-download_source_tmp(TmpDir, {bzr, Url, Rev}) ->
- ok = filelib:ensure_dir(TmpDir),
- rebar_utils:sh(?FMT("bzr branch -r ~s ~s ~s",
- [Rev, Url, filename:basename(TmpDir)]),
- [{cd, filename:dirname(TmpDir)}]);
-download_source_tmp(TmpDir, {svn, Url, Rev}) ->
- ok = filelib:ensure_dir(TmpDir),
- rebar_utils:sh(?FMT("svn checkout -r ~s ~s ~s",
- [Rev, Url, filename:basename(TmpDir)]),
- [{cd, filename:dirname(TmpDir)}]);
-download_source_tmp(TmpDir, {rsync, Url}) ->
- ok = filelib:ensure_dir(TmpDir),
- rebar_utils:sh(?FMT("rsync -az --delete ~s/ ~s", [Url, TmpDir]), []);
-download_source_tmp(TmpDir, {fossil, Url}) ->
- download_source_tmp(TmpDir, {fossil, Url, ""});
-download_source_tmp(TmpDir, {fossil, Url, Version}) ->
- Repository = filename:join(TmpDir, filename:basename(TmpDir) ++ ".fossil"),
- ok = filelib:ensure_dir(Repository),
- ok = file:set_cwd(TmpDir),
- rebar_utils:sh(?FMT("fossil clone ~s ~s", [Url, Repository]),
- [{cd, TmpDir}]),
- rebar_utils:sh(?FMT("fossil open ~s ~s --nested", [Repository, Version]),
- []);
-download_source_tmp(TmpDir, Url) ->
- TmpFile = filename:join(TmpDir, "package.tar.gz"),
- {ok, saved_to_file} = httpc:request(get, {binary_to_list(Url), []}, [], [{stream, TmpFile}]),
- {tarball, TmpFile}.
-
-update_source1(AppDir, Args) when element(1, Args) =:= p4 ->
- download_source_tmp(AppDir, Args);
-update_source1(AppDir, {git, Url}) ->
- update_source1(AppDir, {git, Url, {branch, "HEAD"}});
-update_source1(AppDir, {git, Url, ""}) ->
- update_source1(AppDir, {git, Url, {branch, "HEAD"}});
-update_source1(AppDir, {git, _Url, {branch, Branch}}) ->
- ShOpts = [{cd, AppDir}],
- rebar_utils:sh("git fetch origin", ShOpts),
- rebar_utils:sh(?FMT("git checkout -q ~s", [Branch]), ShOpts),
- rebar_utils:sh(
- ?FMT("git pull --ff-only --no-rebase -q origin ~s", [Branch]),ShOpts);
-update_source1(AppDir, {git, _Url, {tag, Tag}}) ->
- ShOpts = [{cd, AppDir}],
- rebar_utils:sh("git fetch origin", ShOpts),
- rebar_utils:sh(?FMT("git checkout -q ~s", [Tag]), ShOpts);
-update_source1(AppDir, {git, _Url, Refspec}) ->
- ShOpts = [{cd, AppDir}],
- rebar_utils:sh("git fetch origin", ShOpts),
- rebar_utils:sh(?FMT("git checkout -q ~s", [Refspec]), ShOpts);
-update_source1(AppDir, {svn, _Url, Rev}) ->
- rebar_utils:sh(?FMT("svn up -r ~s", [Rev]), [{cd, AppDir}]);
-update_source1(AppDir, {hg, _Url, Rev}) ->
- rebar_utils:sh(?FMT("hg pull -u -r ~s", [Rev]), [{cd, AppDir}]);
-update_source1(AppDir, {bzr, _Url, Rev}) ->
- rebar_utils:sh(?FMT("bzr update -r ~s", [Rev]), [{cd, AppDir}]);
-update_source1(AppDir, {rsync, Url}) ->
- rebar_utils:sh(?FMT("rsync -az --delete ~s/ ~s",[Url,AppDir]),[]);
-update_source1(AppDir, {fossil, Url}) ->
- update_source1(AppDir, {fossil, Url, ""});
-update_source1(AppDir, {fossil, _Url, Version}) ->
- ok = file:set_cwd(AppDir),
- rebar_utils:sh("fossil pull", [{cd, AppDir}]),
- rebar_utils:sh(?FMT("fossil update ~s", [Version]), []).
-
-%% ===================================================================
-%% Source helper functions
-%% ===================================================================
+-spec needs_update(file:filename_all(), rebar_resource:resource()) -> boolean() | {error, string()}.
+needs_update(AppDir, Source) ->
+ case get_resource_type(Source) of
+ {error, _}=Error ->
+ Error;
+ Module ->
+ Module:needs_update(AppDir, Source)
+ end.
-source_engine_avail(Source) ->
- Name = element(1, Source),
- source_engine_avail(Name, Source).
+get_resource_type({Type, Location, _}) ->
+ find_resource_module(Type, Location);
+get_resource_type({Type, _, _, Location}) ->
+ find_resource_module(Type, Location);
+get_resource_type(_) ->
+ rebar_pkg_resource.
-source_engine_avail(Name, Source)
- when Name == hg; Name == git; Name == svn; Name == bzr; Name == rsync;
- Name == fossil; Name == p4 ->
- case vcs_client_vsn(Name) >= required_vcs_client_vsn(Name) of
- true ->
- true;
+find_resource_module(Type, Location) ->
+ case lists:keyfind(Type, 1, ?RESOURCES) of
false ->
- ?ABORT("Rebar requires version ~p or higher of ~s to process ~p\n",
- [required_vcs_client_vsn(Name), Name, Source])
+ case code:which(Type) of
+ non_existing ->
+ {error, io_lib:format("Cannot handle dependency ~s.~n"
+ " No module for resource type ~p", [Location, Type])};
+ _ ->
+ Type
+ end;
+ {Type, Module} ->
+ Module
end.
-
-vcs_client_vsn(false, _VsnArg, _VsnRegex) ->
- false;
-vcs_client_vsn(Path, VsnArg, VsnRegex) ->
- {ok, Info} = rebar_utils:sh(Path ++ VsnArg, [{env, [{"LANG", "C"}]},
- {use_stdout, false}]),
- case re:run(Info, VsnRegex, [{capture, all_but_first, list}]) of
- {match, Match} ->
- list_to_tuple([list_to_integer(S) || S <- Match]);
- _ ->
- false
- end.
-
-required_vcs_client_vsn(p4) -> {2013, 1};
-required_vcs_client_vsn(hg) -> {1, 1};
-required_vcs_client_vsn(git) -> {1, 5};
-required_vcs_client_vsn(bzr) -> {2, 0};
-required_vcs_client_vsn(svn) -> {1, 6};
-required_vcs_client_vsn(rsync) -> {2, 0};
-required_vcs_client_vsn(fossil) -> {1, 0}.
-
-vcs_client_vsn(p4) ->
- vcs_client_vsn(rebar_utils:find_executable("p4"), " -V",
- "Rev\\. .*/(\\d+)\\.(\\d)/");
-vcs_client_vsn(hg) ->
- vcs_client_vsn(rebar_utils:find_executable("hg"), " --version",
- "version (\\d+).(\\d+)");
-vcs_client_vsn(git) ->
- vcs_client_vsn(rebar_utils:find_executable("git"), " --version",
- "git version (\\d+).(\\d+)");
-vcs_client_vsn(bzr) ->
- vcs_client_vsn(rebar_utils:find_executable("bzr"), " --version",
- "Bazaar \\(bzr\\) (\\d+).(\\d+)");
-vcs_client_vsn(svn) ->
- vcs_client_vsn(rebar_utils:find_executable("svn"), " --version",
- "svn, version (\\d+).(\\d+)");
-vcs_client_vsn(rsync) ->
- vcs_client_vsn(rebar_utils:find_executable("rsync"), " --version",
- "rsync version (\\d+).(\\d+)");
-vcs_client_vsn(fossil) ->
- vcs_client_vsn(rebar_utils:find_executable("fossil"), " version",
- "version (\\d+).(\\d+)").
-
-has_vcs_dir(p4, _) ->
- true;
-has_vcs_dir(git, Dir) ->
- filelib:is_dir(filename:join(Dir, ".git"));
-has_vcs_dir(hg, Dir) ->
- filelib:is_dir(filename:join(Dir, ".hg"));
-has_vcs_dir(bzr, Dir) ->
- filelib:is_dir(filename:join(Dir, ".bzr"));
-has_vcs_dir(svn, Dir) ->
- filelib:is_dir(filename:join(Dir, ".svn"))
- orelse filelib:is_dir(filename:join(Dir, "_svn"));
-has_vcs_dir(rsync, _) ->
- true;
-has_vcs_dir(_, _) ->
- true.
-
-print_source({App, _, Source}) ->
- ?CONSOLE("~s~n", [format_source(App, Source)]).
-
-format_source(App, {p4, Url}) ->
- format_source(App, {p4, Url, "#head"});
-format_source(App, {git, Url}) ->
- ?FMT("~p BRANCH ~s ~s", [App, "HEAD", Url]);
-format_source(App, {git, Url, ""}) ->
- ?FMT("~p BRANCH ~s ~s", [App, "HEAD", Url]);
-format_source(App, {git, Url, {branch, Branch}}) ->
- ?FMT("~p BRANCH ~s ~s", [App, Branch, Url]);
-format_source(App, {git, Url, {tag, Tag}}) ->
- ?FMT("~p TAG ~s ~s", [App, Tag, Url]);
-format_source(App, {_, Url, Rev}) ->
- ?FMT("~p REV ~s ~s", [App, Rev, Url]);
-format_source(App, undefined) ->
- ?FMT("~p", [App]).
diff --git a/src/rebar_git_resource.erl b/src/rebar_git_resource.erl
new file mode 100644
index 0000000..a6b60d5
--- /dev/null
+++ b/src/rebar_git_resource.erl
@@ -0,0 +1,146 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+-module(rebar_git_resource).
+
+-behaviour(rebar_resource).
+
+-export([lock/2
+ ,download/2
+ ,needs_update/2
+ ,make_vsn/1]).
+
+-include("rebar.hrl").
+
+lock(AppDir, {git, Url, _}) ->
+ Ref = string:strip(
+ os:cmd("git --git-dir='" ++ AppDir ++ "/.git' rev-parse --verify HEAD")
+ ,both, $\n),
+ {git, Url, {ref, Ref}}.
+
+%% Return true if either the git url or tag/branch/ref is not the same as the currently
+%% checked out git repo for the dep
+needs_update(Dir, {git, Url, {tag, Tag}}) ->
+ {ok, CurrentUrl} = rebar_utils:sh(?FMT("git config --get remote.origin.url", []),
+ [{cd, Dir}]),
+ {ok, Current} = rebar_utils:sh(?FMT("git describe --tags --exact-match", []),
+ [{cd, Dir}]),
+ Current1 = string:strip(string:strip(Current, both, $\n), both, $\r),
+ CurrentUrl1 = string:strip(string:strip(CurrentUrl, both, $\n), both, $\r),
+ ?DEBUG("Comparing git tag ~s with ~s and url ~s with ~s~n", [Tag, Current1, Url, CurrentUrl1]),
+ not ((Current1 =:= Tag) andalso (CurrentUrl1 =:= Url));
+needs_update(Dir, {git, Url, {branch, Branch}}) ->
+ {ok, CurrentUrl} = rebar_utils:sh(?FMT("git config --get remote.origin.url", []),
+ [{cd, Dir}]),
+ {ok, Current} = rebar_utils:sh(?FMT("git symbolic-ref -q --short HEAD", []),
+ [{cd, Dir}]),
+ Current1 = string:strip(string:strip(Current, both, $\n), both, $\r),
+ CurrentUrl1 = string:strip(string:strip(CurrentUrl, both, $\n), both, $\r),
+ ?DEBUG("Comparing git branch ~s with ~s and url ~s with ~s~n", [Branch, Current1, Url, CurrentUrl1]),
+ not ((Current1 =:= Branch) andalso (CurrentUrl1 =:= Url));
+needs_update(Dir, {git, Url, Ref}) ->
+ case Ref of
+ {ref, Ref1} ->
+ Ref1;
+ Ref1 ->
+ Ref1
+ end,
+ {ok, CurrentUrl} = rebar_utils:sh(?FMT("git config --get remote.origin.url", []),
+ [{cd, Dir}]),
+ {ok, Current} = rebar_utils:sh(?FMT("git rev-parse -q HEAD", []),
+ [{cd, Dir}]),
+ Current1 = string:strip(string:strip(Current, both, $\n), both, $\r),
+ CurrentUrl1 = string:strip(string:strip(CurrentUrl, both, $\n), both, $\r),
+ ?DEBUG("Comparing git ref ~s with ~s and url ~s with ~s~n", [Ref1, Current1, Url, CurrentUrl1]),
+ not ((Current1 =:= Ref1) andalso (CurrentUrl1 =:= Url)).
+
+download(Dir, {git, Url}) ->
+ ?WARN("WARNING: It is recommended to use {branch, Name}, {tag, Tag} or {ref, Ref}, otherwise updating the dep may not work as expected.~n", []),
+ download(Dir, {git, Url, {branch, "HEAD"}});
+download(Dir, {git, Url, ""}) ->
+ ?WARN("WARNING: It is recommended to use {branch, Name}, {tag, Tag} or {ref, Ref}, otherwise updating the dep may not work as expected.~n", []),
+ download(Dir, {git, Url, {branch, "HEAD"}});
+download(Dir, {git, Url, {branch, Branch}}) ->
+ ok = filelib:ensure_dir(Dir),
+ rebar_utils:sh(?FMT("git clone ~s ~s -b ~s --single-branch",
+ [Url, filename:basename(Dir), Branch]),
+ [{cd, filename:dirname(Dir)}]);
+download(Dir, {git, Url, {tag, Tag}}) ->
+ ok = filelib:ensure_dir(Dir),
+ rebar_utils:sh(?FMT("git clone ~s ~s -b ~s --single-branch",
+ [Url, filename:basename(Dir), Tag]),
+ [{cd, filename:dirname(Dir)}]);
+download(Dir, {git, Url, {ref, Ref}}) ->
+ ok = filelib:ensure_dir(Dir),
+ rebar_utils:sh(?FMT("git clone -n ~s ~s", [Url, filename:basename(Dir)]),
+ [{cd, filename:dirname(Dir)}]),
+ rebar_utils:sh(?FMT("git checkout -q ~s", [Ref]), [{cd, Dir}]);
+download(Dir, {git, Url, Rev}) ->
+ ?WARN("WARNING: It is recommended to use {branch, Name}, {tag, Tag} or {ref, Ref}, otherwise updating the dep may not work as expected.~n", []),
+ ok = filelib:ensure_dir(Dir),
+ rebar_utils:sh(?FMT("git clone -n ~s ~s", [Url, filename:basename(Dir)]),
+ [{cd, filename:dirname(Dir)}]),
+ rebar_utils:sh(?FMT("git checkout -q ~s", [Rev]), [{cd, Dir}]).
+
+make_vsn(Dir) ->
+ Cwd = file:get_cwd(),
+ try
+ ok = file:set_cwd(Dir),
+ {Vsn, RawRef, RawCount} = collect_default_refcount(),
+ {plain, build_vsn_string(Vsn, RawRef, RawCount)}
+ after
+ file:set_cwd(Cwd)
+ end.
+
+%% Internal functions
+
+collect_default_refcount() ->
+ %% Get the tag timestamp and minimal ref from the system. The
+ %% timestamp is really important from an ordering perspective.
+ RawRef = os:cmd("git log -n 1 --pretty=format:'%h\n' "),
+
+ {Tag, TagVsn} = parse_tags(),
+ RawCount =
+ case Tag of
+ undefined ->
+ os:cmd("git rev-list HEAD | wc -l");
+ _ ->
+ get_patch_count(Tag)
+ end,
+ {TagVsn, RawRef, RawCount}.
+
+build_vsn_string(Vsn, RawRef, RawCount) ->
+ %% Cleanup the tag and the Ref information. Basically leading 'v's and
+ %% whitespace needs to go away.
+ RefTag = case RawRef of
+ undefined ->
+ "";
+ RawRef ->
+ [".ref", re:replace(RawRef, "\\s", "", [global])]
+ end,
+ Count = erlang:iolist_to_binary(re:replace(RawCount, "\\s", "", [global])),
+
+ %% Create the valid [semver](http://semver.org) version from the tag
+ case Count of
+ <<"0">> ->
+ erlang:binary_to_list(erlang:iolist_to_binary(Vsn));
+ _ ->
+ erlang:binary_to_list(erlang:iolist_to_binary([Vsn, "+build.",
+ Count, RefTag]))
+ end.
+
+get_patch_count(RawRef) ->
+ Ref = re:replace(RawRef, "\\s", "", [global]),
+ Cmd = io_lib:format("git rev-list ~s..HEAD | wc -l",
+ [Ref]),
+ os:cmd(Cmd).
+
+parse_tags() ->
+ first_valid_tag(os:cmd("git log --oneline --decorate | fgrep \"tag: \" -1000")).
+
+first_valid_tag(Line) ->
+ case re:run(Line, "(\\(|\\s)tag:\\s(v([^,\\)]+))", [{capture, [2, 3], list}]) of
+ {match,[Tag, Vsn]} ->
+ {Tag, Vsn};
+ nomatch ->
+ {undefined, "0.0.0"}
+ end.
diff --git a/src/rebar_hooks.erl b/src/rebar_hooks.erl
new file mode 100644
index 0000000..2599d8e
--- /dev/null
+++ b/src/rebar_hooks.erl
@@ -0,0 +1,24 @@
+-module(rebar_hooks).
+
+-export([run_compile_hooks/4]).
+
+run_compile_hooks(Dir, Type, Command, State) ->
+ Hooks = rebar_state:get(State, Type, []),
+ lists:foreach(fun({_, C, _}=Hook) when C =:= Command ->
+ apply_hook(Dir, [], Hook);
+ ({C, _}=Hook) when C =:= Command ->
+ apply_hook(Dir, [], Hook);
+ (_) ->
+ continue
+ end, Hooks).
+
+apply_hook(Dir, Env, {Arch, Command, Hook}) ->
+ case rebar_utils:is_arch(Arch) of
+ true ->
+ apply_hook(Dir, Env, {Command, Hook});
+ false ->
+ ok
+ end;
+apply_hook(Dir, Env, {Command, Hook}) ->
+ Msg = lists:flatten(io_lib:format("Hook for ~p failed!~n", [Command])),
+ rebar_utils:sh(Hook, [{cd, Dir}, {env, Env}, {abort_on_error, Msg}]).
diff --git a/src/rebar_pkg_resource.erl b/src/rebar_pkg_resource.erl
new file mode 100644
index 0000000..5cd6fc8
--- /dev/null
+++ b/src/rebar_pkg_resource.erl
@@ -0,0 +1,32 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+-module(rebar_pkg_resource).
+
+-behaviour(rebar_resource).
+
+-export([lock/2
+ ,download/2
+ ,needs_update/2
+ ,make_vsn/1]).
+
+-include("rebar.hrl").
+
+lock(_AppDir, Source) ->
+ Source.
+
+needs_update(Dir, {pkg, _Name, Vsn, _Url}) ->
+ [AppInfo] = rebar_app_discover:find_apps([Dir], all),
+ case rebar_app_info:original_vsn(AppInfo) =:= ec_cnv:to_list(Vsn) of
+ true ->
+ false;
+ false ->
+ true
+ end.
+
+download(Dir, {pkg, _Name, _Vsn, Url}) ->
+ TmpFile = filename:join(Dir, "package.tar.gz"),
+ {ok, saved_to_file} = httpc:request(get, {binary_to_list(Url), []}, [], [{stream, TmpFile}]),
+ {tarball, TmpFile}.
+
+make_vsn(_) ->
+ {error, "Replacing version of type pkg not supported."}.
diff --git a/src/rebar_prv_clean.erl b/src/rebar_prv_clean.erl
index 72b85dc..a64e63a 100644
--- a/src/rebar_prv_clean.erl
+++ b/src/rebar_prv_clean.erl
@@ -27,18 +27,56 @@ init(State) ->
{example, "rebar clean"},
{short_desc, "Remove compiled beam files from apps."},
{desc, ""},
- {opts, []}])),
+ {opts, [{all, $a, "all", undefined, "Clean all apps include deps"}]}])),
{ok, State1}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
ProjectApps = rebar_state:project_apps(State),
- lists:foreach(fun(AppInfo) ->
- ?INFO("Cleaning out ~s...~n", [rebar_app_info:name(AppInfo)]),
- rebar_erlc_compiler:clean(State, ec_cnv:to_list(rebar_app_info:dir(AppInfo)))
- end, ProjectApps),
+ {all, All} = handle_args(State),
+
+ case All of
+ true ->
+ DepsDir = rebar_state:get(State, deps_dir, ?DEFAULT_DEPS_DIR),
+ DepApps = rebar_app_discover:find_apps([DepsDir], all);
+ false ->
+ DepApps = []
+ end,
+
+ %% Need to allow global config vars used on deps
+ %% Right now no way to differeniate and just give deps a new state
+ EmptyState = rebar_state:new(),
+ clean_apps(EmptyState, DepApps),
+
+ Cwd = rebar_utils:get_cwd(),
+ rebar_hooks:run_compile_hooks(Cwd, pre_hooks, clean, State),
+ clean_apps(State, ProjectApps),
+ rebar_hooks:run_compile_hooks(Cwd, post_hooks, clean, State),
+
{ok, State}.
-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}.
format_error(Reason, State) ->
{io_lib:format("~p", [Reason]), State}.
+
+%% ===================================================================
+%% Internal functions
+%% ===================================================================
+
+clean_apps(State, Apps) ->
+ lists:foreach(fun(AppInfo) ->
+ AppDir = rebar_app_info:dir(AppInfo),
+ C = rebar_config:consult(AppDir),
+ S = rebar_state:new(State, C, AppDir),
+
+ ?INFO("Cleaning out ~s...~n", [rebar_app_info:name(AppInfo)]),
+ %% Legacy hook support
+ rebar_hooks:run_compile_hooks(AppDir, pre_hooks, clean, S),
+ rebar_erlc_compiler:clean(State, ec_cnv:to_list(rebar_app_info:dir(AppInfo))),
+ rebar_hooks:run_compile_hooks(AppDir, post_hooks, clean, S)
+ end, Apps).
+
+handle_args(State) ->
+ {Args, _} = rebar_state:command_parsed_args(State),
+ All = proplists:get_value(all, Args, false),
+ {all, All}.
diff --git a/src/rebar_prv_compile.erl b/src/rebar_prv_compile.erl
index 30611cd..d80586d 100644
--- a/src/rebar_prv_compile.erl
+++ b/src/rebar_prv_compile.erl
@@ -31,23 +31,31 @@ init(State) ->
{short_desc, "Compile apps .app.src and .erl files."},
{desc, ""},
{opts, [
- {jobs, $j, "jobs", integer, JobsHelp}
+ {jobs, $j, "jobs", integer, JobsHelp}
]}])),
{ok, State1}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
{ok, State1} = handle_args(State),
+ Jobs = rebar_state:get(State1, jobs),
ProjectApps = rebar_state:project_apps(State1),
Deps = rebar_state:get(State1, deps_to_build, []),
- lists:foreach(fun(AppInfo) ->
- AppDir = rebar_app_info:dir(AppInfo),
- C = rebar_config:consult(AppDir),
- S = rebar_state:new(State1, C, AppDir),
- build(S, AppInfo)
- end, Deps++ProjectApps),
+ %% Need to allow global config vars used on deps
+ %% Right now no way to differeniate and just give deps a new state
+ EmptyState = rebar_state:new(),
+ EmptyState1 = rebar_state:set(EmptyState, jobs, Jobs),
+ build_apps(EmptyState1, Deps),
+
+ %% Use the project State for building project apps
+ Cwd = rebar_utils:get_cwd(),
+ rebar_hooks:run_compile_hooks(Cwd, pre_hooks, compile, State1),
+ %% Set hooks to empty so top-level hooks aren't run for each project app
+ State2 = rebar_state:set(rebar_state:set(State1, post_hooks, []), pre_hooks, []),
+ build_apps(State2, ProjectApps),
+ rebar_hooks:run_compile_hooks(Cwd, post_hooks, compile, State1),
{ok, State1}.
@@ -55,6 +63,18 @@ do(State) ->
format_error(Reason, State) ->
{io_lib:format("~p", [Reason]), State}.
+build_apps(State, Apps) ->
+ lists:foreach(fun(AppInfo) ->
+ AppDir = rebar_app_info:dir(AppInfo),
+ C = rebar_config:consult(AppDir),
+ S = rebar_state:new(State, C, AppDir),
+
+ %% Legacy hook support
+ rebar_hooks:run_compile_hooks(AppDir, pre_hooks, compile, S),
+ build(S, AppInfo),
+ rebar_hooks:run_compile_hooks(AppDir, post_hooks, compile, S)
+ end, Apps).
+
build(State, AppInfo) ->
?INFO("Compiling ~s~n", [rebar_app_info:name(AppInfo)]),
rebar_erlc_compiler:compile(State, ec_cnv:to_list(rebar_app_info:dir(AppInfo))),
diff --git a/src/rebar_prv_install_deps.erl b/src/rebar_prv_install_deps.erl
index 522420d..9fb1630 100644
--- a/src/rebar_prv_install_deps.erl
+++ b/src/rebar_prv_install_deps.erl
@@ -68,19 +68,26 @@ init(State) ->
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
ProjectApps = rebar_state:project_apps(State),
- {ok, State1} = case rebar_state:get(State, locks, []) of
- [] ->
- handle_deps(State, rebar_state:get(State, deps, []));
- Locks ->
- handle_deps(State, Locks)
- end,
-
- Source = ProjectApps ++ rebar_state:src_apps(State1),
- case rebar_topo:sort_apps(Source) of
- {ok, Sort} ->
- {ok, rebar_state:set(State1, deps_to_build, lists:dropwhile(fun rebar_app_info:valid/1, Sort -- ProjectApps))};
- {error, Error} ->
- {error, Error}
+ try
+ {ok, State1} = case rebar_state:get(State, locks, []) of
+ [] ->
+ handle_deps(State, rebar_state:get(State, deps, []));
+ Locks ->
+ handle_deps(State, Locks)
+ end,
+
+ Source = ProjectApps ++ rebar_state:src_apps(State1),
+ case rebar_topo:sort_apps(Source) of
+ {ok, Sort} ->
+ {ok, rebar_state:set(State1, deps_to_build,
+ lists:dropwhile(fun rebar_app_info:valid/1, Sort -- ProjectApps))};
+ {error, Error} ->
+ {error, Error}
+ end
+ catch
+ %% maybe_fetch will maybe_throw an exception to break out of some loops
+ _:Reason ->
+ {error, Reason}
end.
-spec format_error(any(), rebar_state:t()) -> {iolist(), rebar_state:t()}.
@@ -102,7 +109,7 @@ handle_deps(State, Deps) ->
handle_deps(State, Deps, false).
-spec handle_deps(rebar_state:t(), [dep()], boolean() | {true, binary(), integer()})
- -> {ok, rebar_state:t()}.
+ -> {ok, rebar_state:t()} | {error, string()}.
handle_deps(State, [], _) ->
{ok, State};
handle_deps(State, Deps, Update) ->
@@ -116,10 +123,11 @@ handle_deps(State, Deps, Update) ->
SrcDeps),
%% Fetch transitive src deps
- State2 = update_src_deps(0, State1, Update),
+ {State2, _Seen} = update_src_deps(0, State1, Update, sets:new()),
+
Solved = case rebar_state:pkg_deps(State2) of
[] -> %% No pkg deps
- [];
+ [];
PkgDeps1 ->
%% Find pkg deps needed
{ok, S} = rlx_depsolver:solve(Graph, PkgDeps1),
@@ -128,12 +136,12 @@ handle_deps(State, Deps, Update) ->
AppInfo <- package_to_app(DepsDir
,Packages
,Pkg),
- maybe_fetch(AppInfo, Update)]
+ maybe_fetch(AppInfo, Update, sets:new())]
end,
AllDeps = lists:ukeymerge(2
- ,lists:ukeysort(2, rebar_state:src_apps(State2))
- ,lists:ukeysort(2, Solved)),
+ ,lists:ukeysort(2, rebar_state:src_apps(State2))
+ ,lists:ukeysort(2, Solved)),
%% Sort all apps to build order
State3 = rebar_state:set(State2, all_deps, AllDeps),
{ok, State3}.
@@ -154,37 +162,42 @@ package_to_app(DepsDir, Packages, Pkg={_, Vsn}) ->
{ok, AppInfo} = rebar_app_info:new(Name, FmtVsn),
AppInfo1 = rebar_app_info:deps(AppInfo, PkgDeps),
AppInfo2 = rebar_app_info:dir(AppInfo1, get_deps_dir(DepsDir, Name)),
- [rebar_app_info:source(AppInfo2, Link)]
+ [rebar_app_info:source(AppInfo2, {pkg, Name, FmtVsn, Link})]
end.
--spec update_src_deps(integer(), rebar_state:t(), boolean()) -> rebar_state:t().
-update_src_deps(Level, State, Update) ->
+-spec update_src_deps(integer(), rebar_state:t(), boolean(), sets:set(binary())) ->
+ {rebar_state:t(), [binary()]}.
+update_src_deps(Level, State, Update, Seen) ->
SrcDeps = rebar_state:src_deps(State),
- case lists:foldl(fun(AppInfo, {SrcDepsAcc, PkgDepsAcc, StateAcc}) ->
- case Update of
- {true, UpdateName, UpdateLevel} ->
- handle_update(AppInfo
- ,UpdateName
- ,UpdateLevel
- ,SrcDepsAcc
- ,PkgDepsAcc
- ,Level
- ,StateAcc);
- _ ->
- maybe_fetch(AppInfo, false),
- handle_dep(AppInfo
- ,SrcDepsAcc
- ,PkgDepsAcc
- ,Level
- ,StateAcc)
- end
- end, {[], rebar_state:pkg_deps(State), State}, SrcDeps) of
- {[], NewPkgDeps, State1} ->
- rebar_state:pkg_deps(State1, NewPkgDeps);
- {NewSrcDeps, NewPkgDeps, State1} ->
+ case lists:foldl(fun(AppInfo, {SrcDepsAcc, PkgDepsAcc, StateAcc, SeenAcc}) ->
+ SeenAcc1 = sets:add_element(rebar_app_info:name(AppInfo), SeenAcc),
+ {SrcDepsAcc1, PkgDepsAcc1, StateAcc1} =
+ case Update of
+ {true, UpdateName, UpdateLevel} ->
+ handle_update(AppInfo
+ ,UpdateName
+ ,UpdateLevel
+ ,SrcDepsAcc
+ ,PkgDepsAcc
+ ,Level
+ ,StateAcc);
+ _ ->
+ maybe_fetch(AppInfo, false, SeenAcc),
+ handle_dep(AppInfo
+ ,SrcDepsAcc
+ ,PkgDepsAcc
+ ,Level
+ ,StateAcc)
+
+ end,
+ {SrcDepsAcc1, PkgDepsAcc1, StateAcc1, SeenAcc1}
+ end, {[], rebar_state:pkg_deps(State), State, Seen}, SrcDeps) of
+ {[], NewPkgDeps, State1, Seen1} ->
+ {rebar_state:pkg_deps(State1, NewPkgDeps), Seen1};
+ {NewSrcDeps, NewPkgDeps, State1, Seen1} ->
State2 = rebar_state:pkg_deps(State1, NewPkgDeps),
State3 = rebar_state:src_deps(State2, NewSrcDeps),
- update_src_deps(Level+1, State3, Update)
+ update_src_deps(Level+1, State3, Update, Seen1)
end.
handle_update(AppInfo, UpdateName, UpdateLevel, SrcDeps, PkgDeps, Level, State) ->
@@ -194,7 +207,7 @@ handle_update(AppInfo, UpdateName, UpdateLevel, SrcDeps, PkgDeps, Level, State)
case UpdateLevel < DepLevel
orelse Name =:= UpdateName of
true ->
- case maybe_fetch(AppInfo, true) of
+ case maybe_fetch(AppInfo, true, []) of
true ->
handle_dep(AppInfo
,SrcDeps
@@ -228,8 +241,9 @@ handle_dep(DepsDir, AppInfo) ->
{SrcDeps, PkgDeps} = parse_deps(DepsDir, Deps),
{AppInfo1, SrcDeps, PkgDeps}.
--spec maybe_fetch(rebar_app_info:t(), boolean() | {true, binary(), integer()}) -> boolean().
-maybe_fetch(AppInfo, Update) ->
+-spec maybe_fetch(rebar_app_info:t(), boolean() | {true, binary(), integer()},
+ sets:set(binary())) -> boolean().
+maybe_fetch(AppInfo, Update, Seen) ->
AppDir = ec_cnv:to_list(rebar_app_info:dir(AppInfo)),
Apps = rebar_app_discover:find_apps(["_checkouts"], all),
case rebar_app_utils:find(rebar_app_info:name(AppInfo), Apps) of
@@ -253,10 +267,31 @@ maybe_fetch(AppInfo, Update) ->
true ->
?INFO("Fetching ~s~n", [rebar_app_info:name(AppInfo)]),
Source = rebar_app_info:source(AppInfo),
- rebar_fetch:download_source(AppDir, Source),
- true;
+ case rebar_fetch:download_source(AppDir, Source) of
+ {error, Reason} ->
+ throw(Reason);
+ Result ->
+ Result
+ end;
_ ->
- false
+ case sets:is_element(rebar_app_info:name(AppInfo), Seen) of
+ true ->
+ false;
+ false ->
+ Source = rebar_app_info:source(AppInfo),
+ case rebar_fetch:needs_update(AppDir, Source) of
+ true ->
+ ?INFO("Updating ~s~n", [rebar_app_info:name(AppInfo)]),
+ case rebar_fetch:download_source(AppDir, Source) of
+ {error, Reason} ->
+ throw(Reason);
+ Result ->
+ Result
+ end;
+ false ->
+ false
+ end
+ end
end
end.
diff --git a/src/rebar_prv_tar.erl b/src/rebar_prv_tar.erl
index 04a1b33..03117ff 100644
--- a/src/rebar_prv_tar.erl
+++ b/src/rebar_prv_tar.erl
@@ -34,9 +34,9 @@ init(State) ->
do(State) ->
case rebar_state:get(State, relx, []) of
[] ->
- relx:main(["release tar"]);
+ relx:main(["release", "tar"]);
Config ->
- relx:main([{config, Config}], ["release tar"])
+ relx:main([{config, Config}], ["release", "tar"])
end,
{ok, State}.
diff --git a/src/rebar_prv_upgrade.erl b/src/rebar_prv_upgrade.erl
index 1668e1c..8c1c84e 100644
--- a/src/rebar_prv_upgrade.erl
+++ b/src/rebar_prv_upgrade.erl
@@ -12,7 +12,7 @@
-include("rebar.hrl").
-define(PROVIDER, upgrade).
--define(DEPS, [lock]).
+-define(DEPS, []).
%% ===================================================================
%% Public API
@@ -37,14 +37,13 @@ init(State) ->
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
{Args, _} = rebar_state:command_parsed_args(State),
- Name = proplists:get_value(package, Args),
- ?INFO("Updating ~s~n", [Name]),
+ Name = ec_cnv:to_binary(proplists:get_value(package, Args)),
Locks = rebar_state:get(State, locks, []),
- case lists:keyfind(ec_cnv:to_binary(Name), 1, Locks) of
+ case lists:keyfind(Name, 1, Locks) of
{_, _, _, Level} ->
Deps = rebar_state:get(State, deps),
- Dep = lists:keyfind(list_to_atom(Name), 1, Deps),
- rebar_prv_install_deps:handle_deps(State, [Dep], {true, ec_cnv:to_binary(Name), Level}),
+ Dep = lists:keyfind(binary_to_atom(Name, utf8), 1, Deps),
+ rebar_prv_install_deps:handle_deps(State, [Dep], {true, Name, Level}),
{ok, State};
_ ->
{error, io_lib:format("No such dependency ~s~n", [Name])}
diff --git a/src/rebar_resource.erl b/src/rebar_resource.erl
new file mode 100644
index 0000000..04b8d73
--- /dev/null
+++ b/src/rebar_resource.erl
@@ -0,0 +1,43 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+-module(rebar_resource).
+
+-export([]).
+
+-export_types([resource/0
+ ,type/0
+ ,location/0
+ ,ref/0]).
+
+-type resource() :: {type(), location(), ref()}.
+-type type() :: atom().
+-type location() :: string().
+-type ref() :: any().
+
+-ifdef(have_callback_support).
+
+%% In the case where R14 or lower is being used to compile the system
+%% we need to export a behaviour info
+-export([behaviour_info/1]).
+
+-spec behaviour_info(atom()) -> [{atom(), arity()}] | undefined.
+behaviour_info(callbacks) ->
+ [{lock, 2},
+ {download, 2},
+ {needs_update,2},
+ {make_vsn, 1}];
+behaviour_info(_) ->
+ undefined.
+
+-else.
+
+-callback lock(file:filename_all(), tuple()) ->
+ rebar_resource:resource().
+-callback download(file:filename_all(), tuple()) ->
+ {tarball, file:filename_all()} | {ok, any()} | {error, any()}.
+-callback needs_update(file:filename_all(), tuple()) ->
+ {tarball, file:filename_all()} | {ok, any()} | {error, any()}.
+-callback make_vsn(file:filename_all()) ->
+ {plain, string()} | {error, string()}.
+
+-endif.
diff --git a/src/rebar_topo.erl b/src/rebar_topo.erl
index de3351a..d9f426d 100644
--- a/src/rebar_topo.erl
+++ b/src/rebar_topo.erl
@@ -61,7 +61,7 @@ sort_apps(Apps) ->
{ok, Names} ->
{ok, names_to_apps(Names, Apps)};
E ->
- {error, E}
+ E
end.
%% @doc Do a topological sort on the list of pairs.
diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl
index 87387be..ae1d126 100644
--- a/src/rebar_utils.erl
+++ b/src/rebar_utils.erl
@@ -135,7 +135,7 @@ sh(Command0, Options0) ->
?DEBUG("sh info:\n\tcwd: ~p\n\tcmd: ~s\n", [get_cwd(), Command0]),
?DEBUG("\topts: ~p\n", [Options0]),
- DefaultOptions = [use_stdout, abort_on_error],
+ DefaultOptions = [{use_stdout, false}, abort_on_error],
Options = [expand_sh_flag(V)
|| V <- proplists:compact(Options0 ++ DefaultOptions)],
@@ -438,13 +438,15 @@ escript_foldl(Fun, Acc, File) ->
end.
vcs_vsn_1(Vcs, Dir) ->
- case vcs_vsn_cmd(Vcs) of
+ case vcs_vsn_cmd(Vcs, Dir) of
{plain, VsnString} ->
VsnString;
{cmd, CmdString} ->
vcs_vsn_invoke(CmdString, Dir);
unknown ->
?ABORT("vcs_vsn: Unknown vsn format: ~p\n", [Vcs]);
+ {error, Reason} ->
+ ?ABORT("vcs_vsn: ~s\n", [Reason]);
Cmd ->
%% If there is a valid VCS directory in the application directory,
%% use that version info
@@ -471,15 +473,19 @@ vcs_vsn_1(Vcs, Dir) ->
end
end.
-vcs_vsn_cmd(git) -> "git describe --always --tags";
-vcs_vsn_cmd(p4) -> "echo #head";
-vcs_vsn_cmd(hg) -> "hg identify -i";
-vcs_vsn_cmd(bzr) -> "bzr revno";
-vcs_vsn_cmd(svn) -> "svnversion";
-vcs_vsn_cmd(fossil) -> "fossil info";
-vcs_vsn_cmd({cmd, _Cmd}=Custom) -> Custom;
-vcs_vsn_cmd(Version) when is_list(Version) -> {plain, Version};
-vcs_vsn_cmd(_) -> unknown.
+%% Temp work around for repos like relx that use "semver"
+vcs_vsn_cmd(VCS, Dir) when VCS =:= semver ; VCS =:= "semver" ->
+ rebar_git_resource:make_vsn(Dir);
+vcs_vsn_cmd(VCS, Dir) when VCS =:= git ; VCS =:= "git" ->
+ rebar_git_resource:make_vsn(Dir);
+vcs_vsn_cmd(VCS, Dir) when VCS =:= pkg ; VCS =:= "pkg" ->
+ rebar_pkg_resource:make_vsn(Dir);
+vcs_vsn_cmd({cmd, _Cmd}=Custom, _) ->
+ Custom;
+vcs_vsn_cmd(Version, _) when is_list(Version) ->
+ {plain, Version};
+vcs_vsn_cmd(_, _) ->
+ unknown.
vcs_vsn_invoke(Cmd, Dir) ->
{ok, VsnString} = rebar_utils:sh(Cmd, [{cd, Dir}, {use_stdout, false}]),