From 2ff4ac6d5049746be80263e48df5d864606e22d6 Mon Sep 17 00:00:00 2001 From: Fred Hebert Date: Fri, 17 Apr 2015 16:37:33 +0000 Subject: Default deps always to the default profile When fetching dependencies for the first time using a profile (`rebar3 as prod release` or `rebar3 ct`), the dependencies get fetched into the non-default profile. This has two consequences: - the files get re-downloaded on follow-up runs - the lock file includes incomplete or too many deps in its list This patch forces dependencies in the default profile to be stored in _build/default/lib even when running under other profiles, then symlinks them to the correct one. This makes it so common dependencies in 'default' be downloaded there and avoids re-downloading them. Should also fix the lock issues. --- src/rebar_dir.erl | 7 +++- src/rebar_prv_install_deps.erl | 81 ++++++++++++++++++++++++++++----------- src/rebar_prv_lock.erl | 29 ++++++++------ test/rebar_install_deps_SUITE.erl | 67 +++++++++++++++++++++++++++++++- 4 files changed, 146 insertions(+), 38 deletions(-) diff --git a/src/rebar_dir.erl b/src/rebar_dir.erl index 7903ed5..7a12eeb 100644 --- a/src/rebar_dir.erl +++ b/src/rebar_dir.erl @@ -1,6 +1,7 @@ -module(rebar_dir). -export([base_dir/1, + profile_dir/2, deps_dir/1, deps_dir/2, checkouts_dir/1, @@ -24,7 +25,10 @@ -spec base_dir(rebar_state:t()) -> file:filename_all(). base_dir(State) -> - Profiles = rebar_state:current_profiles(State), + profile_dir(State, rebar_state:current_profiles(State)). + +-spec profile_dir(rebar_state:t(), [atom()]) -> file:filename_all(). +profile_dir(State, Profiles) -> ProfilesStrings = case [ec_cnv:to_list(P) || P <- Profiles] of ["default"] -> ["default"]; %% drop `default` from the profile dir if it's implicit and reverse order @@ -34,6 +38,7 @@ base_dir(State) -> ProfilesDir = string:join(ProfilesStrings, "+"), filename:join(rebar_state:get(State, base_dir, ?DEFAULT_BASE_DIR), ProfilesDir). + -spec deps_dir(rebar_state:t()) -> file:filename_all(). deps_dir(State) -> filename:join(base_dir(State), rebar_state:get(State, deps_dir, ?DEFAULT_DEPS_DIR)). diff --git a/src/rebar_prv_install_deps.erl b/src/rebar_prv_install_deps.erl index c535b4d..c39afad 100644 --- a/src/rebar_prv_install_deps.erl +++ b/src/rebar_prv_install_deps.erl @@ -137,7 +137,7 @@ handle_deps(Profile, State0, Deps, Upgrade, Locks) -> Registry = rebar_packages:registry(State0), State = rebar_state:packages(rebar_state:registry(State0, Registry), {Packages, Graph}), %% Split source deps from pkg deps, needed to keep backwards compatibility - DepsDir = rebar_dir:deps_dir(State), + DepsDir = profile_dep_dir(State, Profile), {SrcDeps, PkgDeps} = parse_deps(DepsDir, Deps, State, Locks, 0), %% Fetch transitive src deps @@ -203,7 +203,7 @@ update_pkg_deps(Profile, Packages, PkgDeps, Graph, Upgrade, Seen, State) -> update_pkg_deps(Profile, Pkgs, Packages, Upgrade, Seen, State) -> %% Create app_info record for each pkg dep - DepsDir = rebar_dir:deps_dir(State), + DepsDir = profile_dep_dir(State, Profile), {Solved, _, State1} = lists:foldl(fun(Pkg, {Acc, SeenAcc, StateAcc}) -> handle_pkg_dep(Profile, Pkg, Packages, Upgrade, DepsDir, Acc, SeenAcc, StateAcc) @@ -214,7 +214,7 @@ handle_pkg_dep(Profile, Pkg, Packages, Upgrade, DepsDir, Fetched, Seen, State) - AppInfo = package_to_app(DepsDir, Packages, Pkg), Level = rebar_app_info:dep_level(AppInfo), {NewSeen, NewState} = maybe_lock(Profile, AppInfo, Seen, State, Level), - {_, AppInfo1} = maybe_fetch(AppInfo, Upgrade, Seen, NewState), + {_, AppInfo1} = maybe_fetch(AppInfo, Profile, Upgrade, Seen, NewState), {[AppInfo1 | Fetched], NewSeen, NewState}. maybe_lock(Profile, AppInfo, Seen, State, Level) -> @@ -252,7 +252,7 @@ package_to_app(DepsDir, Packages, {Name, Vsn, Level}) -> || {PkgName,PkgVsn} <- proplists:get_value(<<"deps">>, P, [])], {ok, AppInfo} = rebar_app_info:new(Name, Vsn), AppInfo1 = rebar_app_info:deps(AppInfo, PkgDeps), - AppInfo2 = rebar_app_info:dir(AppInfo1, rebar_dir:deps_dir(DepsDir, Name)), + AppInfo2 = rebar_app_info:dir(AppInfo1, filename:join([DepsDir, Name])), AppInfo3 = rebar_app_info:dep_level(AppInfo2, Level), rebar_app_info:source(AppInfo3, {pkg, Name, Vsn}) end. @@ -278,7 +278,7 @@ update_src_dep(AppInfo, Profile, Level, SrcDeps, PkgDeps, SrcApps, State, Upgrad Name = rebar_app_info:name(AppInfo), case sets:is_element(Name, Seen) of true -> - update_seen_src_dep(AppInfo, Level, + update_seen_src_dep(AppInfo, Profile, Level, SrcDeps, PkgDeps, SrcApps, State, Upgrade, Seen, BaseLocks, Locks); false -> @@ -288,7 +288,13 @@ update_src_dep(AppInfo, Profile, Level, SrcDeps, PkgDeps, SrcApps, State, Upgrad end. -update_seen_src_dep(AppInfo, Level, SrcDeps, PkgDeps, SrcApps, State, Upgrade, Seen, BaseLocks, Locks) -> +profile_dep_dir(State, Profile) -> + case Profile of + default -> filename:join([rebar_dir:profile_dir(State, [default]), rebar_state:get(State, deps_dir, ?DEFAULT_DEPS_DIR)]); + _ -> rebar_dir:deps_dir(State) + end. + +update_seen_src_dep(AppInfo, Profile, Level, SrcDeps, PkgDeps, SrcApps, State, Upgrade, Seen, BaseLocks, Locks) -> Name = rebar_app_info:name(AppInfo), %% If seen from lock file don't print warning about skipping case lists:keymember(Name, 1, BaseLocks) of @@ -303,7 +309,7 @@ update_seen_src_dep(AppInfo, Level, SrcDeps, PkgDeps, SrcApps, State, Upgrade, S {SrcDeps, PkgDeps, SrcApps, State, Seen, Locks}; true -> {NewSrcDeps, NewPkgDeps, NewSrcApps, NewState, NewLocks} - = handle_dep(AppInfo, SrcDeps, PkgDeps, SrcApps, + = handle_dep(AppInfo, Profile, SrcDeps, PkgDeps, SrcApps, Level, State, Locks), {NewSrcDeps, NewPkgDeps, NewSrcApps, NewState, Seen, NewLocks} end. @@ -313,22 +319,22 @@ update_unseen_src_dep(AppInfo, Profile, Level, SrcDeps, PkgDeps, SrcApps, State, {NewSrcDeps, NewPkgDeps, NewSrcApps, State2, NewLocks} = case Upgrade of true -> - handle_upgrade(AppInfo, SrcDeps, PkgDeps, SrcApps, + handle_upgrade(AppInfo, Profile, SrcDeps, PkgDeps, SrcApps, Level, State1, Locks); _ -> - {_, AppInfo1} = maybe_fetch(AppInfo, false, Seen, State1), - handle_dep(AppInfo1, SrcDeps, PkgDeps, SrcApps, + {_, AppInfo1} = maybe_fetch(AppInfo, Profile, false, Seen, State1), + handle_dep(AppInfo1, Profile, SrcDeps, PkgDeps, SrcApps, Level, State1, Locks) end, {NewSrcDeps, NewPkgDeps, NewSrcApps, State2, NewSeen, NewLocks}. -handle_upgrade(AppInfo, SrcDeps, PkgDeps, SrcApps, Level, State, Locks) -> +handle_upgrade(AppInfo, Profile, SrcDeps, PkgDeps, SrcApps, Level, State, Locks) -> Name = rebar_app_info:name(AppInfo), case lists:keyfind(Name, 1, Locks) of false -> - case maybe_fetch(AppInfo, true, sets:new(), State) of + case maybe_fetch(AppInfo, Profile, true, sets:new(), State) of {true, AppInfo1} -> - handle_dep(AppInfo1, SrcDeps, PkgDeps, SrcApps, + handle_dep(AppInfo1, Profile, SrcDeps, PkgDeps, SrcApps, Level, State, Locks); {false, AppInfo1} -> @@ -338,8 +344,8 @@ handle_upgrade(AppInfo, SrcDeps, PkgDeps, SrcApps, Level, State, Locks) -> {[AppInfo|SrcDeps], PkgDeps, SrcApps, State, Locks} end. -handle_dep(AppInfo, SrcDeps, PkgDeps, SrcApps, Level, State, Locks) -> - DepsDir = rebar_dir:deps_dir(State), +handle_dep(AppInfo, Profile, SrcDeps, PkgDeps, SrcApps, Level, State, Locks) -> + DepsDir = profile_dep_dir(State, Profile), {AppInfo1, NewSrcDeps, NewPkgDeps, NewLocks, State1} = handle_dep(State, DepsDir, AppInfo, Locks, Level), AppInfo2 = rebar_app_info:dep_level(AppInfo1, Level), @@ -374,9 +380,9 @@ handle_dep(State, DepsDir, AppInfo, Locks, Level) -> {SrcDeps, PkgDeps} = parse_deps(DepsDir, Deps, S3, Locks, Level), {AppInfo2, SrcDeps, PkgDeps, Locks++NewLocks, State1}. --spec maybe_fetch(rebar_app_info:t(), boolean() | {true, binary(), integer()}, +-spec maybe_fetch(rebar_app_info:t(), atom(), boolean() | {true, binary(), integer()}, sets:set(binary()), rebar_state:t()) -> {boolean(), rebar_app_info:t()}. -maybe_fetch(AppInfo, Upgrade, Seen, State) -> +maybe_fetch(AppInfo, Profile, Upgrade, Seen, State) -> AppDir = ec_cnv:to_list(rebar_app_info:dir(AppInfo)), %% Don't fetch dep if it exists in the _checkouts dir case rebar_app_info:is_checkout(AppInfo) of @@ -385,16 +391,26 @@ maybe_fetch(AppInfo, Upgrade, Seen, State) -> false -> case rebar_app_discover:find_app(AppDir, all) of false -> - case in_default(AppInfo, State) of + case already_in_default(AppInfo, State) of false -> - {fetch_app(AppInfo, AppDir, State), AppInfo}; + case fetch_app(AppInfo, AppDir, State) of + true -> + case needs_symlinking(State, Profile) of + true -> + SymDir = filename:join([rebar_dir:deps_dir(State), rebar_app_info:name(AppInfo)]), + symlink_dep(AppDir, SymDir), + {true, AppInfo}; + false -> + {true, AppInfo} + end; + Other -> + {Other, AppInfo} + end; {true, FoundApp} -> %% Preserve the state we created with overrides AppState = rebar_app_info:state(AppInfo), FoundApp1 = rebar_app_info:state(FoundApp, AppState), - ?INFO("Linking ~s to ~s", [rebar_app_info:dir(FoundApp1), AppDir]), - filelib:ensure_dir(AppDir), - rebar_file_utils:symlink_or_copy(rebar_app_info:dir(FoundApp1), AppDir), + symlink_dep(rebar_app_info:dir(FoundApp1), AppDir), {true, FoundApp1} end; {true, AppInfo1} -> @@ -410,11 +426,30 @@ maybe_fetch(AppInfo, Upgrade, Seen, State) -> end end. -in_default(AppInfo, State) -> +already_in_default(AppInfo, State) -> Name = ec_cnv:to_list(rebar_app_info:name(AppInfo)), DefaultAppDir = filename:join([rebar_state:get(State, base_dir), "default", "lib", Name]), rebar_app_discover:find_app(DefaultAppDir, all). +needs_symlinking(State, Profile) -> + case {rebar_state:current_profiles(State), Profile} of + {[default], default} -> + %% file will be in default already -- this is the only run we have + false; + {_, default} -> + %% file fetched to default, needs to be linked to the current + %% run's directory. + true; + _ -> + %% File fetched to the right directory already + false + end. + +symlink_dep(From, To) -> + ?INFO("Linking ~s to ~s", [From, To]), + filelib:ensure_dir(To), + rebar_file_utils:symlink_or_copy(From, To). + -spec parse_deps(binary(), list(), rebar_state:t(), list(), integer()) -> {[rebar_app_info:t()], [pkg_dep()]}. parse_deps(DepsDir, Deps, State, Locks, Level) -> lists:foldl(fun(Dep, Acc) -> diff --git a/src/rebar_prv_lock.erl b/src/rebar_prv_lock.erl index 5536ec9..f88b1ff 100644 --- a/src/rebar_prv_lock.erl +++ b/src/rebar_prv_lock.erl @@ -29,19 +29,10 @@ init(State) -> -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(State) -> - AllDeps = rebar_state:lock(State), - Locks = [begin - Dir = rebar_app_info:dir(Dep), - Source = rebar_app_info:source(Dep), - - %% If source is tuple it is a source dep - %% e.g. {git, "git://github.com/ninenines/cowboy.git", "master"} - {rebar_app_info:name(Dep) - ,rebar_fetch:lock_source(Dir, Source, State) - ,rebar_app_info:dep_level(Dep)} - end || Dep <- AllDeps, not(rebar_app_info:is_checkout(Dep))], + Locks = build_locks(State), Dir = rebar_state:dir(State), - file:write_file(filename:join(Dir, ?LOCK_FILE), io_lib:format("~p.~n", [Locks])), + file:write_file(filename:join(Dir, ?LOCK_FILE), + io_lib:format("~p.~n", [Locks])), {ok, State}. -spec format_error(any()) -> iolist(). @@ -50,3 +41,17 @@ format_error(Reason) -> info(_) -> "". + +build_locks(State) -> + AllDeps = rebar_state:lock(State), + [begin + Dir = rebar_app_info:dir(Dep), + Source = rebar_app_info:source(Dep), + + %% If source is tuple it is a source dep + %% e.g. {git, "git://github.com/ninenines/cowboy.git", "master"} + {rebar_app_info:name(Dep) + ,rebar_fetch:lock_source(Dir, Source, State) + ,rebar_app_info:dep_level(Dep)} + end || Dep <- AllDeps, not(rebar_app_info:is_checkout(Dep))]. + diff --git a/test/rebar_install_deps_SUITE.erl b/test/rebar_install_deps_SUITE.erl index aebd3e3..68fb9dd 100644 --- a/test/rebar_install_deps_SUITE.erl +++ b/test/rebar_install_deps_SUITE.erl @@ -2,6 +2,7 @@ -compile(export_all). -include_lib("common_test/include/ct.hrl"). -include_lib("eunit/include/eunit.hrl"). +-include_lib("kernel/include/file.hrl"). all() -> [{group, git}, {group, pkg}]. @@ -9,7 +10,7 @@ groups() -> [{all, [], [flat, pick_highest_left, pick_highest_right, pick_smallest1, pick_smallest2, circular1, circular2, circular_skip, - fail_conflict]}, + fail_conflict, default_profile, nondefault_profile]}, {git, [], [{group, all}]}, {pkg, [], [{group, all}]}]. @@ -114,7 +115,17 @@ deps(fail_conflict) -> {[{"B", [{"C", "2", []}]}, {"C", "1", []}], [{"C","2"}], - rebar_abort}. + rebar_abort}; +deps(default_profile) -> + {[{"B", []}, + {"C", []}], + [], + {ok, ["B", "C"]}}; +deps(nondefault_profile) -> + {[{"B", []}, + {"C", []}], + [], + {ok, ["B", "C"]}}. setup_project(fail_conflict, Config0, Deps) -> DepsType = ?config(deps_type, Config0), @@ -134,6 +145,25 @@ setup_project(fail_conflict, Config0, Deps) -> mock_pkg_resource:mock([{pkgdeps, rebar_test_utils:flat_pkgdeps(Deps)}]) end, [{rebarconfig, RebarConf} | Config]; +setup_project(nondefault_profile, Config0, Deps) -> + DepsType = ?config(deps_type, Config0), + Config = rebar_test_utils:init_rebar_state( + Config0, + "nondefault_profile_"++atom_to_list(DepsType)++"_" + ), + AppDir = ?config(apps, Config), + rebar_test_utils:create_app(AppDir, "A", "0.0.0", [kernel, stdlib]), + TopDeps = rebar_test_utils:top_level_deps(Deps), + RebarConf = rebar_test_utils:create_config(AppDir, [{profiles, [ + {nondef, [{deps, TopDeps}]} + ]}]), + case DepsType of + git -> + mock_git_resource:mock([{deps, rebar_test_utils:flat_deps(Deps)}]); + pkg -> + mock_pkg_resource:mock([{pkgdeps, rebar_test_utils:flat_pkgdeps(Deps)}]) + end, + [{rebarconfig, RebarConf} | Config]; setup_project(Case, Config0, Deps) -> DepsType = ?config(deps_type, Config0), Config = rebar_test_utils:init_rebar_state( @@ -174,6 +204,39 @@ fail_conflict(Config) -> ), check_warnings(error_calls(), ?config(warnings, Config), ?config(deps_type, Config)). +default_profile(Config) -> + {ok, RebarConfig} = file:consult(?config(rebarconfig, Config)), + AppDir = ?config(apps, Config), + {ok, Apps} = Expect = ?config(expect, Config), + rebar_test_utils:run_and_check( + Config, RebarConfig, ["as", "profile", "install_deps"], Expect + ), + check_warnings(error_calls(), ?config(warnings, Config), ?config(deps_type, Config)), + BuildDir = filename:join([AppDir, "_build"]), + [?assertMatch({ok, #file_info{type=directory}}, + file:read_file_info(filename:join([BuildDir, "default", "lib", App]))) + || {dep, App} <- Apps], + [?assertMatch({ok, #file_info{type=directory}}, % somehow symlinks return dirs + file:read_file_info(filename:join([BuildDir, "profile", "lib", App]))) + || {dep, App} <- Apps]. + +nondefault_profile(Config) -> + {ok, RebarConfig} = file:consult(?config(rebarconfig, Config)), + AppDir = ?config(apps, Config), + {ok, Apps} = Expect = ?config(expect, Config), + rebar_test_utils:run_and_check( + Config, RebarConfig, ["as", "nondef", "install_deps"], Expect + ), + check_warnings(error_calls(), ?config(warnings, Config), ?config(deps_type, Config)), + BuildDir = filename:join([AppDir, "_build"]), + [?assertMatch({error, enoent}, + file:read_file_info(filename:join([BuildDir, "default", "lib", App]))) + || {dep, App} <- Apps], + [?assertMatch({ok, #file_info{type=directory}}, + file:read_file_info(filename:join([BuildDir, "nondef", "lib", App]))) + || {dep, App} <- Apps]. + + run(Config) -> {ok, RebarConfig} = file:consult(?config(rebarconfig, Config)), rebar_test_utils:run_and_check( -- cgit v1.1 From 326f8401233d6e7f9e7647d61007ddef6a745025 Mon Sep 17 00:00:00 2001 From: Fred Hebert Date: Sat, 18 Apr 2015 01:45:06 +0000 Subject: Add support for an unlock command Allows to remove entries from the lock file, or the lock file as a whole. --- src/rebar.app.src | 1 + src/rebar_prv_lock.erl | 6 +-- src/rebar_prv_unlock.erl | 84 +++++++++++++++++++++++++++++++++ test/rebar_unlock_SUITE.erl | 40 ++++++++++++++++ test/rebar_unlock_SUITE_data/rebar.lock | 40 ++++++++++++++++ 5 files changed, 166 insertions(+), 5 deletions(-) create mode 100644 src/rebar_prv_unlock.erl create mode 100644 test/rebar_unlock_SUITE.erl create mode 100644 test/rebar_unlock_SUITE_data/rebar.lock diff --git a/src/rebar.app.src b/src/rebar.app.src index 63cca9c..b404c42 100644 --- a/src/rebar.app.src +++ b/src/rebar.app.src @@ -49,6 +49,7 @@ rebar_prv_report, rebar_prv_shell, rebar_prv_tar, + rebar_prv_unlock, rebar_prv_update, rebar_prv_upgrade, rebar_prv_version, diff --git a/src/rebar_prv_lock.erl b/src/rebar_prv_lock.erl index f88b1ff..6fdd743 100644 --- a/src/rebar_prv_lock.erl +++ b/src/rebar_prv_lock.erl @@ -23,7 +23,7 @@ init(State) -> {deps, ?DEPS}, {example, ""}, {short_desc, "Locks dependencies."}, - {desc, info("Locks dependencies")}, + {desc, "Locks dependencies"}, {opts, []}])), {ok, State1}. @@ -39,9 +39,6 @@ do(State) -> format_error(Reason) -> io_lib:format("~p", [Reason]). -info(_) -> - "". - build_locks(State) -> AllDeps = rebar_state:lock(State), [begin @@ -54,4 +51,3 @@ build_locks(State) -> ,rebar_fetch:lock_source(Dir, Source, State) ,rebar_app_info:dep_level(Dep)} end || Dep <- AllDeps, not(rebar_app_info:is_checkout(Dep))]. - diff --git a/src/rebar_prv_unlock.erl b/src/rebar_prv_unlock.erl new file mode 100644 index 0000000..dc9fe11 --- /dev/null +++ b/src/rebar_prv_unlock.erl @@ -0,0 +1,84 @@ +-module(rebar_prv_unlock). + +-behaviour(provider). + +-export([init/1, + do/1, + format_error/1]). + +-include("rebar.hrl"). +-include_lib("providers/include/providers.hrl"). + +-define(PROVIDER, unlock). +-define(DEPS, []). + +%% =================================================================== +%% Public API +%% =================================================================== + +-spec init(rebar_state:t()) -> {ok, rebar_state:t()}. +init(State) -> + State1 = rebar_state:add_provider( + State, + providers:create([{name, ?PROVIDER}, + {module, ?MODULE}, + {bare, false}, + {deps, ?DEPS}, + {example, ""}, + {short_desc, "Unlock dependencies."}, + {desc, "Unlock project dependencies. Mentioning no application " + "will unlock all dependencies. To unlock specific dependencies, " + "their name can be listed in the command."}, + {opts, [ + {package, undefined, undefined, string, + "List of packages to upgrade. If not specified, all dependencies are upgraded."} + ]} + ]) + ), + {ok, State1}. + +do(State) -> + Dir = rebar_state:dir(State), + LockFile = filename:join(Dir, ?LOCK_FILE), + case file:consult(LockFile) of + {error, enoent} -> + %% Our work is done. + {ok, State}; + {error, Reason} -> + ?PRV_ERROR({file,Reason}); + {ok, [Locks]} -> + case handle_unlocks(State, Locks, LockFile) of + ok -> + {ok, State}; + {error, Reason} -> + ?PRV_ERROR({file,Reason}) + end; + {ok, _Other} -> + ?PRV_ERROR(unknown_lock_format) + end. + +-spec format_error(any()) -> iolist(). +format_error({file, Reason}) -> + io_lib:format("Lock file editing failed for reason ~p", [Reason]); +format_error(unknown_lock_format) -> + "Lock file format unknown"; +format_error(Reason) -> + io_lib:format("~p", [Reason]). + +handle_unlocks(State, Locks, LockFile) -> + {Args, _} = rebar_state:command_parsed_args(State), + Names = parse_names(ec_cnv:to_binary(proplists:get_value(package, Args, <<"">>))), + case [Lock || Lock = {Name, _, _} <- Locks, not lists:member(Name, Names)] of + [] -> + file:delete(LockFile); + _ when Names =:= [] -> % implicitly all locks + file:delete(LockFile); + NewLocks -> + file:write_file(LockFile, io_lib:format("~p.~n", [NewLocks])) + end. + +parse_names(Bin) -> + case lists:usort(re:split(Bin, <<" *, *">>, [trim])) of + [<<"">>] -> []; % nothing submitted + Other -> Other + end. diff --git a/test/rebar_unlock_SUITE.erl b/test/rebar_unlock_SUITE.erl new file mode 100644 index 0000000..31dca72 --- /dev/null +++ b/test/rebar_unlock_SUITE.erl @@ -0,0 +1,40 @@ +-module(rebar_unlock_SUITE). +-include_lib("common_test/include/ct.hrl"). +-include_lib("eunit/include/eunit.hrl"). +-compile(export_all). + +all() -> [unlock, unlock_all]. + +init_per_testcase(Case, Config0) -> + Config = rebar_test_utils:init_rebar_state(Config0, atom_to_list(Case)), + Lockfile = filename:join(?config(apps, Config), "rebar.lock"), + ec_file:copy(filename:join(?config(data_dir, Config), "rebar.lock"), + Lockfile), + [{lockfile, Lockfile} | Config]. + +end_per_testcase(_, Config) -> + Config. + +unlock(Config) -> + Locks = read_locks(Config), + rebar_test_utils:run_and_check(Config, [], ["unlock", "fakeapp"], {ok, []}), + Locks = read_locks(Config), + rebar_test_utils:run_and_check(Config, [], ["unlock", "uuid"], {ok, []}), + ?assertEqual(Locks -- ["uuid"], read_locks(Config)), + rebar_test_utils:run_and_check(Config, [], ["unlock", "gproc,itc"], {ok, []}), + ?assertEqual(Locks -- ["uuid","gproc","itc"], read_locks(Config)), + rebar_test_utils:run_and_check(Config, [], ["unlock", string:join(Locks,",")], {ok, []}), + ?assertEqual({error, enoent}, read_locks(Config)), + ok. + +unlock_all(Config) -> + [_|_] = read_locks(Config), + rebar_test_utils:run_and_check(Config, [], ["unlock"], {ok, []}), + ?assertEqual({error, enoent}, read_locks(Config)), + ok. + +read_locks(Config) -> + case file:consult(?config(lockfile, Config)) of + {ok, [Locks]} -> [binary_to_list(element(1,Lock)) || Lock <- Locks]; + Other -> Other + end. diff --git a/test/rebar_unlock_SUITE_data/rebar.lock b/test/rebar_unlock_SUITE_data/rebar.lock new file mode 100644 index 0000000..ab68d8e --- /dev/null +++ b/test/rebar_unlock_SUITE_data/rebar.lock @@ -0,0 +1,40 @@ +[{<<"meck">>, + {git,"git://github.com/eproxus/meck", + {ref,"69664df5d0e01a0ae27efb62831d6eea45cc1cd4"}}, + 3}, + {<<"itc">>, + {git,"git://github.com/ferd/Interval-Tree-Clocks.git", + {ref,"168449da42871892f6047733edddf33936dd660f"}}, + 2}, + {<<"bitcask">>, + {git,"https://github.com/basho/bitcask.git", + {ref,"c3e9cc5e64bcfd6e342a85932a90428cfdc1ee2d"}}, + 2}, + {<<"quickrand">>, + {git,"https://github.com/okeuday/quickrand.git", + {ref,"0395a10b94472ccbe38b62bbfa9d0fc1ddac1dd7"}}, + 1}, + {<<"merklet">>, + {git,"git://github.com/ferd/merklet.git", + {ref,"21b5797a21ab6aa1ddb6740799372d2d4b6a6054"}}, + 1}, + {<<"interclock">>, + {git,"git://github.com/ferd/interclock.git", + {ref,"6a8b7443fa200da16d819f058e4dc8a0a75eca1e"}}, + 1}, + {<<"gproc">>, + {git,"git://github.com/uwiger/gproc.git", + {ref,"7655bddc4397d0cc3f7c4d95e7b96790605946fe"}}, + 1}, + {<<"uuid">>, + {git,"https://github.com/okeuday/uuid.git", + {ref,"f7c141c8359cd690faba0d2684b449a07db8e915"}}, + 0}, + {<<"peeranha">>, + {git,"https://github.com/ferd/peeranha.git", + {ref,"3bdbdadf6e34a1705bf2669eb28acd32a4fc9166"}}, + 0}, + {<<"file_monitor">>, + {git,"https://github.com/richcarl/file_monitor.git", + {ref,"4910b991bf3166377985d7ed961665c4b24e3de6"}}, + 0}]. -- cgit v1.1 From c151f4e688bb78d49702b2e9630443d3025866c0 Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Sat, 18 Apr 2015 17:48:34 -0500 Subject: add to end of code path not the beginning in handle_deps --- src/rebar_prv_install_deps.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rebar_prv_install_deps.erl b/src/rebar_prv_install_deps.erl index c39afad..1884a9c 100644 --- a/src/rebar_prv_install_deps.erl +++ b/src/rebar_prv_install_deps.erl @@ -153,7 +153,7 @@ handle_deps(Profile, State0, Deps, Upgrade, Locks) -> %% Sort all apps to build order State3 = rebar_state:all_deps(State2, AllDeps), CodePaths = [rebar_app_info:ebin_dir(A) || A <- AllDeps], - ok = code:add_pathsa(CodePaths), + ok = code:add_pathsz(CodePaths), {ok, AllDeps, State3}. -- cgit v1.1 From cce1ad00ba9d1bbedeeee14b3fe268b8c6dc8f2b Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Sat, 18 Apr 2015 21:21:13 -0500 Subject: ignore optional deps for now --- src/rebar_prv_update.erl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/rebar_prv_update.erl b/src/rebar_prv_update.erl index 6cdabeb..d0ff889 100644 --- a/src/rebar_prv_update.erl +++ b/src/rebar_prv_update.erl @@ -91,7 +91,7 @@ hex_to_graph(Filename) -> {Dict1, Graph}. update_graph(Pkg, PkgVsn, Deps, HexRegistry, Graph) -> - lists:foldl(fun([Dep, DepVsn, _, _], DepsListAcc) -> + lists:foldl(fun([Dep, DepVsn, false, _AppName | _], DepsListAcc) -> case DepVsn of <<"~> ", Vsn/binary>> -> HighestDepVsn = rebar_packages:find_highest_matching(Dep, Vsn, HexRegistry), @@ -100,5 +100,7 @@ update_graph(Pkg, PkgVsn, Deps, HexRegistry, Graph) -> Vsn -> digraph:add_edge(Graph, {Pkg, PkgVsn}, {Dep, Vsn}), [{Dep, Vsn} | DepsListAcc] - end + end; + ([_Dep, _DepVsn, true, _AppName | _], DepsListAcc) -> + DepsListAcc end, [], Deps). -- cgit v1.1 From 2667dbdd0b9da867da348fe0a6b22933daebad3c Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Sun, 19 Apr 2015 14:29:37 -0500 Subject: don't duplicate hooks for top level app --- src/rebar_app_discover.erl | 26 ++++++++++++++++++++++++-- src/rebar_dir.erl | 3 ++- src/rebar_prv_compile.erl | 11 ++++------- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/rebar_app_discover.erl b/src/rebar_app_discover.erl index 16dcf24..41f41f5 100644 --- a/src/rebar_app_discover.erl +++ b/src/rebar_app_discover.erl @@ -37,12 +37,13 @@ merge_deps(AppInfo, State) -> Default = rebar_state:default(State), CurrentProfiles = rebar_state:current_profiles(State), Name = rebar_app_info:name(AppInfo), - C = rebar_config:consult(rebar_app_info:dir(AppInfo)), + C = project_app_config(AppInfo, State), %% We reset the opts here to default so no profiles are applied multiple times AppState = rebar_state:apply_overrides( rebar_state:apply_profiles( - rebar_state:new(rebar_state:opts(State, Default), C, rebar_app_info:dir(AppInfo)), CurrentProfiles), Name), + rebar_state:new(reset_hooks(rebar_state:opts(State, Default)), C, + rebar_app_info:dir(AppInfo)), CurrentProfiles), Name), AppInfo1 = rebar_app_info:state(AppInfo, AppState), State1 = lists:foldl(fun(Profile, StateAcc) -> @@ -56,6 +57,27 @@ merge_deps(AppInfo, State) -> {AppInfo1, State1}. +project_app_config(AppInfo, State) -> + C = rebar_config:consult(rebar_app_info:dir(AppInfo)), + Dir = rebar_app_info:dir(AppInfo), + maybe_reset_hooks(C, Dir, State). + +%% Here we check if the app is at the root of the project. +%% If it is, then drop the hooks from the config so they aren't run twice +maybe_reset_hooks(C, Dir, State) -> + case filename:dirname(rebar_dir:root_dir(State)) of + Dir -> + C1 = proplists:delete(provider_hooks, C), + proplists:delete(hooks, C1); + _ -> + C + end. + +reset_hooks(State) -> + lists:foldl(fun(Key, StateAcc) -> + rebar_state:set(StateAcc, Key, []) + end, State, [post_hooks, pre_hooks, provider_hooks]). + -spec all_app_dirs(list(file:name())) -> list(file:name()). all_app_dirs(LibDirs) -> lists:flatmap(fun(LibDir) -> diff --git a/src/rebar_dir.erl b/src/rebar_dir.erl index 7a12eeb..c0c6bb2 100644 --- a/src/rebar_dir.erl +++ b/src/rebar_dir.erl @@ -4,6 +4,7 @@ profile_dir/2, deps_dir/1, deps_dir/2, + root_dir/1, checkouts_dir/1, checkouts_dir/2, plugins_dir/1, @@ -48,7 +49,7 @@ deps_dir(DepsDir, App) -> filename:join(DepsDir, App). root_dir(State) -> - rebar_state:get(State, root_dir, ?DEFAULT_ROOT_DIR). + filename:absname(rebar_state:get(State, root_dir, ?DEFAULT_ROOT_DIR)). -spec checkouts_dir(rebar_state:t()) -> file:filename_all(). checkouts_dir(State) -> diff --git a/src/rebar_prv_compile.erl b/src/rebar_prv_compile.erl index 94a1e0b..15a5164 100644 --- a/src/rebar_prv_compile.erl +++ b/src/rebar_prv_compile.erl @@ -43,17 +43,14 @@ do(State) -> EmptyState = rebar_state:new(), build_apps(EmptyState, Providers, Deps), - %% Use the project State for building project apps - %% Set hooks to empty so top-level hooks aren't run for each project app - State2 = rebar_state:set(rebar_state:set(State, post_hooks, []), pre_hooks, []), {ok, ProjectApps1} = rebar_digraph:compile_order(ProjectApps), - ProjectApps2 = build_apps(State2, Providers, ProjectApps1), - State3 = rebar_state:project_apps(State2, ProjectApps2), + ProjectApps2 = build_apps(State, Providers, ProjectApps1), + State2 = rebar_state:project_apps(State, ProjectApps2), - rebar_hooks:run_all_hooks(Cwd, post, ?PROVIDER, Providers, State3), + rebar_hooks:run_all_hooks(Cwd, post, ?PROVIDER, Providers, State2), - {ok, State3}. + {ok, State2}. -spec format_error(any()) -> iolist(). format_error(Reason) -> -- cgit v1.1 From 8ed91ab761e775cd18cf1b4925421784822215fa Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Sun, 19 Apr 2015 09:57:55 -0500 Subject: improve erlydtl source and out dir discovery --- src/rebar_base_compiler.erl | 2 +- src/rebar_prv_erlydtl_compiler.erl | 57 ++++++++++++++++++++--------------- src/rebar_prv_escriptize.erl | 62 +++++++++++++++++++++++--------------- 3 files changed, 71 insertions(+), 50 deletions(-) diff --git a/src/rebar_base_compiler.erl b/src/rebar_base_compiler.erl index df950d7..0101218 100644 --- a/src/rebar_base_compiler.erl +++ b/src/rebar_base_compiler.erl @@ -114,7 +114,7 @@ compile_each([Source | Rest], Config, CompileFn) -> skipped -> ?DEBUG("~sSkipped ~s", [rebar_utils:indent(1), filename:basename(Source)]); Error -> - ?INFO("Compiling ~s failed:", + ?ERROR("Compiling ~s failed", [maybe_absname(Config, Source)]), maybe_report(Error), ?DEBUG("Compilation failed: ~p", [Error]), diff --git a/src/rebar_prv_erlydtl_compiler.erl b/src/rebar_prv_erlydtl_compiler.erl index c5fb77a..a7442af 100644 --- a/src/rebar_prv_erlydtl_compiler.erl +++ b/src/rebar_prv_erlydtl_compiler.erl @@ -125,39 +125,48 @@ init(State) -> do(State) -> ?INFO("Running erlydtl...", []), - DtlOpts = proplists:unfold(rebar_state:get(State, erlydtl_opts, [])), - - %% We need a project app to store the results under in _build - %% If there is more than 1 project app, check for an app config - %% if that doesn't exist, error out. - case rebar_state:project_apps(State) of - [App] -> - run_erlydtl(App, DtlOpts, State), - {ok, State}; - Apps -> - case option(app, DtlOpts) of - undefined -> - ?PRV_ERROR(no_main_app); - Name -> - run_erlydtl(rebar_app_utils:find(Name, Apps), DtlOpts, State), - {ok, State} - end + case rebar_state:get(State, escript_main_app, undefined) of + undefined -> + Dir = rebar_state:dir(State), + case rebar_app_discover:find_app(Dir, all) of + {true, AppInfo} -> + AllApps = rebar_state:project_apps(State) ++ rebar_state:all_deps(State), + case rebar_app_utils:find(rebar_app_info:name(AppInfo), AllApps) of + {ok, AppInfo1} -> + %% Use the existing app info instead of newly created one + run_erlydtl(AppInfo1, State); + _ -> + run_erlydtl(AppInfo, State) + end, + {ok, State}; + _ -> + ?PRV_ERROR(no_main_app) + end; + Name -> + AllApps = rebar_state:project_apps(State) ++ rebar_state:all_deps(State), + {ok, App} = rebar_app_utils:find(Name, AllApps), + run_erlydtl(App, State), + {ok, State} end. -run_erlydtl(App, DtlOpts, State) -> - Dir = rebar_app_info:dir(App), +run_erlydtl(App, State) -> + Dir = rebar_state:dir(State), + DtlOpts = proplists:unfold(rebar_state:get(State, erlydtl_opts, [])), + TemplateDir = filename:join(Dir, option(doc_root, DtlOpts)), + DtlOpts2 = [{doc_root, TemplateDir} | proplists:delete(doc_root, DtlOpts)], OutDir = rebar_app_info:ebin_dir(App), + filelib:ensure_dir(filename:join(OutDir, "dummy.beam")), rebar_base_compiler:run(State, [], - filename:join(Dir, option(doc_root, DtlOpts)), - option(source_ext, DtlOpts), + TemplateDir, + option(source_ext, DtlOpts2), OutDir, - option(module_ext, DtlOpts) ++ ".beam", + option(module_ext, DtlOpts2) ++ ".beam", fun(S, T, C) -> - compile_dtl(C, S, T, DtlOpts, Dir, OutDir) + compile_dtl(C, S, T, DtlOpts2, Dir, OutDir) end, [{check_last_mod, false}, - {recursive, option(recursive, DtlOpts)}]). + {recursive, option(recursive, DtlOpts2)}]). -spec format_error(any()) -> iolist(). format_error(no_main_app) -> diff --git a/src/rebar_prv_escriptize.erl b/src/rebar_prv_escriptize.erl index 12ceaca..03332a0 100644 --- a/src/rebar_prv_escriptize.erl +++ b/src/rebar_prv_escriptize.erl @@ -62,17 +62,18 @@ desc() -> do(State) -> ?INFO("Building escript...", []), - case rebar_state:project_apps(State) of - [App] -> - escriptize(State, App); - Apps -> - case rebar_state:get(State, escript_main_app, undefined) of - undefined -> - ?PRV_ERROR(no_main_app); - Name -> - AppInfo = rebar_app_utils:find(Name, Apps), - escriptize(State, AppInfo) - end + case rebar_state:get(State, escript_main_app, undefined) of + undefined -> + case rebar_state:project_apps(State) of + [App] -> + escriptize(State, App); + _ -> + ?PRV_ERROR(no_main_app) + end; + Name -> + AllApps = rebar_state:all_deps(State)++rebar_state:project_apps(State), + AppInfo = rebar_app_utils:find(Name, AllApps), + escriptize(State, AppInfo) end. escriptize(State0, App) -> @@ -89,8 +90,9 @@ escriptize(State0, App) -> %% in the output file. We then use the .app files for each of these %% to pull in all the .beam files. InclApps = lists:usort(rebar_state:get(State, escript_incl_apps, []) - ++ all_deps(State)), - InclBeams = get_app_beams(InclApps), + ++ all_deps(State)), + AllApps = rebar_state:all_deps(State)++rebar_state:project_apps(State), + InclBeams = get_apps_beams(InclApps, AllApps), %% Look for a list of extra files to include in the output file. %% For internal rebar-private use only. Do not use outside rebar. @@ -139,22 +141,32 @@ format_error(no_main_app) -> %% Internal functions %% =================================================================== -get_app_beams(Apps) -> - get_app_beams(Apps, []). +get_apps_beams(Apps, AllApps) -> + get_apps_beams(Apps, AllApps, []). -get_app_beams([], Acc) -> +get_apps_beams([], _, Acc) -> Acc; -get_app_beams([App | Rest], Acc) -> - case code:lib_dir(App, ebin) of - {error, bad_name} -> - throw(?PRV_ERROR({bad_name, App})); - Path -> - Prefix = filename:join(atom_to_list(App), "ebin"), - Acc2 = load_files(Prefix, "*.beam", Path), - Acc3 = load_files(Prefix, "*.app", Path), - get_app_beams(Rest, Acc3 ++ Acc2 ++ Acc) +get_apps_beams([App | Rest], AllApps, Acc) -> + case rebar_app_utils:find(ec_cnv:to_binary(App), AllApps) of + {ok, App1} -> + OutDir = filename:absname(rebar_app_info:ebin_dir(App1)), + Beams = get_app_beams(App, OutDir), + get_apps_beams(Rest, AllApps, Beams ++ Acc); + _-> + case code:lib_dir(App, ebin) of + {error, bad_name} -> + throw(?PRV_ERROR({bad_name, App})); + Path -> + Beams = get_app_beams(App, Path), + get_apps_beams(Rest, AllApps, Beams ++ Acc) + end end. +get_app_beams(App, Path) -> + Prefix = filename:join(atom_to_list(App), "ebin"), + load_files(Prefix, "*.beam", Path) ++ + load_files(Prefix, "*.app", Path). + get_extra(State) -> Extra = rebar_state:get(State, escript_incl_extra, []), lists:foldl(fun({Wildcard, Dir}, Files) -> -- cgit v1.1 From 9e59abacf3c9b811b11f2a2fdae26286c0bebdd6 Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Mon, 20 Apr 2015 13:59:49 -0500 Subject: run project wide pre-compile hooks after deps have compiled --- src/rebar_prv_compile.erl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/rebar_prv_compile.erl b/src/rebar_prv_compile.erl index 15a5164..f3edebc 100644 --- a/src/rebar_prv_compile.erl +++ b/src/rebar_prv_compile.erl @@ -36,8 +36,6 @@ do(State) -> Deps = rebar_state:deps_to_build(State), Cwd = rebar_dir:get_cwd(), - rebar_hooks:run_all_hooks(Cwd, pre, ?PROVIDER, Providers, State), - %% Need to allow global config vars used on deps %% Right now no way to differeniate and just give deps a new state EmptyState = rebar_state:new(), @@ -45,6 +43,9 @@ do(State) -> {ok, ProjectApps1} = rebar_digraph:compile_order(ProjectApps), + %% Run top level hooks *before* project apps compiled but *after* deps are + rebar_hooks:run_all_hooks(Cwd, pre, ?PROVIDER, Providers, State), + ProjectApps2 = build_apps(State, Providers, ProjectApps1), State2 = rebar_state:project_apps(State, ProjectApps2), -- cgit v1.1 From b8c1cb2bf0ffdff35da4754c19bde3da4d97b3ec Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Mon, 20 Apr 2015 18:25:31 -0500 Subject: fix erl_first_files to check entire path of file --- src/rebar_erlc_compiler.erl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/rebar_erlc_compiler.erl b/src/rebar_erlc_compiler.erl index f245eb5..174f5f8 100644 --- a/src/rebar_erlc_compiler.erl +++ b/src/rebar_erlc_compiler.erl @@ -161,7 +161,7 @@ doterl_compile(Config, Dir, OutDir, MoreSources, ErlOpts) -> filename:extension(File) =:= ".erl"], NeededErlFiles = needed_files(G, ErlOpts, Dir, OutDir1, AllErlFiles), - ErlFirstFiles = erl_first_files(Config, NeededErlFiles), + ErlFirstFiles = erl_first_files(Config, Dir, NeededErlFiles), {DepErls, OtherErls} = lists:partition( fun(Source) -> digraph:in_degree(G, Source) > 0 end, [File || File <- NeededErlFiles, not lists:member(File, ErlFirstFiles)]), @@ -176,10 +176,11 @@ doterl_compile(Config, Dir, OutDir, MoreSources, ErlOpts) -> true = code:set_path(CurrPath), ok. -erl_first_files(Config, NeededErlFiles) -> +erl_first_files(Config, Dir, NeededErlFiles) -> ErlFirstFilesConf = rebar_state:get(Config, erl_first_files, []), %% NOTE: order of files in ErlFirstFiles is important! - [File || File <- ErlFirstFilesConf, lists:member(File, NeededErlFiles)]. + [filename:join(Dir, File) || File <- ErlFirstFilesConf, + lists:member(filename:join(Dir, File), NeededErlFiles)]. %% Get subset of SourceFiles which need to be recompiled, respecting %% dependencies induced by given graph G. -- cgit v1.1 From a3d4cc1259babf1541d5e278f11fc9ec9be75bb0 Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Sun, 19 Apr 2015 12:54:32 -0500 Subject: track and cleanup code paths for different contexts --- src/rebar3.erl | 4 +++- src/rebar_erlc_compiler.erl | 2 -- src/rebar_otp_app.erl | 4 ---- src/rebar_prv_common_test.erl | 6 ++++++ src/rebar_prv_compile.erl | 11 +++++++++-- src/rebar_prv_cover.erl | 2 +- src/rebar_prv_dialyzer.erl | 3 +++ src/rebar_prv_eunit.erl | 4 ++++ src/rebar_prv_install_deps.erl | 6 +++--- src/rebar_prv_shell.erl | 13 +++++++------ src/rebar_prv_xref.erl | 22 +++++----------------- src/rebar_state.erl | 14 ++++++++++++++ src/rebar_utils.erl | 8 -------- test/rebar_compile_SUITE.erl | 13 ++++++++----- test/rebar_profiles_SUITE.erl | 11 ++++++++--- test/rebar_test_utils.erl | 3 ++- test/rebar_xref_SUITE.erl | 4 ++-- 17 files changed, 75 insertions(+), 55 deletions(-) diff --git a/src/rebar3.erl b/src/rebar3.erl index 460bc36..e5e3173 100644 --- a/src/rebar3.erl +++ b/src/rebar3.erl @@ -134,7 +134,9 @@ run_aux(State, RawArgs) -> {Task, Args} = parse_args(RawArgs), - rebar_core:init_command(rebar_state:command_args(State7, Args), Task). + State8 = rebar_state:code_paths(State7, default, code:get_path()), + + rebar_core:init_command(rebar_state:command_args(State8, Args), Task). init_config() -> %% Initialize logging system diff --git a/src/rebar_erlc_compiler.erl b/src/rebar_erlc_compiler.erl index 174f5f8..ced8ca8 100644 --- a/src/rebar_erlc_compiler.erl +++ b/src/rebar_erlc_compiler.erl @@ -148,7 +148,6 @@ doterl_compile(Config, Dir, OutDir, MoreSources, ErlOpts) -> %% Make sure that ebin/ exists and is on the path ok = filelib:ensure_dir(filename:join(OutDir, "dummy.beam")), - CurrPath = code:get_path(), true = code:add_path(filename:absname(OutDir)), OutDir1 = proplists:get_value(outdir, ErlOpts, OutDir), @@ -173,7 +172,6 @@ doterl_compile(Config, Dir, OutDir, MoreSources, ErlOpts) -> fun(S, C) -> internal_erl_compile(C, Dir, S, OutDir1, ErlOpts) end), - true = code:set_path(CurrPath), ok. erl_first_files(Config, Dir, NeededErlFiles) -> diff --git a/src/rebar_otp_app.erl b/src/rebar_otp_app.erl index a93defc..41cd5f3 100644 --- a/src/rebar_otp_app.erl +++ b/src/rebar_otp_app.erl @@ -120,10 +120,6 @@ preprocess(State, AppInfo, AppSrcFile) -> AppFile = rebar_app_utils:app_src_to_app(OutDir, AppSrcFile), ok = rebar_file_utils:write_file_if_contents_differ(AppFile, Spec), - %% Make certain that the ebin/ directory is available - %% on the code path - true = code:add_path(filename:absname(filename:dirname(AppFile))), - AppFile; {error, Reason} -> ?PRV_ERROR({file_read, AppSrcFile, Reason}) diff --git a/src/rebar_prv_common_test.erl b/src/rebar_prv_common_test.erl index 1d5806b..a398144 100644 --- a/src/rebar_prv_common_test.erl +++ b/src/rebar_prv_common_test.erl @@ -38,6 +38,9 @@ init(State) -> -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(State) -> ?INFO("Running Common Test suites...", []), + + code:add_paths(rebar_state:code_paths(State, all_deps)), + %% Run ct provider prehooks Providers = rebar_state:providers(State), Cwd = rebar_dir:get_cwd(), @@ -47,11 +50,14 @@ do(State) -> {ok, State1} = Result -> %% Run ct provider posthooks rebar_hooks:run_all_hooks(Cwd, post, ?PROVIDER, Providers, State1), + rebar_utils:cleanup_code_path(rebar_state:code_paths(State1, default)), Result; ?PRV_ERROR(_) = Error -> + rebar_utils:cleanup_code_path(rebar_state:code_paths(State, default)), Error catch throw:{error, Reason} -> + rebar_utils:cleanup_code_path(rebar_state:code_paths(State, default)), ?PRV_ERROR(Reason) end. diff --git a/src/rebar_prv_compile.erl b/src/rebar_prv_compile.erl index f3edebc..25bda8c 100644 --- a/src/rebar_prv_compile.erl +++ b/src/rebar_prv_compile.erl @@ -31,6 +31,9 @@ init(State) -> -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(State) -> + DepsPaths = rebar_state:code_paths(State, all_deps), + code:add_paths(DepsPaths), + ProjectApps = rebar_state:project_apps(State), Providers = rebar_state:providers(State), Deps = rebar_state:deps_to_build(State), @@ -49,9 +52,14 @@ do(State) -> ProjectApps2 = build_apps(State, Providers, ProjectApps1), State2 = rebar_state:project_apps(State, ProjectApps2), + ProjAppsPaths = [filename:join(rebar_app_info:out_dir(X), "ebin") || X <- ProjectApps2], + State3 = rebar_state:code_paths(State2, all_deps, DepsPaths ++ ProjAppsPaths), + rebar_hooks:run_all_hooks(Cwd, post, ?PROVIDER, Providers, State2), - {ok, State2}. + rebar_utils:cleanup_code_path(rebar_state:code_paths(State3, default)), + + {ok, State3}. -spec format_error(any()) -> iolist(). format_error(Reason) -> @@ -80,7 +88,6 @@ build_app(State, Providers, AppInfo) -> AppInfo1 = compile(S, AppInfo), rebar_hooks:run_all_hooks(AppDir, post, ?PROVIDER, Providers, S), - true = code:add_patha(rebar_app_info:ebin_dir(AppInfo1)), AppInfo1. compile(State, AppInfo) -> diff --git a/src/rebar_prv_cover.erl b/src/rebar_prv_cover.erl index 83fe012..b38c6b0 100644 --- a/src/rebar_prv_cover.erl +++ b/src/rebar_prv_cover.erl @@ -150,7 +150,7 @@ analysis(State, Task) -> {Mod, process(Answer), File} end, Mods), - true = code:set_path(OldPath), + true = rebar_utils:cleanup_code_path(OldPath), Analysis. restore_cover_paths(State) -> diff --git a/src/rebar_prv_dialyzer.erl b/src/rebar_prv_dialyzer.erl index ef6a64c..f7cdf3b 100644 --- a/src/rebar_prv_dialyzer.erl +++ b/src/rebar_prv_dialyzer.erl @@ -64,6 +64,7 @@ short_desc() -> -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(State) -> ?INFO("Dialyzer starting, this may take a while...", []), + code:add_paths(rebar_state:code_paths(State, all_deps)), Plt = get_plt_location(State), Apps = rebar_state:project_apps(State), @@ -74,6 +75,8 @@ do(State) -> ?PRV_ERROR({error_processing_apps, Error}); throw:{dialyzer_warnings, Warnings} -> ?PRV_ERROR({dialyzer_warnings, Warnings}) + after + rebar_utils:cleanup_code_path(rebar_state:code_paths(State, default)) end. -spec format_error(any()) -> iolist(). diff --git a/src/rebar_prv_eunit.erl b/src/rebar_prv_eunit.erl index 0ea3ae8..3ee912d 100644 --- a/src/rebar_prv_eunit.erl +++ b/src/rebar_prv_eunit.erl @@ -37,6 +37,7 @@ init(State) -> -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(State) -> ?INFO("Performing EUnit tests...", []), + code:add_paths(rebar_state:code_paths(State, all_deps)), %% Run eunit provider prehooks Providers = rebar_state:providers(State), Cwd = rebar_dir:get_cwd(), @@ -48,11 +49,14 @@ do(State) -> {ok, State1} -> %% Run eunit provider posthooks rebar_hooks:run_all_hooks(Cwd, post, ?PROVIDER, Providers, State1), + rebar_utils:cleanup_code_path(rebar_state:code_paths(State1, default)), {ok, State1}; Error -> + rebar_utils:cleanup_code_path(rebar_state:code_paths(State, default)), Error end; Error -> + rebar_utils:cleanup_code_path(rebar_state:code_paths(State, default)), Error end. diff --git a/src/rebar_prv_install_deps.erl b/src/rebar_prv_install_deps.erl index 1884a9c..e87a09d 100644 --- a/src/rebar_prv_install_deps.erl +++ b/src/rebar_prv_install_deps.erl @@ -150,12 +150,12 @@ handle_deps(Profile, State0, Deps, Upgrade, Locks) -> AllDeps = lists:ukeymerge(2 ,lists:ukeysort(2, SrcApps) ,lists:ukeysort(2, Solved)), - %% Sort all apps to build order + State3 = rebar_state:all_deps(State2, AllDeps), CodePaths = [rebar_app_info:ebin_dir(A) || A <- AllDeps], - ok = code:add_pathsz(CodePaths), + State4 = rebar_state:code_paths(State3, all_deps, CodePaths), - {ok, AllDeps, State3}. + {ok, AllDeps, State4}. %% =================================================================== %% Internal functions diff --git a/src/rebar_prv_shell.erl b/src/rebar_prv_shell.erl index ed75b30..b6a85ab 100644 --- a/src/rebar_prv_shell.erl +++ b/src/rebar_prv_shell.erl @@ -92,7 +92,9 @@ shell(State) -> %% times). removes at most the error_logger added by init and the %% error_logger added by the tty handler ok = remove_error_handler(3), - %% add test paths + %% Add deps to path + code:add_paths(rebar_state:code_paths(State, all_deps)), + %% add project app test paths ok = add_test_paths(State), %% this call never returns (until user quits shell) timer:sleep(infinity). @@ -121,10 +123,9 @@ wait_until_user_started(Timeout) -> add_test_paths(State) -> lists:foreach(fun(App) -> - AppDir = rebar_app_info:out_dir(App), - %% ignore errors resulting from non-existent directories - _ = code:add_path(filename:join([AppDir, "ebin"])), - _ = code:add_path(filename:join([AppDir, "test"])) - end, rebar_state:project_apps(State)), + AppDir = rebar_app_info:out_dir(App), + %% ignore errors resulting from non-existent directories + _ = code:add_path(filename:join([AppDir, "test"])) + end, rebar_state:project_apps(State)), _ = code:add_path(filename:join([rebar_dir:base_dir(State), "test"])), ok. diff --git a/src/rebar_prv_xref.erl b/src/rebar_prv_xref.erl index 67cd554..baec57f 100644 --- a/src/rebar_prv_xref.erl +++ b/src/rebar_prv_xref.erl @@ -36,7 +36,8 @@ init(State) -> -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(State) -> - {OriginalPath, XrefChecks} = prepare(State), + code:add_paths(rebar_state:code_paths(State, all_deps)), + XrefChecks = prepare(State), %% Run xref checks ?INFO("Running cross reference analysis...", []), @@ -45,9 +46,8 @@ do(State) -> %% Run custom queries QueryChecks = rebar_state:get(State, xref_queries, []), QueryResults = lists:foldl(fun check_query/2, [], QueryChecks), - - ok = cleanup(OriginalPath), - + stopped = xref:stop(xref), + rebar_utils:cleanup_code_path(rebar_state:code_paths(State, default)), case XrefResults =:= [] andalso QueryResults =:= [] of true -> {ok, State}; @@ -100,10 +100,6 @@ prepare(State) -> [{ok, _} = xref:add_directory(xref, rebar_app_info:ebin_dir(App)) || App <- rebar_state:project_apps(State)], - %% Save the code path prior to doing any further code path - %% manipulation - OriginalPath = code:get_path(), - %% Get list of xref checks we want to run ConfXrefChecks = rebar_state:get(State, xref_checks, [exports_not_used, @@ -112,15 +108,7 @@ prepare(State) -> XrefChecks = sets:to_list(sets:intersection( sets:from_list(?SUPPORTED_XREFS), sets:from_list(ConfXrefChecks))), - {OriginalPath, XrefChecks}. - -cleanup(Path) -> - %% Restore the code path using the provided path - true = rebar_utils:cleanup_code_path(Path), - - %% Stop xref - stopped = xref:stop(xref), - ok. + XrefChecks. xref_checks(XrefChecks) -> lists:foldl(fun run_xref_check/2, [], XrefChecks). diff --git a/src/rebar_state.erl b/src/rebar_state.erl index f922977..705f723 100644 --- a/src/rebar_state.erl +++ b/src/rebar_state.erl @@ -3,6 +3,8 @@ -export([new/0, new/1, new/2, new/3, get/2, get/3, set/3, + code_paths/2, code_paths/3, + opts/1, opts/2, default/1, default/2, @@ -40,6 +42,7 @@ -record(state_t, {dir :: file:name(), opts = dict:new() :: rebar_dict(), + code_paths = dict:new() :: rebar_dict(), default = dict:new() :: rebar_dict(), escript_path :: undefined | file:filename_all(), @@ -132,6 +135,17 @@ default(#state_t{default=Opts}) -> default(State, Opts) -> State#state_t{default=Opts}. +code_paths(#state_t{code_paths=CodePaths}, Key) -> + case dict:find(Key, CodePaths) of + {ok, CodePath} -> + CodePath; + _ -> + [] + end. + +code_paths(State=#state_t{code_paths=CodePaths}, Key, CodePath) -> + State#state_t{code_paths=dict:store(Key, CodePath, CodePaths)}. + opts(#state_t{opts=Opts}) -> Opts. diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl index bc2e4ac..49f7ad7 100644 --- a/src/rebar_utils.erl +++ b/src/rebar_utils.erl @@ -42,7 +42,6 @@ erl_to_mod/1, beams/1, find_executable/1, - expand_code_path/0, vcs_vsn/2, deprecated/3, deprecated/4, @@ -177,13 +176,6 @@ find_executable(Name) -> "\"" ++ filename:nativename(Path) ++ "\"" end. -%% Convert all the entries in the code path to absolute paths. -expand_code_path() -> - CodePath = lists:foldl(fun(Path, Acc) -> - [filename:absname(Path) | Acc] - end, [], code:get_path()), - code:set_path(lists:reverse(CodePath)). - deprecated(Old, New, Opts, When) when is_list(Opts) -> case lists:member(Old, Opts) of true -> diff --git a/test/rebar_compile_SUITE.erl b/test/rebar_compile_SUITE.erl index 2fdf36d..ee262a1 100644 --- a/test/rebar_compile_SUITE.erl +++ b/test/rebar_compile_SUITE.erl @@ -102,10 +102,11 @@ build_checkout_deps(Config) -> Deps = [{list_to_atom(Name2), Vsn2, {git, "", ""}}], {ok, RebarConfig} = file:consult(rebar_test_utils:create_config(AppDir, [{deps, Deps}])), - rebar_test_utils:run_and_check( + {ok, State} = rebar_test_utils:run_and_check( Config, RebarConfig, ["compile"], {ok, [{app, Name1}, {checkout, Name2}]} ), + code:add_paths(rebar_state:code_paths(State, all_deps)), ok = application:load(list_to_atom(Name2)), Loaded = application:loaded_applications(), {_, _, Vsn2} = lists:keyfind(list_to_atom(Name2), 1, Loaded). @@ -307,10 +308,11 @@ deps_in_path(Config) -> ?assertEqual([], [Path || Path <- code:get_path(), {match, _} <- [re:run(Path, PkgName)]]), %% Build things - rebar_test_utils:run_and_check( + {ok, State} = rebar_test_utils:run_and_check( Config, RConf, ["compile"], {ok, [{app, Name}, {dep, DepName}, {dep, PkgName}]} ), + code:add_paths(rebar_state:code_paths(State, all_deps)), %% Find src name in there ?assertNotEqual([], [Path || Path <- code:get_path(), {match, _} <- [re:run(Path, DepName)]]), @@ -326,11 +328,12 @@ deps_in_path(Config) -> ?assertEqual([], [Path || Path <- code:get_path(), {match, _} <- [re:run(Path, PkgName)]]), %% Rebuild - rebar_test_utils:run_and_check( + {ok, State1} = rebar_test_utils:run_and_check( Config, RConf, ["compile"], {ok, [{app, Name}, {dep, DepName}, {dep, PkgName}]} ), %% Find src name in there + code:add_paths(rebar_state:code_paths(State1, all_deps)), ?assertNotEqual([], [Path || Path <- code:get_path(), {match, _} <- [re:run(Path, DepName)]]), %% find pkg name in there @@ -373,11 +376,11 @@ checkout_priority(Config) -> %% Rebuild and make sure the checkout apps are in path code:set_path(StartPaths), - rebar_test_utils:run_and_check( + {ok, State} = rebar_test_utils:run_and_check( Config, RConf, ["compile"], {ok, [{app, Name}, {checkout, DepName}, {checkout, PkgName}]} ), - + code:add_paths(rebar_state:code_paths(State, all_deps)), [DepPath] = [Path || Path <- code:get_path(), {match, _} <- [re:run(Path, DepName)]], [PkgPath] = [Path || Path <- code:get_path(), diff --git a/test/rebar_profiles_SUITE.erl b/test/rebar_profiles_SUITE.erl index 6288053..72969d3 100644 --- a/test/rebar_profiles_SUITE.erl +++ b/test/rebar_profiles_SUITE.erl @@ -160,9 +160,12 @@ profiles_remain_applied_with_config_present(Config) -> rebar_test_utils:create_config(AppDir, RebarConfig), - rebar_test_utils:run_and_check(Config, RebarConfig, + {ok, State} = rebar_test_utils:run_and_check(Config, RebarConfig, ["as", "not_ok", "compile"], {ok, [{app, Name}]}), + Path = filename:join([AppDir, "_build", "not_ok", "lib", Name, "ebin"]), + code:add_path(Path), + Mod = list_to_atom("not_a_real_src_" ++ Name), true = lists:member({d, not_ok}, proplists:get_value(options, Mod:module_info(compile), [])). @@ -196,7 +199,8 @@ test_profile_applied_before_compile(Config) -> RebarConfig = [{erl_opts, [{d, some_define}]}], rebar_test_utils:create_config(AppDir, RebarConfig), - rebar_test_utils:run_and_check(Config, RebarConfig, ["eunit"], {ok, [{app, Name}]}), + {ok, State} = rebar_test_utils:run_and_check(Config, RebarConfig, ["eunit"], {ok, [{app, Name}]}), + code:add_paths(rebar_state:code_paths(State, all_deps)), S = list_to_atom("not_a_real_src_" ++ Name), true = lists:member({d, 'TEST'}, proplists:get_value(options, S:module_info(compile), [])). @@ -211,7 +215,8 @@ test_profile_applied_before_eunit(Config) -> RebarConfig = [{erl_opts, [{d, some_define}]}], rebar_test_utils:create_config(AppDir, RebarConfig), - rebar_test_utils:run_and_check(Config, RebarConfig, ["eunit"], {ok, [{app, Name}]}), + {ok, State} = rebar_test_utils:run_and_check(Config, RebarConfig, ["eunit"], {ok, [{app, Name}]}), + code:add_paths(rebar_state:code_paths(State, all_deps)), T = list_to_atom("not_a_real_src_" ++ Name ++ "_tests"), true = lists:member({d, 'TEST'}, proplists:get_value(options, T:module_info(compile), [])). diff --git a/test/rebar_test_utils.erl b/test/rebar_test_utils.erl index d245c82..f764146 100644 --- a/test/rebar_test_utils.erl +++ b/test/rebar_test_utils.erl @@ -56,7 +56,8 @@ run_and_check(Config, RebarConfig, Command, Expect) -> ?assertEqual({error, Reason}, Res); {ok, Expected} -> {ok, _} = Res, - check_results(AppDir, Expected); + check_results(AppDir, Expected), + Res; return -> Res end diff --git a/test/rebar_xref_SUITE.erl b/test/rebar_xref_SUITE.erl index b2438cf..75d6786 100644 --- a/test/rebar_xref_SUITE.erl +++ b/test/rebar_xref_SUITE.erl @@ -44,7 +44,7 @@ init_per_testcase(Case, Config) -> [{app_name, Name}, {rebar_config, RebarConfig} | UpdConfig]. -end_per_testcase(_, Config) -> +end_per_testcase(_, _Config) -> ok. all() -> @@ -112,7 +112,7 @@ verify_test_results(xref_test, AppName, XrefResults, _QueryResults) -> ok; verify_test_results(xref_ignore_test, AppName, XrefResults, _QueryResults) -> AppModules = ["behaviour1", "behaviour2", "mymod", "othermod", "somemod"], - [Behaviour1Mod, Behaviour2Mod, MyMod, OtherMod, SomeMod] = + [_Behaviour1Mod, _Behaviour2Mod, _MyMod, _OtherMod, SomeMod] = [list_to_atom(AppName ++ "_" ++ Mod) || Mod <- AppModules], UndefFuns = proplists:get_value(undefined_functions, XrefResults), ?assertNot(lists:keymember(undefined_function_calls, 1, XrefResults)), -- cgit v1.1 From 18c395ff1557d16268101d5b7ea87d56071b5ff0 Mon Sep 17 00:00:00 2001 From: Fred Hebert Date: Wed, 22 Apr 2015 21:12:10 +0000 Subject: Symlink existing default deps when in new profile Should fix #360 --- src/rebar_prv_install_deps.erl | 23 +++++++++++++++-------- test/rebar_install_deps_SUITE.erl | 14 ++++++++++++++ 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/rebar_prv_install_deps.erl b/src/rebar_prv_install_deps.erl index 1884a9c..3612303 100644 --- a/src/rebar_prv_install_deps.erl +++ b/src/rebar_prv_install_deps.erl @@ -395,14 +395,8 @@ maybe_fetch(AppInfo, Profile, Upgrade, Seen, State) -> false -> case fetch_app(AppInfo, AppDir, State) of true -> - case needs_symlinking(State, Profile) of - true -> - SymDir = filename:join([rebar_dir:deps_dir(State), rebar_app_info:name(AppInfo)]), - symlink_dep(AppDir, SymDir), - {true, AppInfo}; - false -> - {true, AppInfo} - end; + maybe_symlink_default(State, Profile, AppDir, AppInfo), + {true, AppInfo}; Other -> {Other, AppInfo} end; @@ -417,6 +411,7 @@ maybe_fetch(AppInfo, Profile, Upgrade, Seen, State) -> %% Preserve the state we created with overrides AppState = rebar_app_info:state(AppInfo), AppInfo2 = rebar_app_info:state(AppInfo1, AppState), + maybe_symlink_default(State, Profile, AppDir, AppInfo2), case sets:is_element(rebar_app_info:name(AppInfo), Seen) of true -> {false, AppInfo2}; @@ -445,6 +440,18 @@ needs_symlinking(State, Profile) -> false end. +maybe_symlink_default(State, Profile, AppDir, AppInfo) -> + case needs_symlinking(State, Profile) of + true -> + SymDir = filename:join([rebar_dir:deps_dir(State), + rebar_app_info:name(AppInfo)]), + symlink_dep(AppDir, SymDir), + true; + false -> + false + end. + + symlink_dep(From, To) -> ?INFO("Linking ~s to ~s", [From, To]), filelib:ensure_dir(To), diff --git a/test/rebar_install_deps_SUITE.erl b/test/rebar_install_deps_SUITE.erl index 68fb9dd..d1a1118 100644 --- a/test/rebar_install_deps_SUITE.erl +++ b/test/rebar_install_deps_SUITE.erl @@ -218,6 +218,13 @@ default_profile(Config) -> || {dep, App} <- Apps], [?assertMatch({ok, #file_info{type=directory}}, % somehow symlinks return dirs file:read_file_info(filename:join([BuildDir, "profile", "lib", App]))) + || {dep, App} <- Apps], + %% A second run to another profile also links default to the right spot + rebar_test_utils:run_and_check( + Config, RebarConfig, ["as", "other", "install_deps"], Expect + ), + [?assertMatch({ok, #file_info{type=directory}}, % somehow symlinks return dirs + file:read_file_info(filename:join([BuildDir, "other", "lib", App]))) || {dep, App} <- Apps]. nondefault_profile(Config) -> @@ -234,6 +241,13 @@ nondefault_profile(Config) -> || {dep, App} <- Apps], [?assertMatch({ok, #file_info{type=directory}}, file:read_file_info(filename:join([BuildDir, "nondef", "lib", App]))) + || {dep, App} <- Apps], + %% A second run to another profile doesn't link dependencies + rebar_test_utils:run_and_check( + Config, RebarConfig, ["as", "other", "install_deps"], Expect + ), + [?assertMatch({error, enoent}, + file:read_file_info(filename:join([BuildDir, "default", "lib", App]))) || {dep, App} <- Apps]. -- cgit v1.1 From 12bd412c22fcfaeb752727a6c0098140704078f0 Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Wed, 22 Apr 2015 17:24:50 -0500 Subject: add_deps_to_patha nd restore_code_path added to api --- src/rebar_api.erl | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/rebar_api.erl b/src/rebar_api.erl index 3fc7f61..a398b53 100644 --- a/src/rebar_api.erl +++ b/src/rebar_api.erl @@ -8,7 +8,9 @@ debug/2, info/2, warn/2, error/2, expand_env_variable/3, get_arch/0, - wordsize/0]). + wordsize/0, + add_deps_to_path/1, + restore_code_path/1]). -export_type([rebar_dict/0, rebar_digraph/0]). @@ -48,3 +50,12 @@ get_arch() -> wordsize() -> rebar_utils:wordsize(). + + +%% Add deps to the code path +add_deps_to_path(State) -> + code:add_paths(rebar_state:code_paths(State, all_deps)). + +%% Revert to only having the beams necessary for running rebar3 and plugins in the path +restore_code_path(State) -> + rebar_utils:cleanup_code_path(rebar_state:code_paths(State, default)). -- cgit v1.1 From 4374999d9567acf93fbd3515aa19319c4e502390 Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Sat, 18 Apr 2015 11:56:51 -0500 Subject: real bootstrapping --- .gitignore | 4 +- .travis.yml | 3 +- bootstrap | 129 ++++++++++++++++++++++++++++++++++++++++++ bootstrap.bat | 2 + bootstrap/bootstrap | 66 --------------------- bootstrap/bootstrap.bat | 2 - bootstrap/rebar | Bin 160323 -> 0 bytes rebar.config | 65 ++++++++++++++------- rebar.lock | 32 +++++++++++ src/rebar3.erl | 1 + src/rebar_api.erl | 2 +- src/rebar_config.erl | 1 - src/rebar_erlc_compiler.erl | 3 +- src/rebar_otp_app.erl | 1 - src/rebar_prv_common_test.erl | 2 +- src/rebar_prv_compile.erl | 3 +- src/rebar_prv_dialyzer.erl | 2 +- src/rebar_prv_eunit.erl | 2 +- src/rebar_prv_shell.erl | 2 +- src/rebar_prv_xref.erl | 2 +- test/rebar_eunit_SUITE.erl | 12 ++-- test/rebar_profiles_SUITE.erl | 2 +- 22 files changed, 230 insertions(+), 108 deletions(-) create mode 100755 bootstrap create mode 100644 bootstrap.bat delete mode 100755 bootstrap/bootstrap delete mode 100644 bootstrap/bootstrap.bat delete mode 100755 bootstrap/rebar create mode 100644 rebar.lock diff --git a/.gitignore b/.gitignore index 4bfc3fe..c84f451 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,9 @@ +rebar3 +_build .depsolver_plt *.beam test/*_data logs -rebar3 /rebar *~ *.orig @@ -13,6 +14,5 @@ rebar3 /.eunit /deps /.rebar -rebar.lock priv/templates/*.dtl.erl ebin diff --git a/.travis.yml b/.travis.yml index df04fd2..b0729f8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,8 @@ otp_release: - 17.0 - R16B03-1 - R15B03 -script: make travis +before_script: "./bootstrap" +script: "./rebar3 ct" branches: only: - master diff --git a/bootstrap b/bootstrap new file mode 100755 index 0000000..7409cbe --- /dev/null +++ b/bootstrap @@ -0,0 +1,129 @@ +#!/usr/bin/env escript +%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*- +%% ex: ft=erlang ts=4 sw=4 et + +main(_Args) -> + %% Fetch and build deps required to build rebar3 + BaseDeps = [{providers, []} + ,{getopt, []} + ,{erlware_commons, ["ec_dictionary.erl", "ec_vsn.erl"]}], + Deps = get_deps(), + [fetch_and_compile(Dep, Deps) || Dep <- BaseDeps], + + %% Build rebar3 modules with compile:file + bootstrap_rebar3(), + + %% Build rebar.app from rebar.app.src + {ok, App} = rebar_app_info:new(rebar, "3.0.0", filename:absname("_build/default/lib/rebar/")), + rebar_otp_app:compile(rebar_state:new(), App), + + %% Because we are compiling files that are loaded already we want to silence + %% not_purged errors in rebar_erlc_compiler:opts_changed/1 + error_logger:tty(false), + + setup_env(), + os:putenv("REBAR_PROFILE", "bootstrap"), + {ok, State} = rebar3:run(["compile"]), + reset_env(), + os:unsetenv("REBAR_PROFILE"), + %% Build erlydtl files (a hook on compile in the default profile) and escript file + DepsPaths = rebar_state:code_paths(State, all_deps), + code:add_pathsa(DepsPaths), + + rebar3:run(["clean", "-a"]), + rebar3:run(["escriptize"]), + + %% Done with compile, can turn back on error logger + error_logger:tty(true), + + %% Finally, update executable perms for our script on *nix, + %% or write out script files on win32. + ec_file:copy("_build/default/bin/rebar3", "./rebar3"), + case os:type() of + {unix,_} -> + [] = os:cmd("chmod u+x rebar3"), + ok; + {win32,_} -> + write_windows_scripts(), + ok; + _ -> + ok + end. + +fetch_and_compile({Name, ErlFirstFiles}, Deps) -> + {Name, _, Repo} = lists:keyfind(Name, 1, Deps), + ok = fetch(Repo, Name), + compile(Name, ErlFirstFiles). + +fetch({git, Url, Source}, App) -> + Dir = filename:join([filename:absname("_build/default/lib/"), App]), + case filelib:is_dir(Dir) of + true -> + true = code:add_path(filename:join(Dir, "ebin")), + ok; + false -> + fetch_source(Dir, Url, Source), + ok + end. + +fetch_source(Dir, Url, {ref, Ref}) -> + ok = filelib:ensure_dir(Dir), + os:cmd(io_lib:format("git clone ~s ~s", [Url, Dir])), + {ok, Cwd} = file:get_cwd(), + file:set_cwd(Dir), + os:cmd(io_lib:format("git checkout -q ~s", [Ref])), + file:set_cwd(Cwd); +fetch_source(Dir, Url, {_, Branch}) -> + ok = filelib:ensure_dir(Dir), + os:cmd(io_lib:format("git clone ~s ~s -b ~s --single-branch", + [Url, Dir, Branch])). + +compile(App, FirstFiles) -> + Dir = filename:join(filename:absname("_build/default/lib/"), App), + filelib:ensure_dir(filename:join([Dir, "ebin", "dummy.beam"])), + code:add_path(filename:join(Dir, "ebin")), + FirstFilesPaths = [filename:join([Dir, "src", Module]) || Module <- FirstFiles], + Sources = FirstFilesPaths ++ filelib:wildcard(filename:join([Dir, "src", "*.erl"])), + [compile:file(X, [{i, filename:join(Dir, "include")} + ,{outdir, filename:join(Dir, "ebin")} + ,return]) || X <- Sources]. + +bootstrap_rebar3() -> + filelib:ensure_dir("_build/default/lib/rebar/ebin/dummy.beam"), + filelib:ensure_dir("_build/default/lib/rebar/src/dummy.erl"), + ec_file:copy("src", "_build/default/lib/rebar/src", [recursive]), + Sources = filelib:wildcard("src/*.erl"), + [compile:file(X, [{outdir, "_build/default/lib/rebar/ebin/"}]) || X <- Sources], + code:add_path(filename:absname("_build/default/lib/rebar/ebin")). + +setup_env() -> + %% We don't need or want erlydtl or relx providers loaded yet + application:load(rebar), + {ok, Providers} = application:get_env(rebar, providers), + Providers1 = Providers -- [rebar_prv_erlydtl_compiler, + rebar_prv_release, + rebar_prv_tar], + application:set_env(rebar, providers, Providers1). + +reset_env() -> + %% Reset the env so we get all providers and can build erlydtl files + application:unset_env(rebar, providers), + application:unload(rebar), + application:load(rebar). + +write_windows_scripts() -> + CmdScript= + "@echo off\r\n" + "setlocal\r\n" + "set rebarscript=%~f0\r\n" + "escript.exe \"%rebarscript:.cmd=%\" %*\r\n", + ok = file:write_file("rebar3.cmd", CmdScript). + +get_deps() -> + case file:consult("rebar.lock") of + {ok, [Deps]} -> + [{binary_to_atom(Name, utf8), "", Source} || {Name, Source, _Level} <- Deps]; + _ -> + {ok, Config} = file:consult("rebar.config"), + proplists:get_value(deps, Config) + end. diff --git a/bootstrap.bat b/bootstrap.bat new file mode 100644 index 0000000..b646a7d --- /dev/null +++ b/bootstrap.bat @@ -0,0 +1,2 @@ +@echo off +escript.exe bootstrap %* diff --git a/bootstrap/bootstrap b/bootstrap/bootstrap deleted file mode 100755 index 4e3d304..0000000 --- a/bootstrap/bootstrap +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env escript -%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*- -%% ex: ft=erlang ts=4 sw=4 et - -main(Args) -> - case lists:member("--help", Args) of - true -> - usage(), - halt(0); - false -> - ok - end, - - %% Check for force=1 flag to force a rebuild - case lists:member("force=1", Args) of - true -> - rm("ebin/*.beam"); - false -> - rm("ebin/rebar.beam") - end, - - %% Extract the system info of the version of OTP we use to compile rebar - - os:cmd("./bootstrap/rebar get-deps compile escriptize"), - - %% Finally, update executable perms for our script on *nix, - %% or write out script files on win32. - case os:type() of - {unix,_} -> - [] = os:cmd("chmod u+x rebar3"), - ok; - {win32,_} -> - write_windows_scripts(), - ok; - _ -> - ok - end, - - %% Add a helpful message - io:format("Congratulations! You now have a self-contained script called" - " \"rebar3\" in\n" - "your current working directory. " - "Place this script anywhere in your path\n" - "and you can use rebar to build OTP-compliant apps.\n"). - -usage() -> - io:format("Usage: bootstrap [OPTION]...~n"), - io:format(" force=1 unconditional build~n"), - io:format(" debug add debug information~n"). - -rm(Path) -> - NativePath = filename:nativename(Path), - Cmd = case os:type() of - {unix,_} -> "rm -f "; - {win32,_} -> "del /q " - end, - [] = os:cmd(Cmd ++ NativePath), - ok. - -write_windows_scripts() -> - CmdScript= - "@echo off\r\n" - "setlocal\r\n" - "set rebarscript=%~f0\r\n" - "escript.exe \"%rebarscript:.cmd=%\" %*\r\n", - ok = file:write_file("rebar.cmd", CmdScript). diff --git a/bootstrap/bootstrap.bat b/bootstrap/bootstrap.bat deleted file mode 100644 index b646a7d..0000000 --- a/bootstrap/bootstrap.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -escript.exe bootstrap %* diff --git a/bootstrap/rebar b/bootstrap/rebar deleted file mode 100755 index 14e5c22..0000000 Binary files a/bootstrap/rebar and /dev/null differ diff --git a/rebar.config b/rebar.config index 36ce9a4..62c7085 100644 --- a/rebar.config +++ b/rebar.config @@ -1,9 +1,22 @@ %% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*- %% ex: ts=4 sw=4 ft=erlang et -%% escript_incl_extra is for internal rebar-private use only. -%% Do not use outside rebar. Config interface is not stable. -{escript_incl_extra, [{"priv/templates/*", "."}, {"rebar/include/*", "."}]}. +{deps, [ + {erlware_commons, "", + {git, "https://github.com/erlware/erlware_commons.git", + {branch, "master"}}}, + {providers, "", + {git, "https://github.com/tsloughter/providers.git", + {tag, "v1.3.1"}}}, + {erlydtl, "", + {git, "https://github.com/erlydtl/erlydtl.git", + {branch, "master"}}}, + {relx, "", + {git, "https://github.com/erlware/relx.git", + {branch, "master"}}}, + {getopt, "", + {git, "https://github.com/jcomellas/getopt.git", + {branch, "master"}}}]}. {escript_incl_apps, [getopt, merl, erlydtl, erlware_commons, relx, providers, rebar]}. @@ -18,23 +31,37 @@ debug_info, warnings_as_errors]}. -{deps, [ - {erlware_commons, ".*", - {git, "https://github.com/erlware/erlware_commons.git", - {branch, "master"}}}, - {providers, "", - {git, "https://github.com/tsloughter/providers.git", - {tag, "v1.3.1"}}}, - {erlydtl, ".*", - {git, "https://github.com/erlydtl/erlydtl.git", - {tag, "0.10.0"}}}, - {relx, "", - {git, "https://github.com/erlware/relx.git", - {branch, "master"}}}, - {getopt, "", {git, "https://github.com/jcomellas/getopt.git", {branch, "master"}}}, - {meck, "", {git, "https://github.com/eproxus/meck.git", {tag, "0.8.2"}}}]}. - {erlydtl_opts, [{doc_root, "priv/templates"}, {compiler_options, [report, return, debug_info]}]}. {dialyzer_plt_apps, [common_test, dialyzer, erlydtl, eunit, snmp]}. + +{provider_hooks, [{post, [{compile, {erlydtl, compile}}]}]}. + +%% Profiles +{profiles, [{test, + [{deps, [ + {meck, "", {git, "https://github.com/eproxus/meck.git", {tag, "0.8.2"}}} + ]} + ] + }, + + %% We don't want erlydtl to attempt to run on the first compile pass to bootstrap + {bootstrap, [{overrides, [{override, relx, [{provider_hooks, [{post, []}]}]}]}, + {provider_hooks, [{post, []}]}]} + ]}. + +%% Overrides +{overrides, [{override, erlware_commons, [{plugins, []}]}, + {override, merl, [{pre_hooks, [{"(linux|darwin|solaris)", compile, "make -C \"$REBAR_DEPS_DIR/merl\" all -W test"}, + {"(freebsd|netbsd|openbsd)", compile, "gmake -C \"$REBAR_DEPS_DIR/merl\" all"}, + {"win32", compile, "make -C \"%REBAR_DEPS_DIR%/merl\" all -W test"}, + {eunit, + "erlc -I include/erlydtl_preparser.hrl -o test" + " test/erlydtl_extension_testparser.yrl"}, + {"(linux|darwin|solaris)", eunit, "make -C \"$REBAR_DEPS_DIR/merl\" test"}, + {"(freebsd|netbsd|openbsd)", eunit, "gmake -C \"$REBAR_DEPS_DIR/merl\" test"}, + {"win32", eunit, "make -C \"%REBAR_DEPS_DIR%/merl\" test"} + ]}]}, + {override, erlydtl, [{pre_hooks, []}]} + ]}. diff --git a/rebar.lock b/rebar.lock new file mode 100644 index 0000000..cc619ef --- /dev/null +++ b/rebar.lock @@ -0,0 +1,32 @@ +[{<<"rebar_vsn_plugin">>, + {git,"https://github.com/erlware/rebar_vsn_plugin.git", + {ref,"fd40c960c7912193631d948fe962e1162a8d1334"}}, + 1}, + {<<"merl">>, + {git,"git://github.com/erlydtl/merl.git", + {ref,"750b09d44425f435ff579a4d28bf5844bb5b4ef1"}}, + 1}, + {<<"eunit_formatters">>, + {git,"git://github.com/seancribbs/eunit_formatters", + {ref,"2c73eb6e46b0863f19507857b386a48a53aaf141"}}, + 1}, + {<<"relx">>, + {git,"https://github.com/erlware/relx.git", + {ref,"3f2462807fe4afb82bc52dd3ff8ff9244aad3bd3"}}, + 0}, + {<<"providers">>, + {git,"https://github.com/tsloughter/providers.git", + {ref,"7563ba7e916d5a35972b25b3aa1945ffe0a8e7a5"}}, + 0}, + {<<"getopt">>, + {git,"https://github.com/jcomellas/getopt.git", + {ref,"626698975e63866156159661d100785d65eab6f9"}}, + 0}, + {<<"erlydtl">>, + {git,"https://github.com/erlydtl/erlydtl.git", + {ref,"a4ac28680d6e066aabf86b3be9f073352a1a4d40"}}, + 0}, + {<<"erlware_commons">>, + {git,"https://github.com/erlware/erlware_commons.git", + {ref,"05b956da26788f30b3cb793fa6ace02b75f481d0"}}, + 0}]. diff --git a/src/rebar3.erl b/src/rebar3.erl index e5e3173..fbbda51 100644 --- a/src/rebar3.erl +++ b/src/rebar3.erl @@ -27,6 +27,7 @@ -module(rebar3). -export([main/1, + run/1, run/2, global_option_spec_list/0, init_config/0, diff --git a/src/rebar_api.erl b/src/rebar_api.erl index a398b53..88c7538 100644 --- a/src/rebar_api.erl +++ b/src/rebar_api.erl @@ -54,7 +54,7 @@ wordsize() -> %% Add deps to the code path add_deps_to_path(State) -> - code:add_paths(rebar_state:code_paths(State, all_deps)). + code:add_pathsa(rebar_state:code_paths(State, all_deps)). %% Revert to only having the beams necessary for running rebar3 and plugins in the path restore_code_path(State) -> diff --git a/src/rebar_config.erl b/src/rebar_config.erl index 76e03ea..58b2c4d 100644 --- a/src/rebar_config.erl +++ b/src/rebar_config.erl @@ -57,7 +57,6 @@ consult_file(File) -> {ok, Terms} = consult_and_eval(File, Script), Terms; false -> - ?DEBUG("Consult config file ~p", [File]), try_consult(File) end end. diff --git a/src/rebar_erlc_compiler.erl b/src/rebar_erlc_compiler.erl index ced8ca8..f906463 100644 --- a/src/rebar_erlc_compiler.erl +++ b/src/rebar_erlc_compiler.erl @@ -148,7 +148,8 @@ doterl_compile(Config, Dir, OutDir, MoreSources, ErlOpts) -> %% Make sure that ebin/ exists and is on the path ok = filelib:ensure_dir(filename:join(OutDir, "dummy.beam")), - true = code:add_path(filename:absname(OutDir)), + true = code:add_patha(filename:absname(OutDir)), + OutDir1 = proplists:get_value(outdir, ErlOpts, OutDir), G = init_erlcinfo(proplists:get_all_values(i, ErlOpts), AllErlFiles, Dir), diff --git a/src/rebar_otp_app.erl b/src/rebar_otp_app.erl index 41cd5f3..260343d 100644 --- a/src/rebar_otp_app.erl +++ b/src/rebar_otp_app.erl @@ -128,7 +128,6 @@ preprocess(State, AppInfo, AppSrcFile) -> load_app_vars(State) -> case rebar_state:get(State, app_vars_file, undefined) of undefined -> - ?DEBUG("No app_vars_file defined.", []), []; Filename -> ?INFO("Loading app vars from ~p", [Filename]), diff --git a/src/rebar_prv_common_test.erl b/src/rebar_prv_common_test.erl index a398144..a848401 100644 --- a/src/rebar_prv_common_test.erl +++ b/src/rebar_prv_common_test.erl @@ -39,7 +39,7 @@ init(State) -> do(State) -> ?INFO("Running Common Test suites...", []), - code:add_paths(rebar_state:code_paths(State, all_deps)), + code:add_pathsa(rebar_state:code_paths(State, all_deps)), %% Run ct provider prehooks Providers = rebar_state:providers(State), diff --git a/src/rebar_prv_compile.erl b/src/rebar_prv_compile.erl index 25bda8c..1fb29bd 100644 --- a/src/rebar_prv_compile.erl +++ b/src/rebar_prv_compile.erl @@ -32,7 +32,7 @@ init(State) -> -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(State) -> DepsPaths = rebar_state:code_paths(State, all_deps), - code:add_paths(DepsPaths), + code:add_pathsa(DepsPaths), ProjectApps = rebar_state:project_apps(State), Providers = rebar_state:providers(State), @@ -83,7 +83,6 @@ build_app(State, Providers, AppInfo) -> end, %% Legacy hook support - rebar_hooks:run_all_hooks(AppDir, pre, ?PROVIDER, Providers, S), AppInfo1 = compile(S, AppInfo), rebar_hooks:run_all_hooks(AppDir, post, ?PROVIDER, Providers, S), diff --git a/src/rebar_prv_dialyzer.erl b/src/rebar_prv_dialyzer.erl index f7cdf3b..67cf4b9 100644 --- a/src/rebar_prv_dialyzer.erl +++ b/src/rebar_prv_dialyzer.erl @@ -64,7 +64,7 @@ short_desc() -> -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(State) -> ?INFO("Dialyzer starting, this may take a while...", []), - code:add_paths(rebar_state:code_paths(State, all_deps)), + code:add_pathsa(rebar_state:code_paths(State, all_deps)), Plt = get_plt_location(State), Apps = rebar_state:project_apps(State), diff --git a/src/rebar_prv_eunit.erl b/src/rebar_prv_eunit.erl index 3ee912d..12dd5f9 100644 --- a/src/rebar_prv_eunit.erl +++ b/src/rebar_prv_eunit.erl @@ -37,7 +37,7 @@ init(State) -> -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(State) -> ?INFO("Performing EUnit tests...", []), - code:add_paths(rebar_state:code_paths(State, all_deps)), + code:add_pathsa(rebar_state:code_paths(State, all_deps)), %% Run eunit provider prehooks Providers = rebar_state:providers(State), Cwd = rebar_dir:get_cwd(), diff --git a/src/rebar_prv_shell.erl b/src/rebar_prv_shell.erl index b6a85ab..6153952 100644 --- a/src/rebar_prv_shell.erl +++ b/src/rebar_prv_shell.erl @@ -93,7 +93,7 @@ shell(State) -> %% error_logger added by the tty handler ok = remove_error_handler(3), %% Add deps to path - code:add_paths(rebar_state:code_paths(State, all_deps)), + code:add_pathsa(rebar_state:code_paths(State, all_deps)), %% add project app test paths ok = add_test_paths(State), %% this call never returns (until user quits shell) diff --git a/src/rebar_prv_xref.erl b/src/rebar_prv_xref.erl index baec57f..1d1afa0 100644 --- a/src/rebar_prv_xref.erl +++ b/src/rebar_prv_xref.erl @@ -36,7 +36,7 @@ init(State) -> -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(State) -> - code:add_paths(rebar_state:code_paths(State, all_deps)), + code:add_pathsa(rebar_state:code_paths(State, all_deps)), XrefChecks = prepare(State), %% Run xref checks diff --git a/test/rebar_eunit_SUITE.erl b/test/rebar_eunit_SUITE.erl index 4ec92f2..ac74146 100644 --- a/test/rebar_eunit_SUITE.erl +++ b/test/rebar_eunit_SUITE.erl @@ -164,8 +164,8 @@ test_basic_defines(Config) -> AppOpts = proplists:get_value(options, App:module_info(compile), []), SuiteOpts = proplists:get_value(options, Suite:module_info(compile), []), Expect = [{d, some_define}], - lists:foreach(fun(Expect) -> true = lists:member(Expect, AppOpts) end, Expect), - lists:foreach(fun(Expect) -> true = lists:member(Expect, SuiteOpts) end, Expect). + lists:foreach(fun(E) -> true = lists:member(E, AppOpts) end, Expect), + lists:foreach(fun(E) -> true = lists:member(E, SuiteOpts) end, Expect). test_multi_defines(Config) -> AppDir = ?config(apps, Config), @@ -198,10 +198,10 @@ test_multi_defines(Config) -> AppOpts2 = proplists:get_value(options, App2:module_info(compile), []), SuiteOpts2 = proplists:get_value(options, Suite2:module_info(compile), []), Expect = [{d, some_define}], - lists:foreach(fun(Expect) -> true = lists:member(Expect, AppOpts1) end, Expect), - lists:foreach(fun(Expect) -> true = lists:member(Expect, SuiteOpts1) end, Expect), - lists:foreach(fun(Expect) -> true = lists:member(Expect, AppOpts2) end, Expect), - lists:foreach(fun(Expect) -> true = lists:member(Expect, SuiteOpts2) end, Expect). + lists:foreach(fun(E) -> true = lists:member(E, AppOpts1) end, Expect), + lists:foreach(fun(E) -> true = lists:member(E, SuiteOpts1) end, Expect), + lists:foreach(fun(E) -> true = lists:member(E, AppOpts2) end, Expect), + lists:foreach(fun(E) -> true = lists:member(E, SuiteOpts2) end, Expect). test_single_app_flag(Config) -> AppDir = ?config(apps, Config), diff --git a/test/rebar_profiles_SUITE.erl b/test/rebar_profiles_SUITE.erl index 72969d3..f0d1c48 100644 --- a/test/rebar_profiles_SUITE.erl +++ b/test/rebar_profiles_SUITE.erl @@ -160,7 +160,7 @@ profiles_remain_applied_with_config_present(Config) -> rebar_test_utils:create_config(AppDir, RebarConfig), - {ok, State} = rebar_test_utils:run_and_check(Config, RebarConfig, + rebar_test_utils:run_and_check(Config, RebarConfig, ["as", "not_ok", "compile"], {ok, [{app, Name}]}), Path = filename:join([AppDir, "_build", "not_ok", "lib", Name, "ebin"]), -- cgit v1.1 From 16e9b3ffa2ddd81e26238530fd1e25a54a42b7dc Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Wed, 22 Apr 2015 21:43:59 -0500 Subject: fix tracking of all profiles dep paths --- bootstrap | 3 +-- src/rebar_prv_common_test.erl | 1 - src/rebar_prv_install_deps.erl | 4 ++-- src/rebar_state.erl | 15 +++++++++++++-- test/rebar_profiles_SUITE.erl | 39 +++++++++++++++++++++++++++++++++++++-- 5 files changed, 53 insertions(+), 9 deletions(-) diff --git a/bootstrap b/bootstrap index 7409cbe..8f7af30 100755 --- a/bootstrap +++ b/bootstrap @@ -90,8 +90,7 @@ compile(App, FirstFiles) -> bootstrap_rebar3() -> filelib:ensure_dir("_build/default/lib/rebar/ebin/dummy.beam"), - filelib:ensure_dir("_build/default/lib/rebar/src/dummy.erl"), - ec_file:copy("src", "_build/default/lib/rebar/src", [recursive]), + file:make_symlink(filename:absname("src"), filename:absname("_build/default/lib/rebar/src")), Sources = filelib:wildcard("src/*.erl"), [compile:file(X, [{outdir, "_build/default/lib/rebar/ebin/"}]) || X <- Sources], code:add_path(filename:absname("_build/default/lib/rebar/ebin")). diff --git a/src/rebar_prv_common_test.erl b/src/rebar_prv_common_test.erl index a848401..9038759 100644 --- a/src/rebar_prv_common_test.erl +++ b/src/rebar_prv_common_test.erl @@ -38,7 +38,6 @@ init(State) -> -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(State) -> ?INFO("Running Common Test suites...", []), - code:add_pathsa(rebar_state:code_paths(State, all_deps)), %% Run ct provider prehooks diff --git a/src/rebar_prv_install_deps.erl b/src/rebar_prv_install_deps.erl index 3b2c9ab..0fa843f 100644 --- a/src/rebar_prv_install_deps.erl +++ b/src/rebar_prv_install_deps.erl @@ -151,9 +151,9 @@ handle_deps(Profile, State0, Deps, Upgrade, Locks) -> ,lists:ukeysort(2, SrcApps) ,lists:ukeysort(2, Solved)), - State3 = rebar_state:all_deps(State2, AllDeps), + State3 = rebar_state:update_all_deps(State2, AllDeps), CodePaths = [rebar_app_info:ebin_dir(A) || A <- AllDeps], - State4 = rebar_state:code_paths(State3, all_deps, CodePaths), + State4 = rebar_state:update_code_paths(State3, all_deps, CodePaths), {ok, AllDeps, State4}. diff --git a/src/rebar_state.erl b/src/rebar_state.erl index 705f723..3909a39 100644 --- a/src/rebar_state.erl +++ b/src/rebar_state.erl @@ -3,7 +3,7 @@ -export([new/0, new/1, new/2, new/3, get/2, get/3, set/3, - code_paths/2, code_paths/3, + code_paths/2, code_paths/3, update_code_paths/3, opts/1, opts/2, default/1, default/2, @@ -24,7 +24,7 @@ project_apps/1, project_apps/2, deps_to_build/1, deps_to_build/2, - all_deps/1, all_deps/2, + all_deps/1, all_deps/2, update_all_deps/2, namespace/1, namespace/2, deps_names/1, @@ -146,6 +146,14 @@ code_paths(#state_t{code_paths=CodePaths}, Key) -> code_paths(State=#state_t{code_paths=CodePaths}, Key, CodePath) -> State#state_t{code_paths=dict:store(Key, CodePath, CodePaths)}. +update_code_paths(State=#state_t{code_paths=CodePaths}, Key, CodePath) -> + case dict:is_key(Key, CodePaths) of + true -> + State#state_t{code_paths=dict:append_list(Key, CodePath, CodePaths)}; + false -> + State#state_t{code_paths=dict:store(Key, CodePath, CodePaths)} + end. + opts(#state_t{opts=Opts}) -> Opts. @@ -312,6 +320,9 @@ all_deps(#state_t{all_deps=Apps}) -> all_deps(State=#state_t{}, NewApps) -> State#state_t{all_deps=NewApps}. +update_all_deps(State=#state_t{all_deps=Apps}, NewApps) -> + State#state_t{all_deps=Apps++NewApps}. + namespace(#state_t{namespace=Namespace}) -> Namespace. diff --git a/test/rebar_profiles_SUITE.erl b/test/rebar_profiles_SUITE.erl index f0d1c48..59c65e9 100644 --- a/test/rebar_profiles_SUITE.erl +++ b/test/rebar_profiles_SUITE.erl @@ -7,6 +7,7 @@ all/0, profile_new_key/1, profile_merge_keys/1, + all_deps_code_paths/1, profile_merges/1, add_to_profile/1, add_to_existing_profile/1, @@ -21,7 +22,7 @@ -include_lib("kernel/include/file.hrl"). all() -> - [profile_new_key, profile_merge_keys, profile_merges, + [profile_new_key, profile_merge_keys, all_deps_code_paths, profile_merges, add_to_profile, add_to_existing_profile, profiles_remain_applied_with_config_present, test_profile_applied_at_completion, @@ -95,6 +96,40 @@ profile_merge_keys(Config) -> ,{dep, "a", "1.0.0"} ,{dep, "b", "2.0.0"}]}). +all_deps_code_paths(Config) -> + AppDir = ?config(apps, Config), + + AllDeps = rebar_test_utils:expand_deps(git, [{"a", "1.0.0", []} + ,{"b", "2.0.0", []}]), + mock_git_resource:mock([{deps, rebar_test_utils:flat_deps(AllDeps)}]), + + Name = rebar_test_utils:create_random_name("all_deps_code_paths"), + Vsn = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), + + Deps = rebar_test_utils:top_level_deps( + rebar_test_utils:expand_deps(git, [{"a", "1.0.0", []}])), + ProfileDeps = rebar_test_utils:top_level_deps( + rebar_test_utils:expand_deps(git, [{"b", "2.0.0", []}])), + + RebarConfig = [{deps, Deps}, + {profiles, + [{all_deps_test, + [{deps, ProfileDeps}]}]}], + os:putenv("REBAR_PROFILE", "all_deps_test"), + {ok, State} = rebar_test_utils:run_and_check(Config, RebarConfig, + ["compile"], {ok, [{app, Name} + ,{dep, "a", "1.0.0"} + ,{dep, "b", "2.0.0"}]}), + os:unsetenv("REBAR_PROFILE"), + + Paths = rebar_state:code_paths(State, all_deps), + Path = lists:reverse(["_build", "all_deps_test", "lib", "b", "ebin"]), + ?assert(lists:any(fun(X) -> + Path =:= lists:sublist(lists:reverse(filename:split(X)), 5) + end, Paths)). + + profile_merges(_Config) -> RebarConfig = [{test1, [{key1, 1, 2}, key2]}, {test2, "hello"}, @@ -164,7 +199,7 @@ profiles_remain_applied_with_config_present(Config) -> ["as", "not_ok", "compile"], {ok, [{app, Name}]}), Path = filename:join([AppDir, "_build", "not_ok", "lib", Name, "ebin"]), - code:add_path(Path), + code:add_patha(Path), Mod = list_to_atom("not_a_real_src_" ++ Name), -- cgit v1.1 From e5988f69e0fc577f9c759f0907bd8b6840851035 Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Wed, 22 Apr 2015 21:51:11 -0500 Subject: R15 support, replace unsetenv with putenv empty string --- bootstrap | 2 +- src/rebar3.erl | 2 ++ test/rebar_profiles_SUITE.erl | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/bootstrap b/bootstrap index 8f7af30..3ed7b2b 100755 --- a/bootstrap +++ b/bootstrap @@ -25,7 +25,7 @@ main(_Args) -> os:putenv("REBAR_PROFILE", "bootstrap"), {ok, State} = rebar3:run(["compile"]), reset_env(), - os:unsetenv("REBAR_PROFILE"), + os:putenv("REBAR_PROFILE", ""), %% Build erlydtl files (a hook on compile in the default profile) and escript file DepsPaths = rebar_state:code_paths(State, all_deps), code:add_pathsa(DepsPaths), diff --git a/src/rebar3.erl b/src/rebar3.erl index fbbda51..b0cc949 100644 --- a/src/rebar3.erl +++ b/src/rebar3.erl @@ -115,6 +115,8 @@ run_aux(State, RawArgs) -> State2 = case os:getenv("REBAR_PROFILE") of false -> State; + "" -> + State; Profile -> rebar_state:apply_profiles(State, [list_to_atom(Profile)]) end, diff --git a/test/rebar_profiles_SUITE.erl b/test/rebar_profiles_SUITE.erl index 59c65e9..2d03432 100644 --- a/test/rebar_profiles_SUITE.erl +++ b/test/rebar_profiles_SUITE.erl @@ -121,7 +121,7 @@ all_deps_code_paths(Config) -> ["compile"], {ok, [{app, Name} ,{dep, "a", "1.0.0"} ,{dep, "b", "2.0.0"}]}), - os:unsetenv("REBAR_PROFILE"), + os:putenv("REBAR_PROFILE", ""), Paths = rebar_state:code_paths(State, all_deps), Path = lists:reverse(["_build", "all_deps_test", "lib", "b", "ebin"]), -- cgit v1.1 From acf8c5ce65718fbaaae666baf312890f3e8857af Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Wed, 22 Apr 2015 22:00:40 -0500 Subject: update readme bootstrap instructions --- README.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/README.md b/README.md index 320b3cf..555cddf 100644 --- a/README.md +++ b/README.md @@ -123,11 +123,7 @@ https://s3.amazonaws.com/rebar3/rebar3 ```sh $ git clone https://github.com/rebar/rebar3 $ cd rebar3 -$ ./bootstrap/bootstrap -==> rebar (compile) -Congratulations! You now have a self-contained script called "rebar3" in -your current working directory. Place this script anywhere in your path -and you can use rebar to build OTP-compliant apps. +$ ./bootstrap ``` -- cgit v1.1 From 390d1afb77fe58c0f083b46ad114a37d1ad1d91d Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Wed, 22 Apr 2015 22:01:13 -0500 Subject: update readme provider --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 555cddf..bc2accd 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,8 @@ Example: -behaviour(rebar_provider). -export([init/1, - do/1]). + do/1, + format_error/1]). -define(PROVIDER, something). -define(DEPS, []). @@ -98,6 +99,10 @@ init(State) -> do(State) -> %% Do something {ok, State}. + +-spec format_error(any()) -> iolist(). +format_error(Reason) -> + io_lib:format("~p", [Reason]). ``` -- cgit v1.1 From 605b7e9f7f2f476d5df9d4bd45a2cc97bdb06dfa Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Wed, 22 Apr 2015 22:02:26 -0500 Subject: remove makefile --- Makefile | 43 ------------------------------------------- 1 file changed, 43 deletions(-) delete mode 100644 Makefile diff --git a/Makefile b/Makefile deleted file mode 100644 index 49f5758..0000000 --- a/Makefile +++ /dev/null @@ -1,43 +0,0 @@ -.PHONY: clean xref_warnings deps test - -REBAR=$(PWD)/rebar3 -RETEST=$(PWD)/deps/retest/retest - -DEPS_PLT=$(CURDIR)/.depsolver_plt - -all: - @./bootstrap/rebar get-deps compile escriptize - -clean: - @rm -rf rebar3 ebin/*.beam inttest/rt.work rt.work .eunit - @rm -f .rebarinfo - -distclean: clean - @rm -rf deps - -debug: - @./bootstrap/bootstrap debug - -check: debug xref deps test - -xref: - @./rebar3 xref - -$(DEPS_PLT): - @echo Building local erts plt at $(DEPS_PLT) - @echo - dialyzer --output_plt $(DEPS_PLT) --build_plt \ - --apps erts kernel stdlib -r deps - -dialyzer: $(DEPS_PLT) - dialyzer --fullpath --plt $(DEPS_PLT) -Wno_opaque -Wrace_conditions -r ./ebin - -binary: VSN = $(shell ./rebar3 -V) -binary: clean all - @cp rebar3 ../rebar.wiki/rebar - (cd ../rebar.wiki && git commit -m "Update $(VSN)" rebar) - -test: - rebar ct - -travis: all test -- cgit v1.1 From 7b723d3a87230a893e61130024b5dbc38a3a749c Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Wed, 22 Apr 2015 22:03:45 -0500 Subject: update readme instructions --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bc2accd..1fb3f57 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,7 @@ You can download a pre-built binary version of rebar3 based on the last commit f https://s3.amazonaws.com/rebar3/rebar3 -#### Building rebar +#### Bootstrapping rebar3 ```sh $ git clone https://github.com/rebar/rebar3 @@ -131,6 +131,15 @@ $ cd rebar3 $ ./bootstrap ``` +### Developing on rebar3 + +When developing you can simply run `escriptize` to build your changes but the new escript is under `_build/default/bin/rebar3` + +```sh +$ ./rebar3 escriptize +$ _build/default/bin/rebar3 +``` + Contributing to rebar ===================== -- cgit v1.1 From 8996084cb542b237e5c198a9518f9b107d619538 Mon Sep 17 00:00:00 2001 From: Richard Jones Date: Thu, 23 Apr 2015 12:51:00 +0100 Subject: Re-add escript_incl_extra, for templates Fixes regression from https://github.com/rebar/rebar3/commit/3a63bec39fde05dcddf3f693dd780879662b599c#diff-31d7a50c99c265ca2793c20961b60979L4 which meant listing templates doesn't work (rebar3 new help) --- rebar.config | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rebar.config b/rebar.config index 62c7085..83da0e5 100644 --- a/rebar.config +++ b/rebar.config @@ -23,6 +23,9 @@ {escript_top_level_app, rebar}. {escript_name, rebar3}. {escript_emu_args, "%%! +sbtu +A0\n"}. +%% escript_incl_extra is for internal rebar-private use only. +%% Do not use outside rebar. Config interface is not stable. +{escript_incl_extra, [{"priv/templates/*", "."}, {"rebar/include/*", "."}]}. {erl_opts, [{platform_define, "R14", no_callback_support}, -- cgit v1.1 From bd2f8bbc5e446dbabeeb9793fd8f93790a38857c Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Thu, 23 Apr 2015 10:49:36 -0500 Subject: print and halt on compile error --- bootstrap | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/bootstrap b/bootstrap index 3ed7b2b..453bdfb 100755 --- a/bootstrap +++ b/bootstrap @@ -84,16 +84,29 @@ compile(App, FirstFiles) -> code:add_path(filename:join(Dir, "ebin")), FirstFilesPaths = [filename:join([Dir, "src", Module]) || Module <- FirstFiles], Sources = FirstFilesPaths ++ filelib:wildcard(filename:join([Dir, "src", "*.erl"])), - [compile:file(X, [{i, filename:join(Dir, "include")} + [compile_file(X, [{i, filename:join(Dir, "include")} ,{outdir, filename:join(Dir, "ebin")} ,return]) || X <- Sources]. +compile_file(File, Opts) -> + case compile:file(File, Opts) of + {ok, _Mod} -> + ok; + {ok, _Mod, []} -> + ok; + {ok, _Mod, Ws} -> + io:format("Warning: ~p~n", [format_warnings(File, Ws)]); + {error, Es, Ws} -> + io:format("~s ~s~n", [format_errors(File, Es), format_warnings(File, Ws)]), + halt(1) + end. + bootstrap_rebar3() -> filelib:ensure_dir("_build/default/lib/rebar/ebin/dummy.beam"), file:make_symlink(filename:absname("src"), filename:absname("_build/default/lib/rebar/src")), Sources = filelib:wildcard("src/*.erl"), [compile:file(X, [{outdir, "_build/default/lib/rebar/ebin/"}]) || X <- Sources], - code:add_path(filename:absname("_build/default/lib/rebar/ebin")). + code:add_patha(filename:absname("_build/default/lib/rebar/ebin")). setup_env() -> %% We don't need or want erlydtl or relx providers loaded yet @@ -126,3 +139,32 @@ get_deps() -> {ok, Config} = file:consult("rebar.config"), proplists:get_value(deps, Config) end. + +format_errors(Source, Errors) -> + format_errors(Source, "", Errors). + +format_warnings(Source, Warnings) -> + format_warnings(Source, Warnings, []). + +format_warnings(Source, Warnings, Opts) -> + Prefix = case lists:member(warnings_as_errors, Opts) of + true -> ""; + false -> "Warning: " + end, + format_errors(Source, Prefix, Warnings). + +format_errors(_MainSource, Extra, Errors) -> + [begin + [format_error(Source, Extra, Desc) || Desc <- Descs] + end + || {Source, Descs} <- Errors]. + +format_error(AbsSource, Extra, {{Line, Column}, Mod, Desc}) -> + ErrorDesc = Mod:format_error(Desc), + io_lib:format("~s:~w:~w: ~s~s~n", [AbsSource, Line, Column, Extra, ErrorDesc]); +format_error(AbsSource, Extra, {Line, Mod, Desc}) -> + ErrorDesc = Mod:format_error(Desc), + io_lib:format("~s:~w: ~s~s~n", [AbsSource, Line, Extra, ErrorDesc]); +format_error(AbsSource, Extra, {Mod, Desc}) -> + ErrorDesc = Mod:format_error(Desc), + io_lib:format("~s: ~s~s~n", [AbsSource, Extra, ErrorDesc]). -- cgit v1.1 From 26161bc1acc1085ac8c29fe759fe6c40b400bc66 Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Thu, 23 Apr 2015 19:07:51 -0500 Subject: support for 18.0+ --- bootstrap | 58 +++++++++++++++++++++++++++++++++++++++++++++---- rebar.lock | 4 ++-- src/rebar_app_info.erl | 2 +- src/rebar_state.erl | 2 +- src/rebar_templater.erl | 2 +- 5 files changed, 59 insertions(+), 9 deletions(-) diff --git a/bootstrap b/bootstrap index 453bdfb..9799647 100755 --- a/bootstrap +++ b/bootstrap @@ -86,7 +86,7 @@ compile(App, FirstFiles) -> Sources = FirstFilesPaths ++ filelib:wildcard(filename:join([Dir, "src", "*.erl"])), [compile_file(X, [{i, filename:join(Dir, "include")} ,{outdir, filename:join(Dir, "ebin")} - ,return]) || X <- Sources]. + ,return | additional_defines()]) || X <- Sources]. compile_file(File, Opts) -> case compile:file(File, Opts) of @@ -95,7 +95,8 @@ compile_file(File, Opts) -> {ok, _Mod, []} -> ok; {ok, _Mod, Ws} -> - io:format("Warning: ~p~n", [format_warnings(File, Ws)]); + io:format("~s~n", [format_warnings(File, Ws)]), + halt(1); {error, Es, Ws} -> io:format("~s ~s~n", [format_errors(File, Es), format_warnings(File, Ws)]), halt(1) @@ -103,9 +104,11 @@ compile_file(File, Opts) -> bootstrap_rebar3() -> filelib:ensure_dir("_build/default/lib/rebar/ebin/dummy.beam"), + code:add_path("_build/default/lib/rebar/ebin/"), file:make_symlink(filename:absname("src"), filename:absname("_build/default/lib/rebar/src")), - Sources = filelib:wildcard("src/*.erl"), - [compile:file(X, [{outdir, "_build/default/lib/rebar/ebin/"}]) || X <- Sources], + Sources = ["src/rebar_resource.erl" | filelib:wildcard("src/*.erl")], + [compile_file(X, [{outdir, "_build/default/lib/rebar/ebin/"} + ,return | additional_defines()]) || X <- Sources], code:add_patha(filename:absname("_build/default/lib/rebar/ebin")). setup_env() -> @@ -168,3 +171,50 @@ format_error(AbsSource, Extra, {Line, Mod, Desc}) -> format_error(AbsSource, Extra, {Mod, Desc}) -> ErrorDesc = Mod:format_error(Desc), io_lib:format("~s: ~s~s~n", [AbsSource, Extra, ErrorDesc]). + +additional_defines() -> + [{d, D} || {Re, D} <- [{"^[0-9]+", namespaced_types}, {"^R1[4|5]", deprecated_crypto}], is_otp_release(Re)]. + +is_otp_release(ArchRegex) -> + case re:run(otp_release(), ArchRegex, [{capture, none}]) of + match -> + true; + nomatch -> + false + end. + +otp_release() -> + otp_release1(erlang:system_info(otp_release)). + +%% If OTP <= R16, otp_release is already what we want. +otp_release1([$R,N|_]=Rel) when is_integer(N) -> + Rel; +%% If OTP >= 17.x, erlang:system_info(otp_release) returns just the +%% major version number, we have to read the full version from +%% a file. See http://www.erlang.org/doc/system_principles/versions.html +%% Read vsn string from the 'OTP_VERSION' file and return as list without +%% the "\n". +otp_release1(Rel) -> + File = filename:join([code:root_dir(), "releases", Rel, "OTP_VERSION"]), + {ok, Vsn} = file:read_file(File), + + %% It's fine to rely on the binary module here because we can + %% be sure that it's available when the otp_release string does + %% not begin with $R. + Size = byte_size(Vsn), + %% The shortest vsn string consists of at least two digits + %% followed by "\n". Therefore, it's safe to assume Size >= 3. + case binary:part(Vsn, {Size, -3}) of + <<"**\n">> -> + %% The OTP documentation mentions that a system patched + %% using the otp_patch_apply tool available to licensed + %% customers will leave a '**' suffix in the version as a + %% flag saying the system consists of application versions + %% from multiple OTP versions. We ignore this flag and + %% drop the suffix, given for all intents and purposes, we + %% cannot obtain relevant information from it as far as + %% tooling is concerned. + binary:bin_to_list(Vsn, {0, Size - 3}); + _ -> + binary:bin_to_list(Vsn, {0, Size - 1}) + end. diff --git a/rebar.lock b/rebar.lock index cc619ef..89dca39 100644 --- a/rebar.lock +++ b/rebar.lock @@ -12,7 +12,7 @@ 1}, {<<"relx">>, {git,"https://github.com/erlware/relx.git", - {ref,"3f2462807fe4afb82bc52dd3ff8ff9244aad3bd3"}}, + {ref,"f8af9f5cd9f70ff43a043fe274dda4e56be82a2d"}}, 0}, {<<"providers">>, {git,"https://github.com/tsloughter/providers.git", @@ -28,5 +28,5 @@ 0}, {<<"erlware_commons">>, {git,"https://github.com/erlware/erlware_commons.git", - {ref,"05b956da26788f30b3cb793fa6ace02b75f481d0"}}, + {ref,"ef0d252b11c863f9c228af2fe93a4e42fba2f7f3"}}, 0}]. diff --git a/src/rebar_app_info.erl b/src/rebar_app_info.erl index 9659c0b..7894e75 100644 --- a/src/rebar_app_info.erl +++ b/src/rebar_app_info.erl @@ -61,7 +61,7 @@ %%============================================================================ %% types %%============================================================================ --type t() :: record(app_info_t). +-type t() :: #app_info_t{}. %%============================================================================ %% API diff --git a/src/rebar_state.erl b/src/rebar_state.erl index 3909a39..ddac9d2 100644 --- a/src/rebar_state.erl +++ b/src/rebar_state.erl @@ -65,7 +65,7 @@ -export_type([t/0]). --type t() :: record(state_t). +-type t() :: #state_t{}. -spec new() -> t(). new() -> diff --git a/src/rebar_templater.erl b/src/rebar_templater.erl index 75cbb87..78d1e83 100644 --- a/src/rebar_templater.erl +++ b/src/rebar_templater.erl @@ -394,7 +394,7 @@ write_file(Output, Data, Force) -> -spec make_template_name(string(), term()) -> module(). make_template_name(Base, Value) -> %% Seed so we get different values each time - random:seed(erlang:now()), + random:seed(os:timestamp()), Hash = erlang:phash2(Value), Ran = random:uniform(10000000), erlang:list_to_atom(Base ++ "_" ++ -- cgit v1.1 From d94c561627a90312b9dc0b680d69ab523474efb3 Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Thu, 23 Apr 2015 19:44:39 -0500 Subject: remove warning if header not found, could be in a macro --- src/rebar_erlc_compiler.erl | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/rebar_erlc_compiler.erl b/src/rebar_erlc_compiler.erl index f906463..862d21e 100644 --- a/src/rebar_erlc_compiler.erl +++ b/src/rebar_erlc_compiler.erl @@ -541,9 +541,6 @@ maybe_expand_include_lib_path(File, Dir) -> %% The use of -include_lib was probably incorrect by the user but lets try to make it work. %% We search in the outdir and outdir/../include to see if the header exists. warn_and_find_path(File, Dir) -> - ?WARN("Bad use of -include_lib(\"~s\")." - " First path component should be the name of an application." - " You probably meant -include(\"~s\").", [File, File]), SrcHeader = filename:join(Dir, File), case filelib:is_regular(SrcHeader) of true -> @@ -555,7 +552,6 @@ warn_and_find_path(File, Dir) -> true -> [filename:join(IncludeDir, File)]; false -> - ?WARN("Could not find header for -include_lib(\"~s\").", [File]), [] end end. -- cgit v1.1 From ee0f4dcd60c5e9eaef4de61ba93af73e57f9d88a Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Thu, 23 Apr 2015 20:40:22 -0500 Subject: merge_locks crashed if a config didn't have a deps entry --- src/rebar_config.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rebar_config.erl b/src/rebar_config.erl index 58b2c4d..c858fef 100644 --- a/src/rebar_config.erl +++ b/src/rebar_config.erl @@ -69,7 +69,7 @@ merge_locks(Config, [[]]) -> Config; %% lockfile with entries merge_locks(Config, [Locks]) -> - {deps, ConfigDeps} = lists:keyfind(deps, 1, Config), + ConfigDeps = proplists:get_value(deps, Config, []), %% We want the top level deps only from the lock file. %% This ensures deterministic overrides for configs. %% Then check if any new deps have been added to the config -- cgit v1.1 From 5d1634448cb89cd4c0b6f49e757ef281d5e71205 Mon Sep 17 00:00:00 2001 From: Fred Hebert Date: Fri, 24 Apr 2015 02:54:37 +0000 Subject: handle transitive deps being promoted --- src/rebar_prv_upgrade.erl | 31 ++++++++++++++++++++----------- test/rebar_upgrade_SUITE.erl | 15 +++++++++++++-- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/rebar_prv_upgrade.erl b/src/rebar_prv_upgrade.erl index 37914a7..d7d2921 100644 --- a/src/rebar_prv_upgrade.erl +++ b/src/rebar_prv_upgrade.erl @@ -91,29 +91,38 @@ parse_names(Bin, Locks) -> prepare_locks([], _, Locks, Unlocks) -> {Locks, Unlocks}; prepare_locks([Name|Names], Deps, Locks, Unlocks) -> + AtomName = binary_to_atom(Name, utf8), case lists:keyfind(Name, 1, Locks) of {_, _, 0} = Lock -> - AtomName = binary_to_atom(Name, utf8), case lists:keyfind(AtomName, 1, Deps) of false -> ?PRV_ERROR({unknown_dependency, Name}); Dep -> - Source = case Dep of - {_, Src} -> Src; - {_, _, Src} -> Src - end, - {NewLocks, NewUnlocks} = unlock_higher_than(0, Locks -- [Lock]), - prepare_locks(Names, - Deps, - NewLocks, + {Source, NewLocks, NewUnlocks} = prepare_lock(Dep, Lock, Locks), + prepare_locks(Names, Deps, NewLocks, + [{Name, Source, 0} | NewUnlocks ++ Unlocks]) + end; + {_, _, Level} = Lock when Level > 0 -> + case lists:keyfind(AtomName, 1, Deps) of + false -> + ?PRV_ERROR({transitive_dependency, Name}); + Dep -> % Dep has been promoted + {Source, NewLocks, NewUnlocks} = prepare_lock(Dep, Lock, Locks), + prepare_locks(Names, Deps, NewLocks, [{Name, Source, 0} | NewUnlocks ++ Unlocks]) end; - {_, _, Level} when Level > 0 -> - ?PRV_ERROR({transitive_dependency, Name}); false -> ?PRV_ERROR({unknown_dependency, Name}) end. +prepare_lock(Dep, Lock, Locks) -> + Source = Source = case Dep of + {_, Src} -> Src; + {_, _, Src} -> Src + end, + {NewLocks, NewUnlocks} = unlock_higher_than(0, Locks -- [Lock]), + {Source, NewLocks, NewUnlocks}. + top_level_deps(Deps, Locks) -> [Dep || Dep <- Deps, lists:keymember(0, 3, Locks)]. diff --git a/test/rebar_upgrade_SUITE.erl b/test/rebar_upgrade_SUITE.erl index 14186be..1dc0af2 100644 --- a/test/rebar_upgrade_SUITE.erl +++ b/test/rebar_upgrade_SUITE.erl @@ -10,7 +10,7 @@ groups() -> pair_a, pair_b, pair_ab, pair_c, pair_all, triplet_a, triplet_b, triplet_c, tree_a, tree_b, tree_c, tree_c2, tree_ac, tree_all, - delete_d]}, + delete_d, promote]}, {git, [], [{group, all}]}, {pkg, [], [{group, all}]}]. @@ -351,7 +351,17 @@ upgrades(delete_d) -> ], ["A","B", "C"], %% upgrade vs. new tree - {"", [{"A","2"}, "B", "C"]}}. + {"", [{"A","2"}, "B", "C"]}}; +upgrades(promote) -> + {[{"A", "1", [{"C", "1", []}]}, + {"B", "1", [{"D", "1", []}]} + ], + [{"A", "2", [{"C", "2", []}]}, + {"B", "2", [{"D", "2", []}]}, + {"C", "3", []} + ], + ["A","B","C","D"], + {"C", [{"A","1"},{"C","3"},{"B","1"},{"D","1"}]}}. %% TODO: add a test that verifies that unlocking files and then %% running the upgrade code is enough to properly upgrade things. @@ -414,6 +424,7 @@ tree_c(Config) -> run(Config). tree_c2(Config) -> run(Config). tree_ac(Config) -> run(Config). tree_all(Config) -> run(Config). +promote(Config) -> run(Config). delete_d(Config) -> meck:new(rebar_log, [no_link, passthrough]), -- cgit v1.1 From f491e70cb83b9966d8a42e4ac47a1d3276515240 Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Thu, 23 Apr 2015 23:30:19 -0500 Subject: support templates even when not run as escript --- src/rebar_templater.erl | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/rebar_templater.erl b/src/rebar_templater.erl index 78d1e83..746e440 100644 --- a/src/rebar_templater.erl +++ b/src/rebar_templater.erl @@ -266,17 +266,29 @@ replace_var([H|T], Acc, Vars) -> %% Load a list of all the files in the escript and on disk find_templates(State) -> - %% Cache the files since we'll potentially need to walk it several times - %% over the course of a run. - Files = cache_escript_files(State), + DiskTemplates = find_disk_templates(State), + {MainTemplates, Files} = + case rebar_state:escript_path(State) of + undefined -> + {find_priv_templates(State), []}; + _ -> + %% Cache the files since we'll potentially need to walk it several times + %% over the course of a run. + F = cache_escript_files(State), + {find_escript_templates(F), F} + end, + AvailTemplates = find_available_templates(DiskTemplates, + MainTemplates), + ?DEBUG("Available templates: ~p\n", [AvailTemplates]), + {AvailTemplates, Files}. - %% Build a list of available templates +find_available_templates(TemplateList1, TemplateList2) -> AvailTemplates = prioritize_templates( - tag_names(find_disk_templates(State)), - tag_names(find_escript_templates(Files))), + tag_names(TemplateList1), + tag_names(TemplateList2)), ?DEBUG("Available templates: ~p\n", [AvailTemplates]), - {AvailTemplates, Files}. + AvailTemplates. %% Scan the current escript for available files cache_escript_files(State) -> @@ -293,6 +305,12 @@ 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]. + %% Fetch template indexes that sit on disk in the user's HOME find_disk_templates(State) -> OtherTemplates = find_other_templates(State), -- cgit v1.1 From 164cff406335cf6aebfe6d30bc95e85c0d0915d1 Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Fri, 24 Apr 2015 22:24:42 -0500 Subject: read in application details into app_info after fetch --- src/rebar_app_info.erl | 13 +++++++++++++ src/rebar_prv_install_deps.erl | 11 ++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/rebar_app_info.erl b/src/rebar_app_info.erl index 7894e75..91640f2 100644 --- a/src/rebar_app_info.erl +++ b/src/rebar_app_info.erl @@ -157,6 +157,19 @@ app_file(AppInfo=#app_info_t{}, AppFile) -> AppInfo#app_info_t{app_file=AppFile}. -spec app_details(t()) -> list(). +app_details(AppInfo=#app_info_t{app_details=[]}) -> + AppFile = case app_file(AppInfo) of + undefined -> + app_file_src(AppInfo); + File -> + File + end, + case file:consult(AppFile) of + {ok, [{application, _, AppDetails}]} -> + AppDetails; + _ -> + [] + end; app_details(#app_info_t{app_details=AppDetails}) -> AppDetails. diff --git a/src/rebar_prv_install_deps.erl b/src/rebar_prv_install_deps.erl index 0fa843f..5598381 100644 --- a/src/rebar_prv_install_deps.erl +++ b/src/rebar_prv_install_deps.erl @@ -396,7 +396,7 @@ maybe_fetch(AppInfo, Profile, Upgrade, Seen, State) -> case fetch_app(AppInfo, AppDir, State) of true -> maybe_symlink_default(State, Profile, AppDir, AppInfo), - {true, AppInfo}; + {true, update_app_info(AppInfo)}; Other -> {Other, AppInfo} end; @@ -563,6 +563,15 @@ fetch_app(AppInfo, AppDir, State) -> Result end. +update_app_info(AppInfo) -> + AppDetails = rebar_app_info:app_details(AppInfo), + Applications = proplists:get_value(applications, AppDetails, []), + IncludedApplications = proplists:get_value(included_applications, AppDetails, []), + AppInfo1 = rebar_app_info:applications( + rebar_app_info:app_details(AppInfo, AppDetails), + IncludedApplications++Applications), + rebar_app_info:valid(AppInfo1, false). + maybe_upgrade(AppInfo, AppDir, false, State) -> Source = rebar_app_info:source(AppInfo), rebar_fetch:needs_update(AppDir, Source, State); -- cgit v1.1 From bbb6bb2d90779630c92feb5460264afa7b468ebd Mon Sep 17 00:00:00 2001 From: Fred Hebert Date: Sat, 25 Apr 2015 15:26:52 +0000 Subject: Avoid topsorting deps twice They can be culled and reused in one sort pass. --- src/rebar_prv_install_deps.erl | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/src/rebar_prv_install_deps.erl b/src/rebar_prv_install_deps.erl index 0fa843f..3cd030a 100644 --- a/src/rebar_prv_install_deps.erl +++ b/src/rebar_prv_install_deps.erl @@ -82,13 +82,9 @@ do(State) -> ?PRV_ERROR({cycles, Cycles}); {error, Error} -> {error, Error}; - no_cycle -> - case compile_order(Source, ProjectApps) of - {ok, ToCompile} -> - {ok, rebar_state:deps_to_build(State1, ToCompile)}; - {error, Error} -> - {error, Error} - end + {no_cycle, Sorted} -> + ToCompile = cull_compile(Sorted, ProjectApps), + {ok, rebar_state:deps_to_build(State1, ToCompile)} end catch %% maybe_fetch will maybe_throw an exception to break out of some loops @@ -171,17 +167,11 @@ find_cycles(Apps) -> case rebar_digraph:compile_order(Apps) of {error, {cycles, Cycles}} -> {cycles, Cycles}; {error, Error} -> {error, Error}; - {ok, _} -> no_cycle + {ok, Sorted} -> {no_cycle, Sorted} end. -compile_order(Source, ProjectApps) -> - case rebar_digraph:compile_order(Source) of - {ok, Sort} -> - %% Valid apps are compiled and good - {ok, lists:dropwhile(fun not_needs_compile/1, Sort -- ProjectApps)}; - {error, Error} -> - {error, Error} - end. +cull_compile(TopSortedDeps, ProjectApps) -> + lists:dropwhile(fun not_needs_compile/1, TopSortedDeps -- ProjectApps). update_pkg_deps(Profile, Packages, PkgDeps, Graph, Upgrade, Seen, State) -> case PkgDeps of -- cgit v1.1 From ae7d1ca1ea9e4ec12a82d6d4510856500964778b Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Sat, 25 Apr 2015 11:29:10 -0500 Subject: include _checkouts in release lib dirs if it exists --- src/rebar_prv_release.erl | 3 ++- src/rebar_prv_tar.erl | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/rebar_prv_release.erl b/src/rebar_prv_release.erl index c9a9c0b..595280c 100644 --- a/src/rebar_prv_release.erl +++ b/src/rebar_prv_release.erl @@ -35,8 +35,9 @@ do(State) -> Caller = rebar_state:get(State, caller, api), Options = rebar_state:command_args(State), DepsDir = rebar_dir:deps_dir(State), + ProjectAppDirs = lists:delete(".", ?DEFAULT_PROJECT_APP_DIRS), LibDirs = rebar_utils:filtermap(fun ec_file:exists/1, - [DepsDir | lists:delete(".", ?DEFAULT_PROJECT_APP_DIRS)]), + [?DEFAULT_CHECKOUTS_DIR, DepsDir | ProjectAppDirs]), OutputDir = filename:join(rebar_dir:base_dir(State), ?DEFAULT_RELEASE_DIR), AllOptions = string:join(["release" | Options], " "), try diff --git a/src/rebar_prv_tar.erl b/src/rebar_prv_tar.erl index 019036e..f7557bd 100644 --- a/src/rebar_prv_tar.erl +++ b/src/rebar_prv_tar.erl @@ -35,8 +35,9 @@ do(State) -> Caller = rebar_state:get(State, caller, api), Options = rebar_state:command_args(State), DepsDir = rebar_dir:deps_dir(State), + ProjectAppDirs = lists:delete(".", ?DEFAULT_PROJECT_APP_DIRS), LibDirs = rebar_utils:filtermap(fun ec_file:exists/1, - [DepsDir | lists:delete(".", ?DEFAULT_PROJECT_APP_DIRS)]), + [?DEFAULT_CHECKOUTS_DIR, DepsDir | ProjectAppDirs]), OutputDir = filename:join(rebar_dir:base_dir(State), ?DEFAULT_RELEASE_DIR), AllOptions = string:join(["release", "tar" | Options], " "), case rebar_state:get(State, relx, []) of -- cgit v1.1 From bce924e04ad087465370e851324896a892bfc690 Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Tue, 28 Apr 2015 09:43:15 -0500 Subject: don't load package registry unless there are pkg deps to solve --- src/rebar_prv_install_deps.erl | 35 ++++++++++++++++++++++------------- test/mock_pkg_resource.erl | 2 +- test/rebar_test_utils.erl | 4 ++-- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/rebar_prv_install_deps.erl b/src/rebar_prv_install_deps.erl index e25e2c5..17346f4 100644 --- a/src/rebar_prv_install_deps.erl +++ b/src/rebar_prv_install_deps.erl @@ -128,30 +128,39 @@ handle_deps(Profile, State, Deps, Locks) when is_list(Locks) -> handle_deps(_Profile, State, [], _, _) -> {ok, [], State}; handle_deps(Profile, State0, Deps, Upgrade, Locks) -> - %% Read in package index and dep graph - {Packages, Graph} = rebar_state:packages(State0), - Registry = rebar_packages:registry(State0), - State = rebar_state:packages(rebar_state:registry(State0, Registry), {Packages, Graph}), %% Split source deps from pkg deps, needed to keep backwards compatibility - DepsDir = profile_dep_dir(State, Profile), - {SrcDeps, PkgDeps} = parse_deps(DepsDir, Deps, State, Locks, 0), + DepsDir = profile_dep_dir(State0, Profile), + + {SrcDeps, PkgDeps} = parse_deps(DepsDir, Deps, State0, Locks, 0), %% Fetch transitive src deps - {State1, SrcApps, PkgDeps1, Seen} = - update_src_deps(Profile, 0, SrcDeps, PkgDeps, [], State, Upgrade, sets:new(), Locks), + {State1, SrcApps, PkgDeps1, Seen} = update_src_deps(Profile, 0, SrcDeps, PkgDeps, [] + ,State0, Upgrade, sets:new(), Locks), - {Solved, State2} = - update_pkg_deps(Profile, Packages, PkgDeps1, Graph, Upgrade, Seen, State1), + {Solved, State4} = + case PkgDeps1 of + [] -> + {[], State1}; + _ -> + %% Read in package index and dep graph + {Packages, Graph} = rebar_state:packages(State1), + Registry = rebar_packages:registry(State1), + State2 = rebar_state:packages(rebar_state:registry(State1, Registry) + ,{Packages, Graph}), + + update_pkg_deps(Profile, Packages, PkgDeps1 + ,Graph, Upgrade, Seen, State2) + end, AllDeps = lists:ukeymerge(2 ,lists:ukeysort(2, SrcApps) ,lists:ukeysort(2, Solved)), - State3 = rebar_state:update_all_deps(State2, AllDeps), + State5 = rebar_state:update_all_deps(State4, AllDeps), CodePaths = [rebar_app_info:ebin_dir(A) || A <- AllDeps], - State4 = rebar_state:update_code_paths(State3, all_deps, CodePaths), + State6 = rebar_state:update_code_paths(State5, all_deps, CodePaths), - {ok, AllDeps, State4}. + {ok, AllDeps, State6}. %% =================================================================== %% Internal functions diff --git a/test/mock_pkg_resource.erl b/test/mock_pkg_resource.erl index 615e8a5..560caef 100644 --- a/test/mock_pkg_resource.erl +++ b/test/mock_pkg_resource.erl @@ -152,7 +152,7 @@ find_parts([{AppName, Deps}|Rest], Skip, Acc) -> end. to_graph_parts(Dict) -> - LastUpdated = now(), + LastUpdated = os:timestamp(), dict:fold(fun(K,V,{Ks,Vs}) -> {_,Deps} = lists:keyfind(<<"deps">>, 1, V), {[{K,LastUpdated}|Ks], diff --git a/test/rebar_test_utils.erl b/test/rebar_test_utils.erl index f764146..2cdc58b 100644 --- a/test/rebar_test_utils.erl +++ b/test/rebar_test_utils.erl @@ -104,12 +104,12 @@ create_config(AppDir, Contents) -> %% @doc Util to create a random variation of a given name. create_random_name(Name) -> - random:seed(erlang:now()), + random:seed(os:timestamp()), Name ++ erlang:integer_to_list(random:uniform(1000000)). %% @doc Util to create a random variation of a given version. create_random_vsn() -> - random:seed(erlang:now()), + random:seed(os:timestamp()), lists:flatten([erlang:integer_to_list(random:uniform(100)), ".", erlang:integer_to_list(random:uniform(100)), ".", erlang:integer_to_list(random:uniform(100))]). -- cgit v1.1