Reputation: 515
How to overwrite config in Elixir using command line flag provided? For example, the application is started by running:
./my_app --mode=mode1 or ./my_app --mode=mode2
Based on the mode provided, I would like to override config.exs
with mode1.exs
or mode2.exs
as shown below
use Mix.Config
# Configures the endpoint
config :my_app,
env: Mix.env
import_config "#{Mix.env}.exs"
import_config "mode1.exs" or import_config "mode2.exs"
Upvotes: 0
Views: 1118
Reputation: 75840
The problem with having different configs based on different command-line arguments is that Elixir applications are compiled, so once you package the application it will contain the configs of only the mode specified at compile time.
If that's not a problem and you still want to use separate configs, it is better to use Environment Variables instead of command-line flags.
use Mix.Config
# Get the Application Mode
default_mode = "1"
app_mode = System.get_env("APP_MODE") || default_mode
mode_config = "mode#{app_mode}.exs"
# Load external configs
import_config("#{Mix.env}.exs")
import_config(mode_config)
Now just pass the mode via environment variable:
$ APP_MODE=1 mix run
Upvotes: 2
Reputation: 75840
Like I mentioned in my other answer, elixir applications are compiled so once the application is packaged, it will only contain configs of that mode. A better solution would be to keep configs for all modes together, and dynamically load appropriate configs in your application.
Here's what you config.exs
file could look like:
use Mix.Config
config :my_app, :app_modes,
default: :mode_1
config :my_app, :mode_1,
x: 1, y: 2, z: 3
config :my_app, :mode_2,
x: 6, y: 7, z: 8
And you could use a custom ModeConfig
module to load the mode configs:
defmodule MyApp.ModeConfig do
@default_mode Application.get_env(:my_app, :app_modes)[:default_mode]
# Get App Mode
def mode do
passed_mode = System.get_env("APP_MODE")
# or you can use OptionParser for command-line flags
String.to_atom(passed_mode) || @default_mode
end
def get, do: Application.get_env(:my_app, mode())
def get(key), do: get()[key]
end
You can set (and fetch) modes in two ways now:
OptionParser.parse/2
System.get_env/1
And appropriate configs can be loaded using the custom Config module:
# App started in Mode 2
MyApp.ModeConfig.get(:x) # => 6
# App started in Mode 1
MyApp.ModeConfig.get(:y) # => 2
Note: If your application gets more complicated (OTP & Processes), you could even have different "adapters" corresponding to each mode, and switch to the appropriate one during bootup of your application supervision tree.
Upvotes: 0
Reputation: 121010
To parse command line arguments one uses OptionParser
.
To overwrite the values from config file one should use Application.put_env/4
, since the configuration file is loaded and processed during the compile time and even more, Mix.Config
as well as the whole Mix
application does not exist in production. So whether you choose this approach, you are to either bring mix
application to prod
(not recommended and strongly discouraged,) or to parse your modeN
files yourself and update application environment manually.
That topic was already largely discussed in Elixir community and the core team pretty fine understands the drawbacks of using compile-time configs.
The best solution at the moment (until we are given with the proper one,) would be to use system environment instead of configs and/or introduce your own JSON/YAML configs.
Upvotes: 0