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

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

Last Post!

christhekeele

christhekeele

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.

Where Next?

Popular in Questions Top

hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
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
Lily
In templates/appointment/index.html.eex: <%= for appointment <- @appointments do %> <tr> <td><%= appoi...
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New

Other popular topics Top

JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1144 54921 245
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
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 49084 226
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New
AstonJ
Posting this to see if we can make things easier for people to get into Neovim. If you use Neovim and have a favourite distro please let ...
New

We're in Beta

About us Mission Statement