Skip to content

Commit

Permalink
Add 'p4' (Perforce) as a dependency type
Browse files Browse the repository at this point in the history
This calls the 'p4' command-line tool to checkout and sync Perforce
trees. It involves significantly more special code in Rebar than
using 'git p4', but it eliminates the indirection of
Rebar->Git->Python->Perforce
  • Loading branch information
waisbrot committed Sep 23, 2013
1 parent 179ed48 commit 485b20b
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 2 deletions.
4 changes: 3 additions & 1 deletion rebar.config.sample
Expand Up @@ -152,11 +152,13 @@
%% name as an atom, eg. mochiweb, a name and a version (from the .app file), or %% 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 %% an application name, a version and the SCM details on how to fetch it (SCM
%% type, location and revision). %% type, location and revision).
%% Rebar currently supports git, hg, bzr, svn, and rsync. %% Rebar currently supports git, p4, hg, bzr, svn, and rsync.
{deps, [application_name, {deps, [application_name,
{application_name, "1.0.*"}, {application_name, "1.0.*"},
{application_name, "1.0.*", {application_name, "1.0.*",
{git, "git://github.com/rebar/rebar.git", {branch, "master"}}}, {git, "git://github.com/rebar/rebar.git", {branch, "master"}}},
{application_name, ".*",
{p4, "//depot/path/to/source"}},
%% Dependencies can be marked as 'raw'. Rebar does not require %% Dependencies can be marked as 'raw'. Rebar does not require
%% such dependencies to have a standard Erlang/OTP layout %% such dependencies to have a standard Erlang/OTP layout
%% which assumes the presence of either %% which assumes the presence of either
Expand Down
48 changes: 47 additions & 1 deletion src/rebar_deps.erl
Expand Up @@ -234,6 +234,8 @@ info_help(Description) ->
{application_name, "1.0.*"}, {application_name, "1.0.*"},
{application_name, "1.0.*", {application_name, "1.0.*",
{git, "git://github.com/rebar/rebar.git", {branch, "master"}}}, {git, "git://github.com/rebar/rebar.git", {branch, "master"}}},
{application_name, ".*",
{p4, "//depot/path/to/source"}},
{application_name, "", {application_name, "",
{git, "git://github.com/rebar/rebar.git", {branch, "master"}}, {git, "git://github.com/rebar/rebar.git", {branch, "master"}},
[raw]}]} [raw]}]}
Expand Down Expand Up @@ -465,6 +467,40 @@ use_source(Config, Dep, Count) ->
use_source(Config, Dep#dep { dir = TargetDir }, Count-1) use_source(Config, Dep#dep { dir = TargetDir }, Count-1)
end. 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}) -> download_source(AppDir, {hg, Url, Rev}) ->
ok = filelib:ensure_dir(AppDir), ok = filelib:ensure_dir(AppDir),
rebar_utils:sh(?FMT("hg clone -U ~s ~s", [Url, filename:basename(AppDir)]), rebar_utils:sh(?FMT("hg clone -U ~s ~s", [Url, filename:basename(AppDir)]),
Expand Down Expand Up @@ -533,6 +569,8 @@ update_source(Config, Dep) ->
Dep Dep
end. end.


update_source1(AppDir, Args) when element(1, Args) =:= p4 ->
download_source(AppDir, Args);
update_source1(AppDir, {git, Url}) -> update_source1(AppDir, {git, Url}) ->
update_source1(AppDir, {git, Url, {branch, "HEAD"}}); update_source1(AppDir, {git, Url, {branch, "HEAD"}});
update_source1(AppDir, {git, Url, ""}) -> update_source1(AppDir, {git, Url, ""}) ->
Expand Down Expand Up @@ -577,7 +615,7 @@ 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 -> Name == fossil; Name == p4 ->
case vcs_client_vsn(Name) >= required_vcs_client_vsn(Name) of case vcs_client_vsn(Name) >= required_vcs_client_vsn(Name) of
true -> true ->
true; true;
Expand All @@ -598,13 +636,17 @@ vcs_client_vsn(Path, VsnArg, VsnRegex) ->
false false
end. end.


required_vcs_client_vsn(p4) -> {2013, 1};
required_vcs_client_vsn(hg) -> {1, 1}; required_vcs_client_vsn(hg) -> {1, 1};
required_vcs_client_vsn(git) -> {1, 5}; required_vcs_client_vsn(git) -> {1, 5};
required_vcs_client_vsn(bzr) -> {2, 0}; required_vcs_client_vsn(bzr) -> {2, 0};
required_vcs_client_vsn(svn) -> {1, 6}; required_vcs_client_vsn(svn) -> {1, 6};
required_vcs_client_vsn(rsync) -> {2, 0}; required_vcs_client_vsn(rsync) -> {2, 0};
required_vcs_client_vsn(fossil) -> {1, 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(hg) ->
vcs_client_vsn(rebar_utils:find_executable("hg"), " --version", vcs_client_vsn(rebar_utils:find_executable("hg"), " --version",
"version (\\d+).(\\d+)"); "version (\\d+).(\\d+)");
Expand All @@ -624,6 +666,8 @@ vcs_client_vsn(fossil) ->
vcs_client_vsn(rebar_utils:find_executable("fossil"), " version", vcs_client_vsn(rebar_utils:find_executable("fossil"), " version",
"version (\\d+).(\\d+)"). "version (\\d+).(\\d+)").


has_vcs_dir(p4, _) ->
true;
has_vcs_dir(git, Dir) -> has_vcs_dir(git, Dir) ->
filelib:is_dir(filename:join(Dir, ".git")); filelib:is_dir(filename:join(Dir, ".git"));
has_vcs_dir(hg, Dir) -> has_vcs_dir(hg, Dir) ->
Expand All @@ -641,6 +685,8 @@ has_vcs_dir(_, _) ->
print_source(#dep{app=App, source=Source}) -> print_source(#dep{app=App, source=Source}) ->
?CONSOLE("~s~n", [format_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}) -> format_source(App, {git, Url}) ->
?FMT("~p BRANCH ~s ~s", [App, "HEAD", Url]); ?FMT("~p BRANCH ~s ~s", [App, "HEAD", Url]);
format_source(App, {git, Url, ""}) -> format_source(App, {git, Url, ""}) ->
Expand Down
20 changes: 20 additions & 0 deletions src/rebar_utils.erl
Expand Up @@ -31,6 +31,7 @@
get_arch/0, get_arch/0,
wordsize/0, wordsize/0,
sh/2, sh/2,
sh_send/3,
find_files/2, find_files/3, find_files/2, find_files/3,
now_str/0, now_str/0,
ensure_dir/1, ensure_dir/1,
Expand Down Expand Up @@ -86,6 +87,24 @@ wordsize() ->
integer_to_list(8 * erlang:system_info(wordsize)) integer_to_list(8 * erlang:system_info(wordsize))
end. 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] %% Options = [Option] -- defaults to [use_stdout, abort_on_error]
%% Option = ErrorOption | OutputOption | {cd, string()} | {env, Env} %% Option = ErrorOption | OutputOption | {cd, string()} | {env, Env}
Expand Down Expand Up @@ -473,6 +492,7 @@ vcs_vsn_1(Vcs, Dir) ->
end. end.


vcs_vsn_cmd(git) -> "git describe --always --tags"; vcs_vsn_cmd(git) -> "git describe --always --tags";
vcs_vsn_cmd(p4) -> "echo #head";
vcs_vsn_cmd(hg) -> "hg identify -i"; vcs_vsn_cmd(hg) -> "hg identify -i";
vcs_vsn_cmd(bzr) -> "bzr revno"; vcs_vsn_cmd(bzr) -> "bzr revno";
vcs_vsn_cmd(svn) -> "svnversion"; vcs_vsn_cmd(svn) -> "svnversion";
Expand Down

0 comments on commit 485b20b

Please sign in to comment.