Something went wrong. Try again.
atproto git client
Something went wrong. Try again.
Rust
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109//! One reading of every boolean atgc takes from the environment.//!//! `ATGC_NO_INPUT`, `ATGC_DEBUG`, `ATGC_USE_BOBBIN`, `ATGC_USE_WEB` and the//! off-switch on each `ATGC_*_LOG` path are all the same shape — a variable//! whose value is a word meaning yes or no — and they were read three//! different ways. The `pr` sources module rejected `false` and `no`; the//! non-interactive gate and the debug switch accepted anything that was not//! `0`, so `ATGC_NO_INPUT=false` turned non-interactive mode *on*; the log//! paths accepted `off` and nothing else. Same prefix, same shape, opposite//! answers for the same word, and which one you got depended on knowing//! which subsystem read it.//!//! The permissive reading wins, and the reason is asymmetric harm. Reading//! `false` as on is a setting that does the opposite of what it says, and//! the user has no way to discover it short of the source: they typed a word//! that means no and got yes. Reading an unrecognised word as on costs//! somebody who typed `ATGC_DEBUG=nope` a screen of debug output, which is//! visible in the first second and fixed by unsetting it. Refusing an//! unrecognised word outright was considered and dropped: these are switches//! people export in a shell profile, and a hard failure on every subsequent//! command over a spelling is a worse trade than a switch that is on.//!//! [`NO_COLOR`](https://no-color.org/) deliberately does **not** come//! through here. Its spec says any non-empty value disables color whatever//! the value is, `NO_COLOR=false` included, and a tool that made an//! exception of that spelling would be the odd one out on a machine rather//! than consistent with itself. It is read where it is used, in//! [`crate::term::say`] and [`crate::term::hyperlink`].
/// The words that read as "off", beside unset: the empty string, `0`,/// `false`, `no` and `off`, in any case and with surrounding whitespace/// ignored.////// The empty string is off because that is what an unset variable looks like/// after a shell has interpolated it — `ATGC_USE_BOBBIN="$MAYBE"` — and the/// same reasoning [`crate::clients::endpoints`] applies to its host/// overrides. Trailing whitespace is ignored because it survives a/// copy-pasted `export` more often than anyone would guess.const OFF: [&str; 5] = ["", "0", "false", "no", "off"];
/// Whether a value means "off". The half of the reading that the `ATGC_*_LOG`/// paths need, since for them any *other* value is a filename rather than a/// yes.pub(crate) fn is_off(value: &str) -> bool { OFF.contains(&value.trim().to_ascii_lowercase().as_str())}
/// Whether the environment variable `name` is switched on.////// A value that is not valid UTF-8 counts as on: it is set, it is not empty,/// and it cannot be any of the words in [`OFF`], so the only reading left is/// the one the user's typing supports.pub(crate) fn switch(name: &str) -> bool { on(std::env::var_os(name) .map(|v| v.to_string_lossy().into_owned()) .as_deref())}
/// The decision itself, kept pure and taking the value as an argument so the/// whole table can be asserted without setting a variable that every other/// test in the process would then see. See [`crate::docs::testing`].fn on(value: Option<&str>) -> bool { value.is_some_and(|v| !is_off(v))}
#[cfg(test)]mod tests { use super::{is_off, on};
/// The whole table, in one place, because the bug this module exists for /// was two readings that agreed on `1` and `0` and disagreed on /// everything a person would actually type. An unset variable and every /// spelling of no are off; every other value, including a misspelling /// and a value that is not a word at all, is on. #[test] fn every_spelling_of_no_is_off_and_everything_else_is_on() { for off in [ "", " ", "0", "false", "FALSE", "False", "no", "NO", "off", "OFF", " false ", "\tno\n", ] { assert!(!on(Some(off)), "{off:?} should be off"); assert!(is_off(off), "{off:?} should be off"); } for switched_on in [ "1", "true", "TRUE", "yes", "on", "2", "-1", "nope", "falsey", "/tmp/atgc.jsonl", ] { assert!(on(Some(switched_on)), "{switched_on:?} should be on"); assert!(!is_off(switched_on), "{switched_on:?} should be on"); } }
/// Unset is off, and is the only input that is not a string. The log /// paths distinguish it from every value — unset means "the default /// path", `off` means "no file" — which is why [`is_off`] takes a `&str` /// and cannot answer this question. #[test] fn an_unset_variable_is_off() { assert!(!on(None)); }}