summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml1
-rwxr-xr-xbootstrap16
-rw-r--r--rebar.config6
-rw-r--r--rebar.config.sample5
-rw-r--r--src/rebar_config.erl16
-rw-r--r--src/rebar_deps.erl49
-rw-r--r--src/rebar_erlc_compiler.erl24
-rw-r--r--src/rebar_utils.erl20
8 files changed, 120 insertions, 17 deletions
diff --git a/.travis.yml b/.travis.yml
index a7eedb4..602266b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,4 +7,5 @@ otp_release:
- R15B
- R14B04
- R14B03
+ - 17.0
script: "make travis"
diff --git a/bootstrap b/bootstrap
index 019aaea..f6aa6cc 100755
--- a/bootstrap
+++ b/bootstrap
@@ -28,10 +28,20 @@ main(Args) ->
%% Extract the system info of the version of OTP we use to compile rebar
OtpInfo = string:strip(erlang:system_info(otp_release), both, $\n),
+ %% Types dict:dict() and digraph:digraph() have been introduced in Erlang 17.
+ %% At the same time, their counterparts dict() and digraph() are to be deprecated
+ %% in Erlang 18. namespaced_types option is used to select proper type name
+ %% depending of the OTP version used.
+ NamespacedTypes = case is_otp(OtpInfo, "^[0-9]+") of
+ true -> {d, namespaced_types};
+ false -> undefined
+ end,
+
%% Compile all src/*.erl to ebin
case make:files(filelib:wildcard("src/*.erl"),
[{outdir, "ebin"}, {i, "include"},
DebugFlag,
+ NamespacedTypes,
{d, 'BUILD_TIME', Built},
{d, 'VCS_INFO', VcsInfo},
{d, 'OTP_INFO', OtpInfo}]) of
@@ -79,6 +89,12 @@ main(Args) ->
"Place this script anywhere in your path\n"
"and you can use rebar to build OTP-compliant apps.\n").
+is_otp(OtpInfo, Regex) ->
+ case re:run(OtpInfo, Regex, [{capture, none}]) of
+ match -> true;
+ nomatch -> false
+ end.
+
rm(Path) ->
NativePath = filename:nativename(Path),
Cmd = case os:type() of
diff --git a/rebar.config b/rebar.config
index 9028737..bf4ef4f 100644
--- a/rebar.config
+++ b/rebar.config
@@ -4,7 +4,11 @@
%% escript_incl_extra is for internal rebar-private use only.
%% Do not use outside rebar. Config interface is not stable.
{escript_incl_extra, [{"priv/templates/*", "."}]}.
-{erl_opts, [warnings_as_errors]}.
+%% Types dict:dict() and digraph:digraph() have been introduced in Erlang 17.
+%% At the same time, their counterparts dict() and digraph() are to be deprecated
+%% in Erlang 18. namespaced_types option is used to select proper type name
+%% depending of the OTP version used.
+{erl_opts, [{platform_define, "^[0-9]+", namespaced_types}, warnings_as_errors]}.
{xref_checks, []}.
{xref_queries,
[{"(XC - UC) || (XU - X - B
diff --git a/rebar.config.sample b/rebar.config.sample
index 515ed00..47812c1 100644
--- a/rebar.config.sample
+++ b/rebar.config.sample
@@ -155,7 +155,7 @@
%% name as an atom, eg. mochiweb, a name and a version (from the .app file), or
%% an application name, a version and the SCM details on how to fetch it (SCM
%% type, location and revision).
-%% Rebar currently supports git, hg, bzr, svn, rsync, and fossil.
+%% Rebar currently supports git, hg, bzr, svn, rsync, fossil, and p4.
{deps, [app_name,
{rebar, "1.0.*"},
{rebar, ".*",
@@ -188,7 +188,8 @@
{app_name, ".*", {svn, "svn://svn.example.org/url"}},
{app_name, ".*", {bzr, "https://www.example.org/url", "Rev"}},
{app_name, ".*", {fossil, "https://www.example.org/url"}},
- {app_name, ".*", {fossil, "https://www.example.org/url", "Vsn"}}]}.
+ {app_name, ".*", {fossil, "https://www.example.org/url", "Vsn"}},
+ {app_name, ".*", {p4, "//depot/subdir/app_dir"}}]}.
%% == Subdirectories ==
diff --git a/src/rebar_config.erl b/src/rebar_config.erl
index 10c6483..1c90d22 100644
--- a/src/rebar_config.erl
+++ b/src/rebar_config.erl
@@ -39,13 +39,21 @@
-include("rebar.hrl").
+-ifdef(namespaced_types).
+% dict:dict() exists starting from Erlang 17.
+-type rebar_dict() :: dict:dict().
+-else.
+% dict() has been obsoleted in Erlang 17 and deprecated in 18.
+-type rebar_dict() :: dict().
+-endif.
+
-record(config, { dir :: file:filename(),
opts = [] :: list(),
- globals = new_globals() :: dict(),
- envs = new_env() :: dict(),
+ globals = new_globals() :: rebar_dict(),
+ envs = new_env() :: rebar_dict(),
%% cross-directory/-command config
- skip_dirs = new_skip_dirs() :: dict(),
- xconf = new_xconf() :: dict() }).
+ skip_dirs = new_skip_dirs() :: rebar_dict(),
+ xconf = new_xconf() :: rebar_dict() }).
-export_type([config/0]).
diff --git a/src/rebar_deps.erl b/src/rebar_deps.erl
index 43bde04..392882c 100644
--- a/src/rebar_deps.erl
+++ b/src/rebar_deps.erl
@@ -277,7 +277,8 @@ info_help(Description) ->
{app_name, ".*", {svn, "svn://svn.example.org/url"}},
{app_name, ".*", {bzr, "https://www.example.org/url", "Rev"}},
{app_name, ".*", {fossil, "https://www.example.org/url"}},
- {app_name, ".*", {fossil, "https://www.example.org/url", "Vsn"}}]}
+ {app_name, ".*", {fossil, "https://www.example.org/url", "Vsn"}},
+ {app_name, ".*", {p4, "//depot/subdir/app_dir"}}]}
]).
%% Added because of trans deps,
@@ -507,6 +508,40 @@ use_source(Config, Dep, Count) ->
use_source(Config, Dep#dep { dir = TargetDir }, Count-1)
end.
+-record(p4_settings, {
+ client=undefined,
+ transport="tcp4:perforce:1666",
+ username,
+ password
+ }).
+init_p4_settings(Basename) ->
+ #p4_settings{client =
+ case inet:gethostname() of
+ {ok,HostName} ->
+ HostName ++ "-"
+ ++ os:getenv("USER") ++ "-"
+ ++ Basename
+ ++ "-Rebar-automated-download"
+ end}.
+
+download_source(AppDir, {p4, Url}) ->
+ download_source(AppDir, {p4, Url, "#head"});
+download_source(AppDir, {p4, Url, Rev}) ->
+ download_source(AppDir, {p4, Url, Rev, init_p4_settings(filename:basename(AppDir))});
+download_source(AppDir, {p4, Url, _Rev, Settings}) ->
+ ok = filelib:ensure_dir(AppDir),
+ 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,
+ AppDir,
+ Url,
+ Settings#p4_settings.client]),
+ []),
+ rebar_utils:sh(?FMT("p4 -c ~s sync -f", [Settings#p4_settings.client]), []);
download_source(AppDir, {hg, Url, Rev}) ->
ok = filelib:ensure_dir(AppDir),
rebar_utils:sh(?FMT("hg clone -U ~s ~s", [Url, filename:basename(AppDir)]),
@@ -573,6 +608,8 @@ update_source(Config, Dep) ->
Dep
end.
+update_source1(AppDir, Args) when element(1, Args) =:= p4 ->
+ download_source(AppDir, Args);
update_source1(AppDir, {git, Url}) ->
update_source1(AppDir, {git, Url, {branch, "HEAD"}});
update_source1(AppDir, {git, Url, ""}) ->
@@ -696,7 +733,7 @@ source_engine_avail(Source) ->
source_engine_avail(Name, Source)
when Name == hg; Name == git; Name == svn; Name == bzr; Name == rsync;
- Name == fossil ->
+ Name == fossil; Name == p4 ->
case vcs_client_vsn(Name) >= required_vcs_client_vsn(Name) of
true ->
true;
@@ -717,6 +754,7 @@ vcs_client_vsn(Path, VsnArg, VsnRegex) ->
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};
@@ -724,6 +762,9 @@ 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+)");
@@ -743,6 +784,8 @@ 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) ->
@@ -760,6 +803,8 @@ has_vcs_dir(_, _) ->
print_source(#dep{app=App, source=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, ""}) ->
diff --git a/src/rebar_erlc_compiler.erl b/src/rebar_erlc_compiler.erl
index b797137..5f541d9 100644
--- a/src/rebar_erlc_compiler.erl
+++ b/src/rebar_erlc_compiler.erl
@@ -47,6 +47,14 @@
info = {[], []} :: erlc_info()
}).
+-ifdef(namespaced_types).
+% digraph:digraph() exists starting from Erlang 17.
+-type rebar_digraph() :: digraph:digraph().
+-else.
+% digraph() has been obsoleted in Erlang 17 and deprecated in 18.
+-type rebar_digraph() :: digraph().
+-endif.
+
%% ===================================================================
%% Public API
%% ===================================================================
@@ -409,17 +417,17 @@ init_erlcinfo(Config, Erls) ->
update_erlcinfo(G, Source, Dirs) ->
case digraph:vertex(G, Source) of
{_, LastUpdated} ->
- LastModified = filelib:last_modified(Source),
- if LastModified == 0 ->
+ case filelib:last_modified(Source) of
+ 0 ->
%% The file doesn't exist anymore,
%% erase it from the graph.
%% All the edges will be erased automatically.
digraph:del_vertex(G, Source),
modified;
- LastUpdated < LastModified ->
- modify_erlcinfo(G, Source, Dirs);
+ LastModified when LastUpdated < LastModified ->
+ modify_erlcinfo(G, Source, Dirs),
modified;
- true ->
+ _ ->
unmodified
end;
false ->
@@ -522,19 +530,19 @@ expand_file_names(Files, Dirs) ->
end
end, Files).
--spec get_parents(digraph(), file:filename()) -> [file:filename()].
+-spec get_parents(rebar_digraph(), file:filename()) -> [file:filename()].
get_parents(G, Source) ->
%% Return all files which the Source depends upon.
digraph_utils:reachable_neighbours([Source], G).
--spec get_children(digraph(), file:filename()) -> [file:filename()].
+-spec get_children(rebar_digraph(), file:filename()) -> [file:filename()].
get_children(G, Source) ->
%% Return all files dependent on the Source.
digraph_utils:reaching_neighbours([Source], G).
-spec internal_erl_compile(rebar_config:config(), file:filename(),
file:filename(), list(),
- digraph()) -> 'ok' | 'skipped'.
+ rebar_digraph()) -> 'ok' | 'skipped'.
internal_erl_compile(Config, Source, OutDir, ErlOpts, G) ->
%% Determine the target name and includes list by inspecting the source file
Module = filename:basename(Source, ".erl"),
diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl
index 517ac33..c02d200 100644
--- a/src/rebar_utils.erl
+++ b/src/rebar_utils.erl
@@ -31,6 +31,7 @@
get_arch/0,
wordsize/0,
sh/2,
+ sh_send/3,
find_files/2, find_files/3,
now_str/0,
ensure_dir/1,
@@ -87,6 +88,24 @@ wordsize() ->
integer_to_list(8 * erlang:system_info(wordsize))
end.
+sh_send(Command0, String, Options0) ->
+ ?INFO("sh_send info:\n\tcwd: ~p\n\tcmd: ~s < ~s\n", [get_cwd(), Command0, String]),
+ ?DEBUG("\topts: ~p\n", [Options0]),
+
+ DefaultOptions = [use_stdout, abort_on_error],
+ Options = [expand_sh_flag(V)
+ || V <- proplists:compact(Options0 ++ DefaultOptions)],
+
+ Command = patch_on_windows(Command0, proplists:get_value(env, Options, [])),
+ PortSettings = proplists:get_all_values(port_settings, Options) ++
+ [exit_status, {line, 16384}, use_stdio, stderr_to_stdout, hide],
+ Port = open_port({spawn, Command}, PortSettings),
+
+ %% allow us to send some data to the shell command's STDIN
+ %% Erlang doesn't let us get any reply after sending an EOF, though...
+ Port ! {self(), {command, String}},
+ port_close(Port).
+
%%
%% Options = [Option] -- defaults to [use_stdout, abort_on_error]
%% Option = ErrorOption | OutputOption | {cd, string()} | {env, Env}
@@ -480,6 +499,7 @@ vcs_vsn_1(Vcs, Dir) ->
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";