diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/rebar.erl | 7 | ||||
-rw-r--r-- | src/rebar_base_compiler.erl | 4 | ||||
-rw-r--r-- | src/rebar_ct.erl | 13 | ||||
-rw-r--r-- | src/rebar_deps.erl | 28 | ||||
-rw-r--r-- | src/rebar_erlydtl_compiler.erl | 103 | ||||
-rw-r--r-- | src/rebar_require_vsn.erl | 29 | ||||
-rw-r--r-- | src/rebar_utils.erl | 7 | ||||
-rw-r--r-- | src/rebar_xref.erl | 19 |
8 files changed, 162 insertions, 48 deletions
diff --git a/src/rebar.erl b/src/rebar.erl index cd0bed5..82e3fac 100644 --- a/src/rebar.erl +++ b/src/rebar.erl @@ -27,6 +27,7 @@ -module(rebar). -export([main/1, + run/2, help/0, parse_args/1, version/0, @@ -52,6 +53,7 @@ %% Public API %% ==================================================================== +%% escript Entry point main(Args) -> case catch(run(Args)) of ok -> @@ -65,6 +67,11 @@ main(Args) -> rebar_utils:delayed_halt(1) end. +%% Erlang-API entry point +run(BaseConfig, Commands) -> + application:load(rebar), + run_aux(BaseConfig, Commands). + %% ==================================================================== %% Internal functions %% ==================================================================== diff --git a/src/rebar_base_compiler.erl b/src/rebar_base_compiler.erl index 63e408b..260cdaf 100644 --- a/src/rebar_base_compiler.erl +++ b/src/rebar_base_compiler.erl @@ -62,9 +62,9 @@ run(Config, FirstFiles, SourceDir, SourceExt, TargetDir, TargetExt, %% Convert simple extension to proper regex SourceExtRe = ".*\\" ++ SourceExt ++ [$$], + Recursive = proplists:get_value(recursive, Opts, true), %% Find all possible source files - FoundFiles = rebar_utils:find_files(SourceDir, SourceExtRe), - + FoundFiles = rebar_utils:find_files(SourceDir, SourceExtRe, Recursive), %% Remove first files from found files RestFiles = [Source || Source <- FoundFiles, not lists:member(Source, FirstFiles)], diff --git a/src/rebar_ct.erl b/src/rebar_ct.erl index 6fd5bc7..e33c6c9 100644 --- a/src/rebar_ct.erl +++ b/src/rebar_ct.erl @@ -65,7 +65,12 @@ run_test_if_present(TestDir, LogDir, Config, File) -> ++ " SUITES - skipping\n", [TestDir]), ok; _ -> - run_test(TestDir, LogDir, Config, File) + try + run_test(TestDir, LogDir, Config, File) + catch + throw:skip -> + ok + end end end. @@ -270,8 +275,10 @@ find_suite_path(Suite, TestDir) -> Path = filename:join(TestDir, Suite ++ "_SUITE.erl"), case filelib:is_regular(Path) of false -> - ?ERROR("Suite ~s not found\n", [Suite]), - ?FAIL; + ?WARN("Suite ~s not found\n", [Suite]), + %% Note - this throw is caught in run_test_if_present/3; + %% this solution was easier than refactoring the entire module. + throw(skip); true -> Path end. diff --git a/src/rebar_deps.erl b/src/rebar_deps.erl index cd49343..074e929 100644 --- a/src/rebar_deps.erl +++ b/src/rebar_deps.erl @@ -69,15 +69,27 @@ preprocess(Config, _) -> %% 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. + %% + %% Also, if skip_deps=comma,separated,app,list, then only the given + %% dependencies are skipped. 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, + "true" -> + lists:foldl( + fun(#dep{dir = Dir}, C) -> + rebar_config:set_skip_dir(C, Dir) + end, Config3, AvailableDeps); + Apps when is_list(Apps) -> + SkipApps = [list_to_atom(App) || App <- string:tokens(Apps, ",")], + lists:foldl( + fun(#dep{dir = Dir, app = App}, C) -> + case lists:member(App, SkipApps) of + true -> rebar_config:set_skip_dir(C, Dir); + false -> C + end + end, Config3, AvailableDeps); + _ -> + Config3 + end, %% Filtering out 'raw' dependencies so that no commands other than %% deps-related can be executed on their directories. diff --git a/src/rebar_erlydtl_compiler.erl b/src/rebar_erlydtl_compiler.erl index 958b976..25981b2 100644 --- a/src/rebar_erlydtl_compiler.erl +++ b/src/rebar_erlydtl_compiler.erl @@ -31,7 +31,11 @@ %% to ebin/*_dtl.beam. %% %% Configuration options should be placed in rebar.config under -%% 'erlydtl_opts'. Available options include: +%% 'erlydtl_opts'. It can be a list of name-value tuples or a list of +%% lists of name-value tuples if you have multiple template directories +%% that need to have different settings (see example below). +%% +%% Available options include: %% %% doc_root: where to find templates to compile %% "templates" by default @@ -45,6 +49,9 @@ %% module_ext: characters to append to the template's module name %% "_dtl" by default %% +%% recursive: boolean that determines if doc_root(s) need to be +%% scanned recursively for matching template file names +%% (default: true). %% For example, if you had: %% /t_src/ %% base.html @@ -70,6 +77,21 @@ %% {source_ext, ".dtl"}, %% {module_ext, "_dtl"} %% ]}. +%% +%% The following example will compile the following templates: +%% "src/*.dtl" files into "ebin/*_dtl.beam" and +%% "templates/*.html" into "ebin/*.beam". Note that any tuple option +%% (such as 'out_dir') in the outer list is added to each inner list: +%% {erlydtl_opts, [ +%% {out_dir, "ebin"}, +%% {recursive, false}, +%% [ +%% {doc_root, "src"}, {module_ext, "_dtl"} +%% ], +%% [ +%% {doc_root, "templates", {module_ext, ""}, {source_ext, ".html"} +%% ] +%% ]}. -module(rebar_erlydtl_compiler). -export([compile/2]). @@ -81,16 +103,23 @@ %% =================================================================== compile(Config, _AppFile) -> - DtlOpts = erlydtl_opts(Config), + MultiDtlOpts = erlydtl_opts(Config), OrigPath = code:get_path(), true = code:add_path(rebar_utils:ebin_dir()), - Result = rebar_base_compiler:run(Config, [], + + Result = lists:foldl(fun(DtlOpts, _) -> + rebar_base_compiler:run(Config, [], option(doc_root, DtlOpts), option(source_ext, DtlOpts), option(out_dir, DtlOpts), option(module_ext, DtlOpts) ++ ".beam", - fun compile_dtl/3, - [{check_last_mod, false}]), + fun(S, T, _C) -> + compile_dtl(S, T, DtlOpts) + end, + [{check_last_mod, false}, + {recursive, option(recursive, DtlOpts)}]) + end, ok, MultiDtlOpts), + true = code:set_path(OrigPath), Result. @@ -100,7 +129,18 @@ compile(Config, _AppFile) -> %% =================================================================== erlydtl_opts(Config) -> - rebar_config:get(Config, erlydtl_opts, []). + Opts = rebar_config:get(Config, erlydtl_opts, []), + Tuples = [{K,V} || {K,V} <- Opts], + case [L || L <- Opts, is_list(L), not io_lib:printable_list(L)] of + [] -> + lists:keysort(1, [Tuples]); + Lists -> + lists:map(fun(L) -> + lists:keysort(1, lists:foldl(fun({K,T}, Acc) -> + lists:keystore(K, 1, Acc, {K, T}) + end, Tuples, L)) + end, Lists) + end. option(Opt, DtlOpts) -> proplists:get_value(Opt, DtlOpts, default(Opt)). @@ -109,9 +149,11 @@ default(doc_root) -> "templates"; default(out_dir) -> "ebin"; default(source_ext) -> ".dtl"; default(module_ext) -> "_dtl"; -default(custom_tags_dir) -> "". +default(custom_tags_dir) -> ""; +default(compiler_options) -> [report, return]; +default(recursive) -> true. -compile_dtl(Source, Target, Config) -> +compile_dtl(Source, Target, DtlOpts) -> case code:which(erlydtl) of non_existing -> ?ERROR("~n===============================================~n" @@ -122,50 +164,62 @@ compile_dtl(Source, Target, Config) -> "===============================================~n~n", []), ?FAIL; _ -> - case needs_compile(Source, Target, Config) of + case needs_compile(Source, Target, DtlOpts) of true -> - do_compile(Source, Target, Config); + do_compile(Source, Target, DtlOpts); false -> skipped end end. -do_compile(Source, Target, Config) -> +do_compile(Source, Target, DtlOpts) -> %% TODO: Check last mod on target and referenced DTLs here.. - DtlOpts = erlydtl_opts(Config), + %% ensure that doc_root and out_dir are defined, %% using defaults if necessary - Opts = [{out_dir, option(out_dir, DtlOpts)}, - {doc_root, option(doc_root, DtlOpts)}, - {custom_tags_dir, option(custom_tags_dir, DtlOpts)}, - report, return], + Opts = lists:ukeymerge(1, + DtlOpts, + lists:sort( + [{out_dir, option(out_dir, DtlOpts)}, + {doc_root, option(doc_root, DtlOpts)}, + {custom_tags_dir, option(custom_tags_dir, DtlOpts)}, + {compiler_options, option(compiler_options, DtlOpts)}])), + ?INFO("Compiling \"~s\" -> \"~s\" with options:~n ~s~n", + [Source, Target, io_lib:format("~p", [Opts])]), case erlydtl:compile(Source, module_name(Target), - Opts++DtlOpts) of + Opts) of ok -> ok; + {error, {File, [{Pos, _Mod, Err}]}} -> + ?ERROR("Compiling template ~p failed:~n (~s): ~p~n", + [File, err_location(Pos), Err]); Reason -> ?ERROR("Compiling template ~s failed:~n ~p~n", [Source, Reason]), ?FAIL end. +err_location({L,C}) -> io_lib:format("line:~w, col:~w", [L, C]); +err_location(L) -> io_lib:format("line:~w", [L]). + module_name(Target) -> F = filename:basename(Target), string:substr(F, 1, length(F)-length(".beam")). -needs_compile(Source, Target, Config) -> +needs_compile(Source, Target, DtlOpts) -> LM = filelib:last_modified(Target), LM < filelib:last_modified(Source) orelse lists:any(fun(D) -> LM < filelib:last_modified(D) end, - referenced_dtls(Source, Config)). + referenced_dtls(Source, DtlOpts)). -referenced_dtls(Source, Config) -> - Set = referenced_dtls1([Source], Config, +referenced_dtls(Source, DtlOpts) -> + DtlOpts1 = lists:keyreplace(doc_root, 1, DtlOpts, + {doc_root, filename:dirname(Source)}), + Set = referenced_dtls1([Source], DtlOpts1, sets:add_element(Source, sets:new())), sets:to_list(sets:del_element(Source, Set)). -referenced_dtls1(Step, Config, Seen) -> - DtlOpts = erlydtl_opts(Config), +referenced_dtls1(Step, DtlOpts, Seen) -> ExtMatch = re:replace(option(source_ext, DtlOpts), "\.", "\\\\\\\\.", [{return, list}]), @@ -184,10 +238,11 @@ referenced_dtls1(Step, Config, Seen) -> end || F <- Step]), DocRoot = option(doc_root, DtlOpts), WithPaths = [ filename:join([DocRoot, F]) || F <- AllRefs ], + ?DEBUG("All deps: ~p\n", [WithPaths]), Existing = [F || F <- WithPaths, filelib:is_regular(F)], New = sets:subtract(sets:from_list(Existing), Seen), case sets:size(New) of 0 -> Seen; - _ -> referenced_dtls1(sets:to_list(New), Config, + _ -> referenced_dtls1(sets:to_list(New), DtlOpts, sets:union(New, Seen)) end. diff --git a/src/rebar_require_vsn.erl b/src/rebar_require_vsn.erl index 327f75c..83cb79d 100644 --- a/src/rebar_require_vsn.erl +++ b/src/rebar_require_vsn.erl @@ -67,4 +67,33 @@ check_versions(Config) -> nomatch -> ?ABORT("OTP release ~s does not match required regex ~s\n", [erlang:system_info(otp_release), OtpRegex]) + end, + + case rebar_config:get(Config, require_min_otp_vsn, undefined) of + undefined -> ?DEBUG("Min OTP version unconfigured~n", []); + MinOtpVsn -> + {MinMaj, MinMin} = version_tuple(MinOtpVsn, "configured"), + {OtpMaj, OtpMin} = version_tuple(erlang:system_info(otp_release), + "OTP Release"), + case {OtpMaj, OtpMin} >= {MinMaj, MinMin} of + true -> + ?DEBUG("~s satisfies the requirement for vsn ~s~n", + [erlang:system_info(otp_release), + MinOtpVsn]); + false -> + ?ABORT("OTP release ~s or later is required, you have: ~s~n", + [MinOtpVsn, + erlang:system_info(otp_release)]) + end + end. + +version_tuple(OtpRelease, Type) -> + case re:run(OtpRelease, "R(\\d+)B?-?(\\d+)?", [{capture, all, list}]) of + {match, [_Full, Maj, Min]} -> + {list_to_integer(Maj), list_to_integer(Min)}; + {match, [_Full, Maj]} -> + {list_to_integer(Maj), 0}; + nomatch -> + ?ABORT("Cannot parse ~s version string: ~s~n", + [Type, OtpRelease]) end. diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl index 1049c1d..bb58460 100644 --- a/src/rebar_utils.erl +++ b/src/rebar_utils.erl @@ -75,8 +75,7 @@ is_arch(ArchRegex) -> get_arch() -> Words = wordsize(), erlang:system_info(otp_release) ++ "-" - ++ erlang:system_info(system_architecture) ++ "-" ++ Words - ++ "-" ++ os_family(). + ++ erlang:system_info(system_architecture) ++ "-" ++ Words. wordsize() -> try erlang:system_info({wordsize, external}) of @@ -318,10 +317,6 @@ processing_base_dir(Config, 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 -> diff --git a/src/rebar_xref.erl b/src/rebar_xref.erl index 84b59f6..a55d71d 100644 --- a/src/rebar_xref.erl +++ b/src/rebar_xref.erl @@ -28,7 +28,8 @@ %% ------------------------------------------------------------------- %% This module borrows heavily from http://github.com/etnt/exrefcheck project as -%% written by Torbjorn Tornkvist <tobbe@kreditor.se>, Daniel Luna and others. +%% written by Torbjorn Tornkvist <tobbe@kreditor.se>, Daniel Luna +%% <daniel@lunas.se> and others. %% ------------------------------------------------------------------- -module(rebar_xref). @@ -43,7 +44,7 @@ xref(Config, _) -> %% Spin up xref {ok, _} = xref:start(xref), - ok = xref:set_library_path(xref, code_path()), + ok = xref:set_library_path(xref, code_path(Config)), xref:set_default(xref, [{warnings, rebar_config:get(Config, xref_warnings, false)}, @@ -131,9 +132,17 @@ check_query({Query, Value}) -> true end. -code_path() -> - [P || P <- code:get_path(), - filelib:is_dir(P)] ++ [filename:join(rebar_utils:get_cwd(), "ebin")]. +code_path(Config) -> + %% Slight hack to ensure that sub_dirs get properly included + %% in code path for xref -- otherwise one gets a lot of undefined + %% functions, even though those functions are present as part + %% of compilation. H/t to @dluna. Long term we should tie more + %% properly into the overall compile code path if possible. + BaseDir = rebar_config:get_xconf(Config, base_dir), + [P || P <- code:get_path() ++ + [filename:join(BaseDir, filename:join(SubDir, "ebin")) + || SubDir <- rebar_config:get(Config, sub_dirs, [])], + filelib:is_dir(P)]. %% %% Ignore behaviour functions, and explicitly marked functions |