summaryrefslogtreecommitdiff
path: root/src/rebar_deps.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/rebar_deps.erl')
-rw-r--r--src/rebar_deps.erl386
1 files changed, 233 insertions, 153 deletions
diff --git a/src/rebar_deps.erl b/src/rebar_deps.erl
index dc2fe84..cd49343 100644
--- a/src/rebar_deps.erl
+++ b/src/rebar_deps.erl
@@ -42,7 +42,8 @@
-record(dep, { dir,
app,
vsn_regex,
- source }).
+ source,
+ is_raw }). %% is_raw = true means non-Erlang/OTP dependency
%% ===================================================================
%% Public API
@@ -52,50 +53,55 @@ preprocess(Config, _) ->
%% Side effect to set deps_dir globally for all dependencies from
%% top level down. Means the root deps_dir is honoured or the default
%% used globally since it will be set on the first time through here
- set_global_deps_dir(Config, rebar_config:get_global(deps_dir, [])),
+ Config1 = set_shared_deps_dir(Config, get_shared_deps_dir(Config, [])),
%% Get the list of deps for the current working directory and identify those
%% deps that are available/present.
- Deps = rebar_config:get_local(Config, deps, []),
- {AvailableDeps, MissingDeps} = find_deps(find, Deps),
+ Deps = rebar_config:get_local(Config1, deps, []),
+ {Config2, {AvailableDeps, MissingDeps}} = find_deps(Config1, find, Deps),
?DEBUG("Available deps: ~p\n", [AvailableDeps]),
?DEBUG("Missing deps : ~p\n", [MissingDeps]),
%% Add available deps to code path
- update_deps_code_path(AvailableDeps),
+ Config3 = update_deps_code_path(Config2, AvailableDeps),
%% If skip_deps=true, mark each dep dir as a skip_dir w/ the core so that
%% the current command doesn't run on the dep dir. However, pre/postprocess
%% WILL run (and we want it to) for transitivity purposes.
- case rebar_config:get_global(skip_deps, false) of
- "true" ->
- lists:foreach(fun (#dep{dir = Dir}) ->
- rebar_core:skip_dir(Dir)
- end, AvailableDeps);
- _ ->
- ok
- end,
+ NewConfig = case rebar_config:get_global(Config3, skip_deps, false) of
+ "true" ->
+ lists:foldl(
+ fun(#dep{dir = Dir}, C) ->
+ rebar_config:set_skip_dir(C, Dir)
+ end, Config3, AvailableDeps);
+ _ ->
+ Config3
+ end,
- %% Return all the available dep directories for process
- {ok, [D#dep.dir || D <- AvailableDeps]}.
+ %% Filtering out 'raw' dependencies so that no commands other than
+ %% deps-related can be executed on their directories.
+ NonRawAvailableDeps = [D || D <- AvailableDeps, not D#dep.is_raw],
+ %% Return all the available dep directories for process
+ {ok, NewConfig, dep_dirs(NonRawAvailableDeps)}.
-postprocess(_Config, _) ->
- case erlang:get(?MODULE) of
+postprocess(Config, _) ->
+ case rebar_config:get_xconf(Config, ?MODULE, undefined) of
undefined ->
{ok, []};
Dirs ->
- erlang:erase(?MODULE),
- {ok, Dirs}
+ NewConfig = rebar_config:erase_xconf(Config, ?MODULE),
+ {ok, NewConfig, Dirs}
end.
-compile(Config, AppFile) ->
- 'check-deps'(Config, AppFile).
+compile(Config, _) ->
+ {Config1, _AvailDeps} = do_check_deps(Config),
+ {ok, Config1}.
%% set REBAR_DEPS_DIR and ERL_LIBS environment variables
-setup_env(_Config) ->
- {true, DepsDir} = get_deps_dir(),
+setup_env(Config) ->
+ {true, DepsDir} = get_deps_dir(Config),
%% include rebar's DepsDir in ERL_LIBS
Separator = case os:type() of
{win32, nt} ->
@@ -111,65 +117,76 @@ setup_env(_Config) ->
end,
[{"REBAR_DEPS_DIR", DepsDir}, ERL_LIBS].
-'check-deps'(Config, _) ->
+%% common function used by 'check-deps' and 'compile'
+do_check_deps(Config) ->
%% Get the list of immediate (i.e. non-transitive) deps that are missing
Deps = rebar_config:get_local(Config, deps, []),
- case find_deps(find, Deps) of
- {_, []} ->
+ case find_deps(Config, find, Deps) of
+ {Config1, {AvailDeps, []}} ->
%% No missing deps
- ok;
- {_, MissingDeps} ->
+ {Config1, AvailDeps};
+ {_Config1, {_, MissingDeps}} ->
lists:foreach(fun (#dep{app=App, vsn_regex=Vsn, source=Src}) ->
?CONSOLE("Dependency not available: "
"~p-~s (~p)\n", [App, Vsn, Src])
end, MissingDeps),
- ?ABORT
+ ?FAIL
end.
+'check-deps'(Config, _) ->
+ {Config1, AvailDeps} = do_check_deps(Config),
+ {ok, save_dep_dirs(Config1, AvailDeps)}.
+
'get-deps'(Config, _) ->
%% Determine what deps are available and missing
Deps = rebar_config:get_local(Config, deps, []),
- {_AvailableDeps, MissingDeps} = find_deps(find, Deps),
+ {Config1, {_AvailableDeps, MissingDeps}} = find_deps(Config, find, Deps),
+ MissingDeps1 = [D || D <- MissingDeps, D#dep.source =/= undefined],
%% For each missing dep with a specified source, try to pull it.
- PulledDeps = [use_source(D) || D <- MissingDeps, D#dep.source /= undefined],
+ {Config2, PulledDeps} =
+ lists:foldl(fun(D, {C, PulledDeps0}) ->
+ {C1, D1} = use_source(C, D),
+ {C1, [D1 | PulledDeps0]}
+ end, {Config1, []}, MissingDeps1),
%% Add each pulled dep to our list of dirs for post-processing. This yields
%% the necessary transitivity of the deps
- erlang:put(?MODULE, [D#dep.dir || D <- PulledDeps]),
- ok.
+ {ok, save_dep_dirs(Config2, lists:reverse(PulledDeps))}.
'update-deps'(Config, _) ->
- %% Determine what deps are available and missing
- Deps = rebar_config:get_local(Config, deps, []),
- UpdatedDeps = [update_source(D) || D <- find_deps(read, Deps),
- D#dep.source /= undefined],
+ %% Determine what deps are required
+ RawDeps = rebar_config:get_local(Config, deps, []),
+ {Config1, Deps} = find_deps(Config, read, RawDeps),
+
+ %% Update each dep
+ UpdatedDeps = [update_source(Config1, D)
+ || D <- Deps, D#dep.source =/= undefined],
+
%% Add each updated dep to our list of dirs for post-processing. This yields
%% the necessary transitivity of the deps
- erlang:put(?MODULE, [D#dep.dir || D <- UpdatedDeps]),
- ok.
+ {ok, save_dep_dirs(Config1, UpdatedDeps)}.
'delete-deps'(Config, _) ->
%% Delete all the available deps in our deps/ directory, if any
- {true, DepsDir} = get_deps_dir(),
+ {true, DepsDir} = get_deps_dir(Config),
Deps = rebar_config:get_local(Config, deps, []),
- {AvailableDeps, _} = find_deps(find, Deps),
+ {Config1, {AvailableDeps, _}} = find_deps(Config, find, Deps),
_ = [delete_dep(D)
|| D <- AvailableDeps,
lists:prefix(DepsDir, D#dep.dir)],
- ok.
+ {ok, Config1}.
'list-deps'(Config, _) ->
Deps = rebar_config:get_local(Config, deps, []),
- case find_deps(find, Deps) of
- {AvailDeps, []} ->
+ case find_deps(Config, find, Deps) of
+ {Config1, {AvailDeps, []}} ->
lists:foreach(fun(Dep) -> print_source(Dep) end, AvailDeps),
- ok;
+ {ok, save_dep_dirs(Config1, AvailDeps)};
{_, MissingDeps} ->
?ABORT("Missing dependencies: ~p\n", [MissingDeps])
end.
-
%% ===================================================================
%% Internal functions
%% ===================================================================
@@ -177,19 +194,29 @@ setup_env(_Config) ->
%% Added because of trans deps,
%% need all deps in same dir and should be the one set by the root rebar.config
%% Sets a default if root config has no deps_dir set
-set_global_deps_dir(Config, []) ->
- rebar_config:set_global(deps_dir,
- rebar_config:get_local(Config, deps_dir, "deps"));
-set_global_deps_dir(_Config, _DepsDir) ->
- ok.
+set_shared_deps_dir(Config, []) ->
+ GlobalDepsDir = rebar_config:get_global(Config, deps_dir, "deps"),
+ DepsDir = rebar_config:get_local(Config, deps_dir, GlobalDepsDir),
+ rebar_config:set_xconf(Config, deps_dir, DepsDir);
+set_shared_deps_dir(Config, _DepsDir) ->
+ Config.
+
+get_shared_deps_dir(Config, Default) ->
+ rebar_config:get_xconf(Config, deps_dir, Default).
+
+get_deps_dir(Config) ->
+ get_deps_dir(Config, "").
+
+get_deps_dir(Config, App) ->
+ BaseDir = rebar_config:get_xconf(Config, base_dir, []),
+ DepsDir = get_shared_deps_dir(Config, "deps"),
+ {true, filename:join([BaseDir, DepsDir, App])}.
-get_deps_dir() ->
- get_deps_dir("").
+dep_dirs(Deps) ->
+ [D#dep.dir || D <- Deps].
-get_deps_dir(App) ->
- BaseDir = rebar_config:get_global(base_dir, []),
- DepsDir = rebar_config:get_global(deps_dir, "deps"),
- {true, filename:join([BaseDir, DepsDir, App])}.
+save_dep_dirs(Config, Deps) ->
+ rebar_config:set_xconf(Config, ?MODULE, dep_dirs(Deps)).
get_lib_dir(App) ->
%% Find App amongst the reachable lib directories
@@ -200,72 +227,83 @@ get_lib_dir(App) ->
Path -> {true, Path}
end.
-update_deps_code_path([]) ->
- ok;
-update_deps_code_path([Dep | Rest]) ->
- case is_app_available(Dep#dep.app, Dep#dep.vsn_regex, Dep#dep.dir) of
- {true, _} ->
- Dir = filename:join(Dep#dep.dir, "ebin"),
- ok = filelib:ensure_dir(filename:join(Dir, "dummy")),
- ?DEBUG("Adding ~s to code path~n", [Dir]),
- true = code:add_patha(Dir);
- {false, _} ->
- true
- end,
- update_deps_code_path(Rest).
-
-
-find_deps(find=Mode, Deps) ->
- find_deps(Mode, Deps, {[], []});
-find_deps(read=Mode, Deps) ->
- find_deps(Mode, Deps, []).
-
-find_deps(find, [], {Avail, Missing}) ->
- {lists:reverse(Avail), lists:reverse(Missing)};
-find_deps(read, [], Deps) ->
- lists:reverse(Deps);
-find_deps(Mode, [App | Rest], Acc) when is_atom(App) ->
- find_deps(Mode, [{App, ".*", undefined} | Rest], Acc);
-find_deps(Mode, [{App, VsnRegex} | Rest], Acc) when is_atom(App) ->
- find_deps(Mode, [{App, VsnRegex, undefined} | Rest], Acc);
-find_deps(Mode, [{App, VsnRegex, Source} | Rest], Acc) ->
+update_deps_code_path(Config, []) ->
+ Config;
+update_deps_code_path(Config, [Dep | Rest]) ->
+ Config2 =
+ case is_app_available(Config, Dep#dep.app,
+ Dep#dep.vsn_regex, Dep#dep.dir, Dep#dep.is_raw) of
+ {Config1, {true, _}} ->
+ Dir = filename:join(Dep#dep.dir, "ebin"),
+ ok = filelib:ensure_dir(filename:join(Dir, "dummy")),
+ ?DEBUG("Adding ~s to code path~n", [Dir]),
+ true = code:add_patha(Dir),
+ Config1;
+ {Config1, {false, _}} ->
+ Config1
+ end,
+ update_deps_code_path(Config2, Rest).
+
+find_deps(Config, find=Mode, Deps) ->
+ find_deps(Config, Mode, Deps, {[], []});
+find_deps(Config, read=Mode, Deps) ->
+ find_deps(Config, Mode, Deps, []).
+
+find_deps(Config, find, [], {Avail, Missing}) ->
+ {Config, {lists:reverse(Avail), lists:reverse(Missing)}};
+find_deps(Config, read, [], Deps) ->
+ {Config, lists:reverse(Deps)};
+find_deps(Config, Mode, [App | Rest], Acc) when is_atom(App) ->
+ find_deps(Config, Mode, [{App, ".*", undefined} | Rest], Acc);
+find_deps(Config, Mode, [{App, VsnRegex} | Rest], Acc) when is_atom(App) ->
+ find_deps(Config, Mode, [{App, VsnRegex, undefined} | Rest], Acc);
+find_deps(Config, Mode, [{App, VsnRegex, Source} | Rest], Acc) ->
+ find_deps(Config, Mode, [{App, VsnRegex, Source, []} | Rest], Acc);
+find_deps(Config, Mode, [{App, VsnRegex, Source, Opts} | Rest], Acc) when is_list(Opts) ->
Dep = #dep { app = App,
vsn_regex = VsnRegex,
- source = Source },
- {Availability, FoundDir} = find_dep(Dep),
- find_deps(Mode, Rest, acc_deps(Mode, Availability, Dep, FoundDir, Acc));
-find_deps(_Mode, [Other | _Rest], _Acc) ->
+ source = Source,
+ %% dependency is considered raw (i.e. non-Erlang/OTP) when
+ %% 'raw' option is present
+ is_raw = proplists:get_value(raw, Opts, false) },
+ {Config1, {Availability, FoundDir}} = find_dep(Config, Dep),
+ find_deps(Config1, Mode, Rest,
+ acc_deps(Mode, Availability, Dep, FoundDir, Acc));
+find_deps(_Config, _Mode, [Other | _Rest], _Acc) ->
?ABORT("Invalid dependency specification ~p in ~s\n",
[Other, rebar_utils:get_cwd()]).
-find_dep(Dep) ->
+find_dep(Config, Dep) ->
%% Find a dep based on its source,
%% e.g. {git, "https://github.com/mochi/mochiweb.git", "HEAD"}
%% Deps with a source must be found (or fetched) locally.
%% Those without a source may be satisfied from lib dir (get_lib_dir).
- find_dep(Dep, Dep#dep.source).
+ find_dep(Config, Dep, Dep#dep.source).
-find_dep(Dep, undefined) ->
+find_dep(Config, Dep, undefined) ->
%% 'source' is undefined. If Dep is not satisfied locally,
%% go ahead and find it amongst the lib_dir's.
- case find_dep_in_dir(Dep, get_deps_dir(Dep#dep.app)) of
- {avail, _Dir} = Avail -> Avail;
- {missing, _} -> find_dep_in_dir(Dep, get_lib_dir(Dep#dep.app))
+ case find_dep_in_dir(Config, Dep, get_deps_dir(Config, Dep#dep.app)) of
+ {_Config1, {avail, _Dir}} = Avail ->
+ Avail;
+ {Config1, {missing, _}} ->
+ find_dep_in_dir(Config1, Dep, get_lib_dir(Dep#dep.app))
end;
-find_dep(Dep, _Source) ->
+find_dep(Config, Dep, _Source) ->
%% _Source is defined. Regardless of what it is, we must find it
%% locally satisfied or fetch it from the original source
%% into the project's deps
- find_dep_in_dir(Dep, get_deps_dir(Dep#dep.app)).
+ find_dep_in_dir(Config, Dep, get_deps_dir(Config, Dep#dep.app)).
-find_dep_in_dir(_Dep, {false, Dir}) ->
- {missing, Dir};
-find_dep_in_dir(Dep, {true, Dir}) ->
+find_dep_in_dir(Config, _Dep, {false, Dir}) ->
+ {Config, {missing, Dir}};
+find_dep_in_dir(Config, Dep, {true, Dir}) ->
App = Dep#dep.app,
VsnRegex = Dep#dep.vsn_regex,
- case is_app_available(App, VsnRegex, Dir) of
- {true, _AppFile} -> {avail, Dir};
- {false, _} -> {missing, Dir}
+ IsRaw = Dep#dep.is_raw,
+ case is_app_available(Config, App, VsnRegex, Dir, IsRaw) of
+ {Config1, {true, _AppFile}} -> {Config1, {avail, Dir}};
+ {Config1, {false, _}} -> {Config1, {missing, Dir}}
end.
acc_deps(find, avail, Dep, AppDir, {Avail, Missing}) ->
@@ -288,57 +326,76 @@ require_source_engine(Source) ->
true = source_engine_avail(Source),
ok.
-is_app_available(App, VsnRegex, Path) ->
+%% IsRaw = false means regular Erlang/OTP dependency
+%%
+%% IsRaw = true means non-Erlang/OTP dependency, e.g. the one that does not
+%% have a proper .app file
+is_app_available(Config, App, VsnRegex, Path, _IsRaw = false) ->
?DEBUG("is_app_available, looking for App ~p with Path ~p~n", [App, Path]),
case rebar_app_utils:is_app_dir(Path) of
{true, AppFile} ->
- case rebar_app_utils:app_name(AppFile) of
- App ->
- Vsn = rebar_app_utils:app_vsn(AppFile),
+ case rebar_app_utils:app_name(Config, AppFile) of
+ {Config1, App} ->
+ {Config2, Vsn} = rebar_app_utils:app_vsn(Config1, AppFile),
?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, Path};
+ {Config2, {true, Path}};
nomatch ->
?WARN("~s has version ~p; requested regex was ~s\n",
[AppFile, Vsn, VsnRegex]),
- {false, {version_mismatch,
- {AppFile,
- {expected, VsnRegex}, {has, Vsn}}}}
+ {Config2,
+ {false, {version_mismatch,
+ {AppFile,
+ {expected, VsnRegex}, {has, Vsn}}}}}
end;
- OtherApp ->
+ {Config1, OtherApp} ->
?WARN("~s has application id ~p; expected ~p\n",
[AppFile, OtherApp, App]),
- {false, {name_mismatch,
- {AppFile, {expected, App}, {has, OtherApp}}}}
+ {Config1,
+ {false, {name_mismatch,
+ {AppFile, {expected, App}, {has, OtherApp}}}}}
end;
false ->
?WARN("Expected ~s to be an app dir (containing ebin/*.app), "
"but no .app found.\n", [Path]),
- {false, {missing_app_file, Path}}
+ {Config, {false, {missing_app_file, Path}}}
+ end;
+is_app_available(Config, App, _VsnRegex, Path, _IsRaw = true) ->
+ ?DEBUG("is_app_available, looking for Raw Depencency ~p with Path ~p~n", [App, Path]),
+ case filelib:is_dir(Path) of
+ true ->
+ %% TODO: look for version string in <Path>/VERSION file? Not clear
+ %% how to detect git/svn/hg/{cmd, ...} settings that can be passed
+ %% to rebar_utils:vcs_vsn/2 to obtain version dynamically
+ {Config, {true, Path}};
+ false ->
+ ?WARN("Expected ~s to be a raw dependency directory, "
+ "but no directory found.\n", [Path]),
+ {Config, {false, {missing_raw_dependency_directory, Path}}}
end.
-use_source(Dep) ->
- use_source(Dep, 3).
+use_source(Config, Dep) ->
+ use_source(Config, Dep, 3).
-use_source(Dep, 0) ->
+use_source(_Config, Dep, 0) ->
?ABORT("Failed to acquire source from ~p after 3 tries.\n",
[Dep#dep.source]);
-use_source(Dep, Count) ->
+use_source(Config, Dep, Count) ->
case filelib:is_dir(Dep#dep.dir) of
true ->
%% Already downloaded -- verify the versioning matches the regex
- case is_app_available(Dep#dep.app,
- Dep#dep.vsn_regex, Dep#dep.dir) of
- {true, _} ->
+ case is_app_available(Config, Dep#dep.app,
+ Dep#dep.vsn_regex, Dep#dep.dir, Dep#dep.is_raw) of
+ {Config1, {true, _}} ->
Dir = filename:join(Dep#dep.dir, "ebin"),
ok = filelib:ensure_dir(filename:join(Dir, "dummy")),
%% Available version matches up -- we're good to go;
%% add the app dir to our code path
true = code:add_patha(Dir),
- Dep;
- {false, Reason} ->
+ {Config1, Dep};
+ {_Config1, {false, Reason}} ->
%% The app that was downloaded doesn't match up (or had
%% errors or something). For the time being, abort.
?ABORT("Dependency dir ~s failed application validation "
@@ -347,9 +404,9 @@ use_source(Dep, Count) ->
false ->
?CONSOLE("Pulling ~p from ~p\n", [Dep#dep.app, Dep#dep.source]),
require_source_engine(Dep#dep.source),
- {true, TargetDir} = get_deps_dir(Dep#dep.app),
+ {true, TargetDir} = get_deps_dir(Config, Dep#dep.app),
download_source(TargetDir, Dep#dep.source),
- use_source(Dep#dep { dir = TargetDir }, Count-1)
+ use_source(Config, Dep#dep { dir = TargetDir }, Count-1)
end.
download_source(AppDir, {hg, Url, Rev}) ->
@@ -388,19 +445,31 @@ download_source(AppDir, {svn, Url, Rev}) ->
[{cd, filename:dirname(AppDir)}]);
download_source(AppDir, {rsync, Url}) ->
ok = filelib:ensure_dir(AppDir),
- rebar_utils:sh(?FMT("rsync -az --delete ~s/ ~s", [Url, AppDir]), []).
-
-update_source(Dep) ->
+ rebar_utils:sh(?FMT("rsync -az --delete ~s/ ~s", [Url, AppDir]), []);
+download_source(AppDir, {fossil, Url}) ->
+ download_source(AppDir, {fossil, Url, ""});
+download_source(AppDir, {fossil, Url, latest}) ->
+ download_source(AppDir, {fossil, Url, ""});
+download_source(AppDir, {fossil, Url, Version}) ->
+ Repository = filename:join(AppDir, filename:basename(AppDir) ++ ".fossil"),
+ ok = filelib:ensure_dir(Repository),
+ ok = file:set_cwd(AppDir),
+ rebar_utils:sh(?FMT("fossil clone ~s ~s", [Url, Repository]),
+ [{cd, AppDir}]),
+ rebar_utils:sh(?FMT("fossil open ~s ~s --nested", [Repository, Version]),
+ []).
+
+update_source(Config, Dep) ->
%% 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(Dep#dep.app),
+ {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]),
require_source_engine(Dep#dep.source),
- update_source(AppDir, Dep#dep.source),
+ update_source1(AppDir, Dep#dep.source),
Dep;
false ->
?WARN("Skipping update for ~p: "
@@ -408,32 +477,38 @@ update_source(Dep) ->
Dep
end.
-update_source(AppDir, {git, Url}) ->
- update_source(AppDir, {git, Url, {branch, "HEAD"}});
-update_source(AppDir, {git, Url, ""}) ->
- update_source(AppDir, {git, Url, {branch, "HEAD"}});
-update_source(AppDir, {git, _Url, {branch, Branch}}) ->
+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 origin/~s", [Branch]), ShOpts);
-update_source(AppDir, {git, _Url, {tag, Tag}}) ->
+update_source1(AppDir, {git, _Url, {tag, Tag}}) ->
ShOpts = [{cd, AppDir}],
rebar_utils:sh("git fetch --tags origin", ShOpts),
rebar_utils:sh(?FMT("git checkout -q ~s", [Tag]), ShOpts);
-update_source(AppDir, {git, _Url, Refspec}) ->
+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_source(AppDir, {svn, _Url, Rev}) ->
+update_source1(AppDir, {svn, _Url, Rev}) ->
rebar_utils:sh(?FMT("svn up -r ~s", [Rev]), [{cd, AppDir}]);
-update_source(AppDir, {hg, _Url, Rev}) ->
+update_source1(AppDir, {hg, _Url, Rev}) ->
rebar_utils:sh(?FMT("hg pull -u -r ~s", [Rev]), [{cd, AppDir}]);
-update_source(AppDir, {bzr, _Url, Rev}) ->
+update_source1(AppDir, {bzr, _Url, Rev}) ->
rebar_utils:sh(?FMT("bzr update -r ~s", [Rev]), [{cd, AppDir}]);
-update_source(AppDir, {rsync, Url}) ->
- rebar_utils:sh(?FMT("rsync -az --delete ~s/ ~s",[Url,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, latest}) ->
+ 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]), []).
%% ===================================================================
@@ -445,7 +520,8 @@ source_engine_avail(Source) ->
source_engine_avail(Name, Source).
source_engine_avail(Name, Source)
- when Name == hg; Name == git; Name == svn; Name == bzr; Name == rsync ->
+ when Name == hg; Name == git; Name == svn; Name == bzr; Name == rsync;
+ Name == fossil ->
case vcs_client_vsn(Name) >= required_vcs_client_vsn(Name) of
true ->
true;
@@ -466,11 +542,12 @@ vcs_client_vsn(Path, VsnArg, VsnRegex) ->
false
end.
-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(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(hg) ->
vcs_client_vsn(rebar_utils:find_executable("hg"), " --version",
@@ -486,7 +563,10 @@ vcs_client_vsn(svn) ->
"svn, version (\\d+).(\\d+)");
vcs_client_vsn(rsync) ->
vcs_client_vsn(rebar_utils:find_executable("rsync"), " --version",
- "rsync version (\\d+).(\\d+)").
+ "rsync version (\\d+).(\\d+)");
+vcs_client_vsn(fossil) ->
+ vcs_client_vsn(rebar_utils:find_executable("fossil"), " version",
+ "version (\\d+).(\\d+)").
has_vcs_dir(git, Dir) ->
filelib:is_dir(filename:join(Dir, ".git"));