fix(config): Make print-config not panic without a config (#5001)
This commit is contained in:
parent
b44f22e375
commit
ce7f984932
|
@ -1,5 +1,6 @@
|
||||||
use crate::configs::Palette;
|
use crate::configs::Palette;
|
||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
|
|
||||||
use crate::serde_utils::{ValueDeserializer, ValueRef};
|
use crate::serde_utils::{ValueDeserializer, ValueRef};
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
use nu_ansi_term::Color;
|
use nu_ansi_term::Color;
|
||||||
|
@ -10,9 +11,9 @@ use serde::{
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::clone::Clone;
|
use std::clone::Clone;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::ffi::OsString;
|
||||||
use std::io::ErrorKind;
|
use std::io::ErrorKind;
|
||||||
|
|
||||||
use std::env;
|
|
||||||
use toml::Value;
|
use toml::Value;
|
||||||
|
|
||||||
/// Root config of a module.
|
/// Root config of a module.
|
||||||
|
@ -120,25 +121,10 @@ pub struct StarshipConfig {
|
||||||
pub config: Option<toml::Table>,
|
pub config: Option<toml::Table>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_config_path() -> Option<String> {
|
|
||||||
if let Ok(path) = env::var("STARSHIP_CONFIG") {
|
|
||||||
// Use $STARSHIP_CONFIG as the config path if available
|
|
||||||
log::debug!("STARSHIP_CONFIG is set: {}", &path);
|
|
||||||
Some(path)
|
|
||||||
} else {
|
|
||||||
// Default to using ~/.config/starship.toml
|
|
||||||
log::debug!("STARSHIP_CONFIG is not set");
|
|
||||||
let config_path = utils::home_dir()?.join(".config/starship.toml");
|
|
||||||
let config_path_str = config_path.to_str()?.to_owned();
|
|
||||||
log::debug!("Using default config path: {}", config_path_str);
|
|
||||||
Some(config_path_str)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StarshipConfig {
|
impl StarshipConfig {
|
||||||
/// Initialize the Config struct
|
/// Initialize the Config struct
|
||||||
pub fn initialize() -> Self {
|
pub fn initialize(config_file_path: &Option<OsString>) -> Self {
|
||||||
Self::config_from_file()
|
Self::config_from_file(config_file_path)
|
||||||
.map(|config| Self {
|
.map(|config| Self {
|
||||||
config: Some(config),
|
config: Some(config),
|
||||||
})
|
})
|
||||||
|
@ -146,10 +132,30 @@ impl StarshipConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a config from a starship configuration file
|
/// Create a config from a starship configuration file
|
||||||
fn config_from_file() -> Option<toml::Table> {
|
fn config_from_file(config_file_path: &Option<OsString>) -> Option<toml::Table> {
|
||||||
let file_path = get_config_path()?;
|
let toml_content = Self::read_config_content_as_str(config_file_path)?;
|
||||||
|
|
||||||
let toml_content = match utils::read_file(file_path) {
|
match toml::from_str(&toml_content) {
|
||||||
|
Ok(parsed) => {
|
||||||
|
log::debug!("Config parsed: {:?}", &parsed);
|
||||||
|
Some(parsed)
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
log::error!("Unable to parse the config file: {}", error);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_config_content_as_str(config_file_path: &Option<OsString>) -> Option<String> {
|
||||||
|
if config_file_path.is_none() {
|
||||||
|
log::debug!(
|
||||||
|
"Unable to determine `config_file_path`. Perhaps `utils::home_dir` is not defined on your platform?"
|
||||||
|
);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let config_file_path = config_file_path.as_ref().unwrap();
|
||||||
|
match utils::read_file(config_file_path) {
|
||||||
Ok(content) => {
|
Ok(content) => {
|
||||||
log::trace!("Config file content: \"\n{}\"", &content);
|
log::trace!("Config file content: \"\n{}\"", &content);
|
||||||
Some(content)
|
Some(content)
|
||||||
|
@ -164,17 +170,6 @@ impl StarshipConfig {
|
||||||
log::log!(level, "Unable to read config file content: {}", &e);
|
log::log!(level, "Unable to read config file content: {}", &e);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}?;
|
|
||||||
|
|
||||||
match toml::from_str(&toml_content) {
|
|
||||||
Ok(parsed) => {
|
|
||||||
log::debug!("Config parsed: {:?}", &parsed);
|
|
||||||
Some(parsed)
|
|
||||||
}
|
|
||||||
Err(error) => {
|
|
||||||
log::error!("Unable to parse the config file: {}", error);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -921,4 +916,13 @@ mod tests {
|
||||||
// Test default behavior
|
// Test default behavior
|
||||||
assert!(get_palette(&palettes, None).is_none());
|
assert!(get_palette(&palettes, None).is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn read_config_no_config_file_path_provided() {
|
||||||
|
assert_eq!(
|
||||||
|
None,
|
||||||
|
StarshipConfig::read_config_content_as_str(&None),
|
||||||
|
"if the platform doesn't have utils::home_dir(), it should return None"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
203
src/configure.rs
203
src/configure.rs
|
@ -1,6 +1,3 @@
|
||||||
use std::env;
|
|
||||||
use std::ffi::OsString;
|
|
||||||
use std::io::ErrorKind;
|
|
||||||
use std::process;
|
use std::process;
|
||||||
use std::process::Stdio;
|
use std::process::Stdio;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
@ -8,6 +5,7 @@ use std::str::FromStr;
|
||||||
use crate::config::ModuleConfig;
|
use crate::config::ModuleConfig;
|
||||||
use crate::config::StarshipConfig;
|
use crate::config::StarshipConfig;
|
||||||
use crate::configs::PROMPT_ORDER;
|
use crate::configs::PROMPT_ORDER;
|
||||||
|
use crate::context::Context;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
@ -18,15 +16,15 @@ const STD_EDITOR: &str = "vi";
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
const STD_EDITOR: &str = "notepad.exe";
|
const STD_EDITOR: &str = "notepad.exe";
|
||||||
|
|
||||||
pub fn update_configuration(name: &str, value: &str) {
|
pub fn update_configuration(context: &Context, name: &str, value: &str) {
|
||||||
let mut doc = get_configuration_edit();
|
let mut doc = get_configuration_edit(context);
|
||||||
|
|
||||||
match handle_update_configuration(&mut doc, name, value) {
|
match handle_update_configuration(&mut doc, name, value) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("{e}");
|
eprintln!("{e}");
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
_ => write_configuration(&doc),
|
_ => write_configuration(context, &doc),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +69,7 @@ fn handle_update_configuration(doc: &mut Document, name: &str, value: &str) -> R
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn print_configuration(use_default: bool, paths: &[String]) {
|
pub fn print_configuration(context: &Context, use_default: bool, paths: &[String]) -> String {
|
||||||
let config = if use_default {
|
let config = if use_default {
|
||||||
// Get default config
|
// Get default config
|
||||||
let default_config = crate::configs::FullConfig::default();
|
let default_config = crate::configs::FullConfig::default();
|
||||||
|
@ -79,7 +77,7 @@ pub fn print_configuration(use_default: bool, paths: &[String]) {
|
||||||
toml::value::Value::try_from(default_config).unwrap()
|
toml::value::Value::try_from(default_config).unwrap()
|
||||||
} else {
|
} else {
|
||||||
// Get config as toml::Value
|
// Get config as toml::Value
|
||||||
let user_config = get_configuration();
|
let user_config = get_configuration(context);
|
||||||
// Convert into FullConfig and fill in default values
|
// Convert into FullConfig and fill in default values
|
||||||
let user_config = crate::configs::FullConfig::load(&user_config);
|
let user_config = crate::configs::FullConfig::load(&user_config);
|
||||||
// Convert back to Value because toml can't serialize FullConfig directly
|
// Convert back to Value because toml can't serialize FullConfig directly
|
||||||
|
@ -124,6 +122,7 @@ pub fn print_configuration(use_default: bool, paths: &[String]) {
|
||||||
let string_config = toml::to_string_pretty(&print_config).unwrap();
|
let string_config = toml::to_string_pretty(&print_config).unwrap();
|
||||||
|
|
||||||
println!("{string_config}");
|
println!("{string_config}");
|
||||||
|
string_config
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_toml_paths(mut config: toml::Value, paths: &[String]) -> toml::Value {
|
fn extract_toml_paths(mut config: toml::Value, paths: &[String]) -> toml::Value {
|
||||||
|
@ -176,15 +175,15 @@ fn extract_toml_paths(mut config: toml::Value, paths: &[String]) -> toml::Value
|
||||||
toml::Value::Table(subset)
|
toml::Value::Table(subset)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toggle_configuration(name: &str, key: &str) {
|
pub fn toggle_configuration(context: &Context, name: &str, key: &str) {
|
||||||
let mut doc = get_configuration_edit();
|
let mut doc = get_configuration_edit(context);
|
||||||
|
|
||||||
match handle_toggle_configuration(&mut doc, name, key) {
|
match handle_toggle_configuration(&mut doc, name, key) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("{e}");
|
eprintln!("{e}");
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
_ => write_configuration(&doc),
|
_ => write_configuration(context, &doc),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,32 +216,15 @@ fn handle_toggle_configuration(doc: &mut Document, name: &str, key: &str) -> Res
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_configuration() -> toml::Table {
|
pub fn get_configuration(context: &Context) -> toml::Table {
|
||||||
let starship_config = StarshipConfig::initialize();
|
let starship_config = StarshipConfig::initialize(&context.get_config_path_os());
|
||||||
|
|
||||||
starship_config
|
starship_config.config.unwrap_or(toml::Table::new())
|
||||||
.config
|
|
||||||
.expect("Failed to load starship config")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_configuration_edit() -> Document {
|
pub fn get_configuration_edit(context: &Context) -> Document {
|
||||||
let file_path = get_config_path();
|
let config_file_path = context.get_config_path_os();
|
||||||
let toml_content = match utils::read_file(file_path) {
|
let toml_content = StarshipConfig::read_config_content_as_str(&config_file_path);
|
||||||
Ok(content) => {
|
|
||||||
log::trace!("Config file content: \"\n{}\"", &content);
|
|
||||||
Some(content)
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
let level = if e.kind() == ErrorKind::NotFound {
|
|
||||||
log::Level::Debug
|
|
||||||
} else {
|
|
||||||
log::Level::Error
|
|
||||||
};
|
|
||||||
|
|
||||||
log::log!(level, "Unable to read config file content: {}", &e);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
toml_content
|
toml_content
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
|
@ -250,8 +232,11 @@ pub fn get_configuration_edit() -> Document {
|
||||||
.expect("Failed to load starship config")
|
.expect("Failed to load starship config")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_configuration(doc: &Document) {
|
pub fn write_configuration(context: &Context, doc: &Document) {
|
||||||
let config_path = get_config_path();
|
let config_path = context.get_config_path_os().unwrap_or_else(|| {
|
||||||
|
eprintln!("config path required to write configuration");
|
||||||
|
process::exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
let config_str = doc.to_string();
|
let config_str = doc.to_string();
|
||||||
|
|
||||||
|
@ -260,10 +245,16 @@ pub fn write_configuration(doc: &Document) {
|
||||||
.expect("Error writing starship config");
|
.expect("Error writing starship config");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn edit_configuration(editor_override: Option<&str>) -> Result<(), Box<dyn std::error::Error>> {
|
pub fn edit_configuration(
|
||||||
|
context: &Context,
|
||||||
|
editor_override: Option<&str>,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
// Argument currently only used for testing, but could be used to specify
|
// Argument currently only used for testing, but could be used to specify
|
||||||
// an editor override on the command line.
|
// an editor override on the command line.
|
||||||
let config_path = get_config_path();
|
let config_path = context.get_config_path_os().unwrap_or_else(|| {
|
||||||
|
eprintln!("config path required to edit configuration");
|
||||||
|
process::exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
let editor_cmd = shell_words::split(&get_editor(editor_override))?;
|
let editor_cmd = shell_words::split(&get_editor(editor_override))?;
|
||||||
let mut command = match utils::create_command(&editor_cmd[0]) {
|
let mut command = match utils::create_command(&editor_cmd[0]) {
|
||||||
|
@ -313,19 +304,18 @@ fn get_editor_internal(visual: Option<String>, editor: Option<String>) -> String
|
||||||
STD_EDITOR.into()
|
STD_EDITOR.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_config_path() -> OsString {
|
|
||||||
if let Some(config_path) = env::var_os("STARSHIP_CONFIG") {
|
|
||||||
return config_path;
|
|
||||||
}
|
|
||||||
utils::home_dir()
|
|
||||||
.expect("couldn't find home directory")
|
|
||||||
.join(".config")
|
|
||||||
.join("starship.toml")
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use std::{fs::create_dir, io};
|
||||||
|
|
||||||
|
use tempfile::TempDir;
|
||||||
|
use toml_edit::Item;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
context::{Shell, Target},
|
||||||
|
context_env::Env,
|
||||||
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
// This is every possible permutation, 3² = 9.
|
// This is every possible permutation, 3² = 9.
|
||||||
|
@ -379,13 +369,13 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn no_panic_when_editor_unparsable() {
|
fn no_panic_when_editor_unparsable() {
|
||||||
let outcome = edit_configuration(Some("\"vim"));
|
let outcome = edit_configuration(&Default::default(), Some("\"vim"));
|
||||||
assert!(outcome.is_err());
|
assert!(outcome.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn no_panic_when_editor_not_found() {
|
fn no_panic_when_editor_not_found() {
|
||||||
let outcome = edit_configuration(Some("this_editor_does_not_exist"));
|
let outcome = edit_configuration(&Default::default(), Some("this_editor_does_not_exist"));
|
||||||
assert!(outcome.is_err());
|
assert!(outcome.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -581,4 +571,115 @@ mod tests {
|
||||||
.as_bool()
|
.as_bool()
|
||||||
.unwrap())
|
.unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn write_and_get_configuration_test() -> io::Result<()> {
|
||||||
|
let dir = tempfile::tempdir()?;
|
||||||
|
let context = setup_config(&dir, true, StarshipConfigEnvScenario::NotSpecified)?;
|
||||||
|
let mut doc = get_configuration_edit(&context);
|
||||||
|
doc["directory"]["format"] = Item::Value("myformat".into());
|
||||||
|
write_configuration(&context, &doc);
|
||||||
|
let doc_reloaded = get_configuration_edit(&context);
|
||||||
|
assert_eq!(
|
||||||
|
"myformat",
|
||||||
|
doc_reloaded["directory"]["format"].as_str().unwrap()
|
||||||
|
);
|
||||||
|
dir.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
const PRINT_CONFIG_DEFAULT: &str = "[custom]";
|
||||||
|
const PRINT_CONFIG_HOME: &str = "[custom.home]";
|
||||||
|
const PRINT_CONFIG_ENV: &str = "[custom.STARSHIP_CONFIG]";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn print_configuration_scenarios() -> io::Result<()> {
|
||||||
|
run_print_configuration_test(
|
||||||
|
"~/.config/starship.toml, no STARSHIP_CONFIG uses home",
|
||||||
|
true,
|
||||||
|
StarshipConfigEnvScenario::NotSpecified,
|
||||||
|
PRINT_CONFIG_HOME,
|
||||||
|
)?;
|
||||||
|
run_print_configuration_test(
|
||||||
|
"no ~/.config/starship.toml, no STARSHIP_CONFIG uses default",
|
||||||
|
false,
|
||||||
|
StarshipConfigEnvScenario::NotSpecified,
|
||||||
|
PRINT_CONFIG_DEFAULT,
|
||||||
|
)?;
|
||||||
|
run_print_configuration_test(
|
||||||
|
"~/.config/starship.toml, STARSHIP_CONFIG nonexisting file uses default",
|
||||||
|
true,
|
||||||
|
StarshipConfigEnvScenario::NonExistingFile,
|
||||||
|
PRINT_CONFIG_DEFAULT,
|
||||||
|
)?;
|
||||||
|
run_print_configuration_test(
|
||||||
|
"~/.config/starship.toml, STARSHIP_CONFIG existing file uses STARSHIP_CONFIG file",
|
||||||
|
true,
|
||||||
|
StarshipConfigEnvScenario::ExistingFile,
|
||||||
|
PRINT_CONFIG_ENV,
|
||||||
|
)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
enum StarshipConfigEnvScenario {
|
||||||
|
NotSpecified,
|
||||||
|
NonExistingFile,
|
||||||
|
ExistingFile,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_print_configuration_test(
|
||||||
|
message: &str,
|
||||||
|
home_file_exists: bool,
|
||||||
|
starship_config_env_scenario: StarshipConfigEnvScenario,
|
||||||
|
expected_first_line: &str,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
let dir = tempfile::tempdir()?;
|
||||||
|
let context = setup_config(&dir, home_file_exists, starship_config_env_scenario)?;
|
||||||
|
let config = print_configuration(&context, false, &["custom".to_string()]);
|
||||||
|
let first_line = config.split('\n').next().unwrap();
|
||||||
|
assert_eq!(expected_first_line, first_line, "{message}");
|
||||||
|
dir.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_config(
|
||||||
|
dir: &TempDir,
|
||||||
|
home_file_exists: bool,
|
||||||
|
starship_config_env_scenario: StarshipConfigEnvScenario,
|
||||||
|
) -> io::Result<Context> {
|
||||||
|
let config_path = dir.path().to_path_buf().join(".config");
|
||||||
|
create_dir(&config_path)?;
|
||||||
|
let home_starship_toml = config_path.join("starship.toml");
|
||||||
|
let env_toml = dir.path().join("env.toml");
|
||||||
|
if home_file_exists {
|
||||||
|
let mut home_file = File::create(home_starship_toml)?;
|
||||||
|
home_file.write_all(PRINT_CONFIG_HOME.as_bytes())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let env_starship_config = match starship_config_env_scenario {
|
||||||
|
StarshipConfigEnvScenario::NotSpecified => None,
|
||||||
|
StarshipConfigEnvScenario::NonExistingFile => Some(env_toml),
|
||||||
|
StarshipConfigEnvScenario::ExistingFile => {
|
||||||
|
let mut env_toml_file = File::create(&env_toml)?;
|
||||||
|
env_toml_file.write_all(PRINT_CONFIG_ENV.as_bytes())?;
|
||||||
|
Some(env_toml)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut env = Env::default();
|
||||||
|
if let Some(v) = env_starship_config {
|
||||||
|
env.insert("STARSHIP_CONFIG", v.to_string_lossy().to_string());
|
||||||
|
}
|
||||||
|
env.insert(
|
||||||
|
"HOME",
|
||||||
|
dir.path().to_path_buf().to_string_lossy().to_string(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(Context::new_with_shell_and_path(
|
||||||
|
Default::default(),
|
||||||
|
Shell::Unknown,
|
||||||
|
Target::Main,
|
||||||
|
Default::default(),
|
||||||
|
Default::default(),
|
||||||
|
env,
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
use crate::config::{ModuleConfig, StarshipConfig};
|
use crate::config::{ModuleConfig, StarshipConfig};
|
||||||
use crate::configs::StarshipRootConfig;
|
use crate::configs::StarshipRootConfig;
|
||||||
|
use crate::context_env::Env;
|
||||||
use crate::module::Module;
|
use crate::module::Module;
|
||||||
use crate::utils::{create_command, exec_timeout, read_file, CommandOutput, PathExt};
|
use crate::utils::{create_command, exec_timeout, read_file, CommandOutput, PathExt};
|
||||||
|
|
||||||
use crate::modules;
|
use crate::modules;
|
||||||
use crate::utils::{self, home_dir};
|
use crate::utils;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use gix::{
|
use gix::{
|
||||||
sec::{self as git_sec, trust::DefaultForLevel},
|
sec::{self as git_sec, trust::DefaultForLevel},
|
||||||
|
@ -60,8 +61,7 @@ pub struct Context<'a> {
|
||||||
pub width: usize,
|
pub width: usize,
|
||||||
|
|
||||||
/// A HashMap of environment variable mocks
|
/// A HashMap of environment variable mocks
|
||||||
#[cfg(test)]
|
pub env: Env<'a>,
|
||||||
pub env: HashMap<&'a str, String>,
|
|
||||||
|
|
||||||
/// A HashMap of command mocks
|
/// A HashMap of command mocks
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -107,7 +107,14 @@ impl<'a> Context<'a> {
|
||||||
.or_else(|| env::var("PWD").map(PathBuf::from).ok())
|
.or_else(|| env::var("PWD").map(PathBuf::from).ok())
|
||||||
.unwrap_or_else(|| path.clone());
|
.unwrap_or_else(|| path.clone());
|
||||||
|
|
||||||
Context::new_with_shell_and_path(arguments, shell, target, path, logical_path)
|
Context::new_with_shell_and_path(
|
||||||
|
arguments,
|
||||||
|
shell,
|
||||||
|
target,
|
||||||
|
path,
|
||||||
|
logical_path,
|
||||||
|
Default::default(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new instance of Context for the provided directory
|
/// Create a new instance of Context for the provided directory
|
||||||
|
@ -117,8 +124,9 @@ impl<'a> Context<'a> {
|
||||||
target: Target,
|
target: Target,
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
logical_path: PathBuf,
|
logical_path: PathBuf,
|
||||||
|
env: Env<'a>,
|
||||||
) -> Context<'a> {
|
) -> Context<'a> {
|
||||||
let config = StarshipConfig::initialize();
|
let config = StarshipConfig::initialize(&get_config_path_os(&env));
|
||||||
|
|
||||||
// If the vector is zero-length, we should pretend that we didn't get a
|
// If the vector is zero-length, we should pretend that we didn't get a
|
||||||
// pipestatus at all (since this is the input `--pipestatus=""`)
|
// pipestatus at all (since this is the input `--pipestatus=""`)
|
||||||
|
@ -162,11 +170,10 @@ impl<'a> Context<'a> {
|
||||||
shell,
|
shell,
|
||||||
target,
|
target,
|
||||||
width,
|
width,
|
||||||
|
env,
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
root_dir: tempfile::TempDir::new().unwrap(),
|
root_dir: tempfile::TempDir::new().unwrap(),
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
env: HashMap::new(),
|
|
||||||
#[cfg(test)]
|
|
||||||
cmd: HashMap::new(),
|
cmd: HashMap::new(),
|
||||||
#[cfg(feature = "battery")]
|
#[cfg(feature = "battery")]
|
||||||
battery_info_provider: &crate::modules::BatteryInfoProviderImpl,
|
battery_info_provider: &crate::modules::BatteryInfoProviderImpl,
|
||||||
|
@ -177,37 +184,19 @@ impl<'a> Context<'a> {
|
||||||
|
|
||||||
// Tries to retrieve home directory from a table in testing mode or else retrieves it from the os
|
// Tries to retrieve home directory from a table in testing mode or else retrieves it from the os
|
||||||
pub fn get_home(&self) -> Option<PathBuf> {
|
pub fn get_home(&self) -> Option<PathBuf> {
|
||||||
if cfg!(test) {
|
home_dir(&self.env)
|
||||||
return self.get_env("HOME").map(PathBuf::from).or_else(home_dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
home_dir()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieves a environment variable from the os or from a table if in testing mode
|
// Retrieves a environment variable from the os or from a table if in testing mode
|
||||||
#[cfg(test)]
|
|
||||||
pub fn get_env<K: AsRef<str>>(&self, key: K) -> Option<String> {
|
|
||||||
self.env
|
|
||||||
.get(key.as_ref())
|
|
||||||
.map(std::string::ToString::to_string)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(test))]
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_env<K: AsRef<str>>(&self, key: K) -> Option<String> {
|
pub fn get_env<K: AsRef<str>>(&self, key: K) -> Option<String> {
|
||||||
env::var(key.as_ref()).ok()
|
self.env.get_env(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieves a environment variable from the os or from a table if in testing mode (os version)
|
// Retrieves a environment variable from the os or from a table if in testing mode (os version)
|
||||||
#[cfg(test)]
|
|
||||||
pub fn get_env_os<K: AsRef<str>>(&self, key: K) -> Option<OsString> {
|
|
||||||
self.env.get(key.as_ref()).map(OsString::from)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(test))]
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_env_os<K: AsRef<str>>(&self, key: K) -> Option<OsString> {
|
pub fn get_env_os<K: AsRef<str>>(&self, key: K) -> Option<OsString> {
|
||||||
env::var_os(key.as_ref())
|
self.env.get_env_os(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a `~` in a path to the home directory
|
/// Convert a `~` in a path to the home directory
|
||||||
|
@ -401,6 +390,32 @@ impl<'a> Context<'a> {
|
||||||
|
|
||||||
read_file(self.current_dir.join(file_name)).ok()
|
read_file(self.current_dir.join(file_name)).ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_config_path_os(&self) -> Option<OsString> {
|
||||||
|
get_config_path_os(&self.env)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Context<'_> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Context::new(Default::default(), Target::Main)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn home_dir(env: &Env) -> Option<PathBuf> {
|
||||||
|
if cfg!(test) {
|
||||||
|
if let Some(home) = env.get_env("HOME") {
|
||||||
|
return Some(PathBuf::from(home));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
utils::home_dir()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_config_path_os(env: &Env) -> Option<OsString> {
|
||||||
|
if let Some(config_path) = env.get_env_os("STARSHIP_CONFIG") {
|
||||||
|
return Some(config_path);
|
||||||
|
}
|
||||||
|
Some(home_dir(env)?.join(".config").join("starship.toml").into())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -907,6 +922,7 @@ mod tests {
|
||||||
Target::Main,
|
Target::Main,
|
||||||
test_path.clone(),
|
test_path.clone(),
|
||||||
test_path.clone(),
|
test_path.clone(),
|
||||||
|
Default::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_ne!(context.current_dir, context.logical_dir);
|
assert_ne!(context.current_dir, context.logical_dir);
|
||||||
|
@ -931,6 +947,7 @@ mod tests {
|
||||||
Target::Main,
|
Target::Main,
|
||||||
test_path.clone(),
|
test_path.clone(),
|
||||||
test_path.clone(),
|
test_path.clone(),
|
||||||
|
Default::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let expected_current_dir = &test_path;
|
let expected_current_dir = &test_path;
|
||||||
|
@ -952,6 +969,7 @@ mod tests {
|
||||||
Target::Main,
|
Target::Main,
|
||||||
test_path.clone(),
|
test_path.clone(),
|
||||||
test_path.clone(),
|
test_path.clone(),
|
||||||
|
Default::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let expected_current_dir = home_dir()
|
let expected_current_dir = home_dir()
|
||||||
|
@ -973,6 +991,7 @@ mod tests {
|
||||||
Target::Main,
|
Target::Main,
|
||||||
test_path.clone(),
|
test_path.clone(),
|
||||||
test_path,
|
test_path,
|
||||||
|
Default::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let expected_path = Path::new(r"C:\");
|
let expected_path = Path::new(r"C:\");
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
#[cfg(test)]
|
||||||
|
use std::collections::HashMap;
|
||||||
|
#[cfg(not(test))]
|
||||||
|
use std::env;
|
||||||
|
use std::ffi::OsString;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Env<'a> {
|
||||||
|
/// A HashMap of environment variable mocks
|
||||||
|
#[cfg(test)]
|
||||||
|
pub env: HashMap<&'a str, String>,
|
||||||
|
|
||||||
|
#[cfg(not(test))]
|
||||||
|
_marker: std::marker::PhantomData<&'a ()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Env<'a> {
|
||||||
|
// Retrieves a environment variable from the os or from a table if in testing mode
|
||||||
|
#[cfg(test)]
|
||||||
|
pub fn get_env<K: AsRef<str>>(&self, key: K) -> Option<String> {
|
||||||
|
self.env
|
||||||
|
.get(key.as_ref())
|
||||||
|
.map(std::string::ToString::to_string)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(test))]
|
||||||
|
#[inline]
|
||||||
|
pub fn get_env<K: AsRef<str>>(&self, key: K) -> Option<String> {
|
||||||
|
env::var(key.as_ref()).ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieves a environment variable from the os or from a table if in testing mode (os version)
|
||||||
|
#[cfg(test)]
|
||||||
|
pub fn get_env_os<K: AsRef<str>>(&self, key: K) -> Option<OsString> {
|
||||||
|
self.env.get(key.as_ref()).map(OsString::from)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(test))]
|
||||||
|
#[inline]
|
||||||
|
pub fn get_env_os<K: AsRef<str>>(&self, key: K) -> Option<OsString> {
|
||||||
|
env::var_os(key.as_ref())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub fn insert(&mut self, k: &'a str, v: String) -> Option<String> {
|
||||||
|
self.env.insert(k, v)
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ pub mod config;
|
||||||
pub mod configs;
|
pub mod configs;
|
||||||
pub mod configure;
|
pub mod configure;
|
||||||
pub mod context;
|
pub mod context;
|
||||||
|
pub mod context_env;
|
||||||
pub mod formatter;
|
pub mod formatter;
|
||||||
pub mod init;
|
pub mod init;
|
||||||
pub mod logger;
|
pub mod logger;
|
||||||
|
|
15
src/main.rs
15
src/main.rs
|
@ -10,7 +10,7 @@ use clap::{CommandFactory, Parser, Subcommand};
|
||||||
use clap_complete::{generate, Shell as CompletionShell};
|
use clap_complete::{generate, Shell as CompletionShell};
|
||||||
use rand::distributions::Alphanumeric;
|
use rand::distributions::Alphanumeric;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use starship::context::{Properties, Target};
|
use starship::context::{Context, Properties, Target};
|
||||||
use starship::module::ALL_MODULES;
|
use starship::module::ALL_MODULES;
|
||||||
use starship::*;
|
use starship::*;
|
||||||
|
|
||||||
|
@ -208,17 +208,22 @@ fn main() {
|
||||||
}
|
}
|
||||||
Commands::Preset { name, list, output } => print::preset_command(name, output, list),
|
Commands::Preset { name, list, output } => print::preset_command(name, output, list),
|
||||||
Commands::Config { name, value } => {
|
Commands::Config { name, value } => {
|
||||||
|
let context = Context::default();
|
||||||
if let Some(name) = name {
|
if let Some(name) = name {
|
||||||
if let Some(value) = value {
|
if let Some(value) = value {
|
||||||
configure::update_configuration(&name, &value)
|
configure::update_configuration(&context, &name, &value)
|
||||||
}
|
}
|
||||||
} else if let Err(reason) = configure::edit_configuration(None) {
|
} else if let Err(reason) = configure::edit_configuration(&context, None) {
|
||||||
eprintln!("Could not edit configuration: {reason}");
|
eprintln!("Could not edit configuration: {reason}");
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Commands::PrintConfig { default, name } => configure::print_configuration(default, &name),
|
Commands::PrintConfig { default, name } => {
|
||||||
Commands::Toggle { name, value } => configure::toggle_configuration(&name, &value),
|
configure::print_configuration(&Context::default(), default, &name);
|
||||||
|
}
|
||||||
|
Commands::Toggle { name, value } => {
|
||||||
|
configure::toggle_configuration(&Context::default(), &name, &value)
|
||||||
|
}
|
||||||
Commands::BugReport => bug_report::create(),
|
Commands::BugReport => bug_report::create(),
|
||||||
Commands::Time => {
|
Commands::Time => {
|
||||||
match SystemTime::now()
|
match SystemTime::now()
|
||||||
|
|
|
@ -386,6 +386,7 @@ fn git_status_wsl(context: &Context, conf: &GitStatusConfig) -> Option<String> {
|
||||||
use crate::utils::create_command;
|
use crate::utils::create_command;
|
||||||
use nix::sys::utsname::uname;
|
use nix::sys::utsname::uname;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use std::ffi::OsString;
|
||||||
use std::io::ErrorKind;
|
use std::io::ErrorKind;
|
||||||
|
|
||||||
let starship_exe = conf.windows_starship?;
|
let starship_exe = conf.windows_starship?;
|
||||||
|
@ -454,7 +455,9 @@ fn git_status_wsl(context: &Context, conf: &GitStatusConfig) -> Option<String> {
|
||||||
.map(|mut c| {
|
.map(|mut c| {
|
||||||
c.env(
|
c.env(
|
||||||
"STARSHIP_CONFIG",
|
"STARSHIP_CONFIG",
|
||||||
crate::config::get_config_path().unwrap_or_else(|| "/dev/null".to_string()),
|
context
|
||||||
|
.get_config_path_os()
|
||||||
|
.unwrap_or_else(|| OsString::from("/dev/null")),
|
||||||
)
|
)
|
||||||
.env("WSLENV", wslenv)
|
.env("WSLENV", wslenv)
|
||||||
.args(["module", "git_status", "--path", winpath]);
|
.args(["module", "git_status", "--path", winpath]);
|
||||||
|
|
|
@ -735,6 +735,7 @@ version = "12"
|
||||||
Target::Main,
|
Target::Main,
|
||||||
dir.path().into(),
|
dir.path().into(),
|
||||||
dir.path().into(),
|
dir.path().into(),
|
||||||
|
Default::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -756,6 +757,7 @@ version = "12"
|
||||||
Target::Main,
|
Target::Main,
|
||||||
dir.path().into(),
|
dir.path().into(),
|
||||||
dir.path().into(),
|
dir.path().into(),
|
||||||
|
Default::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -777,6 +779,7 @@ version = "12"
|
||||||
Target::Main,
|
Target::Main,
|
||||||
dir.path().into(),
|
dir.path().into(),
|
||||||
dir.path().into(),
|
dir.path().into(),
|
||||||
|
Default::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -800,6 +803,7 @@ version = "12"
|
||||||
Target::Main,
|
Target::Main,
|
||||||
child_dir_path.clone(),
|
child_dir_path.clone(),
|
||||||
child_dir_path,
|
child_dir_path,
|
||||||
|
Default::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -820,6 +824,7 @@ version = "12"
|
||||||
Target::Main,
|
Target::Main,
|
||||||
dir.path().into(),
|
dir.path().into(),
|
||||||
dir.path().into(),
|
dir.path().into(),
|
||||||
|
Default::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(find_rust_toolchain_file(&context), None);
|
assert_eq!(find_rust_toolchain_file(&context), None);
|
||||||
|
@ -838,6 +843,7 @@ version = "12"
|
||||||
Target::Main,
|
Target::Main,
|
||||||
dir.path().into(),
|
dir.path().into(),
|
||||||
dir.path().into(),
|
dir.path().into(),
|
||||||
|
Default::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -859,6 +865,7 @@ version = "12"
|
||||||
Target::Main,
|
Target::Main,
|
||||||
dir.path().into(),
|
dir.path().into(),
|
||||||
dir.path().into(),
|
dir.path().into(),
|
||||||
|
Default::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -882,6 +889,7 @@ version = "12"
|
||||||
Target::Main,
|
Target::Main,
|
||||||
child_dir_path.clone(),
|
child_dir_path.clone(),
|
||||||
child_dir_path,
|
child_dir_path,
|
||||||
|
Default::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
|
@ -43,6 +43,7 @@ pub fn default_context() -> Context<'static> {
|
||||||
Target::Main,
|
Target::Main,
|
||||||
PathBuf::new(),
|
PathBuf::new(),
|
||||||
PathBuf::new(),
|
PathBuf::new(),
|
||||||
|
Default::default(),
|
||||||
);
|
);
|
||||||
context.config = StarshipConfig { config: None };
|
context.config = StarshipConfig { config: None };
|
||||||
context
|
context
|
||||||
|
|
Loading…
Reference in New Issue