Skip to content

Prob in elixirc paths used by :path dependencies in Elixir 1.2/1.3 #4792

@myronmarston

Description

@myronmarston

Environment

  • Elixir version (elixir -v):

Erlang/OTP 18 [erts-7.2.1] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Elixir 1.3.0-rc.1 (9eb4781)

  • Operating system:

El Capitan

Current behavior

There's an example app for this in josevalim/umbrella_sample#6.

Running against that branch, if I use a :path dependency (set via the BAR_DEP env var) and run mix test, everything passes:

$ export BAR_DEP=path && elixir -v && rm -rf _build && mix test
Erlang/OTP 18 [erts-7.2.1] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Elixir 1.3.0-rc.1 (9eb4781)
"/Users/myron/code/umbrella_sample/apps/bar"
"/Users/myron/code/umbrella_sample/apps/bar"
"/Users/myron/code/umbrella_sample/apps/bar"
==> bar
Compiling 2 files (.ex)
Generated bar app
"/Users/myron/code/umbrella_sample/apps/bar"
==> foo
Compiling 1 file (.ex)
Generated foo app
==> bar
"/Users/myron/code/umbrella_sample/apps/bar"
.

Finished in 0.04 seconds
1 test, 0 failures

Randomized with seed 220497
"/Users/myron/code/umbrella_sample/apps/bar"
==> foo
.

Finished in 0.03 seconds
1 test, 0 failures

Randomized with seed 300412

(BTW, you can ignore the printed "/Users/myron/code/umbrella_sample/apps/bar" bits: I added that to confirm that the path was in fact correct regardless of which directory is the current working dir).

But, if I use a :path dependency, cd into apps/foo, and run mix test, if fails -- a module defined in the dependency's test/support directory (which has been added to elixirc_paths), it fails:

$ export BAR_DEP=path && elixir -v && rm -rf _build && (cd apps/foo && mix test)
Erlang/OTP 18 [erts-7.2.1] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Elixir 1.3.0-rc.1 (9eb4781)
"/Users/myron/code/umbrella_sample/apps/bar"
"/Users/myron/code/umbrella_sample/apps/bar"
==> bar
Compiling 1 file (.ex)
Generated bar app
==> foo
Compiling 1 file (.ex)
Generated foo app
** (CompileError) test/foo_test.exs:3: module Bar.TestHelper is not loaded and could not be found
    (stdlib) erl_eval.erl:669: :erl_eval.do_apply/6
    (elixir) lib/code.ex:363: Code.require_file/2
    (elixir) lib/kernel/parallel_require.ex:56: anonymous fn/2 in Kernel.ParallelRequire.spawn_requires/5

If I instead use in_umbrella: true for the bar dependency, it works in both cases:

$ export BAR_DEP=umbrella && elixir -v && rm -rf _build && mix test
Erlang/OTP 18 [erts-7.2.1] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Elixir 1.3.0-rc.1 (9eb4781)
==> bar
Compiling 2 files (.ex)
Generated bar app
==> foo
Compiling 1 file (.ex)
Generated foo app
==> bar
.

Finished in 0.05 seconds
1 test, 0 failures

Randomized with seed 709339
==> foo
.

Finished in 0.02 seconds
1 test, 0 failures

Randomized with seed 792854

$ export BAR_DEP=umbrella && elixir -v && rm -rf _build && (cd apps/foo && mix test)
Erlang/OTP 18 [erts-7.2.1] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Elixir 1.3.0-rc.1 (9eb4781)
==> bar
Compiling 2 files (.ex)
Generated bar app
==> foo
Compiling 1 file (.ex)
Generated foo app
.

Finished in 0.02 seconds
1 test, 0 failures

Randomized with seed 590057

On 1.2, the same behavior I've described exists:

$ export BAR_DEP=path && elixir -v && rm -rf _build && mix test
Erlang/OTP 18 [erts-7.2.1] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Elixir 1.2.1
"/Users/myron/code/umbrella_sample/apps/bar"
"/Users/myron/code/umbrella_sample/apps/bar"
"/Users/myron/code/umbrella_sample/apps/bar"
==> bar
Compiled test/support/bar_helper.ex
Compiled lib/bar.ex
Generated bar app
"/Users/myron/code/umbrella_sample/apps/bar"
==> foo
Compiled lib/foo.ex
Generated foo app
Consolidated List.Chars
Consolidated Collectable
Consolidated String.Chars
Consolidated Enumerable
Consolidated IEx.Info
Consolidated Inspect
==> bar
"/Users/myron/code/umbrella_sample/apps/bar"
.

Finished in 0.07 seconds (0.07s on load, 0.00s on tests)
1 test, 0 failures

Randomized with seed 767345
"/Users/myron/code/umbrella_sample/apps/bar"
==> foo
.

Finished in 0.00 seconds
1 test, 0 failures

Randomized with seed 803551

$ export BAR_DEP=path && elixir -v && rm -rf _build && (cd apps/foo && mix test)
Erlang/OTP 18 [erts-7.2.1] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Elixir 1.2.1
"/Users/myron/code/umbrella_sample/apps/bar"
"/Users/myron/code/umbrella_sample/apps/bar"
==> bar
Compiled lib/bar.ex
Generated bar app
==> foo
Compiled lib/foo.ex
Generated foo app
Consolidated List.Chars
Consolidated Collectable
Consolidated String.Chars
Consolidated Enumerable
Consolidated IEx.Info
Consolidated Inspect
** (CompileError) test/foo_test.exs:3: module Bar.TestHelper is not loaded and could not be found

