Hi Kurtis,

If I understand your description correctly, this is by design.  An
application inside an umbrella doesn't know it belongs to an umbrella
because you should be able to also run it in isolation. That's why we
explicitly have configs tha point to the parent directory.

Your solution is to either have a tmp_path that you introduce to each
application that points to this shared path or rely on one of the existing
configs that point to the parent, such as build_path. Otherwise, generally
speaking, we simply don't know we are inside an umbrella and we generally
want to avoid this coupling.

On Wed, Jun 24, 2020 at 2:31 AM Kurtis Rainbolt-Greene <
[email protected]> wrote:

> Let's say you have an umbrella project and that umbrella project has a mix
> task that wants to write to a tmp/ directory in the root. Well if you're me
> then you just realized there's no method that gets you this exact value,
> even though there are a lot of methods that get you close! Of course there
> are plenty of tricks/hacks you can employ to get the value as well, but the
> point of a stdlib is to give you foundational elements like this so that a
> 1 line doesn't get written a million times.
>
> Alright, so here's what we have:
>
>   0. `app_path` -> `"/path/to/project/_build/shared/lib/app"`, fails on an
> umbrella project
>   0. `apps_paths` -> `%{my_app1: "apps/my_app1", my_app2:
> "apps/my_app2"}`, this is actually pretty close, but on a non-standard
> umbrella application it gets really weird. Like what if you have some
> things in `apps/` and some things in `applications/` due to weird legacy?
> Not a great solve. It's also very strange that these are not expanded paths
> like many other functions? ALSO it's not "app_path" of each of your apps,
> it's really just the `umbrella_app_paths` if anything.
>   0. `build_path` -> `"/path/to/project/_build/shared"` or
> `"/path/to/project/_build/dev"` depending on `Mix.env()`, still not very
> helpful.
>   0. `compile_path` -> See: `build_path`
>   0. `config_files` -> `["/path/to/project/_build/dev/.mix/compile.lock",
> "/path/to/project/config/dev.exs", "/path/to/project/config/config.exs",
> "/path/to/project/mix.exs"]` Okay a step in the right direction as they're
> all absolute, but only the last file is really helpful. One trick here
> would be `config_files() |> List.last |> Path.dirname`, assuming the list
> is always in order and mix.exs is always last.
>   0. `consolidation_path` -> See: `build_path`
>   0. `deps_path` -> `"/path/to/project/deps"` This function gets us the
> closest: [x] It's absolute, [x] It's just one path, [x] It works in an
> umbrella application, [x] It can be fed to `Path.dirname`, but [ ] It's not
> configurable, so it's brittle
>   0. `deps_paths` -> `%{foo: "deps/foo", bar: "custom/path/dep"}` which
> isn't even close to useful. The example on this by the way in the docs
> could be significantly more informative.
>   0. `manifest_path` -> See: `build_path`
>
>
> So in summery the closest we get is `deps_path()`, but even then it's
> kinda shaky. Okay, fine so I thought to myself: How are these functions
> determining where these pieces are? Well turns out most of them look in one
> of two places:
>
>   0. `MIX_*` (`MIX_BUILD_PATH` for example), which isn't very helpful
>   0. `Mix.Project.config()`, which is a `list(map)`, where each map is a
> mix project?
>
>   For example:
>
>   ```
>   def deps_path(config \\ config()) do
>     System.get_env("MIX_DEPS_PATH", config[:deps_path]) |> Path.expand
>   end
>   ```
>
> Despite it being a list of maps, when you go to access a key it just looks
> at the first project. In this case:
>
> ```
> Mix.Project.config[:deps_path] # => "deps"
> ```
>
> and then:
>
> ```
> Path.expand("deps") # => "/path/to/project/deps"
> ```
>
> At this point you've probably been screaming: Kurtis! Why aren't you just
> using File.cwd??? Well, okay, here's why:
>
> ```
> iex(1)> File.cwd
> {:ok, "/path/to/project"}
> ```
>
> but let's say you have a task in one of your apps that calls `File.cwd`:
>
> ```
> $ mix print-working-direcotry-task
> {:ok, "/path/to/project/apps/example"}
> ```
>
> The same thing happens when I define the path as a property in
> `config/config.exs`, despite being in the root. With that said, here's my
> proposal:
>
> ```
> @spec umbrella_path() :: Path.t()
> def umbrella_path() do
>   File.cwd!
> end
> ```
>
> "Can't you do that yourself? By defining it in the mix.exs module?" While
> you can define it alright, it's seemingly inaccessible from inside an app's
> tasks.
>
> The great thing is that initially I was worried there would be special
> logic needed for when you talk about `Mix.Project.umbrella_path` inside a
> app, but you'll find `Mix.Project.deps_path` returns the umbrella project's
> deps path!
>
> --
> You received this message because you are subscribed to the Google Groups
> "elixir-lang-core" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/elixir-lang-core/623ace74-b11c-4c47-9e13-f04b13f03c97o%40googlegroups.com
> <https://groups.google.com/d/msgid/elixir-lang-core/623ace74-b11c-4c47-9e13-f04b13f03c97o%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
>

-- 
You received this message because you are subscribed to the Google Groups 
"elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4LgLaUO3S3wD5jdXO36wf9GKXZ4iC%3DiYYSZWQHef%3DfYFQ%40mail.gmail.com.

Reply via email to