Skip to content

Commit

Permalink
fix: Invalid env var separator on bash
Browse files Browse the repository at this point in the history
We use `.` as the env var separator in order to differentiate between the prefix
and different levels of the config vs individual config field names
(which would be in UPPER_SNAKE_CASE). However, `.` is not a valid bash
identifier, so we need to use something different.

Switch to using a double underscore (`__`) instead of `.`. This way, we can
support bash and still be able to differentiate between the prefix
and different levels of the config vs individual config field names.

Closes: #219
  • Loading branch information
spencewenski committed Jun 21, 2024
1 parent c15d9e3 commit d85e85d
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 7 deletions.
10 changes: 9 additions & 1 deletion src/config/app_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ pub struct AppConfig {
}

pub const ENV_VAR_PREFIX: &str = "ROADSTER";
pub const ENV_VAR_SEPARATOR: &str = ".";
pub const ENV_VAR_SEPARATOR: &str = "__";

impl AppConfig {
// This runs before tracing is initialized, so we need to use `println` in order to
Expand Down Expand Up @@ -86,6 +86,14 @@ impl AppConfig {
.convert_case(Case::Kebab)
.separator(ENV_VAR_SEPARATOR),
)
// This source is kept for backwards compatibility and may be removed in the next
// semver breaking release (0.4+)
.add_source(
config::Environment::default()
.prefix(ENV_VAR_PREFIX)
.convert_case(Case::Kebab)
.separator("."),
)
.set_override(ENVIRONMENT_ENV_VAR_NAME, environment_str)?
.build()?;
let config: AppConfig = config.try_deserialize()?;
Expand Down
23 changes: 17 additions & 6 deletions src/config/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,32 @@ pub(crate) const ENVIRONMENT_ENV_VAR_NAME: &str = "ENVIRONMENT";

const ENV_VAR_WITH_PREFIX: &str =
concatcp!(ENV_VAR_PREFIX, ENV_VAR_SEPARATOR, ENVIRONMENT_ENV_VAR_NAME);
// This env var is used for backwards compatibility and may be removed in the next
// semver breaking release (0.4+)
const ENV_VAR_WITH_PREFIX_OLD: &str = concatcp!(ENV_VAR_PREFIX, ".", ENVIRONMENT_ENV_VAR_NAME);

impl Environment {
// This runs before tracing is initialized, so we need to use `println` in order to
// log from this method.
#[allow(clippy::disallowed_macros)]
pub fn new() -> RoadsterResult<Self> {
// Get the stage, and validate it by parsing to the Environment enum
let environment = env::var(ENV_VAR_WITH_PREFIX)
.map_err(|_| anyhow!("Env var `{ENV_VAR_WITH_PREFIX}` not defined."))?;
let environment = if let Ok(value) = env::var(ENV_VAR_WITH_PREFIX) {
println!("Using environment from `{ENV_VAR_WITH_PREFIX}` env var: {value:?}");
value
} else if let Ok(value) = env::var(ENV_VAR_WITH_PREFIX_OLD) {
// This env var is used for backwards compatibility and may be removed in the next
// semver breaking release (0.4+)
println!("Using environment from `{ENV_VAR_WITH_PREFIX_OLD}` env var: {value:?}");
value
} else {
Err(anyhow!("Neither `{ENV_VAR_WITH_PREFIX}` nor `{ENV_VAR_WITH_PREFIX_OLD}` env vars are defined."))?;
unreachable!()
};
let environment = <Environment as FromStr>::from_str(&environment).map_err(|err| {
anyhow!(
"Unable to parse `{ENV_VAR_WITH_PREFIX}` env var with value `{environment}`: {err}"
)
anyhow!("Unable to parse environment from env var value `{environment}`: {err}")
})?;
println!("Using environment from `{ENV_VAR_WITH_PREFIX}` env var: {environment:?}");
println!("Parsed environment from env var: {environment:?}");
Ok(environment)
}
}

0 comments on commit d85e85d

Please sign in to comment.