Escript app trying to write ~/.rc file

I have written an Escript app with Elixir.

I have a Config module that checks for a config file that contains some json. The location of the file is supposed to be in ~/.myapprc

This works (for me) when I build the app with mix escript.build locally. However when I build it in our CI/CD environment it looks like ~ is being expanded to /root/.myapprc

config.exs:

config :app, config_file: Path.join([System.user_home(), '.myapprc'])

config module

  @config_file Application.get_env(:app, :config_file)
...
  def check do
    say("Looking for #{@config_file}")
    unless File.exists?(@config_file) do
      say("*** profile config file not found")
      create_file(@config_file, Poison.encode!(%{}), [:binary])
    end
  end

Output from local build

./_build/app
Looking for /Users/tomha/.myapprc

Output from build from CI/CD

$ ./app
Looking for /root/.myapprc
*** profile config file not found
 *     error enoent

Is this because the config.exs are compiling the build systems user into the application?

Exactly this, it is a set environment.

What you probably want to do is do something like define a function callback, like I’d change your config to:

config :app, config_file: fn -> Path.join([System.user_home(), '.myapprc']) end

And use it like:

  def check do
    config_file =
      case Application.get_env(:app, :config_file) do # Don't worry, this is very very fast
        nil -> "~/.myapprc"
        fun when is_function(fun) -> fun.() |> case do s when is_binary(s) -> s end
        str when is_binary(str) -> str
        {:system, key} -> System.get_env(key)
        # And whatever other styles you want to support, you can wrap this part up into a standalone funtion for ease of use too
      end
    say("Looking for #{config_file}")
    unless File.exists?(config_file) do
      say("*** profile config file not found")
      create_file(config_file, Poison.encode!(%{}), [:binary])
    end
  end
1 Like

Awesome I’ll give that a shot!

Thanks for the quick reply

1 Like