1
0
mirror of https://github.com/Llewellynvdm/starship.git synced 2024-05-28 22:20:53 +00:00
starship/src/modules/hostname.rs
Tilmann Meyer 2233683410
feat: add error messaging (#1576)
This creates a custom logger for the log crate which logs everything to a file (/tmp/starship/session_$STARSHIP_SESSION_KEY.log) and it logs everything above Warn to stderr, but only if the log file does not contain the line that should be logged resulting in an error or warning to be only logged at the first starship invocation after opening the shell.
2020-09-28 16:38:50 -04:00

172 lines
4.8 KiB
Rust

use super::{Context, Module};
use std::ffi::OsString;
use crate::config::RootModuleConfig;
use crate::configs::hostname::HostnameConfig;
use crate::formatter::StringFormatter;
/// Creates a module with the system hostname
///
/// Will display the hostname if all of the following criteria are met:
/// - hostname.disabled is absent or false
/// - hostname.ssh_only is false OR the user is currently connected as an SSH session (`$SSH_CONNECTION`)
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
let mut module = context.new_module("hostname");
let config: HostnameConfig = HostnameConfig::try_load(module.config);
let ssh_connection = context.get_env("SSH_CONNECTION");
if config.ssh_only && ssh_connection.is_none() {
return None;
}
let os_hostname: OsString = gethostname::gethostname();
let host = match os_hostname.into_string() {
Ok(host) => host,
Err(bad) => {
log::warn!("hostname is not valid UTF!\n{:?}", bad);
return None;
}
};
//rustc doesn't let you do an "if" and an "if let" in the same if statement
// if this changes in the future this can become a lot cleaner
let host = if config.trim_at != "" {
if let Some(index) = host.find(config.trim_at) {
host.split_at(index).0
} else {
host.as_ref()
}
} else {
host.as_ref()
};
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
formatter
.map_style(|variable| match variable {
"style" => Some(Ok(config.style)),
_ => None,
})
.map(|variable| match variable {
"hostname" => Some(Ok(host)),
_ => None,
})
.parse(None)
});
module.set_segments(match parsed {
Ok(segments) => segments,
Err(error) => {
log::warn!("Error in module `hostname`:\n{}", error);
return None;
}
});
Some(module)
}
#[cfg(test)]
mod tests {
use crate::test::ModuleRenderer;
use ansi_term::{Color, Style};
use std::io;
macro_rules! get_hostname {
() => {
if let Some(hostname) = gethostname::gethostname().into_string().ok() {
hostname
} else {
println!(
"hostname was not tested because gethostname failed! \
This could be caused by your hostname containing invalid UTF."
);
return Ok(());
}
};
}
#[test]
fn ssh_only_false() -> io::Result<()> {
let hostname = get_hostname!();
let actual = ModuleRenderer::new("hostname")
.config(toml::toml! {
[hostname]
ssh_only = false
trim_at = ""
})
.collect();
let expected = Some(format!("{} in ", style().paint(hostname)));
assert_eq!(expected, actual);
Ok(())
}
#[test]
fn no_ssh() -> io::Result<()> {
let actual = ModuleRenderer::new("hostname")
.config(toml::toml! {
[hostname]
ssh_only = true
})
.collect();
let expected = None;
assert_eq!(expected, actual);
Ok(())
}
#[test]
fn ssh() -> io::Result<()> {
let hostname = get_hostname!();
let actual = ModuleRenderer::new("hostname")
.config(toml::toml! {
[hostname]
ssh_only = true
trim_at = ""
})
.env("SSH_CONNECTION", "something")
.collect();
let expected = Some(format!("{} in ", style().paint(hostname)));
assert_eq!(expected, actual);
Ok(())
}
#[test]
fn no_trim_at() -> io::Result<()> {
let hostname = get_hostname!();
let actual = ModuleRenderer::new("hostname")
.config(toml::toml! {
[hostname]
ssh_only = false
trim_at = ""
})
.collect();
let expected = Some(format!("{} in ", style().paint(hostname)));
assert_eq!(expected, actual);
Ok(())
}
#[test]
fn trim_at() -> io::Result<()> {
let hostname = get_hostname!();
let (remainder, trim_at) = hostname.split_at(1);
let actual = ModuleRenderer::new("hostname")
.config(toml::toml! {
[hostname]
ssh_only = false
trim_at = trim_at
})
.collect();
let expected = Some(format!("{} in ", style().paint(remainder)));
assert_eq!(expected, actual);
Ok(())
}
fn style() -> Style {
Color::Green.bold().dimmed()
}
}