mirror of
https://github.com/Llewellynvdm/starship.git
synced 2024-12-01 01:04:00 +00:00
Add support for prompt configuration (#62)
- Create `Config` struct that is added to `Context` when initialized - Read `~/.confg/starship.toml` during initialization (can be updated later to also look at `$XDG_CONFIG_HOME`) - `Context` now has a method for creating modules. This allows us to provide modules with a reference to the configuration specific to that module
This commit is contained in:
parent
8239fbd12b
commit
097f1b05f1
@ -57,7 +57,7 @@ I'm very new to Rust, so any help is appreciated when it comes to improving deve
|
|||||||
|
|
||||||
### Other features
|
### Other features
|
||||||
|
|
||||||
- [ ] `.starshiprc` configuration (JSON or TOML)
|
- [x] `starship.toml` configuration
|
||||||
- [ ] Custom sections given commands or binaries
|
- [ ] Custom sections given commands or binaries
|
||||||
- [ ] Self-updating
|
- [ ] Self-updating
|
||||||
|
|
||||||
@ -69,9 +69,9 @@ I'm very new to Rust, so any help is appreciated when it comes to improving deve
|
|||||||
|
|
||||||
### Test strategy
|
### Test strategy
|
||||||
|
|
||||||
- [x] Per-segment benchmarking
|
- [ ] Per-segment benchmarking
|
||||||
- [x] Per-segment unit + integration tests
|
- [x] Per-segment unit + integration tests
|
||||||
- [ ] Shell + OS matrix acceptance tests
|
- [x] Shell + OS matrix acceptance tests
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
|
@ -8,7 +8,11 @@ jobs:
|
|||||||
- script: docker pull starshipcommand/starship-test
|
- script: docker pull starshipcommand/starship-test
|
||||||
displayName: Pull docker image
|
displayName: Pull docker image
|
||||||
|
|
||||||
- script: ./integration_test
|
- script: |
|
||||||
|
# In order to run tests as a non-root user in docker,
|
||||||
|
# the files need to be accessible to non-root users
|
||||||
|
chmod -R a+w .
|
||||||
|
./integration_test
|
||||||
displayName: Run integration test suite
|
displayName: Run integration test suite
|
||||||
|
|
||||||
- script: |
|
- script: |
|
||||||
|
@ -7,8 +7,10 @@ jobs:
|
|||||||
vmImage: ubuntu-16.04
|
vmImage: ubuntu-16.04
|
||||||
MacOS:
|
MacOS:
|
||||||
vmImage: macOS-10.13
|
vmImage: macOS-10.13
|
||||||
Windows:
|
# # Temporarily disabling Windows tests while I'm away
|
||||||
vmImage: vs2017-win2016
|
# # Will reenable Windows tests once I'm able to troubleshoot Windows bugs
|
||||||
|
# Windows:
|
||||||
|
# vmImage: vs2017-win2016
|
||||||
pool:
|
pool:
|
||||||
vmImage: $(vmImage)
|
vmImage: $(vmImage)
|
||||||
|
|
||||||
@ -19,5 +21,6 @@ jobs:
|
|||||||
|
|
||||||
- template: azure-setup-test-env.yml
|
- template: azure-setup-test-env.yml
|
||||||
|
|
||||||
- script: cargo test -- --ignored
|
# "-Z unstable-options" is required for "--include-ignored"
|
||||||
|
- script: cargo test -- -Z unstable-options --include-ignored
|
||||||
displayName: cargo test
|
displayName: cargo test
|
||||||
|
@ -13,4 +13,4 @@ docker build -f tests/Dockerfile \
|
|||||||
.
|
.
|
||||||
|
|
||||||
printf 'Running test suite:\n'
|
printf 'Running test suite:\n'
|
||||||
docker run --rm -v $(pwd):/starship starshipcommand/starship-test
|
docker run --rm -v $(pwd):/src/starship starshipcommand/starship-test
|
||||||
|
42
src/config.rs
Normal file
42
src/config.rs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
use crate::utils;
|
||||||
|
|
||||||
|
use dirs::home_dir;
|
||||||
|
|
||||||
|
pub struct Config {
|
||||||
|
data: toml::value::Table,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
/// Initialize the Config struct
|
||||||
|
pub fn initialize() -> Config {
|
||||||
|
if let Some(file_data) = Config::config_from_file() {
|
||||||
|
return Config { data: file_data };
|
||||||
|
}
|
||||||
|
|
||||||
|
Config {
|
||||||
|
data: toml::value::Table::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a config from a starship configuration file
|
||||||
|
fn config_from_file() -> Option<toml::value::Table> {
|
||||||
|
let file_path = home_dir()?.join(".config/starship.toml");
|
||||||
|
let toml_content = utils::read_file(&file_path.to_str()?).ok()?;
|
||||||
|
log::trace!("Config file content: \n{}", &toml_content);
|
||||||
|
|
||||||
|
let config = toml::from_str(&toml_content).ok()?;
|
||||||
|
log::debug!("Config found: \n{:?}", &config);
|
||||||
|
Some(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the subset of the table for a module by its name
|
||||||
|
pub fn get_module_config(&self, module_name: &str) -> Option<&toml::value::Table> {
|
||||||
|
let module_config = self
|
||||||
|
.data
|
||||||
|
.get(module_name)
|
||||||
|
.map(toml::Value::as_table)
|
||||||
|
.unwrap_or(None);
|
||||||
|
log::debug!("Config found for {}: {:?}", &module_name, &module_config);
|
||||||
|
module_config
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,6 @@
|
|||||||
|
use crate::config::Config;
|
||||||
|
use crate::module::Module;
|
||||||
|
|
||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
use git2::Repository;
|
use git2::Repository;
|
||||||
use std::env;
|
use std::env;
|
||||||
@ -6,6 +9,7 @@ use std::fs;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub struct Context<'a> {
|
pub struct Context<'a> {
|
||||||
|
pub config: Config,
|
||||||
pub current_dir: PathBuf,
|
pub current_dir: PathBuf,
|
||||||
pub dir_files: Vec<PathBuf>,
|
pub dir_files: Vec<PathBuf>,
|
||||||
pub arguments: ArgMatches<'a>,
|
pub arguments: ArgMatches<'a>,
|
||||||
@ -28,6 +32,8 @@ impl<'a> Context<'a> {
|
|||||||
where
|
where
|
||||||
T: Into<PathBuf>,
|
T: Into<PathBuf>,
|
||||||
{
|
{
|
||||||
|
let config = Config::initialize();
|
||||||
|
|
||||||
// TODO: Currently gets the physical directory. Get the logical directory.
|
// TODO: Currently gets the physical directory. Get the logical directory.
|
||||||
let current_dir = Context::expand_tilde(dir.into());
|
let current_dir = Context::expand_tilde(dir.into());
|
||||||
|
|
||||||
@ -51,6 +57,7 @@ impl<'a> Context<'a> {
|
|||||||
.and_then(|repo| get_current_branch(&repo));
|
.and_then(|repo| get_current_branch(&repo));
|
||||||
|
|
||||||
Context {
|
Context {
|
||||||
|
config,
|
||||||
arguments,
|
arguments,
|
||||||
current_dir,
|
current_dir,
|
||||||
dir_files,
|
dir_files,
|
||||||
@ -68,6 +75,10 @@ impl<'a> Context<'a> {
|
|||||||
dir
|
dir
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_module(&self, name: &str) -> Module {
|
||||||
|
Module::new(name, self.config.get_module_config(name))
|
||||||
|
}
|
||||||
|
|
||||||
// returns a new ScanDir struct with reference to current dir_files of context
|
// returns a new ScanDir struct with reference to current dir_files of context
|
||||||
// see ScanDir for methods
|
// see ScanDir for methods
|
||||||
pub fn new_scan_dir(&'a self) -> ScanDir<'a> {
|
pub fn new_scan_dir(&'a self) -> ScanDir<'a> {
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
// Lib is present to allow for benchmarking
|
// Lib is present to allow for benchmarking
|
||||||
|
mod config;
|
||||||
pub mod context;
|
pub mod context;
|
||||||
pub mod module;
|
pub mod module;
|
||||||
pub mod modules;
|
pub mod modules;
|
||||||
pub mod print;
|
pub mod print;
|
||||||
pub mod segment;
|
pub mod segment;
|
||||||
|
mod utils;
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate clap;
|
extern crate clap;
|
||||||
|
|
||||||
|
mod config;
|
||||||
mod context;
|
mod context;
|
||||||
mod module;
|
mod module;
|
||||||
mod modules;
|
mod modules;
|
||||||
mod print;
|
mod print;
|
||||||
mod segment;
|
mod segment;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
use clap::{App, Arg, SubCommand};
|
use clap::{App, Arg, SubCommand};
|
||||||
|
|
||||||
|
@ -6,7 +6,10 @@ use std::string::ToString;
|
|||||||
|
|
||||||
/// A module is a collection of segments showing data for a single integration
|
/// A module is a collection of segments showing data for a single integration
|
||||||
/// (e.g. The git module shows the current git branch and status)
|
/// (e.g. The git module shows the current git branch and status)
|
||||||
pub struct Module {
|
pub struct Module<'a> {
|
||||||
|
/// The module's configuration map if available
|
||||||
|
config: Option<&'a toml::value::Table>,
|
||||||
|
|
||||||
/// The module's name, to be used in configuration and logging.
|
/// The module's name, to be used in configuration and logging.
|
||||||
name: String,
|
name: String,
|
||||||
|
|
||||||
@ -23,10 +26,11 @@ pub struct Module {
|
|||||||
suffix: ModuleAffix,
|
suffix: ModuleAffix,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Module {
|
impl<'a> Module<'a> {
|
||||||
/// Creates a module with no segments.
|
/// Creates a module with no segments.
|
||||||
pub fn new(name: &str) -> Module {
|
pub fn new(name: &str, config: Option<&'a toml::value::Table>) -> Module<'a> {
|
||||||
Module {
|
Module {
|
||||||
|
config,
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
style: Style::default(),
|
style: Style::default(),
|
||||||
prefix: ModuleAffix::default_prefix(name.to_string()),
|
prefix: ModuleAffix::default_prefix(name.to_string()),
|
||||||
@ -42,7 +46,8 @@ impl Module {
|
|||||||
{
|
{
|
||||||
let mut segment = Segment::new(name);
|
let mut segment = Segment::new(name);
|
||||||
segment.set_style(self.style);
|
segment.set_style(self.style);
|
||||||
segment.set_value(value.into());
|
// Use the provided value unless overwritten by config
|
||||||
|
segment.set_value(self.config_value(name).unwrap_or_else(|| value.into()));
|
||||||
self.segments.push(segment);
|
self.segments.push(segment);
|
||||||
|
|
||||||
self.segments.last_mut().unwrap()
|
self.segments.last_mut().unwrap()
|
||||||
@ -66,7 +71,7 @@ impl Module {
|
|||||||
/// Sets the style of the segment.
|
/// Sets the style of the segment.
|
||||||
///
|
///
|
||||||
/// Accepts either `Color` or `Style`.
|
/// Accepts either `Color` or `Style`.
|
||||||
pub fn set_style<T>(&mut self, style: T) -> &mut Module
|
pub fn set_style<T>(&mut self, style: T) -> &mut Module<'a>
|
||||||
where
|
where
|
||||||
T: Into<Style>,
|
T: Into<Style>,
|
||||||
{
|
{
|
||||||
@ -80,8 +85,7 @@ impl Module {
|
|||||||
let mut ansi_strings = self
|
let mut ansi_strings = self
|
||||||
.segments
|
.segments
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| s.ansi_strings())
|
.map(|s| s.ansi_string())
|
||||||
.flat_map(|s| s.into_iter())
|
|
||||||
.collect::<Vec<ANSIString>>();
|
.collect::<Vec<ANSIString>>();
|
||||||
|
|
||||||
ansi_strings.insert(0, self.prefix.ansi_string());
|
ansi_strings.insert(0, self.prefix.ansi_string());
|
||||||
@ -93,9 +97,22 @@ impl Module {
|
|||||||
pub fn to_string_without_prefix(&self) -> String {
|
pub fn to_string_without_prefix(&self) -> String {
|
||||||
ANSIStrings(&self.ansi_strings()[1..]).to_string()
|
ANSIStrings(&self.ansi_strings()[1..]).to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a module's config value as a string
|
||||||
|
fn config_value(&self, key: &str) -> Option<String> {
|
||||||
|
self.config
|
||||||
|
// Find the config value by its key
|
||||||
|
.map(|config| config.get(key))
|
||||||
|
.unwrap_or(None)
|
||||||
|
// Get the config value as a `&str`
|
||||||
|
.map(toml::Value::as_str)
|
||||||
|
.unwrap_or(None)
|
||||||
|
// Convert it to a String
|
||||||
|
.map(str::to_string)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Module {
|
impl<'a> fmt::Display for Module<'a> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let ansi_strings = self.ansi_strings();
|
let ansi_strings = self.ansi_strings();
|
||||||
write!(f, "{}", ANSIStrings(&ansi_strings))
|
write!(f, "{}", ANSIStrings(&ansi_strings))
|
||||||
|
@ -3,7 +3,7 @@ use ansi_term::Color;
|
|||||||
use super::{Context, Module};
|
use super::{Context, Module};
|
||||||
|
|
||||||
/// Creates a segment for the battery percentage and charging state
|
/// Creates a segment for the battery percentage and charging state
|
||||||
pub fn segment(_context: &Context) -> Option<Module> {
|
pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||||
const BATTERY_FULL: &str = "•";
|
const BATTERY_FULL: &str = "•";
|
||||||
const BATTERY_CHARGING: &str = "⇡";
|
const BATTERY_CHARGING: &str = "⇡";
|
||||||
const BATTERY_DISCHARGING: &str = "⇣";
|
const BATTERY_DISCHARGING: &str = "⇣";
|
||||||
@ -22,7 +22,7 @@ pub fn segment(_context: &Context) -> Option<Module> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Set style based on percentage when threshold is modifiable
|
// TODO: Set style based on percentage when threshold is modifiable
|
||||||
let mut module = Module::new("battery");
|
let mut module = context.new_module("battery");
|
||||||
module.set_style(Color::Red.bold());
|
module.set_style(Color::Red.bold());
|
||||||
module.get_prefix().set_value("");
|
module.get_prefix().set_value("");
|
||||||
|
|
||||||
|
@ -9,12 +9,12 @@ use ansi_term::Color;
|
|||||||
/// (green by default)
|
/// (green by default)
|
||||||
/// - If the exit-code was anything else, the arrow will be formatted with
|
/// - If the exit-code was anything else, the arrow will be formatted with
|
||||||
/// `COLOR_FAILURE` (red by default)
|
/// `COLOR_FAILURE` (red by default)
|
||||||
pub fn segment(context: &Context) -> Option<Module> {
|
pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||||
const PROMPT_CHAR: &str = "➜";
|
const PROMPT_CHAR: &str = "➜";
|
||||||
let color_success = Color::Green.bold();
|
let color_success = Color::Green.bold();
|
||||||
let color_failure = Color::Red.bold();
|
let color_failure = Color::Red.bold();
|
||||||
|
|
||||||
let mut module = Module::new("char");
|
let mut module = context.new_module("char");
|
||||||
module.get_prefix().set_value("");
|
module.get_prefix().set_value("");
|
||||||
|
|
||||||
let symbol = module.new_segment("symbol", PROMPT_CHAR);
|
let symbol = module.new_segment("symbol", PROMPT_CHAR);
|
||||||
|
@ -12,12 +12,12 @@ use super::{Context, Module};
|
|||||||
///
|
///
|
||||||
/// **Truncation**
|
/// **Truncation**
|
||||||
/// Paths will be limited in length to `3` path components by default.
|
/// Paths will be limited in length to `3` path components by default.
|
||||||
pub fn segment(context: &Context) -> Option<Module> {
|
pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||||
const HOME_SYMBOL: &str = "~";
|
const HOME_SYMBOL: &str = "~";
|
||||||
const DIR_TRUNCATION_LENGTH: usize = 3;
|
const DIR_TRUNCATION_LENGTH: usize = 3;
|
||||||
let module_color = Color::Cyan.bold();
|
let module_color = Color::Cyan.bold();
|
||||||
|
|
||||||
let mut module = Module::new("directory");
|
let mut module = context.new_module("directory");
|
||||||
module.set_style(module_color);
|
module.set_style(module_color);
|
||||||
|
|
||||||
let current_dir = &context.current_dir;
|
let current_dir = &context.current_dir;
|
||||||
|
@ -5,13 +5,13 @@ use super::{Context, Module};
|
|||||||
/// Creates a segment with the Git branch in the current directory
|
/// Creates a segment with the Git branch in the current directory
|
||||||
///
|
///
|
||||||
/// Will display the branch name if the current directory is a git repo
|
/// Will display the branch name if the current directory is a git repo
|
||||||
pub fn segment(context: &Context) -> Option<Module> {
|
pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||||
let branch_name = context.branch_name.as_ref()?;
|
let branch_name = context.branch_name.as_ref()?;
|
||||||
|
|
||||||
const GIT_BRANCH_CHAR: &str = " ";
|
const GIT_BRANCH_CHAR: &str = " ";
|
||||||
let segment_color = Color::Purple.bold();
|
let segment_color = Color::Purple.bold();
|
||||||
|
|
||||||
let mut module = Module::new("git_branch");
|
let mut module = context.new_module("git_branch");
|
||||||
module.set_style(segment_color);
|
module.set_style(segment_color);
|
||||||
module.get_prefix().set_value("on ");
|
module.get_prefix().set_value("on ");
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ use super::{Context, Module};
|
|||||||
/// - `+` — A new file has been added to the staging area
|
/// - `+` — A new file has been added to the staging area
|
||||||
/// - `»` — A renamed file has been added to the staging area
|
/// - `»` — A renamed file has been added to the staging area
|
||||||
/// - `✘` — A file's deletion has been added to the staging area
|
/// - `✘` — A file's deletion has been added to the staging area
|
||||||
pub fn segment(context: &Context) -> Option<Module> {
|
pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||||
// This is the order that the sections will appear in
|
// This is the order that the sections will appear in
|
||||||
const GIT_STATUS_CONFLICTED: &str = "=";
|
const GIT_STATUS_CONFLICTED: &str = "=";
|
||||||
const GIT_STATUS_AHEAD: &str = "⇡";
|
const GIT_STATUS_AHEAD: &str = "⇡";
|
||||||
@ -35,7 +35,7 @@ pub fn segment(context: &Context) -> Option<Module> {
|
|||||||
let repository = Repository::open(repo_root).ok()?;
|
let repository = Repository::open(repo_root).ok()?;
|
||||||
|
|
||||||
let module_style = Color::Red.bold();
|
let module_style = Color::Red.bold();
|
||||||
let mut module = Module::new("git_status");
|
let mut module = context.new_module("git_status");
|
||||||
module.get_prefix().set_value("[").set_style(module_style);
|
module.get_prefix().set_value("[").set_style(module_style);
|
||||||
module.get_suffix().set_value("] ").set_style(module_style);
|
module.get_suffix().set_value("] ").set_style(module_style);
|
||||||
module.set_style(module_style);
|
module.set_style(module_style);
|
||||||
|
@ -13,7 +13,7 @@ use super::{Context, Module};
|
|||||||
/// - Current directory contains a `Gopkg.lock` file
|
/// - Current directory contains a `Gopkg.lock` file
|
||||||
/// - Current directory contains a `.go` file
|
/// - Current directory contains a `.go` file
|
||||||
/// - Current directory contains a `Godeps` directory
|
/// - Current directory contains a `Godeps` directory
|
||||||
pub fn segment(context: &Context) -> Option<Module> {
|
pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||||
let is_go_project = context
|
let is_go_project = context
|
||||||
.new_scan_dir()
|
.new_scan_dir()
|
||||||
.set_files(&["go.mod", "go.sum", "glide.yaml", "Gopkg.yml", "Gopkg.lock"])
|
.set_files(&["go.mod", "go.sum", "glide.yaml", "Gopkg.yml", "Gopkg.lock"])
|
||||||
@ -30,7 +30,7 @@ pub fn segment(context: &Context) -> Option<Module> {
|
|||||||
const GO_CHAR: &str = "🐹 ";
|
const GO_CHAR: &str = "🐹 ";
|
||||||
let module_color = Color::Cyan.bold();
|
let module_color = Color::Cyan.bold();
|
||||||
|
|
||||||
let mut module = Module::new("go");
|
let mut module = context.new_module("go");
|
||||||
module.set_style(module_color);
|
module.set_style(module_color);
|
||||||
|
|
||||||
let formatted_version = format_go_version(go_version)?;
|
let formatted_version = format_go_version(go_version)?;
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
use super::{Context, Module};
|
use super::{Context, Module};
|
||||||
|
|
||||||
/// Creates a segment for the line break
|
/// Creates a segment for the line break
|
||||||
pub fn segment(_context: &Context) -> Option<Module> {
|
pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||||
const LINE_ENDING: &str = "\n";
|
const LINE_ENDING: &str = "\n";
|
||||||
|
|
||||||
let mut module = Module::new("line_break");
|
let mut module = context.new_module("line_break");
|
||||||
|
|
||||||
module.get_prefix().set_value("");
|
module.get_prefix().set_value("");
|
||||||
module.get_suffix().set_value("");
|
module.get_suffix().set_value("");
|
||||||
|
@ -14,7 +14,7 @@ mod username;
|
|||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
use crate::module::Module;
|
use crate::module::Module;
|
||||||
|
|
||||||
pub fn handle(module: &str, context: &Context) -> Option<Module> {
|
pub fn handle<'a>(module: &str, context: &'a Context) -> Option<Module<'a>> {
|
||||||
match module {
|
match module {
|
||||||
"dir" | "directory" => directory::segment(context),
|
"dir" | "directory" => directory::segment(context),
|
||||||
"char" | "character" => character::segment(context),
|
"char" | "character" => character::segment(context),
|
||||||
|
@ -9,7 +9,7 @@ use super::{Context, Module};
|
|||||||
/// - Current directory contains a `.js` file
|
/// - Current directory contains a `.js` file
|
||||||
/// - Current directory contains a `package.json` file
|
/// - Current directory contains a `package.json` file
|
||||||
/// - Current directory contains a `node_modules` directory
|
/// - Current directory contains a `node_modules` directory
|
||||||
pub fn segment(context: &Context) -> Option<Module> {
|
pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||||
let is_js_project = context
|
let is_js_project = context
|
||||||
.new_scan_dir()
|
.new_scan_dir()
|
||||||
.set_files(&["package.json"])
|
.set_files(&["package.json"])
|
||||||
@ -26,7 +26,7 @@ pub fn segment(context: &Context) -> Option<Module> {
|
|||||||
const NODE_CHAR: &str = "⬢ ";
|
const NODE_CHAR: &str = "⬢ ";
|
||||||
let module_color = Color::Green.bold();
|
let module_color = Color::Green.bold();
|
||||||
|
|
||||||
let mut module = Module::new("node");
|
let mut module = context.new_module("node");
|
||||||
module.set_style(module_color);
|
module.set_style(module_color);
|
||||||
|
|
||||||
let formatted_version = node_version.trim();
|
let formatted_version = node_version.trim();
|
||||||
|
@ -1,23 +1,20 @@
|
|||||||
use super::{Context, Module};
|
use super::{Context, Module};
|
||||||
|
use crate::utils;
|
||||||
|
|
||||||
use ansi_term::Color;
|
use ansi_term::Color;
|
||||||
use serde_json;
|
use serde_json as json;
|
||||||
use std::fs::File;
|
|
||||||
use std::io;
|
|
||||||
use std::io::Read;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use toml;
|
use toml;
|
||||||
|
|
||||||
/// Creates a segment with the current package version
|
/// Creates a segment with the current package version
|
||||||
///
|
///
|
||||||
/// Will display if a version is defined for your Node.js or Rust project (if one exists)
|
/// Will display if a version is defined for your Node.js or Rust project (if one exists)
|
||||||
pub fn segment(context: &Context) -> Option<Module> {
|
pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||||
match get_package_version(context) {
|
match get_package_version() {
|
||||||
Some(package_version) => {
|
Some(package_version) => {
|
||||||
const PACKAGE_CHAR: &str = "📦 ";
|
const PACKAGE_CHAR: &str = "📦 ";
|
||||||
let module_color = Color::Red.bold();
|
let module_color = Color::Red.bold();
|
||||||
|
|
||||||
let mut module = Module::new("package");
|
let mut module = context.new_module("package");
|
||||||
module.set_style(module_color);
|
module.set_style(module_color);
|
||||||
module.get_prefix().set_value("is ");
|
module.get_prefix().set_value("is ");
|
||||||
|
|
||||||
@ -30,27 +27,8 @@ pub fn segment(context: &Context) -> Option<Module> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Combine into one function and just call for different file names!
|
|
||||||
fn is_cargo_toml(dir_entry: &PathBuf) -> bool {
|
|
||||||
dir_entry.is_file() && dir_entry.file_name().unwrap_or_default() == "Cargo.toml"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_package_json(dir_entry: &PathBuf) -> bool {
|
|
||||||
dir_entry.is_file() && dir_entry.file_name().unwrap_or_default() == "package.json"
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Move to `utils.rs` file and import
|
|
||||||
fn read_file(file_name: &str) -> io::Result<String> {
|
|
||||||
let mut file = File::open(file_name)?;
|
|
||||||
let mut data = String::new();
|
|
||||||
|
|
||||||
file.read_to_string(&mut data)?;
|
|
||||||
|
|
||||||
Ok(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extract_cargo_version(file_contents: &str) -> Option<String> {
|
fn extract_cargo_version(file_contents: &str) -> Option<String> {
|
||||||
let cargo_toml = file_contents.parse::<toml::Value>().ok()?;
|
let cargo_toml: toml::Value = toml::from_str(&file_contents).ok()?;
|
||||||
let raw_version = cargo_toml.get("package")?.get("version")?.as_str()?;
|
let raw_version = cargo_toml.get("package")?.get("version")?.as_str()?;
|
||||||
|
|
||||||
let formatted_version = format_version(raw_version);
|
let formatted_version = format_version(raw_version);
|
||||||
@ -58,7 +36,7 @@ fn extract_cargo_version(file_contents: &str) -> Option<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn extract_package_version(file_contents: &str) -> Option<String> {
|
fn extract_package_version(file_contents: &str) -> Option<String> {
|
||||||
let package_json: serde_json::Value = serde_json::from_str(&file_contents).ok()?;
|
let package_json: json::Value = json::from_str(&file_contents).ok()?;
|
||||||
let raw_version = package_json.get("version")?.as_str()?;
|
let raw_version = package_json.get("version")?.as_str()?;
|
||||||
if raw_version == "null" {
|
if raw_version == "null" {
|
||||||
return None;
|
return None;
|
||||||
@ -68,17 +46,15 @@ fn extract_package_version(file_contents: &str) -> Option<String> {
|
|||||||
Some(formatted_version)
|
Some(formatted_version)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_package_version(context: &Context) -> Option<String> {
|
fn get_package_version() -> Option<String> {
|
||||||
let has_cargo_toml = context.dir_files.iter().any(is_cargo_toml);
|
let cargo_toml = utils::read_file("Cargo.toml");
|
||||||
if has_cargo_toml {
|
if let Ok(cargo_toml) = cargo_toml {
|
||||||
let file_contents = read_file("Cargo.toml").ok()?;
|
return extract_cargo_version(&cargo_toml);
|
||||||
return extract_cargo_version(&file_contents);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let has_package_json = context.dir_files.iter().any(is_package_json);
|
let package_json = utils::read_file("package.json");
|
||||||
if has_package_json {
|
if let Ok(package_json) = package_json {
|
||||||
let file_contents = read_file("package.json").ok()?;
|
return extract_package_version(&package_json);
|
||||||
return extract_package_version(&file_contents);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
@ -99,15 +75,19 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_extract_cargo_version() {
|
fn test_extract_cargo_version() {
|
||||||
let cargo_with_version = "[package]
|
let cargo_with_version = r#"
|
||||||
name = \"starship\"
|
[package]
|
||||||
version = \"0.1.0\"";
|
name = "starship"
|
||||||
|
version = "0.1.0"
|
||||||
|
"#;
|
||||||
|
|
||||||
let expected_version = Some("v0.1.0".to_string());
|
let expected_version = Some("v0.1.0".to_string());
|
||||||
assert_eq!(extract_cargo_version(&cargo_with_version), expected_version);
|
assert_eq!(extract_cargo_version(&cargo_with_version), expected_version);
|
||||||
|
|
||||||
let cargo_without_version = "[package]
|
let cargo_without_version = r#"
|
||||||
name = \"starship\"";
|
[package]
|
||||||
|
name = "starship"
|
||||||
|
"#;
|
||||||
|
|
||||||
let expected_version = None;
|
let expected_version = None;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -118,7 +98,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_extract_package_version() {
|
fn test_extract_package_version() {
|
||||||
let package_with_version = serde_json::json!({
|
let package_with_version = json::json!({
|
||||||
"name": "spacefish",
|
"name": "spacefish",
|
||||||
"version": "0.1.0"
|
"version": "0.1.0"
|
||||||
})
|
})
|
||||||
@ -130,7 +110,7 @@ mod tests {
|
|||||||
expected_version
|
expected_version
|
||||||
);
|
);
|
||||||
|
|
||||||
let package_without_version = serde_json::json!({
|
let package_without_version = json::json!({
|
||||||
"name": "spacefish"
|
"name": "spacefish"
|
||||||
})
|
})
|
||||||
.to_string();
|
.to_string();
|
||||||
|
@ -10,15 +10,10 @@ use super::{Context, Module};
|
|||||||
/// - Current directory contains a `.python-version` file
|
/// - Current directory contains a `.python-version` file
|
||||||
/// - Current directory contains a `requirements.txt` file
|
/// - Current directory contains a `requirements.txt` file
|
||||||
/// - Current directory contains a `pyproject.toml` file
|
/// - Current directory contains a `pyproject.toml` file
|
||||||
pub fn segment(context: &Context) -> Option<Module> {
|
pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||||
let is_py_project = context
|
let is_py_project = context
|
||||||
.new_scan_dir()
|
.new_scan_dir()
|
||||||
.set_files(&[
|
.set_files(&["requirements.txt", ".python-version", "pyproject.toml"])
|
||||||
"requirements.txt",
|
|
||||||
".python-version",
|
|
||||||
"pyproject.toml",
|
|
||||||
"pyproject.toml",
|
|
||||||
])
|
|
||||||
.set_extensions(&["py"])
|
.set_extensions(&["py"])
|
||||||
.scan();
|
.scan();
|
||||||
|
|
||||||
@ -31,7 +26,7 @@ pub fn segment(context: &Context) -> Option<Module> {
|
|||||||
const PYTHON_CHAR: &str = "🐍 ";
|
const PYTHON_CHAR: &str = "🐍 ";
|
||||||
let module_color = Color::Yellow.bold();
|
let module_color = Color::Yellow.bold();
|
||||||
|
|
||||||
let mut module = Module::new("python");
|
let mut module = context.new_module("python");
|
||||||
module.set_style(module_color);
|
module.set_style(module_color);
|
||||||
|
|
||||||
let formatted_version = format_python_version(python_version);
|
let formatted_version = format_python_version(python_version);
|
||||||
|
@ -8,7 +8,7 @@ use super::{Context, Module};
|
|||||||
/// Will display the Rust version if any of the following criteria are met:
|
/// Will display the Rust version if any of the following criteria are met:
|
||||||
/// - Current directory contains a file with a `.rs` extension
|
/// - Current directory contains a file with a `.rs` extension
|
||||||
/// - Current directory contains a `Cargo.toml` file
|
/// - Current directory contains a `Cargo.toml` file
|
||||||
pub fn segment(context: &Context) -> Option<Module> {
|
pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||||
let is_rs_project = context
|
let is_rs_project = context
|
||||||
.new_scan_dir()
|
.new_scan_dir()
|
||||||
.set_files(&["Cargo.toml"])
|
.set_files(&["Cargo.toml"])
|
||||||
@ -24,7 +24,7 @@ pub fn segment(context: &Context) -> Option<Module> {
|
|||||||
const RUST_CHAR: &str = "🦀 ";
|
const RUST_CHAR: &str = "🦀 ";
|
||||||
let module_color = Color::Red.bold();
|
let module_color = Color::Red.bold();
|
||||||
|
|
||||||
let mut module = Module::new("rust");
|
let mut module = context.new_module("rust");
|
||||||
module.set_style(module_color);
|
module.set_style(module_color);
|
||||||
|
|
||||||
let formatted_version = format_rustc_version(rust_version);
|
let formatted_version = format_rustc_version(rust_version);
|
||||||
|
@ -10,7 +10,7 @@ use super::{Context, Module};
|
|||||||
/// - The current user isn't the same as the one that is logged in ($LOGNAME != $USER)
|
/// - The current user isn't the same as the one that is logged in ($LOGNAME != $USER)
|
||||||
/// - The current user is root (UID = 0)
|
/// - The current user is root (UID = 0)
|
||||||
/// - The user is currently connected as an SSH session ($SSH_CONNECTION)
|
/// - The user is currently connected as an SSH session ($SSH_CONNECTION)
|
||||||
pub fn segment(_context: &Context) -> Option<Module> {
|
pub fn segment<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||||
let user = env::var("USER").ok();
|
let user = env::var("USER").ok();
|
||||||
let logname = env::var("LOGNAME").ok();
|
let logname = env::var("LOGNAME").ok();
|
||||||
let ssh_connection = env::var("SSH_CONNECTION").ok();
|
let ssh_connection = env::var("SSH_CONNECTION").ok();
|
||||||
@ -18,7 +18,7 @@ pub fn segment(_context: &Context) -> Option<Module> {
|
|||||||
let mut module_color = Color::Yellow.bold();
|
let mut module_color = Color::Yellow.bold();
|
||||||
|
|
||||||
if user != logname || ssh_connection.is_some() || is_root(&mut module_color) {
|
if user != logname || ssh_connection.is_some() || is_root(&mut module_color) {
|
||||||
let mut module = Module::new("username");
|
let mut module = context.new_module("username");
|
||||||
module.set_style(module_color);
|
module.set_style(module_color);
|
||||||
module.new_segment("username", user?);
|
module.new_segment("username", user?);
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use ansi_term::{ANSIString, ANSIStrings, Style};
|
use ansi_term::{ANSIString, Style};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
/// A segment is a single configurable element in a module. This will usually
|
/// A segment is a single configurable element in a module. This will usually
|
||||||
@ -11,14 +11,8 @@ pub struct Segment {
|
|||||||
/// The segment's style. If None, will inherit the style of the module containing it.
|
/// The segment's style. If None, will inherit the style of the module containing it.
|
||||||
style: Option<Style>,
|
style: Option<Style>,
|
||||||
|
|
||||||
/// The prefix used to preceed the contents of a segment.
|
|
||||||
prefix: Option<SegmentAffix>,
|
|
||||||
|
|
||||||
/// The string value of the current segment.
|
/// The string value of the current segment.
|
||||||
value: String,
|
value: String,
|
||||||
|
|
||||||
/// The suffix used following the contents of a segment.
|
|
||||||
suffix: Option<SegmentAffix>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Segment {
|
impl Segment {
|
||||||
@ -27,9 +21,7 @@ impl Segment {
|
|||||||
Segment {
|
Segment {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
style: None,
|
style: None,
|
||||||
prefix: None,
|
|
||||||
value: "".to_string(),
|
value: "".to_string(),
|
||||||
suffix: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,59 +46,6 @@ impl Segment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns the ANSIString of the segment value, not including its prefix and suffix
|
// Returns the ANSIString of the segment value, not including its prefix and suffix
|
||||||
fn value_ansi_string(&self) -> ANSIString {
|
|
||||||
match self.style {
|
|
||||||
Some(style) => style.paint(&self.value),
|
|
||||||
None => ANSIString::from(&self.value),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a vector of colored ANSIString elements to be later used with
|
|
||||||
/// `ANSIStrings()` to optimize ANSI codes
|
|
||||||
pub fn ansi_strings(&self) -> Vec<ANSIString> {
|
|
||||||
let prefix = self.prefix.as_ref().and_then(|p| Some(p.ansi_string()));
|
|
||||||
let suffix = self.suffix.as_ref().and_then(|s| Some(s.ansi_string()));
|
|
||||||
let value = Some(self.value_ansi_string());
|
|
||||||
|
|
||||||
// Remove `None` values from the vector
|
|
||||||
vec![prefix, value, suffix]
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|e| e)
|
|
||||||
.collect::<Vec<ANSIString>>()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Segment {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
let ansi_strings = self.ansi_strings();
|
|
||||||
write!(f, "{}", ANSIStrings(&ansi_strings))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Segment affixes are to be used for the prefix or suffix of a segment.
|
|
||||||
/// By default they will inherit the styling of its segment, unless otherwise specified.
|
|
||||||
pub struct SegmentAffix {
|
|
||||||
/// The affix's name, to be used in configuration and logging.
|
|
||||||
name: String,
|
|
||||||
|
|
||||||
/// The affix's style. If None, will inherit the style of the segment containing it.
|
|
||||||
style: Option<Style>,
|
|
||||||
|
|
||||||
/// The string value of the affix.
|
|
||||||
value: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SegmentAffix {
|
|
||||||
/// Creates a segment affix with no contents.
|
|
||||||
pub fn new() -> SegmentAffix {
|
|
||||||
SegmentAffix {
|
|
||||||
name: String::new(),
|
|
||||||
style: None,
|
|
||||||
value: String::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Generates the colored ANSIString output.
|
|
||||||
pub fn ansi_string(&self) -> ANSIString {
|
pub fn ansi_string(&self) -> ANSIString {
|
||||||
match self.style {
|
match self.style {
|
||||||
Some(style) => style.paint(&self.value),
|
Some(style) => style.paint(&self.value),
|
||||||
@ -115,7 +54,7 @@ impl SegmentAffix {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for SegmentAffix {
|
impl fmt::Display for Segment {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{}", self.ansi_string())
|
write!(f, "{}", self.ansi_string())
|
||||||
}
|
}
|
||||||
|
11
src/utils.rs
Normal file
11
src/utils.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
use std::fs::File;
|
||||||
|
use std::io::{Read, Result};
|
||||||
|
|
||||||
|
/// Return the string contents of a file
|
||||||
|
pub fn read_file(file_name: &str) -> Result<String> {
|
||||||
|
let mut file = File::open(file_name)?;
|
||||||
|
let mut data = String::new();
|
||||||
|
|
||||||
|
file.read_to_string(&mut data)?;
|
||||||
|
Ok(data)
|
||||||
|
}
|
@ -1,36 +1,46 @@
|
|||||||
FROM rust
|
FROM rust
|
||||||
|
|
||||||
|
# Create /src as root
|
||||||
|
RUN mkdir /src && chmod -R a+w /src
|
||||||
|
|
||||||
|
# Create non-root user
|
||||||
|
RUN useradd -ms /bin/bash nonroot
|
||||||
|
USER nonroot
|
||||||
|
|
||||||
# Install Node.js
|
# Install Node.js
|
||||||
ENV NODE_VERSION 12.0.0
|
ENV NODE_VERSION 12.0.0
|
||||||
ENV PATH /root/.nvm/versions/node/v$NODE_VERSION/bin:$PATH
|
ENV NVM_DIR /home/nonroot/.nvm
|
||||||
|
ENV PATH $NVM_DIR/versions/node/v$NODE_VERSION/bin:$PATH
|
||||||
RUN curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash
|
RUN curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash
|
||||||
# Check that Node.js was correctly installed
|
# Check that Node.js was correctly installed
|
||||||
RUN node --version
|
RUN node --version
|
||||||
|
|
||||||
# Install Go
|
# Install Go
|
||||||
ENV GO_VERSION 1.10.0
|
ENV GO_VERSION 1.10.0
|
||||||
ENV GOENV_ROOT /root/.goenv
|
ENV GOENV_ROOT /home/nonroot/.goenv
|
||||||
ENV PATH $GOENV_ROOT/bin:$GOENV_ROOT/shims:$PATH
|
ENV PATH $GOENV_ROOT/bin:$GOENV_ROOT/shims:$PATH
|
||||||
RUN git clone https://github.com/syndbg/goenv.git $GOENV_ROOT \
|
RUN git clone https://github.com/syndbg/goenv.git $GOENV_ROOT \
|
||||||
&& eval "$(goenv init -)" \
|
&& eval "$(goenv init -)" \
|
||||||
&& goenv install $GO_VERSION \
|
&& goenv install $GO_VERSION \
|
||||||
&& goenv global $GO_VERSION
|
&& goenv global $GO_VERSION \
|
||||||
|
&& chmod -R a+x $GOENV_ROOT
|
||||||
# Check that Go was correctly installed
|
# Check that Go was correctly installed
|
||||||
RUN go version
|
RUN go version
|
||||||
|
|
||||||
# Install Python
|
# Install Python
|
||||||
ENV PYTHON_VERSION 3.6.8
|
ENV PYTHON_VERSION 3.6.8
|
||||||
ENV PYENV_ROOT /root/.pyenv
|
ENV PYENV_ROOT /home/nonroot/.pyenv
|
||||||
ENV PATH $PYENV_ROOT/bin:$PYENV_ROOT/shims:$PATH
|
ENV PATH $PYENV_ROOT/bin:$PYENV_ROOT/shims:$PATH
|
||||||
RUN curl https://pyenv.run | bash \
|
RUN curl https://pyenv.run | bash \
|
||||||
&& pyenv install $PYTHON_VERSION \
|
&& pyenv install $PYTHON_VERSION \
|
||||||
&& pyenv global $PYTHON_VERSION
|
&& pyenv global $PYTHON_VERSION \
|
||||||
|
&& chmod -R a+x $PYENV_ROOT
|
||||||
# Check that Python was correctly installed
|
# Check that Python was correctly installed
|
||||||
RUN python --version
|
RUN python --version
|
||||||
|
|
||||||
# Create blank project
|
# Create blank project
|
||||||
RUN USER=root cargo new --bin starship
|
RUN USER=nonroot cargo new --bin /src/starship
|
||||||
WORKDIR /starship
|
WORKDIR /src/starship
|
||||||
|
|
||||||
# We want dependencies cached, so copy those first
|
# We want dependencies cached, so copy those first
|
||||||
COPY ./Cargo.lock ./Cargo.lock
|
COPY ./Cargo.lock ./Cargo.lock
|
||||||
@ -41,13 +51,8 @@ RUN mkdir benches
|
|||||||
RUN touch benches/my_benchmark.rs
|
RUN touch benches/my_benchmark.rs
|
||||||
|
|
||||||
# This is a dummy build to get dependencies cached
|
# This is a dummy build to get dependencies cached
|
||||||
RUN cargo build --release
|
RUN cargo build --release \
|
||||||
|
&& rm -rf src target/debug/starship*
|
||||||
|
|
||||||
# Delete the dummy build
|
# "-Z unstable-options" is required for "--include-ignored"
|
||||||
RUN rm -rf /starship
|
CMD ["cargo", "test", "--", "-Z", "unstable-options", "--include-ignored"]
|
||||||
|
|
||||||
# Create the directory for the real source files
|
|
||||||
RUN mkdir starship
|
|
||||||
WORKDIR /starship
|
|
||||||
|
|
||||||
CMD ["cargo", "test", "--", "--ignored"]
|
|
||||||
|
@ -67,10 +67,10 @@ fn root_directory() -> io::Result<()> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn directory_in_root() -> io::Result<()> {
|
fn directory_in_root() -> io::Result<()> {
|
||||||
let output = common::render_module("dir").arg("--path=/tmp").output()?;
|
let output = common::render_module("dir").arg("--path=/usr").output()?;
|
||||||
let actual = String::from_utf8(output.stdout).unwrap();
|
let actual = String::from_utf8(output.stdout).unwrap();
|
||||||
|
|
||||||
let expected = format!("in {} ", Color::Cyan.bold().paint("/tmp"));
|
let expected = format!("in {} ", Color::Cyan.bold().paint("/usr"));
|
||||||
assert_eq!(expected, actual);
|
assert_eq!(expected, actual);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -7,31 +7,34 @@ use crate::common;
|
|||||||
// Requires mocking
|
// Requires mocking
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn no_username_shown() -> io::Result<()> {
|
fn no_env_variables() -> io::Result<()> {
|
||||||
let expected = "";
|
|
||||||
|
|
||||||
// No environment variables
|
|
||||||
let output = common::render_module("username").env_clear().output()?;
|
let output = common::render_module("username").env_clear().output()?;
|
||||||
let actual = String::from_utf8(output.stdout).unwrap();
|
let actual = String::from_utf8(output.stdout).unwrap();
|
||||||
assert_eq!(expected, actual);
|
assert_eq!("", actual);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
// LOGNAME == USER
|
#[test]
|
||||||
|
fn logname_equals_user() -> io::Result<()> {
|
||||||
let output = common::render_module("username")
|
let output = common::render_module("username")
|
||||||
.env_clear()
|
.env_clear()
|
||||||
.env("LOGNAME", "astronaut")
|
.env("LOGNAME", "astronaut")
|
||||||
.env("USER", "astronaut")
|
.env("USER", "astronaut")
|
||||||
.output()?;
|
.output()?;
|
||||||
let actual = String::from_utf8(output.stdout).unwrap();
|
let actual = String::from_utf8(output.stdout).unwrap();
|
||||||
assert_eq!(expected, actual);
|
assert_eq!("", actual);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ssh_wo_username() -> io::Result<()> {
|
||||||
// SSH connection w/o username
|
// SSH connection w/o username
|
||||||
let output = common::render_module("username")
|
let output = common::render_module("username")
|
||||||
.env_clear()
|
.env_clear()
|
||||||
.env("SSH_CONNECTION", "192.168.223.17 36673 192.168.223.229 22")
|
.env("SSH_CONNECTION", "192.168.223.17 36673 192.168.223.229 22")
|
||||||
.output()?;
|
.output()?;
|
||||||
let actual = String::from_utf8(output.stdout).unwrap();
|
let actual = String::from_utf8(output.stdout).unwrap();
|
||||||
assert_eq!(expected, actual);
|
assert_eq!("", actual);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user