Fl4m3Ph03n1x

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

LostKobrakai

That’s the way to go yes.

Also Liked

LostKobrakai

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

entone

Additionally you can use the :code.priv_dir/1 function

https://www.erlang.org/doc/man/code.html#priv_dir-1

christhekeele

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()}
LostKobrakai

LostKobrakai

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. But I do like the approach of having functions return the paths. I’ve used that approach as well in some projects. It puts a clear interface of what paths are provided by an application / which ones are used by downstream consumers.

Fl4m3Ph03n1x

Fl4m3Ph03n1x

I am generally not comfortable having functions that return configuration settings.

To me, configurations are different from the functionality an application offers, they are a prerequisite and should therefore have their own space, instead of polluting the main API that I expose to the public.

Still, if nothing else works, I will definitely use such approaches, I find code that actually does something better than code that is theoretically more perfect, but then does nothing :stuck_out_tongue:

Also, thanks @christhekeele for your input. I appreciate you took the time to read all the threads and then took even more time to add your own opinion, even though the topic is becoming long and I had marked it as solved.

Where Next?

Popular in Questions Top

pgiesin
This should be a simple problem but I just can’t seem to figure it out. I have a standalone Elixir app that won’t find the database. Dep...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lis...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
kostonstyle
Hi all I want to have a unix time, from the current time plus 1 hour. DateTime.now + 1 hour How to get it in elixir? Thanks
New
chewm
Hi guys, nice to meet you to the whole forum, I’m new here, I’m trying to configure visual studio code for elixir, right now the intellis...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers' Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New

Other popular topics Top

senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
yawaramin
In the Dialyzer docs ( http://erlang.org/doc/man/dialyzer.html#requesting-or-suppressing-warnings-in-source-files ), there is a way to tu...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 45766 226
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New

We're in Beta

About us Mission Statement