Skip to content

Commit c4c606b

Browse files
authored
Bridge: load config from string (env var or cli flag) (#999)
## Motivation Writing out config data to disk can sometimes be awkward. Users of the Bridge docker image would either need to customize, using the bridge image as a base then add their config file to the fs, or otherwise use a volume mount (or similar). k8s users have the benefit of config maps, which can be represented as files on disk, but this is not always a good option. ## Solution Allows Bridge to load its config data from a string, which can be supplied as an env var or directly on the cli with `--cfg`. The original flag for specifying an alternative file path to read config data from (formerly `--cfg` or `-c`) has been renamed to `--cfg-file`. Sorry that's so confusing! - Use `--cfg` to pass config as string - Use `--cfg-file` to read from file, non-default loction Additionally, a naive "search path" has been provided to look for the default config file using a series of names: - `svix-bridge.yaml` - `svix-bridge.yml` - `svix-bridge.json` This was done specifically to formalize the fact we're advertising "we accept json config data" in the readme.
2 parents 55dba4e + dc666ab commit c4c606b

File tree

2 files changed

+45
-20
lines changed

2 files changed

+45
-20
lines changed

bridge/README.md

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,15 +123,22 @@ If you don't want to use docker, see [Building from Source](../README.md#buildin
123123
124124
# Usage and Configuration
125125
126+
The CLI itself will look for a config file named `svix-bridge.yaml` or `svix-bridge.json` in the current working
127+
directory.
128+
Additionally, Bridge can load its configuration from a different location via `--cfg-file` (or `SVIX_BRIDGE_CFG_FILE`),
129+
or otherwise the config can be given as a string via `--cfg` (or `SVIX_BRIDGE_CFG`).
130+
131+
Examples:
126132
```
127-
$ svix-bridge -c path/to/svix-bridge.yaml
128-
```
133+
# Using the default config file location
134+
$ svix-bridge
129135

130-
The CLI itself exposes only a single flag (`-c`, `--cfg`) used to set the path for the config file.
131-
The location of the config file can also be set with the `SVIX_BRIDGE_CFG` env var.
132-
The config file itself does the heavy lifting.
136+
# Specifying an alternate location
137+
$ svix-bridge --cfg-file path/to/svix-bridge.json
133138

134-
When unset, the current working directory is checked for a file named `svix-bridge.yaml`.
139+
# Config data supplied directly
140+
$ svix-bridge --cfg '{"log_format": "json", "senders": []}'
141+
```
135142
136143
## Variable Expansion
137144

bridge/svix-bridge/src/main.rs

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -147,27 +147,45 @@ async fn supervise_senders(inputs: Vec<Box<dyn SenderInput>>) -> Result<()> {
147147

148148
#[derive(Parser)]
149149
pub struct Args {
150-
#[arg(short, long, env = "SVIX_BRIDGE_CFG")]
151-
cfg: Option<PathBuf>,
150+
#[arg(long, env = "SVIX_BRIDGE_CFG_FILE", help = "Path to the config file.")]
151+
cfg_file: Option<PathBuf>,
152+
#[arg(
153+
long,
154+
env = "SVIX_BRIDGE_CFG",
155+
help = "Config data as a string (instead of a file on disk).",
156+
conflicts_with = "cfg_file"
157+
)]
158+
cfg: Option<String>,
152159
}
153160

154161
#[tokio::main]
155162
async fn main() -> Result<()> {
156163
let args = Args::parse();
157164

158-
let config_path = args.cfg.unwrap_or_else(|| {
159-
std::env::current_dir()
160-
.expect("current dir")
161-
.join("svix-bridge.yaml")
162-
});
165+
let mut config_search_paths = vec![];
163166

164-
let cfg_source = std::fs::read_to_string(&config_path).map_err(|e| {
165-
let p = config_path
166-
.into_os_string()
167-
.into_string()
168-
.expect("config path");
169-
Error::new(ErrorKind::Other, format!("Failed to read {p}: {e}"))
170-
})?;
167+
if let Some(fp) = args.cfg_file {
168+
config_search_paths.push(fp)
169+
} else {
170+
for name in ["svix-bridge.yaml", "svix-bridge.yml", "svix-bridge.json"] {
171+
config_search_paths.push(std::env::current_dir().expect("current dir").join(name));
172+
}
173+
}
174+
175+
// Clap will ensure we have only one or the other (cfg and cfg_file can't be specified together).
176+
let cfg_source = match args.cfg {
177+
Some(cfg_source) => cfg_source,
178+
None => {
179+
let fp = config_search_paths
180+
.into_iter()
181+
.find(|x| x.exists())
182+
.expect("config file path");
183+
std::fs::read_to_string(&fp).map_err(|e| {
184+
let p = fp.into_os_string().into_string().expect("config file path");
185+
Error::new(ErrorKind::Other, format!("Failed to read {p}: {e}"))
186+
})
187+
}?,
188+
};
171189

172190
let vars = std::env::vars().collect();
173191
let cfg = Config::from_src(&cfg_source, Some(vars).as_ref())?;

0 commit comments

Comments
 (0)