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.

Reply via email to