Skip to content

Issues with mix xref on umbrella apps #12629

@japhib

Description

@japhib

Elixir and Erlang/OTP versions

Erlang/OTP 25 [erts-13.1.1] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [jit:ns]

Elixir 1.14.3 (compiled with Erlang/OTP 25)

Operating system

MacOS Ventura 13.4

Current behavior

The behavior of various mix xref tools is weird, and in some cases just plain doesn't work, on umbrella apps. Here's a sample umbrella app that I did testing on: https://github.com/japhib/simple_umbrella_app

1. mix xref trace doesn't work with relative paths

$ mix xref trace apps/app_b/lib/app_b.ex
** (Code.LoadError) could not load /Users/japhib/projects/simple_umbrella_app/apps/app_a/apps/app_b/lib/app_b.ex. Reason: enoent
    (elixir 1.14.3) lib/code.ex:1826: Code.find_file!/2
    (elixir 1.14.3) lib/code.ex:1521: anonymous fn/2 in Code.compile_file/2
    (mix 1.14.3) lib/mix/tasks/xref.ex:471: Mix.Tasks.Xref.handle_trace/2
    (mix 1.14.3) lib/mix/task.ex:421: anonymous fn/3 in Mix.Task.run_task/4
    (mix 1.14.3) lib/mix/project.ex:397: Mix.Project.in_project/4
    (elixir 1.14.3) lib/file.ex:1607: File.cd!/2
    (mix 1.14.3) lib/mix/task.ex:577: anonymous fn/4 in Mix.Task.run_in_children_projects/2

Note that above ^ the error comes from attempting to load the path I passed in, apps/app_b/lib/app_b.ex, under the prefix of apps/app_a. My guess is that it tries to find the provided path in every app rather than just a single one.

When I provide an absolute path, it works fine:

$ mix xref trace /Users/japhib/projects/simple_umbrella_app/apps/app_b/lib/app_b.ex
==> app_a
/Users/japhib/projects/simple_umbrella_app/apps/app_b/lib/app_b.ex:4: struct StructInAppA (export)
/Users/japhib/projects/simple_umbrella_app/apps/app_b/lib/app_b.ex:4: alias StructInAppA (runtime)
/Users/japhib/projects/simple_umbrella_app/apps/app_b/lib/app_b.ex:9: call AppA.hello/0 (runtime)

2. mix xref graph --include-siblings does not include dependencies on other apps

According to the docs, using the --include-siblings flag should:

includes dependencies that have :in_umbrella set to true in the current project in the reports. This can be used to find callers or to analyze graphs between projects.

In my test project simple_umbrella_app, there is a dependency from lib/app_b.ex on both lib/app_a.ex and lib/struct_in_app_a.ex. Neither of these dependencies are shown.

$ mix xref graph --include-siblings
==> app_a
lib/app_a.ex
└── lib/struct_in_app_a.ex (export)
lib/struct_in_app_a.ex
==> app_b
lib/app_b.ex

3. The --sink and --source options on mix xref graph do not work

The --sink option is supposed to show a graph of modules that reference the specified module, while the --source option is supposed to show a graph of modules that the specified module references. This rarely works (see below) and seems to have something to do with the way the path is specified.

# app_a.ex

$ mix xref graph --sink lib/app_a.ex
** (Mix) Sinks could not be found: lib/app_a.ex
$ mix xref graph --sink apps/app_a/lib/app_a.ex
** (Mix) Sinks could not be found: apps/app_a/lib/app_a.ex
$ mix xref graph --sink /Users/japhib/projects/simple_umbrella_app/apps/app_a/lib/app_a.ex
** (Mix) Sinks could not be found: /Users/japhib/projects/simple_umbrella_app/apps/app_a/lib/app_a.ex
$ mix xref graph --source lib/app_a.ex
==> app_a
lib/app_a.ex
└── lib/struct_in_app_a.ex (export)
** (Mix) Sources could not be found: lib/app_a.ex
$ mix xref graph --source apps/app_a/lib/app_a.ex
** (Mix) Sources could not be found: apps/app_a/lib/app_a.ex
$ mix xref graph --source /Users/japhib/projects/simple_umbrella_app/apps/app_a/lib/app_a.ex
** (Mix) Sources could not be found: /Users/japhib/projects/simple_umbrella_app/apps/app_a/lib/app_a.ex

# app_b.ex

$ mix xref graph --sink lib/app_b.ex
** (Mix) Sinks could not be found: lib/app_b.ex
$ mix xref graph --sink apps/app_b/lib/app_b.ex
** (Mix) Sinks could not be found: apps/app_b/lib/app_b.ex
$ mix xref graph --sink /Users/japhib/projects/simple_umbrella_app/apps/app_b/lib/app_b.ex
** (Mix) Sinks could not be found: /Users/japhib/projects/simple_umbrella_app/apps/app_b/lib/app_b.ex
$ mix xref graph --source lib/app_b.ex
** (Mix) Sources could not be found: lib/app_b.ex
$ mix xref graph --source apps/app_b/lib/app_b.ex
** (Mix) Sources could not be found: apps/app_b/lib/app_b.ex
$ mix xref graph --source /Users/japhib/projects/simple_umbrella_app/apps/app_b/lib/app_b.ex
** (Mix) Sources could not be found: /Users/japhib/projects/simple_umbrella_app/apps/app_b/lib/app_b.ex

My unproven guess is that, like above, Mix is trying to use this path on every app rather than just the app it belongs to. At least, if it goes in alphabetical order (tries app_a, then app_b) then that would explain why above, with mix xref graph --source lib/app_a.ex it actually does appear to work at first (when it runs on app_a), but then still prints out an error message (when it tries to run on app_b).

Expected behavior

I would expect mix xref graph and mix xref trace to be just as useful on umbrella apps as they are on regular/non-umbrella 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