I have multiple umbrella apps which use the same apps. To have no copies of those apps, I tried to place them in a directory and use symbolic links like in the minimal example below (“project1” is a fresh umbrella project):
But when app2 depends on app1 via in_umbrella: true, like below
$ cat shared_apps/app2/mix.exs
defmodule App2.MixProject do
use Mix.Project
def project do
[
app: :app2,
version: "0.1.0",
elixir: "~> 1.9",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end
# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger]
]
end
# Run "mix help deps" to learn about dependencies.
defp deps do
[
{:app1, in_umbrella: true}
# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
]
end
end
then I get error messages:
$ cd project1/ && mix deps.get
Dependencies have diverged:
* app1 (apps/app1)
the dependency app1 in mix.exs is overriding a child dependency:
> In mix.exs:
{:app1, [path: "apps/app1", from_umbrella: true, env: :dev]}
> In /home/peter/tmp/testapps/shared_apps/app2/mix.exs:
{:app1, [env: :dev, path: "../app1", in_umbrella: true]}
Please remove the conflicting options from your definition
** (Mix) Can't continue due to errors on dependencies
I now use bindfs instead of symbolic links to avoid copies of the same code (shared apps). This seems to work.
But it would still nice to know if it can’t be done with symbolic links…
TBH it sounds more like you have one umbrella app that several artifacts are created from. It’s possible to package just some applications from the umbrella into a release, so you could have one release that contained project_1, app1, app2 and another that contained project_2, app1, app2.
If project_1 and project_2 are so dissimilar that they shouldn’t be in one umbrella, definitely consider a more-structured way of controlling when changes from app1 and app2 affect each project (via Hex packaging or similar); what happens in the symlink approach when a change to app1 to support new code in project_1 breaks project_2?
To handle different machines, I thougt about having a git repository contining all the apps (which is not an umbrella project) and other git repositories for each project that uses them. To release one I thought it would be easy to just clone the apps repository and one project repo, then set the symbolic link and generate the release.
If it was possible, what would you think about this? (I think the multiple artifacts proposal of al2o3cr is appropriate for me)
At this point with your helpful proposal, it seems convenient to not only package just some applications into a release but also to be able to start just some applications when I invoke iex -S mix (before I build a release).
Do you know of any convenient way of specifying that only some application and its dependencies (instead of all apps that are located in the apps directory of an umbrella project) shall be started when I do iex -S mix?
If you only want to start one app within the umbrella, then cd into the app, cd apps/foo and do iex -S mix or possibly iex -S mix phx.server. That will start only that app and any of it’s dependencies.
This is also a good way to verify that you have the apps separated the way you want. You should only be able to see the modules of other apps in iex that are listed as a dependency in the started app’s mix file, i.e. {:bar, in_umbrella: true}.