summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Thompson <andrew@hijacked.us>2013-10-16 19:48:00 -0400
committerAndrew Thompson <andrew@hijacked.us>2013-10-16 19:58:02 -0400
commitd983beafe93a0f58272d3351f12329984541878f (patch)
tree472784a2f40c8ff3963a7e7ff96f7ae3910db1c5
parented88055a750736c5c9807ca4da4803ff8a6aef16 (diff)
Don't over-aggressively clean the code path in the presence of lib_dir directives
Rebar, when it encounters a lib_dir directive, caches the current code path, adds the libdir(s) and returns the cached copy of the path. When rebar has finished processing that directory, it restores the cached path. This is problematic in the below scenario: /(lib_dir)->G A -> B -> C -> D -> E \-> F -> D -> E When rebar is finished processing B, it restores the code path to what it was before it processed B, removing C, D, E and G from the code path. This means when it comes to process F, neither D or E are in the code path, so any header includes, rebar plugins or parse transforms will not be in the code path. Without the lib_dir directive, rebar does no code path cleanups, so everything works fine. This change makes rebar only remove the explicit lib_dir code paths it added and adds an inttest that replicates the above scenario.
-rw-r--r--inttest/tdeps3/a.erl3
-rw-r--r--inttest/tdeps3/a.rebar.config4
-rw-r--r--inttest/tdeps3/b.hrl1
-rw-r--r--inttest/tdeps3/b.rebar.config5
-rw-r--r--inttest/tdeps3/c.hrl1
-rw-r--r--inttest/tdeps3/c.rebar.config1
-rw-r--r--inttest/tdeps3/d.hrl1
-rw-r--r--inttest/tdeps3/d.rebar.config1
-rw-r--r--inttest/tdeps3/e.hrl1
-rw-r--r--inttest/tdeps3/f.hrl1
-rw-r--r--inttest/tdeps3/root.rebar.config1
-rw-r--r--inttest/tdeps3/tdeps3_rt.erl89
-rw-r--r--src/rebar_core.erl9
13 files changed, 114 insertions, 4 deletions
diff --git a/inttest/tdeps3/a.erl b/inttest/tdeps3/a.erl
new file mode 100644
index 0000000..5a387eb
--- /dev/null
+++ b/inttest/tdeps3/a.erl
@@ -0,0 +1,3 @@
+-module({{module}}).
+
+-include_lib("{{dep}}/include/{{dep}}.hrl").
diff --git a/inttest/tdeps3/a.rebar.config b/inttest/tdeps3/a.rebar.config
new file mode 100644
index 0000000..19b8ef8
--- /dev/null
+++ b/inttest/tdeps3/a.rebar.config
@@ -0,0 +1,4 @@
+{deps, [
+ {b, "1", {git, "../repo/b"}},
+ {f, "1", {git, "../repo/f"}}
+]}.
diff --git a/inttest/tdeps3/b.hrl b/inttest/tdeps3/b.hrl
new file mode 100644
index 0000000..efbeab1
--- /dev/null
+++ b/inttest/tdeps3/b.hrl
@@ -0,0 +1 @@
+-include_lib("c/include/c.hrl").
diff --git a/inttest/tdeps3/b.rebar.config b/inttest/tdeps3/b.rebar.config
new file mode 100644
index 0000000..d1ccae2
--- /dev/null
+++ b/inttest/tdeps3/b.rebar.config
@@ -0,0 +1,5 @@
+{deps, [
+ {c, "1", {git, "../repo/c"}}
+]}.
+
+{lib_dirs, [apps]}.
diff --git a/inttest/tdeps3/c.hrl b/inttest/tdeps3/c.hrl
new file mode 100644
index 0000000..cc87fff
--- /dev/null
+++ b/inttest/tdeps3/c.hrl
@@ -0,0 +1 @@
+-include_lib("d/include/d.hrl").
diff --git a/inttest/tdeps3/c.rebar.config b/inttest/tdeps3/c.rebar.config
new file mode 100644
index 0000000..b590771
--- /dev/null
+++ b/inttest/tdeps3/c.rebar.config
@@ -0,0 +1 @@
+{deps, [{d, "1", {git, "../repo/d"}}]}.
diff --git a/inttest/tdeps3/d.hrl b/inttest/tdeps3/d.hrl
new file mode 100644
index 0000000..02f8088
--- /dev/null
+++ b/inttest/tdeps3/d.hrl
@@ -0,0 +1 @@
+-include_lib("e/include/e.hrl").
diff --git a/inttest/tdeps3/d.rebar.config b/inttest/tdeps3/d.rebar.config
new file mode 100644
index 0000000..4c7cd54
--- /dev/null
+++ b/inttest/tdeps3/d.rebar.config
@@ -0,0 +1 @@
+{deps, [{e, "1", {git, "../repo/e"}}]}.
diff --git a/inttest/tdeps3/e.hrl b/inttest/tdeps3/e.hrl
new file mode 100644
index 0000000..9f02fab
--- /dev/null
+++ b/inttest/tdeps3/e.hrl
@@ -0,0 +1 @@
+-define(HELLO, hello).
diff --git a/inttest/tdeps3/f.hrl b/inttest/tdeps3/f.hrl
new file mode 100644
index 0000000..02f8088
--- /dev/null
+++ b/inttest/tdeps3/f.hrl
@@ -0,0 +1 @@
+-include_lib("e/include/e.hrl").
diff --git a/inttest/tdeps3/root.rebar.config b/inttest/tdeps3/root.rebar.config
new file mode 100644
index 0000000..d1c3793
--- /dev/null
+++ b/inttest/tdeps3/root.rebar.config
@@ -0,0 +1 @@
+{sub_dirs, ["apps/a"]}.
diff --git a/inttest/tdeps3/tdeps3_rt.erl b/inttest/tdeps3/tdeps3_rt.erl
new file mode 100644
index 0000000..da87d43
--- /dev/null
+++ b/inttest/tdeps3/tdeps3_rt.erl
@@ -0,0 +1,89 @@
+-module(tdeps3_rt).
+
+-compile(export_all).
+
+%% Exercise transitive dependencies where there are multiple files
+%% depending on the same set of deps as well as lib_dir directives
+%% A -> B -> C -> D -> E
+%% |--> G(via lib_dir)
+%% |--> F -> D -> E
+
+files() ->
+ [
+ %% A1 application
+ {create, "ebin/a.app", app(a, [a])},
+ {template, "a.erl", "src/a.erl", dict:from_list([{module, a}, {dep, b}])},
+
+ {copy, "a.rebar.config", "rebar.config"},
+ {copy, "../../rebar", "rebar"},
+
+ %% B application
+ {create, "repo/b/ebin/b.app", app(b, [b])},
+ {template, "a.erl", "repo/b/src/b.erl", dict:from_list([{module, b}, {dep, b}])},
+ {copy, "b.rebar.config", "repo/b/rebar.config"},
+ {copy, "b.hrl", "repo/b/include/b.hrl"},
+
+ %% C application
+ {create, "repo/c/ebin/c.app", app(c, [c])},
+ {template, "a.erl", "repo/c/src/c.erl", dict:from_list([{module, c}, {dep, d}])},
+ {copy, "c.rebar.config", "repo/c/rebar.config"},
+ {copy, "c.hrl", "repo/c/include/c.hrl"},
+
+ %% D application
+ {create, "repo/d/ebin/d.app", app(d, [d])},
+ {template, "a.erl", "repo/d/src/d.erl", dict:from_list([{module, d}, {dep, e}])},
+ {copy, "d.rebar.config", "repo/d/rebar.config"},
+ {copy, "d.hrl", "repo/d/include/d.hrl"},
+
+ %% E application
+ {create, "repo/e/ebin/e.app", app(e, [])},
+ {copy, "e.hrl", "repo/e/include/e.hrl"},
+
+
+ %% F application
+ {create, "repo/f/ebin/f.app", app(f, [f])},
+ {template, "a.erl", "repo/f/src/f.erl", dict:from_list([{module, f}, {dep, d}])},
+ {copy, "c.rebar.config", "repo/f/rebar.config"},
+ {copy, "f.hrl", "repo/f/include/f.hrl"},
+
+ %% G application, which is part of the B repo, in a lib_dir
+ {create, "repo/b/apps/g/ebin/g.app", app(g, [])},
+ {copy, "e.hrl", "repo/b/apps/g/include/g.hrl"}
+
+ ].
+
+apply_cmds([], _Params) ->
+ ok;
+apply_cmds([Cmd | Rest], Params) ->
+ io:format("Running: ~s (~p)\n", [Cmd, Params]),
+ {ok, _} = retest_sh:run(Cmd, Params),
+ apply_cmds(Rest, Params).
+
+run(_Dir) ->
+ %% Initialize the b/c apps as git repos so that dependencies pull
+ %% properly
+ GitCmds = ["git init",
+ "git add -A",
+ "git config user.email 'tdeps@example.com'",
+ "git config user.name 'tdeps'",
+ "git commit -a -m 'Initial Commit'"],
+ ok = apply_cmds(GitCmds, [{dir, "repo/b"}]),
+ ok = apply_cmds(GitCmds, [{dir, "repo/c"}]),
+ ok = apply_cmds(GitCmds, [{dir, "repo/d"}]),
+ ok = apply_cmds(GitCmds, [{dir, "repo/e"}]),
+ ok = apply_cmds(GitCmds, [{dir, "repo/f"}]),
+
+ {ok, _} = retest_sh:run("./rebar -v get-deps compile", []),
+ ok.
+
+%%
+%% Generate the contents of a simple .app file
+%%
+app(Name, Modules) ->
+ App = {application, Name,
+ [{description, atom_to_list(Name)},
+ {vsn, "1"},
+ {modules, Modules},
+ {registered, []},
+ {applications, [kernel, stdlib]}]},
+ io_lib:format("~p.\n", [App]).
diff --git a/src/rebar_core.erl b/src/rebar_core.erl
index 4d50f4f..2e0768e 100644
--- a/src/rebar_core.erl
+++ b/src/rebar_core.erl
@@ -399,18 +399,19 @@ update_code_path(Config) ->
[] ->
no_change;
Paths ->
- OldPath = code:get_path(),
LibPaths = expand_lib_dirs(Paths, rebar_utils:get_cwd(), []),
ok = code:add_pathsa(LibPaths),
- {old, OldPath}
+ %% track just the paths we added, so we can remove them without
+ %% removing other paths added by this dep
+ {added, LibPaths}
end.
restore_code_path(no_change) ->
ok;
-restore_code_path({old, Path}) ->
+restore_code_path({added, Paths}) ->
%% Verify that all of the paths still exist -- some dynamically
%% added paths can get blown away during clean.
- true = code:set_path([F || F <- Path, erl_prim_loader_is_file(F)]),
+ [true = code:del_path(F) || F <- Paths, erl_prim_loader_is_file(F)],
ok.
erl_prim_loader_is_file(File) ->