diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/rebar.hrl | 5 | ||||
-rw-r--r-- | src/rebar3.erl | 25 | ||||
-rw-r--r-- | src/rebar_app_info.erl | 5 | ||||
-rw-r--r-- | src/rebar_app_utils.erl | 38 | ||||
-rw-r--r-- | src/rebar_dir.erl | 31 | ||||
-rw-r--r-- | src/rebar_packages.erl | 33 | ||||
-rw-r--r-- | src/rebar_pkg_resource.erl | 10 | ||||
-rw-r--r-- | src/rebar_prv_common_test.erl | 32 | ||||
-rw-r--r-- | src/rebar_prv_compile.erl | 4 | ||||
-rw-r--r-- | src/rebar_prv_cover.erl | 18 | ||||
-rw-r--r-- | src/rebar_prv_new.erl | 23 | ||||
-rw-r--r-- | src/rebar_prv_update.erl | 52 | ||||
-rw-r--r-- | src/rebar_templater.erl | 52 | ||||
-rw-r--r-- | src/rebar_utils.erl | 10 |
14 files changed, 247 insertions, 91 deletions
diff --git a/src/rebar.hrl b/src/rebar.hrl index 8ad0faa..f4e7f5e 100644 --- a/src/rebar.hrl +++ b/src/rebar.hrl @@ -22,8 +22,9 @@ -define(DEFAULT_TEST_DEPS_DIR, "test/lib"). -define(DEFAULT_RELEASE_DIR, "rel"). -define(DEFAULT_CONFIG_FILE, "rebar.config"). --define(DEFAULT_CDN, "https://s3.amazonaws.com/s3.hex.pm/tarballs"). --define(DEFAULT_HEX_REGISTRY, "https://s3.amazonaws.com/s3.hex.pm/registry.ets.gz"). +-define(DEFAULT_CDN, "https://s3.amazonaws.com/s3.hex.pm/"). +-define(REMOTE_PACKAGE_DIR, "tarballs"). +-define(REMOTE_REGISTRY_FILE, "registry.ets.gz"). -define(LOCK_FILE, "rebar.lock"). -define(PACKAGE_INDEX_VERSION, 3). diff --git a/src/rebar3.erl b/src/rebar3.erl index 2b73844..9106bb8 100644 --- a/src/rebar3.erl +++ b/src/rebar3.erl @@ -105,25 +105,32 @@ run_aux(State, RawArgs) -> rebar_state:apply_profiles(State, [list_to_atom(Profile)]) end, + State2 = case os:getenv("HEX_CDN") of + false -> + State1; + CDN -> + rebar_state:set(State1, rebar_packages_cdn, CDN) + end, + %% bootstrap test profile - State2 = rebar_state:add_to_profile(State1, test, test_state(State1)), + State3 = rebar_state:add_to_profile(State2, test, test_state(State1)), %% Process each command, resetting any state between each one BaseDir = rebar_state:get(State, base_dir, ?DEFAULT_BASE_DIR), - State3 = rebar_state:set(State2, base_dir, - filename:join(filename:absname(rebar_state:dir(State2)), BaseDir)), + State4 = rebar_state:set(State3, base_dir, + filename:join(filename:absname(rebar_state:dir(State3)), BaseDir)), {ok, Providers} = application:get_env(rebar, providers), %% Providers can modify profiles stored in opts, so set default after initializing providers - State4 = rebar_state:create_logic_providers(Providers, State3), - State5 = rebar_plugins:project_apps_install(State4), - State6 = rebar_state:default(State5, rebar_state:opts(State5)), + State5 = rebar_state:create_logic_providers(Providers, State4), + State6 = rebar_plugins:project_apps_install(State5), + State7 = rebar_state:default(State6, rebar_state:opts(State6)), {Task, Args} = parse_args(RawArgs), - State7 = rebar_state:code_paths(State6, default, code:get_path()), + State8 = rebar_state:code_paths(State7, default, code:get_path()), - rebar_core:init_command(rebar_state:command_args(State7, Args), Task). + rebar_core:init_command(rebar_state:command_args(State8, Args), Task). init_config() -> %% Initialize logging system @@ -339,4 +346,4 @@ safe_define_test_macro(Opts) -> test_defined([{d, 'TEST'}|_]) -> true; test_defined([{d, 'TEST', true}|_]) -> true; test_defined([_|Rest]) -> test_defined(Rest); -test_defined([]) -> false.
\ No newline at end of file +test_defined([]) -> false. diff --git a/src/rebar_app_info.erl b/src/rebar_app_info.erl index 95b4624..9fee4e0 100644 --- a/src/rebar_app_info.erl +++ b/src/rebar_app_info.erl @@ -23,6 +23,7 @@ original_vsn/1, original_vsn/2, ebin_dir/1, + priv_dir/1, applications/1, applications/2, profiles/1, @@ -361,6 +362,10 @@ out_dir(AppInfo=#app_info_t{}, OutDir) -> ebin_dir(#app_info_t{out_dir=OutDir}) -> ec_cnv:to_list(filename:join(OutDir, "ebin")). +-spec priv_dir(t()) -> file:name(). +priv_dir(#app_info_t{out_dir=OutDir}) -> + ec_cnv:to_list(filename:join(OutDir, "priv")). + -spec resource_type(t(), pkg | src) -> t(). resource_type(AppInfo=#app_info_t{}, Type) -> AppInfo#app_info_t{resource_type=Type}. diff --git a/src/rebar_app_utils.erl b/src/rebar_app_utils.erl index 602fd42..ae1ea1c 100644 --- a/src/rebar_app_utils.erl +++ b/src/rebar_app_utils.erl @@ -118,14 +118,14 @@ parse_dep(Dep, Parent, DepsDir, State, Locks, Level) -> end. parse_dep(Parent, {Name, Vsn, {pkg, PkgName}}, DepsDir, IsLock, State) -> - {PkgName1, PkgVsn} = parse_goal(ec_cnv:to_binary(PkgName), ec_cnv:to_binary(Vsn)), + {PkgName1, PkgVsn} = {ec_cnv:to_binary(PkgName), ec_cnv:to_binary(Vsn)}, dep_to_app(Parent, DepsDir, Name, PkgVsn, {pkg, PkgName1, PkgVsn}, IsLock, State); parse_dep(Parent, {Name, {pkg, PkgName}}, DepsDir, IsLock, State) -> %% Package dependency with different package name from app name dep_to_app(Parent, DepsDir, Name, undefined, {pkg, ec_cnv:to_binary(PkgName), undefined}, IsLock, State); parse_dep(Parent, {Name, Vsn}, DepsDir, IsLock, State) when is_list(Vsn); is_binary(Vsn) -> %% Versioned Package dependency - {PkgName, PkgVsn} = parse_goal(ec_cnv:to_binary(Name), ec_cnv:to_binary(Vsn)), + {PkgName, PkgVsn} = {ec_cnv:to_binary(Name), ec_cnv:to_binary(Vsn)}, dep_to_app(Parent, DepsDir, PkgName, PkgVsn, {pkg, PkgName, PkgVsn}, IsLock, State); parse_dep(Parent, Name, DepsDir, IsLock, State) when is_atom(Name); is_binary(Name) -> %% Unversioned package dependency @@ -168,21 +168,22 @@ dep_to_app(Parent, DepsDir, Name, Vsn, Source, IsLock, State) -> AppInfo3 = rebar_app_info:apply_overrides(rebar_app_info:get(AppInfo2, overrides, []), AppInfo2), rebar_app_info:is_lock(AppInfo3, IsLock). -update_source(AppInfo, {pkg, PkgName, undefined}, State) -> - {PkgName1, PkgVsn1} = get_package(PkgName, State), +update_source(AppInfo, {pkg, PkgName, PkgVsn}, State) -> + {PkgName1, PkgVsn1} = case PkgVsn of + undefined -> + get_package(PkgName, "0", State); + <<"~>", Vsn/binary>> -> + [Vsn1] = binary:split(Vsn, [<<" ">>], [trim_all, global]), + get_package(PkgName, Vsn1, State); + _ -> + {PkgName, PkgVsn} + end, AppInfo1 = rebar_app_info:source(AppInfo, {pkg, PkgName1, PkgVsn1}), Deps = rebar_packages:deps(PkgName1 ,PkgVsn1 ,State), AppInfo2 = rebar_app_info:resource_type(rebar_app_info:deps(AppInfo1, Deps), pkg), rebar_app_info:original_vsn(AppInfo2, PkgVsn1); -update_source(AppInfo, {pkg, PkgName, PkgVsn}, State) -> - AppInfo1 = rebar_app_info:source(AppInfo, {pkg, PkgName, PkgVsn}), - Deps = rebar_packages:deps(PkgName - ,PkgVsn - ,State), - AppInfo2 = rebar_app_info:resource_type(rebar_app_info:deps(AppInfo1, Deps), pkg), - rebar_app_info:original_vsn(AppInfo2, PkgVsn); update_source(AppInfo, Source, _State) -> rebar_app_info:source(AppInfo, Source). @@ -198,19 +199,8 @@ format_error(Error) -> %% Internal functions %% =================================================================== --spec parse_goal(binary(), binary()) -> {binary(), binary()} | {binary(), binary(), binary()}. -parse_goal(Name, Constraint) -> - case re:run(Constraint, "([^\\d]*)(\\d.*)", [{capture, [1,2], binary}]) of - {match, [<<>>, Vsn]} -> - {Name, Vsn}; - {match, [Op, Vsn]} -> - {Name, Vsn, binary_to_atom(Op, utf8)}; - nomatch -> - throw(?PRV_ERROR({bad_constraint, Name, Constraint})) - end. - -get_package(Dep, State) -> - case rebar_packages:find_highest_matching(Dep, "0", ?PACKAGE_TABLE, State) of +get_package(Dep, Vsn, State) -> + case rebar_packages:find_highest_matching(Dep, Vsn, ?PACKAGE_TABLE, State) of {ok, HighestDepVsn} -> {Dep, HighestDepVsn}; none -> diff --git a/src/rebar_dir.erl b/src/rebar_dir.erl index 09e3114..3729704 100644 --- a/src/rebar_dir.erl +++ b/src/rebar_dir.erl @@ -121,8 +121,37 @@ processing_base_dir(State, Dir) -> AbsDir = filename:absname(Dir), AbsDir =:= rebar_state:get(State, base_dir). +make_absolute_path(Path) -> + case filename:pathtype(Path) of + absolute -> + Path; + relative -> + {ok, Dir} = file:get_cwd(), + filename:join([Dir, Path]); + volumerelative -> + Volume = hd(filename:split(Path)), + {ok, Dir} = file:get_cwd(Volume), + filename:join([Dir, Path]) + end. + +make_normalized_path(Path) -> + AbsPath = make_absolute_path(Path), + Components = filename:split(AbsPath), + make_normalized_path(Components, []). + +make_normalized_path([], NormalizedPath) -> + filename:join(lists:reverse(NormalizedPath)); +make_normalized_path([H|T], NormalizedPath) -> + case H of + "." -> make_normalized_path(T, NormalizedPath); + ".." -> make_normalized_path(T, tl(NormalizedPath)); + _ -> make_normalized_path(T, [H|NormalizedPath]) + end. + make_relative_path(Source, Target) -> - do_make_relative_path(filename:split(Source), filename:split(Target)). + AbsSource = make_normalized_path(Source), + AbsTarget = make_normalized_path(Target), + do_make_relative_path(filename:split(AbsSource), filename:split(AbsTarget)). do_make_relative_path([H|T1], [H|T2]) -> do_make_relative_path(T1, T2); diff --git a/src/rebar_packages.erl b/src/rebar_packages.erl index c0ed69d..c56009e 100644 --- a/src/rebar_packages.erl +++ b/src/rebar_packages.erl @@ -46,7 +46,7 @@ close_packages() -> catch ets:delete(?PACKAGE_TABLE). load_and_verify_version(State) -> - RegistryDir = registry_dir(State), + {ok, RegistryDir} = registry_dir(State), case ets:file2tab(filename:join(RegistryDir, ?INDEX_FILE)) of {ok, _} -> case ets:lookup_element(?PACKAGE_TABLE, package_index_version, 2) of @@ -89,21 +89,30 @@ registry_dir(State) -> ?DEFAULT_CDN -> RegistryDir = filename:join([CacheDir, "hex", "default"]), ok = filelib:ensure_dir(filename:join(RegistryDir, "placeholder")), - RegistryDir; + {ok, RegistryDir}; CDN -> - {ok, {_, _, Host, _, Path, _}} = http_uri:parse(CDN), - CDNHostPath = lists:reverse(string:tokens(Host, ".")), - CDNPath = tl(filename:split(Path)), - RegistryDir = filename:join([CacheDir, "hex"] ++ CDNHostPath ++ CDNPath), - ok = filelib:ensure_dir(filename:join(RegistryDir, "placeholder")), - RegistryDir + case rebar_utils:url_append_path(CDN, ?REMOTE_PACKAGE_DIR) of + {ok, Parsed} -> + {ok, {_, _, Host, _, Path, _}} = http_uri:parse(Parsed), + CDNHostPath = lists:reverse(string:tokens(Host, ".")), + CDNPath = tl(filename:split(Path)), + RegistryDir = filename:join([CacheDir, "hex"] ++ CDNHostPath ++ CDNPath), + ok = filelib:ensure_dir(filename:join(RegistryDir, "placeholder")), + {ok, RegistryDir}; + _ -> + {uri_parse_error, CDN} + end end. package_dir(State) -> - RegistryDir = registry_dir(State), - PackageDir = filename:join([RegistryDir, "packages"]), - ok = filelib:ensure_dir(filename:join(PackageDir, "placeholder")), - PackageDir. + case registry_dir(State) of + {ok, RegistryDir} -> + PackageDir = filename:join([RegistryDir, "packages"]), + ok = filelib:ensure_dir(filename:join(PackageDir, "placeholder")), + {ok, PackageDir}; + Error -> + Error + end. registry_checksum({pkg, Name, Vsn}, State) -> try diff --git a/src/rebar_pkg_resource.erl b/src/rebar_pkg_resource.erl index 4f55ad1..33687e4 100644 --- a/src/rebar_pkg_resource.erl +++ b/src/rebar_pkg_resource.erl @@ -30,11 +30,15 @@ needs_update(Dir, {pkg, _Name, Vsn}) -> download(TmpDir, Pkg={pkg, Name, Vsn}, State) -> CDN = rebar_state:get(State, rebar_packages_cdn, ?DEFAULT_CDN), - PackageDir = rebar_packages:package_dir(State), + {ok, PackageDir} = rebar_packages:package_dir(State), Package = binary_to_list(<<Name/binary, "-", Vsn/binary, ".tar">>), CachePath = filename:join(PackageDir, Package), - Url = string:join([CDN, Package], "/"), - cached_download(TmpDir, CachePath, Pkg, Url, etag(CachePath), State). + case rebar_utils:url_append_path(CDN, filename:join(?REMOTE_PACKAGE_DIR, Package)) of + {ok, Url} -> + cached_download(TmpDir, CachePath, Pkg, Url, etag(CachePath), State); + _ -> + {fetch_fail, Name, Vsn} + end. cached_download(TmpDir, CachePath, Pkg={pkg, Name, Vsn}, Url, ETag, State) -> case request(Url, ETag) of diff --git a/src/rebar_prv_common_test.erl b/src/rebar_prv_common_test.erl index 05a1dc6..1136e08 100644 --- a/src/rebar_prv_common_test.erl +++ b/src/rebar_prv_common_test.erl @@ -340,7 +340,7 @@ test_dirs(State, Apps, Opts) -> {Suites, Dir} when is_integer(hd(Dir)) -> set_compile_dirs(State, Apps, join(Suites, Dir)); {Suites, [Dir]} when is_integer(hd(Dir)) -> - set_compile_dirs(State, Apps, join(Suites, Dir)); + set_compile_dirs(State, Apps, join(Suites, Dir)); {_Suites, _Dirs} -> {error, "Only a single directory may be specified when specifying suites"} end. @@ -375,6 +375,17 @@ find_suite_dirs(Suites) -> maybe_inject_test_dir(State, AppAcc, [App|Rest], Dir) -> case rebar_file_utils:path_from_ancestor(Dir, rebar_app_info:dir(App)) of + {ok, []} -> + %% normal operation involves copying the entire directory a + %% suite exists in but if the suite is in the app root directory + %% the current compiler tries to compile all subdirs including priv + %% instead copy only files ending in `.erl' and directories + %% ending in `_SUITE_data' into the `_build/PROFILE/extras' dir + {ok, RelAppDir} = rebar_file_utils:path_from_ancestor(rebar_app_info:dir(App), rebar_state:dir(State)), + ExtrasDir = filename:join([rebar_dir:base_dir(State), "extras", RelAppDir]), + ok = copy_bare_suites(Dir, ExtrasDir), + Opts = inject_test_dir(rebar_state:opts(State), ExtrasDir), + {rebar_state:opts(State, Opts), AppAcc}; {ok, Path} -> Opts = inject_test_dir(rebar_app_info:opts(App), Path), {State, AppAcc ++ [rebar_app_info:opts(App, Opts)] ++ Rest}; @@ -384,8 +395,15 @@ maybe_inject_test_dir(State, AppAcc, [App|Rest], Dir) -> maybe_inject_test_dir(State, AppAcc, [], Dir) -> case rebar_file_utils:path_from_ancestor(Dir, rebar_state:dir(State)) of {ok, []} -> - ?WARN("Can't have suites in root of project dir, dropping from tests", []), - {State, AppAcc}; + %% normal operation involves copying the entire directory a + %% suite exists in but if the suite is in the root directory + %% that results in a loop as we copy `_build' into itself + %% instead copy only files ending in `.erl' and directories + %% ending in `_SUITE_data' in the `_build/PROFILE/extras' dir + ExtrasDir = filename:join([rebar_dir:base_dir(State), "extras"]), + ok = copy_bare_suites(Dir, ExtrasDir), + Opts = inject_test_dir(rebar_state:opts(State), ExtrasDir), + {rebar_state:opts(State, Opts), AppAcc}; {ok, Path} -> Opts = inject_test_dir(rebar_state:opts(State), Path), {rebar_state:opts(State, Opts), AppAcc}; @@ -393,6 +411,14 @@ maybe_inject_test_dir(State, AppAcc, [], Dir) -> {State, AppAcc} end. +copy_bare_suites(From, To) -> + filelib:ensure_dir(filename:join([To, "dummy.txt"])), + SrcFiles = rebar_utils:find_files(From, ".*\\.[e|h]rl\$", false), + DataDirs = lists:filter(fun filelib:is_dir/1, + filelib:wildcard(filename:join([From, "*_SUITE_data"]))), + ok = rebar_file_utils:cp_r(SrcFiles, To), + rebar_file_utils:cp_r(DataDirs, To). + inject_test_dir(Opts, Dir) -> %% append specified test targets to app defined `extra_src_dirs` ExtraSrcDirs = rebar_opts:get(Opts, extra_src_dirs, []), diff --git a/src/rebar_prv_compile.erl b/src/rebar_prv_compile.erl index 2996aee..d57b82b 100644 --- a/src/rebar_prv_compile.erl +++ b/src/rebar_prv_compile.erl @@ -217,6 +217,10 @@ copy(OldAppDir, AppDir, Dir) -> %% TODO: use ec_file:copy/2 to do this, it preserves timestamps and %% may prevent recompilation of files in extra dirs +copy(Source, Source) -> + %% allow users to specify a directory in _build as a directory + %% containing additional source/tests + ok; copy(Source, Target) -> %% important to do this so no files are copied onto themselves %% which truncates them to zero length on some platforms diff --git a/src/rebar_prv_cover.erl b/src/rebar_prv_cover.erl index 15a067e..c915141 100644 --- a/src/rebar_prv_cover.erl +++ b/src/rebar_prv_cover.erl @@ -207,6 +207,8 @@ format_table(Stats, CoverFiles) -> MaxLength = max(lists:foldl(fun max_length/2, 0, Stats), 20), Header = header(MaxLength), Seperator = seperator(MaxLength), + TotalLabel = format("total", MaxLength), + TotalCov = format(calculate_total(Stats), 8), [io_lib:format("~ts~n~ts~n~ts~n", [Seperator, Header, Seperator]), lists:map(fun({Mod, Coverage}) -> Name = format(Mod, MaxLength), @@ -214,6 +216,8 @@ format_table(Stats, CoverFiles) -> io_lib:format(" | ~ts | ~ts |~n", [Name, Cov]) end, Stats), io_lib:format("~ts~n", [Seperator]), + io_lib:format(" | ~ts | ~ts |~n", [TotalLabel, TotalCov]), + io_lib:format("~ts~n", [Seperator]), io_lib:format(" coverage calculated from:~n", []), lists:map(fun(File) -> io_lib:format(" ~ts~n", [File]) @@ -234,6 +238,18 @@ seperator(Width) -> format(String, Width) -> io_lib:format("~*.ts", [Width, String]). +calculate_total(Stats) when length(Stats) =:= 0 -> + "0%"; +calculate_total(Stats) -> + TotalStats = length(Stats), + TotalCovInt = round(lists:foldl( + fun({_Mod, Coverage, _File}, Acc) -> + Acc + (list_to_integer(string:strip(Coverage, right, $%)) / TotalStats); + ({_Mod, Coverage}, Acc) -> + Acc + (list_to_integer(string:strip(Coverage, right, $%)) / TotalStats) + end, 0, Stats)), + integer_to_list(TotalCovInt) ++ "%". + write_index(State, Coverage) -> CoverDir = cover_dir(State), FileName = filename:join([CoverDir, "index.html"]), @@ -265,6 +281,8 @@ write_index_section(F, [{Section, DataFile, Mods}|Rest]) -> [strip_coverdir(Report), Mod, Cov]) end, lists:foreach(fun(M) -> ok = file:write(F, FmtLink(M)) end, Mods), + ok = file:write(F, ?FMT("<tr><td><strong>Total</strong></td><td>~ts</td>\n", + [calculate_total(Mods)])), ok = file:write(F, "</table>\n"), write_index_section(F, Rest). diff --git a/src/rebar_prv_new.erl b/src/rebar_prv_new.erl index 28572a9..064315e 100644 --- a/src/rebar_prv_new.erl +++ b/src/rebar_prv_new.erl @@ -7,6 +7,7 @@ format_error/1]). -include("rebar.hrl"). +-include_lib("providers/include/providers.hrl"). -define(PROVIDER, new). -define(DEPS, []). @@ -35,16 +36,16 @@ do(State) -> case strip_flags(rebar_state:command_args(State)) of ["help"] -> ?CONSOLE("Call `rebar3 new help <template>` for a detailed description~n", []), - show_short_templates(rebar_templater:list_templates(State)), + show_short_templates(list_templates(State)), {ok, State}; ["help", TemplateName] -> - case lists:keyfind(TemplateName, 1, rebar_templater:list_templates(State)) of + case lists:keyfind(TemplateName, 1, list_templates(State)) of false -> ?CONSOLE("template not found.", []); Term -> show_template(Term) end, {ok, State}; [TemplateName | Opts] -> - case lists:keyfind(TemplateName, 1, rebar_templater:list_templates(State)) of + case lists:keyfind(TemplateName, 1, list_templates(State)) of false -> ?CONSOLE("template not found.", []); _ -> @@ -53,11 +54,13 @@ do(State) -> end, {ok, State}; [] -> - show_short_templates(rebar_templater:list_templates(State)), + show_short_templates(list_templates(State)), {ok, State} end. -spec format_error(any()) -> iolist(). +format_error({consult, File, Reason}) -> + io_lib:format("Error consulting file at ~s for reason ~p", [File, Reason]); format_error(Reason) -> io_lib:format("~p", [Reason]). @@ -65,6 +68,15 @@ format_error(Reason) -> %% Internal functions %% =================================================================== +list_templates(State) -> + lists:foldl(fun({error, {consult, File, Reason}}, Acc) -> + ?WARN("Error consulting template file ~s for reason ~p", + [File, Reason]), + Acc + ; (Tpl, Acc) -> + [Tpl|Acc] + end, [], lists:reverse(rebar_templater:list_templates(State))). + info() -> io_lib:format( "Create rebar3 project based on template and vars.~n" @@ -120,10 +132,13 @@ show_template({Name, Type, Location, Description, Vars}) -> format_vars(Vars)]). format_type(escript) -> "built-in"; +format_type(plugin) -> "plugin"; format_type(file) -> "custom". format_type(escript, _) -> "built-in template"; +format_type(plugin, Loc) -> + io_lib:format("plugin template (~s)", [Loc]); format_type(file, Loc) -> io_lib:format("custom template (~s)", [Loc]). diff --git a/src/rebar_prv_update.erl b/src/rebar_prv_update.erl index 33d757a..1cdf6af 100644 --- a/src/rebar_prv_update.erl +++ b/src/rebar_prv_update.erl @@ -36,26 +36,36 @@ init(State) -> -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(State) -> try - RegistryDir = rebar_packages:registry_dir(State), - filelib:ensure_dir(filename:join(RegistryDir, "dummy")), - HexFile = filename:join(RegistryDir, "registry"), - ?INFO("Updating package registry...", []), - TmpDir = ec_file:insecure_mkdtemp(), - TmpFile = filename:join(TmpDir, "packages.gz"), + case rebar_packages:registry_dir(State) of + {ok, RegistryDir} -> + filelib:ensure_dir(filename:join(RegistryDir, "dummy")), + HexFile = filename:join(RegistryDir, "registry"), + ?INFO("Updating package registry...", []), + TmpDir = ec_file:insecure_mkdtemp(), + TmpFile = filename:join(TmpDir, "packages.gz"), - Url = rebar_state:get(State, rebar_packages_cdn, ?DEFAULT_HEX_REGISTRY), - case httpc:request(get, {Url, []}, - [], [{stream, TmpFile}, {sync, true}], - rebar) of - {ok, saved_to_file} -> - {ok, Data} = file:read_file(TmpFile), - Unzipped = zlib:gunzip(Data), - ok = file:write_file(HexFile, Unzipped), - ?INFO("Writing registry to ~s", [HexFile]), - hex_to_index(State), - {ok, State}; - _ -> - ?PRV_ERROR(package_index_download) + CDN = rebar_state:get(State, rebar_packages_cdn, ?DEFAULT_CDN), + case rebar_utils:url_append_path(CDN, ?REMOTE_REGISTRY_FILE) of + {ok, Url} -> + ?DEBUG("Fetching registry from ~p", [Url]), + case httpc:request(get, {Url, []}, + [], [{stream, TmpFile}, {sync, true}], + rebar) of + {ok, saved_to_file} -> + {ok, Data} = file:read_file(TmpFile), + Unzipped = zlib:gunzip(Data), + ok = file:write_file(HexFile, Unzipped), + ?INFO("Writing registry to ~s", [HexFile]), + hex_to_index(State), + {ok, State}; + _ -> + ?PRV_ERROR(package_index_download) + end; + _ -> + ?PRV_ERROR({package_parse_cdn, CDN}) + end; + {uri_parse_error, CDN} -> + ?PRV_ERROR({package_parse_cdn, CDN}) end catch _E:C -> @@ -64,6 +74,8 @@ do(State) -> end. -spec format_error(any()) -> iolist(). +format_error({package_parse_cdn, Uri}) -> + io_lib:format("Failed to parse CDN url: ~p", [Uri]); format_error(package_index_download) -> "Failed to download package index."; format_error(package_index_write) -> @@ -75,7 +87,7 @@ is_supported(<<"rebar3">>) -> true; is_supported(_) -> false. hex_to_index(State) -> - RegistryDir = rebar_packages:registry_dir(State), + {ok, RegistryDir} = rebar_packages:registry_dir(State), HexFile = filename:join(RegistryDir, "registry"), try ets:file2tab(HexFile) of {ok, Registry} -> diff --git a/src/rebar_templater.erl b/src/rebar_templater.erl index c7fb2af..f687637 100644 --- a/src/rebar_templater.erl +++ b/src/rebar_templater.erl @@ -59,10 +59,14 @@ list_templates(State) -> %% Expand a single template's value list_template(Files, {Name, Type, File}, State) -> - TemplateTerms = consult(load_file(Files, Type, File)), - {Name, Type, File, - get_template_description(TemplateTerms), - get_template_vars(TemplateTerms, State)}. + case consult(load_file(Files, Type, File)) of + {error, Reason} -> + {error, {consult, File, Reason}}; + TemplateTerms -> + {Name, Type, File, + get_template_description(TemplateTerms), + get_template_vars(TemplateTerms, State)} + end. %% Load up the template description out from a list of attributes read in %% a .template file. @@ -235,6 +239,7 @@ replace_var([H|T], Acc, Vars) -> %% Load a list of all the files in the escript and on disk find_templates(State) -> DiskTemplates = find_disk_templates(State), + PluginTemplates = find_plugin_templates(State), {MainTemplates, Files} = case rebar_state:escript_path(State) of undefined -> @@ -245,19 +250,23 @@ find_templates(State) -> F = cache_escript_files(State), {find_escript_templates(F), F} end, - AvailTemplates = find_available_templates(DiskTemplates, - MainTemplates), + AvailTemplates = find_available_templates([MainTemplates, + PluginTemplates, + DiskTemplates]), ?DEBUG("Available templates: ~p\n", [AvailTemplates]), {AvailTemplates, Files}. -find_available_templates(TemplateList1, TemplateList2) -> - AvailTemplates = prioritize_templates( - tag_names(TemplateList1), - tag_names(TemplateList2)), - +find_available_templates(TemplateListList) -> + AvailTemplates = prioritize_templates(TemplateListList), ?DEBUG("Available templates: ~p\n", [AvailTemplates]), AvailTemplates. +prioritize_templates([TemplateList]) -> + tag_names(TemplateList); +prioritize_templates([TemplateList | TemplateListList]) -> + prioritize_templates(tag_names(TemplateList), + prioritize_templates(TemplateListList)). + %% Scan the current escript for available files cache_escript_files(State) -> {ok, Files} = rebar_utils:escript_foldl( @@ -295,6 +304,14 @@ find_other_templates(State) -> rebar_utils:find_files(TemplateDir, ?TEMPLATE_RE) end. +%% Fetch template indexes that sit on disk in plugins +find_plugin_templates(State) -> + [{plugin, File} + || App <- rebar_state:all_plugin_deps(State), + Priv <- [rebar_app_info:priv_dir(App)], + Priv =/= undefined, + File <- rebar_utils:find_files(Priv, ?TEMPLATE_RE)]. + %% Take an existing list of templates and tag them by name the way %% the user would enter it from the CLI tag_names(List) -> @@ -312,6 +329,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); + {_, plugin, _} -> + ?DEBUG("Skipping template ~p, due to presence of a plugin " + "template with the same name", [Name]), + prioritize_templates(Rest, Valid); {_, file, _} -> ?DEBUG("Skipping template ~p, due to presence of a custom " "template at ~s", [Name, File]), @@ -323,6 +344,9 @@ prioritize_templates([{Name, Type, File} | Rest], Valid) -> load_file(Files, escript, Name) -> {Name, Bin} = lists:keyfind(Name, 1, Files), Bin; +load_file(_Files, plugin, Name) -> + {ok, Bin} = file:read_file(Name), + Bin; load_file(_Files, file, Name) -> {ok, Bin} = file:read_file(Name), Bin. @@ -338,8 +362,10 @@ consult(Cont, Str, Acc) -> {done, Result, Remaining} -> case Result of {ok, Tokens, _} -> - {ok, Term} = erl_parse:parse_term(Tokens), - consult([], Remaining, [Term | Acc]); + case erl_parse:parse_term(Tokens) of + {ok, Term} -> consult([], Remaining, [Term | Acc]); + {error, Reason} -> {error, Reason} + end; {eof, _Other} -> lists:reverse(Acc); {error, Info, _} -> diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl index fb651c3..746c57a 100644 --- a/src/rebar_utils.erl +++ b/src/rebar_utils.erl @@ -61,6 +61,7 @@ tup_find/2, line_count/1, set_httpc_options/0, + url_append_path/2, escape_chars/1, escape_double_quotes/1, escape_double_quotes_weak/1, @@ -798,6 +799,15 @@ set_httpc_options(Scheme, Proxy) -> {ok, {_, _, Host, Port, _, _}} = http_uri:parse(Proxy), httpc:set_options([{Scheme, {{Host, Port}, []}}], rebar). +url_append_path(Url, ExtraPath) -> + case http_uri:parse(Url) of + {ok, {Scheme, UserInfo, Host, Port, Path, Query}} -> + {ok, lists:append([atom_to_list(Scheme), "://", UserInfo, Host, ":", integer_to_list(Port), + filename:join(Path, ExtraPath), "?", Query])}; + _ -> + error + end. + %% escape\ as\ a\ shell\? escape_chars(Str) when is_atom(Str) -> escape_chars(atom_to_list(Str)); |