summaryrefslogtreecommitdiff
path: root/src/rebar_fetch.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/rebar_fetch.erl')
-rw-r--r--src/rebar_fetch.erl304
1 files changed, 63 insertions, 241 deletions
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]).