mirror of
https://github.com/starship/starship.git
synced 2025-02-28 16:23:31 +01:00
feat: allow loading configuration values from the environment
This commit is contained in:
parent
36134d896b
commit
bf0c17b600
2
.github/config-schema.json
vendored
2
.github/config-schema.json
vendored
@ -6552,4 +6552,4 @@
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,6 +44,25 @@ Or for Cmd (Windows) would be adding this line to your `starship.lua`:
|
||||
os.setenv('STARSHIP_CONFIG', 'C:\\Users\\user\\example\\non\\default\\path\\starship.toml')
|
||||
```
|
||||
|
||||
### Loading additional configuration from the environment
|
||||
|
||||
In addition to the configuration file, starship also allows you to set configuration values by using environment variables. The variables should be formatted like this: `STARSHIP_CONFIG__SECTION_NAME__KEY=value`. The configuration keys in the environment need to start with `STARSHIP_CONFIG__` and table keys need to be separated with `__`.
|
||||
|
||||
In most POSIX-like shells, you can set the `disabled` key of the `status` module to `false` with the following:
|
||||
|
||||
```sh
|
||||
export STARSHIP_CONFIG__STATUS__DISABLED=false
|
||||
```
|
||||
|
||||
Equivalently in PowerShell (Windows) would be adding this line:
|
||||
|
||||
```powershell
|
||||
$ENV:STARSHIP_CONFIG__STATUS__DISABLED = "false"
|
||||
```
|
||||
|
||||
Other shells may use a different syntax to set environment variables.
|
||||
At this time, only simple values like such as numbers, floats, booleans and strings can be set with environment variables. This method cannot be used to set complex values like tables or arrays. If the environment values cannot be directly parsed as TOML values, they are treated as strings. This means that `true` is parsed as a boolean when it's not quoted, but is parsed as a string when it is quoted. In contrast, when a value matches neither a number, float, nor boolean like `starship` is found, it is treated as a string.
|
||||
|
||||
### Logging
|
||||
|
||||
By default starship logs warnings and errors into a file named `~/.cache/starship/session_${STARSHIP_SESSION_KEY}.log`, where the session key is corresponding to an instance of your terminal.
|
||||
|
156
src/config.rs
156
src/config.rs
@ -124,11 +124,18 @@ pub struct StarshipConfig {
|
||||
impl StarshipConfig {
|
||||
/// Initialize the Config struct
|
||||
pub fn initialize(config_file_path: &Option<OsString>) -> Self {
|
||||
Self::config_from_file(config_file_path)
|
||||
#[cfg_attr(test, allow(unused_mut))]
|
||||
let mut out = Self::config_from_file(config_file_path)
|
||||
.map(|config| Self {
|
||||
config: Some(config),
|
||||
})
|
||||
.unwrap_or_default()
|
||||
.unwrap_or_default();
|
||||
|
||||
// Avoid tainting config in tests
|
||||
#[cfg(not(test))]
|
||||
out.load_from_env();
|
||||
|
||||
out
|
||||
}
|
||||
|
||||
/// Create a config from a starship configuration file
|
||||
@ -173,6 +180,68 @@ impl StarshipConfig {
|
||||
}
|
||||
}
|
||||
|
||||
/// Load additional config values from the environment
|
||||
/// Variables are prefixed with `STARSHIP_` and delimited with `__`
|
||||
/// e.g. `STARSHIP_CONFIG__JAVA__DISABLED`
|
||||
pub fn load_from_env(&mut self) {
|
||||
for (key, value) in std::env::vars() {
|
||||
if let Some(name) = key.strip_prefix("STARSHIP_CONFIG__") {
|
||||
log::debug!("Loading config from environment: {name}={value}");
|
||||
|
||||
if let Err(e) = self.load_key_from_env(name, &value) {
|
||||
log::error!("Unable to load config {name}={value} from environment: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
log::debug!("Config with env: {:?}", &self.config);
|
||||
}
|
||||
|
||||
/// Load a config value from a `__` delimited uppercase key name (environment variable)
|
||||
pub fn load_key_from_env(&mut self, name: &str, value: &str) -> Result<(), String> {
|
||||
let config = match self.config.as_mut() {
|
||||
Some(c) => c,
|
||||
None => {
|
||||
self.config = Some(toml::value::Table::new());
|
||||
self.config.as_mut().unwrap()
|
||||
}
|
||||
};
|
||||
|
||||
let mut keys = name.split("__").map(str::to_ascii_lowercase);
|
||||
|
||||
let first_key = match keys.next() {
|
||||
Some(key) if !key.is_empty() => key,
|
||||
_ => return Err("Empty table keys are not supported.".to_owned()),
|
||||
};
|
||||
|
||||
let mut current_item = config
|
||||
.entry(first_key)
|
||||
.or_insert(toml::Value::Table(toml::value::Table::new()));
|
||||
|
||||
for key in keys {
|
||||
if key.is_empty() {
|
||||
return Err("Empty table keys are not supported.".to_owned());
|
||||
}
|
||||
|
||||
let table = match current_item.as_table_mut() {
|
||||
Some(t) => t,
|
||||
None => return Err(format!("{key} is not a table.")),
|
||||
};
|
||||
|
||||
if !table.contains_key(&key) {
|
||||
table.insert(key.clone(), toml::Value::Table(toml::value::Table::new()));
|
||||
}
|
||||
|
||||
current_item = table.get_mut(&key).unwrap();
|
||||
}
|
||||
|
||||
let new_value = parse_toml_value(value);
|
||||
|
||||
log::trace!("Setting config value: {:?}", &new_value);
|
||||
|
||||
*current_item = new_value;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get the subset of the table for a module by its name
|
||||
pub fn get_module_config(&self, module_name: &str) -> Option<&Value> {
|
||||
let module_config = self.get_config(&[module_name]);
|
||||
@ -508,6 +577,24 @@ fn parse_color_string(
|
||||
predefined_color
|
||||
}
|
||||
|
||||
/// Parses a string as a simple TOML value (String, Integer, etc.)
|
||||
/// TODO: support complex values like arrays/tables?
|
||||
fn parse_toml_value(value: &str) -> Value {
|
||||
use toml_edit::Value as EValue;
|
||||
if let Ok(t) = value.parse::<EValue>() {
|
||||
// Support for parsing quoted values, to allow parsing "true" as a string
|
||||
match t {
|
||||
EValue::String(s) => return Value::String(s.into_value()),
|
||||
EValue::Integer(s) => return Value::Integer(s.into_value()),
|
||||
EValue::Float(s) => return Value::Float(s.into_value()),
|
||||
EValue::Boolean(s) => return Value::Boolean(s.into_value()),
|
||||
_ => (),
|
||||
}
|
||||
};
|
||||
|
||||
Value::String(value.to_owned())
|
||||
}
|
||||
|
||||
fn get_palette<'a>(
|
||||
palettes: &'a HashMap<String, Palette>,
|
||||
palette_name: Option<&str>,
|
||||
@ -994,6 +1081,71 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
fn test_config() -> StarshipConfig {
|
||||
StarshipConfig {
|
||||
config: Some(toml::toml! {
|
||||
[status]
|
||||
disabled = false
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_env_config_wrong_type() {
|
||||
let mut cfg = test_config();
|
||||
|
||||
assert!(cfg
|
||||
.load_key_from_env("status__disabled__not_a_table", "true")
|
||||
.is_err());
|
||||
|
||||
assert!(cfg.config.unwrap()["status"]["disabled"].is_bool(),);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_env_config_simple() {
|
||||
let mut cfg = test_config();
|
||||
|
||||
assert!(!cfg.config.as_ref().unwrap()["status"]["disabled"]
|
||||
.as_bool()
|
||||
.unwrap());
|
||||
|
||||
cfg.load_key_from_env("status__disabled", "true").unwrap();
|
||||
|
||||
assert!(cfg.config.unwrap()["status"]["disabled"].as_bool().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_value_config_parse() {
|
||||
assert!(parse_toml_value("true").as_bool().unwrap());
|
||||
assert_eq!(parse_toml_value("0").as_integer().unwrap(), 0);
|
||||
assert!(parse_toml_value("0.0").is_float());
|
||||
assert_eq!(parse_toml_value("a string").as_str().unwrap(), "a string");
|
||||
assert_eq!(parse_toml_value("\"true\"").as_str().unwrap(), "true");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_update_config_empty() {
|
||||
let mut cfg = test_config();
|
||||
|
||||
assert!(cfg.load_key_from_env("", "true").is_err());
|
||||
assert!(cfg.load_key_from_env("______", "true").is_err());
|
||||
assert!(cfg.load_key_from_env("a__a__a____a__a", "true").is_err());
|
||||
assert!(cfg.load_key_from_env("a__a__a__a__a__", "true").is_err());
|
||||
assert!(cfg.load_key_from_env("__a__a__a__a__a", "true").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_update_config_deep() {
|
||||
let mut cfg = test_config();
|
||||
|
||||
cfg.load_key_from_env("a__b__c__d__e__f__g__h", "true")
|
||||
.unwrap();
|
||||
|
||||
assert!(cfg.config.unwrap()["a"]["b"]["c"]["d"]["e"]["f"]["g"]["h"]
|
||||
.as_bool()
|
||||
.unwrap())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn table_get_colors_palette() {
|
||||
// Test using colors defined in palette
|
||||
|
Loading…
Reference in New Issue
Block a user