summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/rebar_erlc_compiler.erl16
-rw-r--r--src/rebar_file_utils.erl117
-rw-r--r--src/rebar_prv_edoc.erl36
-rw-r--r--src/rebar_prv_new.erl3
-rw-r--r--src/rebar_templater.erl20
5 files changed, 155 insertions, 37 deletions
diff --git a/src/rebar_erlc_compiler.erl b/src/rebar_erlc_compiler.erl
index 95573fd..f7244dc 100644
--- a/src/rebar_erlc_compiler.erl
+++ b/src/rebar_erlc_compiler.erl
@@ -322,6 +322,10 @@ needed_files(G, ErlOpts, RebarOpts, Dir, OutDir, SourceFiles) ->
AllOpts = [{outdir, filename:dirname(Target)}
,{i, filename:join(Dir, "include")}
,{i, Dir}] ++ PrivIncludes ++ ErlOpts,
+ %% necessary for erlang:function_exported/3 to work as expected
+ %% called here for clarity as it's required by both opts_changed/2
+ %% and erl_compiler_opts_set/0
+ _ = code:ensure_loaded(compile),
digraph:vertex(G, Source) > {Source, filelib:last_modified(Target)}
orelse opts_changed(AllOpts, TargetBase)
orelse erl_compiler_opts_set()
@@ -342,8 +346,12 @@ maybe_rm_beam_and_edge(G, OutDir, Source) ->
end.
opts_changed(NewOpts, Target) ->
+ TotalOpts = case erlang:function_exported(compile, env_compiler_options, 0) of
+ true -> NewOpts ++ compile:env_compiler_options();
+ false -> NewOpts
+ end,
case compile_info(Target) of
- {ok, Opts} -> lists:sort(Opts) =/= lists:sort(NewOpts);
+ {ok, Opts} -> lists:sort(Opts) =/= lists:sort(TotalOpts);
_ -> true
end.
@@ -358,10 +366,12 @@ compile_info(Target) ->
end.
erl_compiler_opts_set() ->
- case os:getenv("ERL_COMPILER_OPTIONS") of
+ EnvSet = case os:getenv("ERL_COMPILER_OPTIONS") of
false -> false;
_ -> true
- end.
+ end,
+ %% return false if changed env opts would have been caught in opts_changed/2
+ EnvSet andalso not erlang:function_exported(compile, env_compiler_options, 0).
erlcinfo_file(Dir) ->
filename:join(rebar_dir:local_cache_dir(Dir), ?ERLCINFO_FILE).
diff --git a/src/rebar_file_utils.erl b/src/rebar_file_utils.erl
index 8645641..8158312 100644
--- a/src/rebar_file_utils.erl
+++ b/src/rebar_file_utils.erl
@@ -185,32 +185,113 @@ mv(Source, Dest) ->
ok
end;
{win32, _} ->
- Cmd = case filelib:is_dir(Source) of
- true ->
- ?FMT("robocopy /move /e \"~s\" \"~s\" 1> nul",
- [rebar_utils:escape_double_quotes(filename:nativename(Source)),
- rebar_utils:escape_double_quotes(filename:nativename(Dest))]);
- false ->
- ?FMT("robocopy /move /e \"~s\" \"~s\" \"~s\" 1> nul",
- [rebar_utils:escape_double_quotes(filename:nativename(filename:dirname(Source))),
- rebar_utils:escape_double_quotes(filename:nativename(Dest)),
- rebar_utils:escape_double_quotes(filename:basename(Source))])
- end,
- Res = rebar_utils:sh(Cmd,
- [{use_stdout, false}, return_on_error]),
- case win32_ok(Res) of
- true -> ok;
+ case filelib:is_dir(Source) of
+ true ->
+ SrcDir = filename:nativename(Source),
+ DestDir = case filelib:is_dir(Dest) of
+ true ->
+ %% to simulate unix/posix mv, we have to replicate
+ %% the same directory movement by moving the whole
+ %% top-level directory, not just the insides
+ SrcName = filename:basename(Source),
+ filename:nativename(filename:join(Dest, SrcName));
+ false ->
+ filename:nativename(Dest)
+ end,
+ robocopy_dir(SrcDir, DestDir);
false ->
- {error, lists:flatten(
- io_lib:format("Failed to move ~s to ~s~n",
- [Source, Dest]))}
+ SrcDir = filename:nativename(filename:dirname(Source)),
+ SrcName = filename:basename(Source),
+ DestDir = filename:nativename(filename:dirname(Dest)),
+ DestName = filename:basename(Dest),
+ IsDestDir = filelib:is_dir(Dest),
+ if IsDestDir ->
+ %% if basename and target name are different because
+ %% we move to a directory, then just move there.
+ %% Similarly, if they are the same but we're going to
+ %% a directory, let's just do that directly.
+ FullDestDir = filename:nativename(Dest),
+ robocopy_file(SrcDir, FullDestDir, SrcName)
+ ; SrcName =:= DestName ->
+ %% if basename and target name are the same and both are files,
+ %% we do a regular move with robocopy without rename.
+ robocopy_file(SrcDir, DestDir, DestName)
+ ; SrcName =/= DestName->
+ robocopy_mv_and_rename(Source, Dest, SrcDir, SrcName, DestDir, DestName)
+ end
+
end
end.
+robocopy_mv_and_rename(Source, Dest, SrcDir, SrcName, DestDir, DestName) ->
+ %% If we're moving a file and the origin and
+ %% destination names are different:
+ %% - mktmp
+ %% - robocopy source_dir tmp_dir srcname
+ %% - rename srcname destname (to avoid clobbering)
+ %% - robocopy tmp_dir dest_dir destname
+ %% - remove tmp_dir
+ case ec_file:insecure_mkdtemp() of
+ {error, _Reason} ->
+ {error, lists:flatten(
+ io_lib:format("Failed to move ~s to ~s (tmpdir failed)~n",
+ [Source, Dest]))};
+ TmpPath ->
+ case robocopy_file(SrcDir, TmpPath, SrcName) of
+ {error, Reason} ->
+ {error, Reason};
+ ok ->
+ TmpSrc = filename:join(TmpPath, SrcName),
+ TmpDst = filename:join(TmpPath, DestName),
+ case file:rename(TmpSrc, TmpDst) of
+ {error, _} ->
+ {error, lists:flatten(
+ io_lib:format("Failed to move ~s to ~s (via rename)~n",
+ [Source, Dest]))};
+ ok ->
+ case robocopy_file(TmpPath, DestDir, DestName) of
+ Err = {error, _} -> Err;
+ OK -> rm_rf(TmpPath), OK
+ end
+ end
+ end
+ end.
+
+robocopy_file(SrcPath, DestPath, FileName) ->
+ Cmd = ?FMT("robocopy /move /e \"~s\" \"~s\" \"~s\"",
+ [rebar_utils:escape_double_quotes(SrcPath),
+ rebar_utils:escape_double_quotes(DestPath),
+ rebar_utils:escape_double_quotes(FileName)]),
+ Res = rebar_utils:sh(Cmd, [{use_stdout, false}, return_on_error]),
+ case win32_ok(Res) of
+ false ->
+ {error, lists:flatten(
+ io_lib:format("Failed to move ~s to ~s~n",
+ [filename:join(SrcPath, FileName),
+ filename:join(DestPath, FileName)]))};
+ true ->
+ ok
+ end.
+
+robocopy_dir(Source, Dest) ->
+ Cmd = ?FMT("robocopy /move /e \"~s\" \"~s\"",
+ [rebar_utils:escape_double_quotes(Source),
+ rebar_utils:escape_double_quotes(Dest)]),
+ Res = rebar_utils:sh(Cmd,
+ [{use_stdout, false}, return_on_error]),
+ case win32_ok(Res) of
+ true -> ok;
+ false ->
+ {error, lists:flatten(
+ io_lib:format("Failed to move ~s to ~s~n",
+ [Source, Dest]))}
+ end.
+
win32_ok({ok, _}) -> true;
win32_ok({error, {Rc, _}}) when Rc<9; Rc=:=16 -> true;
win32_ok(_) -> false.
+
delete_each([]) ->
ok;
delete_each([File | Rest]) ->
diff --git a/src/rebar_prv_edoc.erl b/src/rebar_prv_edoc.erl
index 465fc34..97f70a9 100644
--- a/src/rebar_prv_edoc.erl
+++ b/src/rebar_prv_edoc.erl
@@ -7,6 +7,7 @@
format_error/1]).
-include("rebar.hrl").
+-include_lib("providers/include/providers.hrl").
-define(PROVIDER, edoc).
-define(DEPS, [compile]).
@@ -28,7 +29,8 @@ init(State) ->
{profiles, [docs]}])),
{ok, State1}.
--spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
+-spec do(rebar_state:t()) ->
+ {ok, rebar_state:t()} | {error, string()} | {error, {module(), any()}}.
do(State) ->
code:add_pathsa(rebar_state:code_paths(State, all_deps)),
ProjectApps = rebar_state:project_apps(State),
@@ -37,26 +39,42 @@ do(State) ->
ShouldAccPaths = not has_configured_paths(EdocOpts),
Cwd = rebar_state:dir(State),
rebar_hooks:run_all_hooks(Cwd, pre, ?PROVIDER, Providers, State),
- lists:foldl(fun(AppInfo, EdocOptsAcc) ->
+ Res = try
+ lists:foldl(fun(AppInfo, EdocOptsAcc) ->
rebar_hooks:run_all_hooks(Cwd, pre, ?PROVIDER, Providers, AppInfo, State),
AppName = ec_cnv:to_list(rebar_app_info:name(AppInfo)),
?INFO("Running edoc for ~s", [AppName]),
AppDir = rebar_app_info:dir(AppInfo),
- ok = edoc:application(list_to_atom(AppName), AppDir, EdocOptsAcc),
+ AppRes = (catch edoc:application(list_to_atom(AppName), AppDir, EdocOptsAcc)),
rebar_hooks:run_all_hooks(Cwd, post, ?PROVIDER, Providers, AppInfo, State),
- case ShouldAccPaths of
- true ->
+ case {AppRes, ShouldAccPaths} of
+ {ok, true} ->
%% edoc wants / on all OSes
add_to_paths(EdocOptsAcc, AppDir++"/doc");
- false ->
- EdocOptsAcc
+ {ok, false} ->
+ EdocOptsAcc;
+ {{'EXIT', error}, _} ->
+ %% EDoc is not very descriptive
+ %% in terms of failures
+ throw({app_failed, AppName})
end
- end, EdocOpts, ProjectApps),
+ end, EdocOpts, ProjectApps)
+ catch
+ {app_failed, AppName} ->
+ {app_failed, AppName}
+ end,
rebar_hooks:run_all_hooks(Cwd, post, ?PROVIDER, Providers, State),
rebar_utils:cleanup_code_path(rebar_state:code_paths(State, default)),
- {ok, State}.
+ case Res of
+ {app_failed, App} ->
+ ?PRV_ERROR({app_failed, App});
+ _ ->
+ {ok, State}
+ end.
-spec format_error(any()) -> iolist().
+format_error({app_failed, AppName}) ->
+ io_lib:format("Failed to generate documentation for app '~s'", [AppName]);
format_error(Reason) ->
io_lib:format("~p", [Reason]).
diff --git a/src/rebar_prv_new.erl b/src/rebar_prv_new.erl
index 064315e..152a56e 100644
--- a/src/rebar_prv_new.erl
+++ b/src/rebar_prv_new.erl
@@ -132,11 +132,14 @@ show_template({Name, Type, Location, Description, Vars}) ->
format_vars(Vars)]).
format_type(escript) -> "built-in";
+format_type(builtin) -> "built-in";
format_type(plugin) -> "plugin";
format_type(file) -> "custom".
format_type(escript, _) ->
"built-in template";
+format_type(builtin, _) ->
+ "built-in template";
format_type(plugin, Loc) ->
io_lib:format("plugin template (~s)", [Loc]);
format_type(file, Loc) ->
diff --git a/src/rebar_templater.erl b/src/rebar_templater.erl
index e64ce71..9b33ec5 100644
--- a/src/rebar_templater.erl
+++ b/src/rebar_templater.erl
@@ -267,8 +267,8 @@ find_templates(State) ->
PluginTemplates = find_plugin_templates(State),
{MainTemplates, Files} =
case rebar_state:escript_path(State) of
- undefined ->
- {find_priv_templates(State), []};
+ undefined -> % running in local install
+ {find_localinstall_templates(State), []};
_ ->
%% Cache the files since we'll potentially need to walk it several times
%% over the course of a run.
@@ -307,11 +307,10 @@ find_escript_templates(Files) ->
|| {Name, _Bin} <- Files,
re:run(Name, ?TEMPLATE_RE, [{capture, none}]) == match].
-find_priv_templates(State) ->
- OtherTemplates = rebar_utils:find_files(code:priv_dir(rebar), ?TEMPLATE_RE),
- HomeFiles = rebar_utils:find_files(rebar_dir:template_dir(State),
- ?TEMPLATE_RE, true), % recursive
- [{file, F} || F <- OtherTemplates ++ HomeFiles].
+find_localinstall_templates(_State) ->
+ Templates = rebar_utils:find_files(code:priv_dir(rebar), ?TEMPLATE_RE),
+ %% Pretend we're still running escripts; should work transparently.
+ [{builtin, F} || F <- Templates].
%% Fetch template indexes that sit on disk in the user's HOME
find_disk_templates(State) ->
@@ -354,6 +353,10 @@ prioritize_templates([{Name, Type, File} | Rest], Valid) ->
?DEBUG("Skipping template ~p, due to presence of a built-in "
"template with the same name", [Name]),
prioritize_templates(Rest, Valid);
+ {_, builtin, _} ->
+ ?DEBUG("Skipping template ~p, due to presence of a built-in "
+ "template with the same name", [Name]),
+ prioritize_templates(Rest, Valid);
{_, plugin, _} ->
?DEBUG("Skipping template ~p, due to presence of a plugin "
"template with the same name", [Name]),
@@ -369,6 +372,9 @@ prioritize_templates([{Name, Type, File} | Rest], Valid) ->
load_file(Files, escript, Name) ->
{Name, Bin} = lists:keyfind(Name, 1, Files),
Bin;
+load_file(_Files, builtin, Name) ->
+ {ok, Bin} = file:read_file(Name),
+ Bin;
load_file(_Files, plugin, Name) ->
{ok, Bin} = file:read_file(Name),
Bin;