Fl4m3Ph03n1x
How to add extra files to umbrella release?
Background
I have an umbrella project with several apps inside. I want to create a special release that will have additional files inside, like JSON files, configuration, images etc.
I know that in a normal Phoenix project everything inside the priv folder will be in the release under "#{child-app-name}-#{child-app-version}/priv".
Problem
The issue here is that some of my configuration files depend on these assets. So in my config/prod.exs I have tried several ways to get the path dynamically, bu nothing works. The following examples all fail:
config :my_app,
products: "application-data\\lib\\web_interface-#{Application.spec(:web_interface, :vsn) |> to_string()}\\priv\\persistence\\products.json"
config :my_app,
products: "application-data\\lib\\web_interface-#{WebInterface.Mixfile.project()[:version]}\\priv\\persistence\\products.json"
config :my_app,
products: "application-data\\lib\\web_interface-#{Application.get_application(:web_interface)}\\priv\\persistence\\products.json"
The one that works is as follows:
products: "application-data\\lib\\web_interface-2.2.0\\priv\\persistence\\products.json",
You can see the issue here is that the version number will change from release to release, and I don’t want to change my prod.exs every time a new release is made.
My solution would be to move the assets I depend on to the root level, so my configuation can access them via "application-data\\assets\\products.json or something similar.
Questions
Is this possible to achieve, given that I am building a tar in my release?
Marked As Solved
LostKobrakai
Also Liked
LostKobrakai
You should be using Application.app_dir(:app_name, "priv/dir/…") in your code to reference files in priv/ folder. You can use configuration for the second parameter if needed.
entone
christhekeele
FWIW these days I register these release-resiliant path concerns in my application’s compile-time config.exs. I find it to be more reliable and easier to reason about if I do it myself:
# config/config.exs
import Config
root_dir = Path.expand("../..", __DIR__)
priv_dir = Path.expand(Path.join(project_root, "priv"))
assets_dir = Path.expand(Path.join(project_root, "assets"))
static_dir = Path.expand(Path.join(priv_dir, "static"))
static_assets_dir = Path.expand(Path.join(static_dir, "assets"))
config :project, :root_dir, root_dir
config :project, :priv_dir, priv_dir
config :project, :assets_dir, assets_dir
config :project, :static_dir, static_dir
config :project, :static_assets_dir, static_assets_dir
# Use variables above to configure things like `:esbuild` in this file
# Use `Application.compile_env!(:project, :static_assets_dir)`
# to configure things like `Plug.Static`
This works well for umbrella apps, since the each have their own config :app_name space.
For often-referenced paths, I’ll even add a shortcut in my project’s main entrypoint module:
# lib/project/application.ex
defmodule Project.Application do
def app_name, do: :project
def root_dir, do: Application.compile_env!(app_name(), :root_dir)
def static_dir, do: Path.relative_to(Application.compile_env!(app_name(), :static_dir), root_dir())
end
Then, for example, configuring Plug.Static can look like:
# lib/project_web/endpoint.ex
plug Plug.Static,
at: "/",
from: {Project.Application.name(), Project.Application.static_dir()}
Last Post!
christhekeele
Tbh that feels a bit bend over backwards to start with relative paths, expand them to absolute paths for the context of the mix project, just to turn them back into relative paths within the application code again.
I’ll admit the project I took this from has a whole lot of going on in the priv dir, in many different umbrellas, so at some point it became worth abstracting further; I don’t think I’d recommend it for the standard standalone phoenix web app.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #hex









