diff options
Diffstat (limited to 'src/rebar_utils.erl')
-rw-r--r-- | src/rebar_utils.erl | 215 |
1 files changed, 139 insertions, 76 deletions
diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl index 27b2440..1049c1d 100644 --- a/src/rebar_utils.erl +++ b/src/rebar_utils.erl @@ -31,8 +31,7 @@ get_arch/0, wordsize/0, sh/2, - find_files/2, - find_files/3, + find_files/2, find_files/3, now_str/0, ensure_dir/1, beam_to_mod/2, beams/1, @@ -42,13 +41,18 @@ find_executable/1, prop_check/3, expand_code_path/0, - deprecated/3, deprecated/4, expand_env_variable/3, - vcs_vsn/2, - get_deprecated_global/3, get_deprecated_global/4, + vcs_vsn/3, + deprecated/3, deprecated/4, + get_deprecated_global/4, get_deprecated_global/5, + get_experimental_global/3, get_experimental_local/3, get_deprecated_list/4, get_deprecated_list/5, get_deprecated_local/4, get_deprecated_local/5, - delayed_halt/1]). + delayed_halt/1, + erl_opts/1, + src_dirs/1, + ebin_dir/0, + processing_base_dir/1, processing_base_dir/2]). -include("rebar.hrl"). @@ -71,7 +75,8 @@ is_arch(ArchRegex) -> get_arch() -> Words = wordsize(), erlang:system_info(otp_release) ++ "-" - ++ erlang:system_info(system_architecture) ++ "-" ++ Words. + ++ erlang:system_info(system_architecture) ++ "-" ++ Words + ++ "-" ++ os_family(). wordsize() -> try erlang:system_info({wordsize, external}) of @@ -171,7 +176,7 @@ prop_check(false, Msg, Args) -> ?ABORT(Msg, Args). %% Convert all the entries in the code path to absolute paths. expand_code_path() -> - CodePath = lists:foldl(fun (Path, Acc) -> + CodePath = lists:foldl(fun(Path, Acc) -> [filename:absname(Path) | Acc] end, [], code:get_path()), code:set_path(lists:reverse(CodePath)). @@ -195,65 +200,31 @@ expand_env_variable(InStr, VarName, RawVarValue) -> re:replace(InStr, RegEx, [VarValue, "\\2"], ReOpts) end. -vcs_vsn(Vcs, Dir) -> +vcs_vsn(Config, Vcs, Dir) -> Key = {Vcs, Dir}, - try ets:lookup_element(rebar_vsn_cache, Key, 2) - catch - error:badarg -> + Cache = rebar_config:get_xconf(Config, vsn_cache), + case dict:find(Key, Cache) of + error -> VsnString = vcs_vsn_1(Vcs, Dir), - ets:insert(rebar_vsn_cache, {Key, VsnString}), - VsnString + Cache1 = dict:store(Key, VsnString, Cache), + Config1 = rebar_config:set_xconf(Config, vsn_cache, Cache1), + {Config1, VsnString}; + {ok, VsnString} -> + {Config, VsnString} end. -vcs_vsn_1(Vcs, Dir) -> - case vcs_vsn_cmd(Vcs) of - {unknown, VsnString} -> - ?DEBUG("vcs_vsn: Unknown VCS atom in vsn field: ~p\n", [Vcs]), - VsnString; - {cmd, CmdString} -> - vcs_vsn_invoke(CmdString, Dir); - Cmd -> - %% If there is a valid VCS directory in the application directory, - %% use that version info - Extension = lists:concat([".", Vcs]), - case filelib:is_dir(filename:join(Dir, Extension)) of - true -> - ?DEBUG("vcs_vsn: Primary vcs used for ~s\n", [Dir]), - vcs_vsn_invoke(Cmd, Dir); - false -> - %% No VCS directory found for the app. Depending on source - %% tree structure, there may be one higher up, but that can - %% yield unexpected results when used with deps. So, we - %% fallback to searching for a priv/vsn.Vcs file. - VsnFile = filename:join([Dir, "priv", "vsn" ++ Extension]), - case file:read_file(VsnFile) of - {ok, VsnBin} -> - ?DEBUG("vcs_vsn: Read ~s from priv/vsn.~p\n", - [VsnBin, Vcs]), - string:strip(binary_to_list(VsnBin), right, $\n); - {error, enoent} -> - ?DEBUG("vcs_vsn: Fallback to vcs for ~s\n", [Dir]), - vcs_vsn_invoke(Cmd, Dir) - end - end - end. +get_deprecated_global(Config, OldOpt, NewOpt, When) -> + get_deprecated_global(Config, OldOpt, NewOpt, undefined, When). -get_deprecated_global(OldOpt, NewOpt, When) -> - get_deprecated_global(OldOpt, NewOpt, undefined, When). +get_deprecated_global(Config, OldOpt, NewOpt, Default, When) -> + get_deprecated_3(fun rebar_config:get_global/3, + Config, OldOpt, NewOpt, Default, When). -get_deprecated_global(OldOpt, NewOpt, Default, When) -> - case rebar_config:get_global(NewOpt, Default) of - Default -> - case rebar_config:get_global(OldOpt, Default) of - Default -> - Default; - Old -> - deprecated(OldOpt, NewOpt, When), - Old - end; - New -> - New - end. +get_experimental_global(Config, Opt, Default) -> + get_experimental_3(fun rebar_config:get_global/3, Config, Opt, Default). + +get_experimental_local(Config, Opt, Default) -> + get_experimental_3(fun rebar_config:get_local/3, Config, Opt, Default). get_deprecated_list(Config, OldOpt, NewOpt, When) -> get_deprecated_list(Config, OldOpt, NewOpt, undefined, When). @@ -313,10 +284,44 @@ delayed_halt(Code) -> end end. +%% @doc Return list of erl_opts +-spec erl_opts(rebar_config:config()) -> list(). +erl_opts(Config) -> + RawErlOpts = filter_defines(rebar_config:get(Config, erl_opts, []), []), + Defines = [{d, list_to_atom(D)} || + D <- rebar_config:get_xconf(Config, defines, [])], + Opts = Defines ++ RawErlOpts, + case proplists:is_defined(no_debug_info, Opts) of + true -> + [O || O <- Opts, O =/= no_debug_info]; + false -> + [debug_info|Opts] + end. + +-spec src_dirs([string()]) -> [file:filename(), ...]. +src_dirs([]) -> + ["src"]; +src_dirs(SrcDirs) -> + SrcDirs. + +ebin_dir() -> + filename:join(get_cwd(), "ebin"). + +processing_base_dir(Config) -> + Cwd = rebar_utils:get_cwd(), + processing_base_dir(Config, Cwd). + +processing_base_dir(Config, Dir) -> + Dir =:= rebar_config:get_xconf(Config, base_dir). + %% ==================================================================== %% Internal functions %% ==================================================================== +os_family() -> + {OsFamily, _} = os:type(), + atom_to_list(OsFamily). + get_deprecated_3(Get, Config, OldOpt, NewOpt, Default, When) -> case Get(Config, NewOpt, Default) of Default -> @@ -331,6 +336,16 @@ get_deprecated_3(Get, Config, OldOpt, NewOpt, Default, When) -> New end. +get_experimental_3(Get, Config, Opt, Default) -> + Val = Get(Config, Opt, Default), + case Val of + Default -> + Default; + Val -> + ?CONSOLE("NOTICE: Using experimental option '~p'~n", [Opt]), + Val + end. + %% We do the shell variable substitution ourselves on Windows and hope that the %% command doesn't use any other shell magic. patch_on_windows(Cmd, Env) -> @@ -341,7 +356,8 @@ patch_on_windows(Cmd, Env) -> expand_env_variable(Acc, Key, Value) end, Cmd, Env), %% Remove left-over vars - re:replace(Cmd1, "\\\$\\w+|\\\${\\w+}", "", [global, {return, list}]); + re:replace(Cmd1, "\\\$\\w+|\\\${\\w+}", "", + [global, {return, list}]); _ -> Cmd end. @@ -427,23 +443,70 @@ emulate_escript_foldl(Fun, Acc, File) -> Error end. -vcs_vsn_cmd(git) -> - %% git describe the last commit that touched CWD - %% required for correct versioning of apps in subdirs, such as apps/app1 - case os:type() of - {win32,nt} -> - "FOR /F \"usebackq tokens=* delims=\" %i in " - "(`git log -n 1 \"--pretty=format:%h\" .`) do " - "@git describe --always --tags %i"; - _ -> - "git describe --always --tags `git log -n 1 --pretty=format:%h .`" - end; -vcs_vsn_cmd(hg) -> "hg identify -i"; -vcs_vsn_cmd(bzr) -> "bzr revno"; -vcs_vsn_cmd(svn) -> "svnversion"; +vcs_vsn_1(Vcs, Dir) -> + case vcs_vsn_cmd(Vcs) of + {unknown, VsnString} -> + ?DEBUG("vcs_vsn: Unknown VCS atom in vsn field: ~p\n", [Vcs]), + VsnString; + {cmd, CmdString} -> + vcs_vsn_invoke(CmdString, Dir); + Cmd -> + %% If there is a valid VCS directory in the application directory, + %% use that version info + Extension = lists:concat([".", Vcs]), + case filelib:is_dir(filename:join(Dir, Extension)) of + true -> + ?DEBUG("vcs_vsn: Primary vcs used for ~s\n", [Dir]), + vcs_vsn_invoke(Cmd, Dir); + false -> + %% No VCS directory found for the app. Depending on source + %% tree structure, there may be one higher up, but that can + %% yield unexpected results when used with deps. So, we + %% fallback to searching for a priv/vsn.Vcs file. + VsnFile = filename:join([Dir, "priv", "vsn" ++ Extension]), + case file:read_file(VsnFile) of + {ok, VsnBin} -> + ?DEBUG("vcs_vsn: Read ~s from priv/vsn.~p\n", + [VsnBin, Vcs]), + string:strip(binary_to_list(VsnBin), right, $\n); + {error, enoent} -> + ?DEBUG("vcs_vsn: Fallback to vcs for ~s\n", [Dir]), + vcs_vsn_invoke(Cmd, Dir) + end + end + end. + +vcs_vsn_cmd(git) -> "git describe --always --tags"; +vcs_vsn_cmd(hg) -> "hg identify -i"; +vcs_vsn_cmd(bzr) -> "bzr revno"; +vcs_vsn_cmd(svn) -> "svnversion"; +vcs_vsn_cmd(fossil) -> "fossil info"; vcs_vsn_cmd({cmd, _Cmd}=Custom) -> Custom; vcs_vsn_cmd(Version) -> {unknown, Version}. vcs_vsn_invoke(Cmd, Dir) -> {ok, VsnString} = rebar_utils:sh(Cmd, [{cd, Dir}, {use_stdout, false}]), string:strip(VsnString, right, $\n). + +%% +%% Filter a list of erl_opts platform_define options such that only +%% those which match the provided architecture regex are returned. +%% +filter_defines([], Acc) -> + lists:reverse(Acc); +filter_defines([{platform_define, ArchRegex, Key} | Rest], Acc) -> + case rebar_utils:is_arch(ArchRegex) of + true -> + filter_defines(Rest, [{d, Key} | Acc]); + false -> + filter_defines(Rest, Acc) + end; +filter_defines([{platform_define, ArchRegex, Key, Value} | Rest], Acc) -> + case rebar_utils:is_arch(ArchRegex) of + true -> + filter_defines(Rest, [{d, Key, Value} | Acc]); + false -> + filter_defines(Rest, Acc) + end; +filter_defines([Opt | Rest], Acc) -> + filter_defines(Rest, [Opt | Acc]). |