$ export BAR_DEP=umbrella && elixir -v && rm -rf _build && mix test
Erlang/OTP 18 [erts-7.2.1] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Elixir 1.2.1
==> bar
Compiled test/support/bar_helper.ex
Compiled lib/bar.ex
Generated bar app
==> foo
Compiled lib/foo.ex
Generated foo app
Consolidated List.Chars
Consolidated Collectable
Consolidated String.Chars
Consolidated Enumerable
Consolidated IEx.Info
Consolidated Inspect
==> bar
.

Finished in 0.06 seconds (0.06s on load, 0.00s on tests)
1 test, 0 failures

Randomized with seed 170481
==> foo
.

Finished in 0.00 seconds
1 test, 0 failures

Randomized with seed 205215

$ export BAR_DEP=umbrella && elixir -v && rm -rf _build && (cd apps/foo && mix test)

Erlang/OTP 18 [erts-7.2.1] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Elixir 1.2.1
==> bar
Compiled test/support/bar_helper.ex
Compiled lib/bar.ex
Generated bar app
==> foo
Compiled lib/foo.ex
Generated foo app
Consolidated List.Chars
Consolidated String.Chars
Consolidated Collectable
Consolidated Enumerable
Consolidated IEx.Info
Consolidated Inspect
.

Finished in 0.05 seconds (0.05s on load, 0.00s on tests)
1 test, 0 failures

Randomized with seed 953446

However, there is a noticeable difference in behavior between 1.2 and 1.3. In 1.2, if you do mix test and then do cd apps/foo && mix test, it works:

xport BAR_DEP=path && elixir -v && rm -rf _build && mix test && (cd apps/foo && mix test)
Erlang/OTP 18 [erts-7.2.1] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Elixir 1.2.1
"/Users/myron/code/umbrella_sample/apps/bar"
"/Users/myron/code/umbrella_sample/apps/bar"
"/Users/myron/code/umbrella_sample/apps/bar"
==> bar
Compiled test/support/bar_helper.ex
Compiled lib/bar.ex
Generated bar app
"/Users/myron/code/umbrella_sample/apps/bar"
==> foo
Compiled lib/foo.ex
Generated foo app
Consolidated List.Chars
Consolidated String.Chars
Consolidated Collectable
Consolidated Enumerable
Consolidated IEx.Info
Consolidated Inspect
==> bar
"/Users/myron/code/umbrella_sample/apps/bar"
.

Finished in 0.07 seconds (0.07s on load, 0.00s on tests)
1 test, 0 failures

Randomized with seed 576670
"/Users/myron/code/umbrella_sample/apps/bar"
==> foo
.

Finished in 0.00 seconds
1 test, 0 failures

Randomized with seed 608613
"/Users/myron/code/umbrella_sample/apps/bar"
"/Users/myron/code/umbrella_sample/apps/bar"
Compiled lib/foo.ex
Generated foo app
Consolidated List.Chars
Consolidated Collectable
Consolidated String.Chars
Consolidated Enumerable
Consolidated IEx.Info
Consolidated Inspect
.

Finished in 0.05 seconds (0.05s on load, 0.00s on tests)
1 test, 0 failures

Randomized with seed 525439

...so the act of first running mix test at the umbrella root fixes it. But when I do that on 1.3, it still does not work when I'm in the child app directory:

$ export BAR_DEP=path && elixir -v && rm -rf _build && mix test && (cd apps/foo && mix test)
Erlang/OTP 18 [erts-7.2.1] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Elixir 1.3.0-rc.1 (9eb4781)
"/Users/myron/code/umbrella_sample/apps/bar"
"/Users/myron/code/umbrella_sample/apps/bar"
"/Users/myron/code/umbrella_sample/apps/bar"
==> bar
Compiling 2 files (.ex)
Generated bar app
"/Users/myron/code/umbrella_sample/apps/bar"
==> foo
Compiling 1 file (.ex)
Generated foo app
==> bar
"/Users/myron/code/umbrella_sample/apps/bar"
.

Finished in 0.04 seconds
1 test, 0 failures

Randomized with seed 886356
"/Users/myron/code/umbrella_sample/apps/bar"
==> foo
.

Finished in 0.02 seconds
1 test, 0 failures

Randomized with seed 951032
"/Users/myron/code/umbrella_sample/apps/bar"
"/Users/myron/code/umbrella_sample/apps/bar"
==> bar
Generated bar app
==> foo
** (CompileError) test/foo_test.exs:3: module Bar.TestHelper is not loaded and could not be found
    (stdlib) erl_eval.erl:669: :erl_eval.do_apply/6
    (elixir) lib/code.ex:363: Code.require_file/2
    (elixir) lib/kernel/parallel_require.ex:56: anonymous fn/2 in Kernel.ParallelRequire.spawn_ruires/5

Sorry if that's too much detail; I spent many hours trimming my large umbrella project into something small and reproducible here, and only figured out that our use of :path dependencies was causing the problem. As it so happens, we're only using :path as a way to work around an issue with :in_umbrella that I brought up on the mailing list and that, from what I understand, is fixed in Elixir 1.3, so we should be able to switch back to :in_umbrella to work around this problem.

Still, the behavior of :path dependencies is surprising; it seems like :elixirc_paths in them should work fine.

Expected behavior

The :elixirc_paths option should work on dependencies regardless of if the dependency is specified as an :in_umbrella dependency or a :path dependency. It should work both from the root project directory and from the directory of one of the child apps.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions