diff options
| author | tv <tv@krebsco.de> | 2026-10-26 05:30:09 +0100 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-10-26 05:30:09 +0100 |
| commit | af53e0dee3e1c38c907b92733239b1cca448e0b0 (patch) | |
| tree | 555397b11221214a13f9847cdae7c4bc7d3cb4ee /src/config | |
| parent | f9955f3a5afcb82a591e7f434c20fa224878c009 (diff) | |
allow force only in args, not in files
Diffstat (limited to 'src/config')
| -rw-r--r-- | src/config/mod.rs | 32 |
1 files changed, 31 insertions, 1 deletions
diff --git a/src/config/mod.rs b/src/config/mod.rs index 0aaccd6..b8a2ba0 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -122,7 +122,7 @@ pub(crate) const OPTIONS: &[OptionSpec] = &[ Kind::List, "NAME,[NAME...]", None, - "Override checks that otherwise refuse to start: true for all, or names: swarmId (a document to start on is of another swarm than the state file remembers), badDocumentFile (an unusable document file: moved aside, start without it), replaceDocumentFile (recover-from while the document file holds a document).", + "Override checks that otherwise refuse to start (command line only: it is for one start): true for all, or names: swarmId (a document to start on is of another swarm than the state file remembers), badDocumentFile (an unusable document file: moved aside, start without it), replaceDocumentFile (recover-from while the document file holds a document).", ), option( "recover-from", @@ -902,6 +902,16 @@ pub(crate) fn load() -> Result<Loaded> { } fn resolve(merged: Layer, files: Vec<PathBuf>) -> Result<Loaded> { + // An override is for the start it was given for; in a file it would silently apply + // to every start, e.g. replacing the document file with a backup each time. + if let Some(entry) = merged.get("force").filter(|entry| { + !entry.value.is_null() && matches!(entry.origin.provenance, Provenance::File(_)) + }) { + bail!( + "force can only be given on the command line: it overrides checks for one start, and in a file ({}) it would apply to every start", + entry.origin + ); + } // Unset options take their defaults. let object: serde_json::Map<String, JsonValue> = merged .iter() @@ -958,6 +968,26 @@ mod tests { } #[test] + fn force_only_on_the_command_line() { + let from = |provenance| Entry { + value: json!(["swarmId"]), + origin: Origin { + provenance, + unset: false, + imports: Vec::new(), + }, + }; + let mut merged = layer(json!({ "htpasswd": "u" })); + merged.insert( + "force".to_owned(), + from(Provenance::File(PathBuf::from("continuum.toml"))), + ); + assert!(resolve(merged.clone(), Vec::new()).is_err()); + merged.insert("force".to_owned(), from(Provenance::Argument)); + assert!(resolve(merged, Vec::new()).is_ok()); + } + + #[test] fn options_and_settings_agree() { // Every option is a Settings field, and every field an option. let loaded = resolve(layer(json!({ "htpasswd": "users" })), Vec::new()).unwrap(); |
