feat(module): Add `sudo` module (#3135)
* add feature - sudo module * add sudo module identifiers and entry point * fix test test_sudo_not_cached * add test test_sudo_cached * add `allow_windows` and `binary` options * rustfmt sudo_x_cached and rmv them on windows * add false `allow_windows` block windows test * add `doas` cached/not_cached tests * better description in `starship explain` * fix `test_doas_cached` with `-n` flag Co-authored-by: David Knaack <davidkna@users.noreply.github.com> * rmv `binary` alternatives and their tests * fix symbol and update config/README * fix all mocks to use `sudo -n true` * fix expected output in `test_sudo_cached` * proper checking for blocked sudo Co-authored-by: David Knaack <davidkna@users.noreply.github.com> * add `allow_windows = true` to non-windows tests * allow sudo_* tests to run on windows + fix parsed * rustfmt `blocks_windows` test Co-authored-by: David Knaack <davidkna@users.noreply.github.com>
This commit is contained in:
parent
c3e33ea1c7
commit
779e53cd66
|
@ -243,6 +243,7 @@ $openstack\
|
|||
$env_var\
|
||||
$crystal\
|
||||
$custom\
|
||||
$sudo\
|
||||
$cmd_duration\
|
||||
$line_break\
|
||||
$jobs\
|
||||
|
@ -2947,6 +2948,58 @@ disabled = false
|
|||
|
||||
```
|
||||
|
||||
## Sudo
|
||||
|
||||
The `sudo` module displays if sudo credentials are currently cached.
|
||||
The module will only be shown if credentials are cached.
|
||||
|
||||
::: tip
|
||||
|
||||
This module is disabled by default.
|
||||
To enable it, set `disabled` to `false` in your configuration file.
|
||||
|
||||
:::
|
||||
|
||||
### Options
|
||||
|
||||
| Option | Default | Description |
|
||||
| -------------- | ----------------------- | ------------------------------------------------------------ |
|
||||
| `format` | `[as $symbol]($style)"` | The format of the module |
|
||||
| `symbol` | `"🧙 "` | The symbol displayed when credentials are cached |
|
||||
| `style` | `"bold blue"` | The style for the module. |
|
||||
| `allow_windows`| `false` | Since windows has no default sudo, default is disabled. |
|
||||
| `disabled` | `true` | Disables the `sudo` module. |
|
||||
|
||||
### Variables
|
||||
|
||||
| Variable | Example | Description |
|
||||
| --------- | ------- | ------------------------------------ |
|
||||
| symbol | | Mirrors the value of option `symbol` |
|
||||
| style\* | | Mirrors the value of option `style` |
|
||||
|
||||
\*: This variable can only be used as a part of a style string
|
||||
|
||||
### Example
|
||||
|
||||
```toml
|
||||
|
||||
# ~/.config/starship.toml
|
||||
|
||||
[sudo]
|
||||
style = "bold green"
|
||||
symbol = "👩💻 "
|
||||
disabled = false
|
||||
```
|
||||
|
||||
```toml
|
||||
# On windows
|
||||
# $HOME\.starship\config.toml
|
||||
|
||||
[sudo]
|
||||
allow_windows = true
|
||||
disabled = false
|
||||
```
|
||||
|
||||
## Swift
|
||||
|
||||
By default the `swift` module shows the currently installed version of [Swift](https://swift.org/).
|
||||
|
|
|
@ -226,6 +226,9 @@ format = '\[[$symbol($version)]($style)\]'
|
|||
[scala]
|
||||
format = '\[[$symbol($version)]($style)\]'
|
||||
|
||||
[sudo]
|
||||
format = '\[[as $symbol]\]
|
||||
|
||||
[swift]
|
||||
format = '\[[$symbol($version)]($style)\]'
|
||||
|
||||
|
@ -375,6 +378,9 @@ symbol = "rs "
|
|||
[scala]
|
||||
symbol = "scala "
|
||||
|
||||
[sudo]
|
||||
symbol = "sudo "
|
||||
|
||||
[swift]
|
||||
symbol = "swift "
|
||||
```
|
||||
|
|
|
@ -61,6 +61,7 @@ pub mod shlvl;
|
|||
pub mod singularity;
|
||||
mod starship_root;
|
||||
pub mod status;
|
||||
pub mod sudo;
|
||||
pub mod swift;
|
||||
pub mod terraform;
|
||||
pub mod time;
|
||||
|
@ -138,6 +139,7 @@ pub struct FullConfig<'a> {
|
|||
shlvl: shlvl::ShLvlConfig<'a>,
|
||||
singularity: singularity::SingularityConfig<'a>,
|
||||
status: status::StatusConfig<'a>,
|
||||
sudo: sudo::SudoConfig<'a>,
|
||||
swift: swift::SwiftConfig<'a>,
|
||||
terraform: terraform::TerraformConfig<'a>,
|
||||
time: time::TimeConfig<'a>,
|
||||
|
@ -214,6 +216,7 @@ impl<'a> Default for FullConfig<'a> {
|
|||
shlvl: Default::default(),
|
||||
singularity: Default::default(),
|
||||
status: Default::default(),
|
||||
sudo: Default::default(),
|
||||
swift: Default::default(),
|
||||
terraform: Default::default(),
|
||||
time: Default::default(),
|
||||
|
|
|
@ -76,6 +76,7 @@ pub const PROMPT_ORDER: &[&str] = &[
|
|||
"env_var",
|
||||
"crystal",
|
||||
"custom",
|
||||
"sudo",
|
||||
"cmd_duration",
|
||||
"line_break",
|
||||
"jobs",
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
use crate::config::ModuleConfig;
|
||||
|
||||
use serde::Serialize;
|
||||
use starship_module_config_derive::ModuleConfig;
|
||||
|
||||
#[derive(Clone, ModuleConfig, Serialize)]
|
||||
pub struct SudoConfig<'a> {
|
||||
pub format: &'a str,
|
||||
pub symbol: &'a str,
|
||||
pub style: &'a str,
|
||||
pub allow_windows: bool,
|
||||
pub disabled: bool,
|
||||
}
|
||||
|
||||
impl<'a> Default for SudoConfig<'a> {
|
||||
fn default() -> Self {
|
||||
SudoConfig {
|
||||
format: "[as $symbol]($style)",
|
||||
symbol: "🧙 ",
|
||||
style: "bold blue",
|
||||
allow_windows: false,
|
||||
disabled: true,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -65,6 +65,7 @@ pub const ALL_MODULES: &[&str] = &[
|
|||
"shlvl",
|
||||
"singularity",
|
||||
"status",
|
||||
"sudo",
|
||||
"swift",
|
||||
"terraform",
|
||||
"time",
|
||||
|
|
|
@ -55,6 +55,7 @@ mod shell;
|
|||
mod shlvl;
|
||||
mod singularity;
|
||||
mod status;
|
||||
mod sudo;
|
||||
mod swift;
|
||||
mod terraform;
|
||||
mod time;
|
||||
|
@ -139,6 +140,7 @@ pub fn handle<'a>(module: &str, context: &'a Context) -> Option<Module<'a>> {
|
|||
"singularity" => singularity::module(context),
|
||||
"swift" => swift::module(context),
|
||||
"status" => status::module(context),
|
||||
"sudo" => sudo::module(context),
|
||||
"terraform" => terraform::module(context),
|
||||
"time" => time::module(context),
|
||||
"crystal" => crystal::module(context),
|
||||
|
@ -226,6 +228,7 @@ pub fn description(module: &str) -> &'static str {
|
|||
"shlvl" => "The current value of SHLVL",
|
||||
"singularity" => "The currently used Singularity image",
|
||||
"status" => "The status of the last command",
|
||||
"sudo" => "The sudo credentials are currently cached",
|
||||
"swift" => "The currently installed version of Swift",
|
||||
"terraform" => "The currently selected terraform workspace and version",
|
||||
"time" => "The current local time",
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
use std::env;
|
||||
|
||||
use super::{Context, Module, RootModuleConfig};
|
||||
|
||||
use crate::configs::sudo::SudoConfig;
|
||||
use crate::formatter::StringFormatter;
|
||||
|
||||
/// Creates a module with sudo credential cache status
|
||||
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||
let mut module = context.new_module("sudo");
|
||||
let config = SudoConfig::try_load(module.config);
|
||||
|
||||
if config.disabled {
|
||||
return None;
|
||||
}
|
||||
|
||||
if !config.allow_windows && env::consts::FAMILY == "windows" {
|
||||
return None;
|
||||
}
|
||||
|
||||
let is_sudo_cached = context.exec_cmd("sudo", &["-n", "true"]).is_some();
|
||||
|
||||
if !is_sudo_cached {
|
||||
return None;
|
||||
}
|
||||
|
||||
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
|
||||
formatter
|
||||
.map_meta(|variable, _| match variable {
|
||||
"symbol" => Some(config.symbol),
|
||||
_ => None,
|
||||
})
|
||||
.map_style(|variable| match variable {
|
||||
"style" => Some(Ok(config.style)),
|
||||
_ => None,
|
||||
})
|
||||
.parse(None, Some(context))
|
||||
});
|
||||
|
||||
module.set_segments(match parsed {
|
||||
Ok(segments) => segments,
|
||||
Err(error) => {
|
||||
log::warn!("Error in module `sudo`:\n{}", error);
|
||||
return None;
|
||||
}
|
||||
});
|
||||
|
||||
Some(module)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{test::ModuleRenderer, utils::CommandOutput};
|
||||
use ansi_term::Color;
|
||||
|
||||
#[test]
|
||||
fn test_sudo_not_cached() {
|
||||
let actual = ModuleRenderer::new("sudo")
|
||||
.cmd("sudo -n true", None)
|
||||
.config(toml::toml! {
|
||||
[sudo]
|
||||
disabled = false
|
||||
allow_windows = true
|
||||
})
|
||||
.collect();
|
||||
let expected = None;
|
||||
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sudo_cached() {
|
||||
let actual = ModuleRenderer::new("sudo")
|
||||
.cmd(
|
||||
"sudo -n true",
|
||||
Some(CommandOutput {
|
||||
stdout: "".to_owned(),
|
||||
stderr: "".to_owned(),
|
||||
}),
|
||||
)
|
||||
.config(toml::toml! {
|
||||
[sudo]
|
||||
disabled = false
|
||||
allow_windows = true
|
||||
})
|
||||
.collect();
|
||||
let expected = Some(format!("{}", Color::Blue.bold().paint("as 🧙 ")));
|
||||
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(windows)]
|
||||
fn test_allow_windows_disabled_blocks_windows() {
|
||||
let actual = ModuleRenderer::new("sudo")
|
||||
.cmd(
|
||||
"sudo -n true",
|
||||
Some(CommandOutput {
|
||||
stdout: "".to_owned(),
|
||||
stderr: "".to_owned(),
|
||||
}),
|
||||
)
|
||||
.config(toml::toml! {
|
||||
[sudo]
|
||||
disabled = false
|
||||
allow_windows = false
|
||||
})
|
||||
.collect();
|
||||
let expected = None;
|
||||
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue