Open eproxus opened 2 years ago
If the directory is added back with either code:add_patha/1
or code:add_pathz/1
it is removed again. However, it is possible to add another directory from outside the OTP lib directory which is never removed.
My initial guess is that this is because r3:do(compile)
will not contain the test
profile on the next invocation. You may get less confusion by calling r3:do(as, "test compile")
or something like that first. I'm not quite sure what the syntax was to re-invoke under a profile.
Ugh, I get something working with r3:do(do, "default as test compile").
-- other formats I think don't inherit the magic profile-managing of the rebar3 CLI. Another option would be to set the OS REBAR_PROFILE
var.
The issue seems to be with extra_src_drs
. If I configure with {extra_src_dirs, ["test/kernel"]}
the path to the OTP kernel application is removed (!).
A workaround for my particular situation is to use {extra_src_dirs, [{"test", [{recursive, true}]}]}.
which doesn't exhibit the same issue.
Adding context from the slack debugging session:
The reason the recursive approach likely juggles things around the paths because it ends up in <whatever>/test/ebin
rather than <whatever>/test/kernel/ebin
and that de-confuses paths. The path is always a sort of <pathname>/ebin
-- recursive source compiling goes look into all sub-directories for source files, but the VM only always supports a flat ebin/
, so we collapse the recursive source into a single top-level ebin
.
I would generally not expect the bug to be in rebar_paths
because I recall writing it to really use app-provided paths (https://github.com/erlang/rebar3/blob/main/src/rebar_paths.erl#L200-L206). I'm thinking the bug could actually be in https://github.com/erlang/rebar3/blob/main/src/rebar_agent.erl#L219 where we just call code:replace_path(App, Path)
https://github.com/erlang/otp/blob/eccc556e79f315d1f87c10fb46f2c4af50a63f20/lib/kernel/src/code_server.erl#L904-L915
Which seems to be the thing that gets confused:
%% Replace an old occurrence of an directory with name .../Name[-*].
%% If it does not exist, put the new directory last in Path.
so that code in OTP prioritize the selection of the OTP-provided directory and removes it in favor of the newer one that has the same name
so uh, no. I'm not sure it's actually a rebar3 bug? We update the path to force a reload, but the code in OTP is the one that gets confused... (this stuff is messy, that's a cool bug!)
I think the discriminating factor for blame will be which app we're trying to swap, maybe, and we should be able to see that with a run that defines DIAGNOSTIC=1
Here's a (anonymized) diagnostic log:
$ DIAGNOSTIC=1 rebar3 as test shell
===> Load global config file /Users/user/.config/rebar3/rebar.config
===> 24.2.2 satisfies the requirement for minimum OTP version 18
===> Evaluating config script "/Users/user/.cache/rebar3/24.2.2/plugins/hex_core/rebar.config.script"
===> 24.2.2 satisfies the requirement for minimum OTP version 19.3
===> Setting paths to [deps]
===> Compile (apps)
===> Setting paths to [plugins]
===> Setting paths to [deps]
===> Setting paths to [plugins]
===> Setting paths to [plugins]
===> Expanded command sequence to be run: [as]
===> Running provider: as
===> Expanded command sequence to be run: [app_discovery,install_deps,lock,compile,shell]
===> Running provider: app_discovery
===> Found top-level apps: [my_app]
using config: [{src_dirs,["src"]},{lib_dirs,["apps/*","lib/*","."]}]
===> Evaluating config script "/Users/user/my_app/_build/default/lib/jsx/rebar.config.script"
===> Running provider: install_deps
===> Verifying dependencies...
===> sh info:
cwd: "/Users/user/my_app"
cmd: git --version
===> opts: []
===> Port Cmd: git --version
Port Opts: [exit_status,
{line,16384},
use_stdio,stderr_to_stdout,hide,eof,binary]
===> sh info:
cwd: "/Users/user/my_app"
cmd: git rev-parse --short=7 -q HEAD
===> opts: [{cd,"/Users/user/my_app/_build/default/lib/my_dep"}]
===> Port Cmd: git rev-parse --short=7 -q HEAD
Port Opts: [{cd,"/Users/user/my_app/_build/default/lib/my_dep"},
exit_status,
{line,16384},
use_stdio,stderr_to_stdout,hide,eof,binary]
===> Comparing git ref d233d5b with d233d5b
===> Running provider: lock
===> Running provider: compile
===> Setting paths to [deps]
===> Compile (apps)
===> Setting paths to [plugins]
===> Setting paths to [deps]
===> Running hooks for compile with configuration:
===> {pre_hooks, []}.
===> run_hooks("/Users/user/my_app", pre_hooks, compile) -> no hooks defined
===> sh info:
cwd: "/Users/user/my_app"
cmd: mkdir -p /Users/user/my_app/_build/test/lib/my_app/test
===> opts: [{use_stdout,false},abort_on_error]
===> Port Cmd: mkdir -p /Users/user/my_app/_build/test/lib/my_app/test
Port Opts: [exit_status,
{line,16384},
use_stdio,stderr_to_stdout,hide,eof,binary]
===> sh info:
cwd: "/Users/user/my_app"
cmd: cp -Rp /Users/user/my_app/test/my_app_eqc_SUITE.erl /Users/user/my_app/test/my_app_SUITE_data /Users/user/my_app/test/my_app_SUITE.erl /Users/user/my_app/test/kernel "/Users/user/my_app/_build/test/lib/my_app/test"
===> opts: [{use_stdout,true},abort_on_error]
===> Port Cmd: cp -Rp /Users/user/my_app/test/my_app_eqc_SUITE.erl /Users/user/my_app/test/my_app_SUITE_data /Users/user/my_app/test/my_app_SUITE.erl /Users/user/my_app/test/kernel "/Users/user/my_app/_build/test/lib/my_app/test"
Port Opts: [exit_status,
{line,16384},
use_stdio,stderr_to_stdout,hide,eof,binary]
===> sh info:
cwd: "/Users/user/my_app"
cmd: mkdir -p /Users/user/my_app/_build/test/lib/my_app/test/kernel
===> opts: [{use_stdout,false},abort_on_error]
===> Port Cmd: mkdir -p /Users/user/my_app/_build/test/lib/my_app/test/kernel
Port Opts: [exit_status,
{line,16384},
use_stdio,stderr_to_stdout,hide,eof,binary]
===> sh info:
cwd: "/Users/user/my_app"
cmd: cp -Rp /Users/user/my_app/test/kernel/my_app_srv2_component.erl /Users/user/my_app/test/kernel/my_app_srv1_component.erl /Users/user/my_app/test/kernel/my_app_display_component.erl /Users/user/my_app/test/kernel/my_app_drv_component.erl "/Users/user/my_app/_build/test/lib/my_app/test/kernel"
===> opts: [{use_stdout,true},abort_on_error]
===> Port Cmd: cp -Rp /Users/user/my_app/test/kernel/my_app_srv2_component.erl /Users/user/my_app/test/kernel/my_app_srv1_component.erl /Users/user/my_app/test/kernel/my_app_display_component.erl /Users/user/my_app/test/kernel/my_app_drv_component.erl "/Users/user/my_app/_build/test/lib/my_app/test/kernel"
Port Opts: [exit_status,
{line,16384},
use_stdio,stderr_to_stdout,hide,eof,binary]
===> Compile (project_apps)
===> Running hooks for compile in app my_app (/Users/user/my_app) with configuration:
===> {pre_hooks, [{"(linux)",compile,"make -C c_src"}]}.
===> Running hooks for erlc_compile in app my_app (/Users/user/my_app) with configuration:
===> {pre_hooks, []}.
===> Setting paths to [deps]
===> Analyzing applications...
===> Compiling my_app
===> compile options: {erl_opts, [debug_info,{d,'TEST'}]}.
===> files to analyze ["/Users/user/my_app/src/my_app_srv2.erl",
"/Users/user/my_app/src/my_app_drv.erl",
"/Users/user/my_app/src/my_app_ebcontroller.erl",
"/Users/user/my_app/src/my_app_mngmt.erl",
"/Users/user/my_app/src/my_app_client.erl",
"/Users/user/my_app/src/my_app_client_ws.erl",
"/Users/user/my_app/src/my_app_display.erl",
"/Users/user/my_app/src/my_app_sup.erl",
"/Users/user/my_app/src/my_app_inotify.erl",
"/Users/user/my_app/src/my_app_cert.erl",
"/Users/user/my_app/src/my_app_app.erl",
"/Users/user/my_app/src/my_app_tls.erl",
"/Users/user/my_app/src/my_app_srv1.erl",
"/Users/user/my_app/src/my_app_img.erl"]
===> Starting 0 worker(s)
===> compile options: {erl_opts, [{i,
"/Users/user/my_app/src"},
debug_info,
{d,'TEST'}]}.
===> files to analyze ["/Users/user/my_app/test/my_app_SUITE.erl",
"/Users/user/my_app/test/my_app_eqc_SUITE.erl"]
===> Starting 0 worker(s)
===> compile options: {erl_opts, [{i,
"/Users/user/my_app/src"},
debug_info,
{d,'TEST'}]}.
===> files to analyze ["/Users/user/my_app/test/kernel/my_app_drv_component.erl",
"/Users/user/my_app/test/kernel/my_app_display_component.erl",
"/Users/user/my_app/test/kernel/my_app_srv1_component.erl",
"/Users/user/my_app/test/kernel/my_app_srv2_component.erl"]
===> Starting 0 worker(s)
===> Running hooks for erlc_compile in app my_app (/Users/user/my_app) with configuration:
===> {post_hooks, []}.
===> Running hooks for app_compile in app my_app (/Users/user/my_app) with configuration:
===> {pre_hooks, []}.
===> Setting paths to [plugins]
===> Setting paths to [deps]
===> Running hooks for app_compile in app my_app (/Users/user/my_app) with configuration:
===> {post_hooks, []}.
===> Running hooks for compile in app my_app (/Users/user/my_app) with configuration:
===> {post_hooks, []}.
===> Running hooks for compile with configuration:
===> {post_hooks, []}.
===> run_hooks("/Users/user/my_app", post_hooks, compile) -> no hooks defined
===> Setting paths to [plugins]
===> Running provider: shell
Erlang/OTP 24 [erts-12.2.1] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit]
Eshell V12.2.1 (abort with ^G)
1> ===> No script_file specified.
1> [P || P <- code:get_path(), string:find(P, "kernel") =/= nomatch].
["/Users/user/my_app/_build/test/lib/my_app/test/kernel",
"/Users/user/.asdf/installs/erlang/24.2.2/lib/kernel-8.2/ebin"]
2> r3:do(compile).
===> This feature is experimental and may be modified or removed at any time.
===> Load global config file /Users/user/.config/rebar3/rebar.config
===> 24.2.2 satisfies the requirement for minimum OTP version 18
===> Evaluating config script "/Users/user/.cache/rebar3/24.2.2/plugins/hex_core/rebar.config.script"
===> 24.2.2 satisfies the requirement for minimum OTP version 19.3
===> Setting paths to [deps]
===> Compile (apps)
===> Setting paths to [plugins]
===> Setting paths to [deps]
===> Setting paths to [plugins]
===> Setting paths to [plugins]
Expanded command sequence to be run: [do]
Running provider: do
Expanded command sequence to be run: [app_discovery,install_deps,lock,compile]
Running provider: app_discovery
Found top-level apps: [my_app]
using config: [{src_dirs,["src"]},{lib_dirs,["apps/*","lib/*","."]}]
Evaluating config script "/Users/user/my_app/_build/default/lib/jsx/rebar.config.script"
Running provider: install_deps
Verifying dependencies...
sh info:
cwd: "/Users/user/my_app"
cmd: git rev-parse --short=7 -q HEAD
opts: [{cd,"/Users/user/my_app/_build/default/lib/my_dep"}]
Port Cmd: git rev-parse --short=7 -q HEAD
Port Opts: [{cd,"/Users/user/my_app/_build/default/lib/my_dep"},
exit_status,
{line,16384},
use_stdio,stderr_to_stdout,hide,eof,binary]
Comparing git ref d233d5b with d233d5b
Running provider: lock
Running provider: compile
Setting paths to [deps]
Compile (apps)
Setting paths to [plugins]
Setting paths to [deps]
Running hooks for compile with configuration:
{pre_hooks, []}.
run_hooks("/Users/user/my_app", pre_hooks, compile) -> no hooks defined
sh info:
cwd: "/Users/user/my_app"
cmd: mkdir -p /Users/user/my_app/_build/test/lib/my_app/test
opts: [{use_stdout,false},abort_on_error]
Port Cmd: mkdir -p /Users/user/my_app/_build/test/lib/my_app/test
Port Opts: [exit_status,
{line,16384},
use_stdio,stderr_to_stdout,hide,eof,binary]
sh info:
cwd: "/Users/user/my_app"
cmd: cp -Rp /Users/user/my_app/test/my_app_eqc_SUITE.erl /Users/user/my_app/test/my_app_SUITE_data /Users/user/my_app/test/my_app_SUITE.erl /Users/user/my_app/test/kernel "/Users/user/my_app/_build/test/lib/my_app/test"
opts: [{use_stdout,true},abort_on_error]
Port Cmd: cp -Rp /Users/user/my_app/test/my_app_eqc_SUITE.erl /Users/user/my_app/test/my_app_SUITE_data /Users/user/my_app/test/my_app_SUITE.erl /Users/user/my_app/test/kernel "/Users/user/my_app/_build/test/lib/my_app/test"
Port Opts: [exit_status,
{line,16384},
use_stdio,stderr_to_stdout,hide,eof,binary]
sh info:
cwd: "/Users/user/my_app"
cmd: mkdir -p /Users/user/my_app/_build/test/lib/my_app/test/kernel
opts: [{use_stdout,false},abort_on_error]
Port Cmd: mkdir -p /Users/user/my_app/_build/test/lib/my_app/test/kernel
Port Opts: [exit_status,
{line,16384},
use_stdio,stderr_to_stdout,hide,eof,binary]
sh info:
cwd: "/Users/user/my_app"
cmd: cp -Rp /Users/user/my_app/test/kernel/my_app_srv2_component.erl /Users/user/my_app/test/kernel/my_app_srv1_component.erl /Users/user/my_app/test/kernel/my_app_display_component.erl /Users/user/my_app/test/kernel/my_app_drv_component.erl "/Users/user/my_app/_build/test/lib/my_app/test/kernel"
opts: [{use_stdout,true},abort_on_error]
Port Cmd: cp -Rp /Users/user/my_app/test/kernel/my_app_srv2_component.erl /Users/user/my_app/test/kernel/my_app_srv1_component.erl /Users/user/my_app/test/kernel/my_app_display_component.erl /Users/user/my_app/test/kernel/my_app_drv_component.erl "/Users/user/my_app/_build/test/lib/my_app/test/kernel"
Port Opts: [exit_status,
{line,16384},
use_stdio,stderr_to_stdout,hide,eof,binary]
Compile (project_apps)
Running hooks for compile in app my_app (/Users/user/my_app) with configuration:
{pre_hooks, [{"(linux)",compile,"make -C c_src"}]}.
Running hooks for erlc_compile in app my_app (/Users/user/my_app) with configuration:
{pre_hooks, []}.
Setting paths to [deps]
Analyzing applications...
Compiling my_app
compile options: {erl_opts, [debug_info,{d,'TEST'}]}.
files to analyze ["/Users/user/my_app/src/my_app_srv2.erl",
"/Users/user/my_app/src/my_app_drv.erl",
"/Users/user/my_app/src/my_app_ebcontroller.erl",
"/Users/user/my_app/src/my_app_mngmt.erl",
"/Users/user/my_app/src/my_app_client.erl",
"/Users/user/my_app/src/my_app_client_ws.erl",
"/Users/user/my_app/src/my_app_display.erl",
"/Users/user/my_app/src/my_app_sup.erl",
"/Users/user/my_app/src/my_app_inotify.erl",
"/Users/user/my_app/src/my_app_cert.erl",
"/Users/user/my_app/src/my_app_app.erl",
"/Users/user/my_app/src/my_app_tls.erl",
"/Users/user/my_app/src/my_app_srv1.erl",
"/Users/user/my_app/src/my_app_img.erl"]
Starting 0 worker(s)
compile options: {erl_opts, [{i,"/Users/user/my_app/src"},
debug_info,
{d,'TEST'}]}.
files to analyze ["/Users/user/my_app/test/my_app_SUITE.erl",
"/Users/user/my_app/test/my_app_eqc_SUITE.erl"]
Starting 0 worker(s)
compile options: {erl_opts, [{i,"/Users/user/my_app/src"},
debug_info,
{d,'TEST'}]}.
files to analyze ["/Users/user/my_app/test/kernel/my_app_drv_component.erl",
"/Users/user/my_app/test/kernel/my_app_display_component.erl",
"/Users/user/my_app/test/kernel/my_app_srv1_component.erl",
"/Users/user/my_app/test/kernel/my_app_srv2_component.erl"]
Starting 0 worker(s)
Running hooks for erlc_compile in app my_app (/Users/user/my_app) with configuration:
{post_hooks, []}.
Running hooks for app_compile in app my_app (/Users/user/my_app) with configuration:
{pre_hooks, []}.
Setting paths to [plugins]
Setting paths to [deps]
Running hooks for app_compile in app my_app (/Users/user/my_app) with configuration:
{post_hooks, []}.
Running hooks for compile in app my_app (/Users/user/my_app) with configuration:
{post_hooks, []}.
Running hooks for compile with configuration:
{post_hooks, []}.
run_hooks("/Users/user/my_app", post_hooks, compile) -> no hooks defined
Setting paths to [plugins]
Removing [deps,plugins] paths
reloading [my_app_srv2_component,my_app_display_component,my_app_drv_component,
my_app_srv1_component] from /Users/user/my_app/_build/test/lib/my_app/test/kernel
ok
3> [P || P <- code:get_path(), string:find(P, "kernel") =/= nomatch].
["/Users/user/my_app/_build/test/lib/my_app/test/kernel"]
Okay, nice. So like all annoying bugs, it's a bit of everything:
Lines 195-196 misidentify the app being reloaded as kernel because it uses the trailing end of the path as the app name. Mostly there's little choice there because the extra dirs do not have a proper app name containing them. Then once that path is refreshed for the modules at lines 216-219, the right modules in the right path are identified, but since the app name clashes (kernel
), the OTP code drops the other one.
code:replace_path()
if it's not about an OTP app but I don't know if that would break reloading there)
With QuickCheck installed in the
lib
folder of my Erlang installation (as is the default when running the QuickCheck installer)rebar3 as test shell
removes it from the path after subsequent calls tor3:do(compile)
.Environment
rebar3 report
to your message:Current behaviour
Expected behaviour
The default Erlang path is not destroyed when re-compiling code.