summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/config/README.md39
-rw-r--r--src/configs/mod.rs1
-rw-r--r--src/configs/openstack.rs21
-rw-r--r--src/configs/starship_root.rs1
-rw-r--r--src/module.rs1
-rw-r--r--src/modules/mod.rs3
-rw-r--r--src/modules/openstack.rs144
7 files changed, 210 insertions, 0 deletions
diff --git a/docs/config/README.md b/docs/config/README.md
index 53d3f8a59..ef6a871af 100644
--- a/docs/config/README.md
+++ b/docs/config/README.md
@@ -223,6 +223,7 @@ $conda\
$memory_usage\
$aws\
$gcloud\
+$openstack\
$env_var\
$crystal\
$cmd_duration\
@@ -1786,6 +1787,44 @@ The module will be shown if any of the following conditions are met:
format = "via [🐪 $version]($style) "
```
+## OpenStack
+
+The `openstack` module shows the current OpenStack cloud and project. The module
+only active when the `OS_CLOUD` env var is set, in which case it will read
+`clouds.yaml` file from any of the [default locations](https://docs.openstack.org/python-openstackclient/latest/configuration/index.html#configuration-files).
+to fetch the current project in use.
+
+### Options
+
+| Option | Default | Description |
+| ---------------- | ------------------------------------------------ | --------------------------------------------------------------- |
+| `format` | `"on [$symbol$cloud(\\($project\\))]($style) "` | The format for the module. |
+| `symbol` | `"☁️ "` | The symbol used before displaying the current OpenStack cloud. |
+| `style` | `"bold yellow"` | The style for the module. |
+| `disabled` | `false` | Disables the `OpenStack` module. |
+
+### Variables
+
+| Variable | Example | Description |
+| -------- | ---------- | ------------------------------------ |
+| cloud | `corp` | The current OpenStack cloud |
+| project | `dev` | The current OpenStack project |
+| 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
+
+[openstack]
+format = "on [$symbol$cloud(\\($project\\))]($style) "
+style = "bold yellow"
+symbol = "☁️ "
+```
+
## Perl
The `perl` module shows the currently installed version of Perl.
diff --git a/src/configs/mod.rs b/src/configs/mod.rs
index 2643fe513..26770a426 100644
--- a/src/configs/mod.rs
+++ b/src/configs/mod.rs
@@ -32,6 +32,7 @@ pub mod nim;
pub mod nix_shell;
pub mod nodejs;
pub mod ocaml;
+pub mod openstack;
pub mod package;
pub mod perl;
pub mod php;
diff --git a/src/configs/openstack.rs b/src/configs/openstack.rs
new file mode 100644
index 000000000..0517fa4bd
--- /dev/null
+++ b/src/configs/openstack.rs
@@ -0,0 +1,21 @@
+use crate::config::{ModuleConfig, RootModuleConfig};
+use starship_module_config_derive::ModuleConfig;
+
+#[derive(Clone, ModuleConfig)]
+pub struct OspConfig<'a> {
+ pub format: &'a str,
+ pub symbol: &'a str,
+ pub style: &'a str,
+ pub disabled: bool,
+}
+
+impl<'a> RootModuleConfig<'a> for OspConfig<'a> {
+ fn new() -> Self {
+ OspConfig {
+ format: "on [$symbol$cloud(\\($project\\))]($style) ",
+ symbol: "☁️ ",
+ style: "bold yellow",
+ disabled: false,
+ }
+ }
+}
diff --git a/src/configs/starship_root.rs b/src/configs/starship_root.rs
index 99ad5b295..85171c9f6 100644
--- a/src/configs/starship_root.rs
+++ b/src/configs/starship_root.rs
@@ -56,6 +56,7 @@ pub const PROMPT_ORDER: &[&str] = &[
"memory_usage",
"aws",
"gcloud",
+ "openstack",
"env_var",
"crystal",
"cmd_duration",
diff --git a/src/module.rs b/src/module.rs
index fc20cf1f7..86d444052 100644
--- a/src/module.rs
+++ b/src/module.rs
@@ -43,6 +43,7 @@ pub const ALL_MODULES: &[&str] = &[
"nix_shell",
"nodejs",
"ocaml",
+ "openstack",
"package",
"perl",
"purescript",
diff --git a/src/modules/mod.rs b/src/modules/mod.rs
index 28cf2882b..7215f8b07 100644
--- a/src/modules/mod.rs
+++ b/src/modules/mod.rs
@@ -33,6 +33,7 @@ mod nim;
mod nix_shell;
mod nodejs;
mod ocaml;
+mod openstack;
mod package;
mod perl;
mod php;
@@ -99,6 +100,7 @@ pub fn handle<'a>(module: &str, context: &'a Context) -> Option<Module<'a>> {
"nix_shell" => nix_shell::module(context),
"nodejs" => nodejs::module(context),
"ocaml" => ocaml::module(context),
+ "openstack" => openstack::module(context),
"package" => package::module(context),
"perl" => perl::module(context),
"php" => php::module(context),
@@ -172,6 +174,7 @@ pub fn description(module: &str) -> &'static str {
"nix_shell" => "The nix-shell environment",
"nodejs" => "The currently installed version of NodeJS",
"ocaml" => "The currently installed version of OCaml",
+ "openstack" => "The current OpenStack cloud and project",
"package" => "The package version of the current directory's project",
"perl" => "The currently installed version of Perl",
"php" => "The currently installed version of PHP",
diff --git a/src/modules/openstack.rs b/src/modules/openstack.rs
new file mode 100644
index 000000000..be6c51257
--- /dev/null
+++ b/src/modules/openstack.rs
@@ -0,0 +1,144 @@
+use yaml_rust::YamlLoader;
+
+use super::{Context, Module, RootModuleConfig};
+
+use crate::configs::openstack::OspConfig;
+use crate::formatter::StringFormatter;
+use crate::utils;
+
+type Cloud = String;
+type Project = String;
+
+fn get_osp_project_from_config(context: &Context, osp_cloud: Option<&str>) -> Option<Project> {
+ // Attempt to follow OpenStack standards for clouds.yaml location:
+ // 1st = $PWD/clouds.yaml, 2nd = $HOME/.config/openstack/clouds.yaml, 3rd = /etc/openstack/clouds.yaml
+ let config = vec![
+ utils::read_file(context.get_env("PWD").unwrap() + "/clouds.yaml"),
+ utils::read_file(dirs_next::home_dir()?.join(".config/openstack/clouds.yaml")),
+ utils::read_file("/etc/openstack/clouds.yaml"),
+ ];
+ let clouds =
+ YamlLoader::load_from_str(&config.into_iter().find_map(Result::ok).unwrap()).ok()?;
+ let project = &clouds[0]["clouds"][osp_cloud.unwrap()]["auth"]["project_name"]
+ .as_str()
+ .unwrap_or("");
+ if project.is_empty() {
+ return None;
+ }
+ Some(project.to_string())
+}
+
+fn get_osp_cloud_and_project(context: &Context) -> (Option<Cloud>, Option<Project>) {
+ match (
+ context.get_env("OS_CLOUD"),
+ context.get_env("OS_PROJECT_NAME"),
+ ) {
+ (Some(p), Some(r)) => (Some(p), Some(r)),
+ (None, Some(r)) => (None, Some(r)),
+ (Some(ref p), None) => (
+ Some(p.to_owned()),
+ get_osp_project_from_config(context, Some(p)),
+ ),
+ (None, None) => (None, None),
+ }
+}
+
+pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
+ let mut module = context.new_module("openstack");
+ let config: OspConfig = OspConfig::try_load(module.config);
+
+ let (osp_cloud, osp_project) = get_osp_cloud_and_project(context);
+
+ osp_cloud.as_ref()?;
+
+ 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,
+ })
+ .map(|variable| match variable {
+ "cloud" => osp_cloud.as_ref().map(Ok),
+ "project" => osp_project.as_ref().map(Ok),
+ _ => None,
+ })
+ .parse(None)
+ });
+
+ module.set_segments(match parsed {
+ Ok(segments) => segments,
+ Err(error) => {
+ log::error!("Error in module `openstack`: \n{}", error);
+ return None;
+ }
+ });
+
+ Some(module)
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::test::ModuleRenderer;
+ use ansi_term::Color;
+ use std::fs::File;
+ use std::io::{self, Write};
+
+ #[test]
+ fn parse_valid_config() -> io::Result<()> {
+ let dir = tempfile::tempdir()?;
+ let config_path = dir.path().join("clouds.yaml");
+ let mut file = File::create(&config_path)?;
+ file.write_all(
+ b"---
+clouds:
+ corp:
+ auth:
+ auth_url: https://overcloud.example.com:13000/v3
+ project_name: testproject
+ identity_api_version: '3'
+ interface: public
+",
+ )?;
+ let actual = ModuleRenderer::new("openstack")
+ .env("PWD", dir.path().to_str().unwrap())
+ .env("OS_CLOUD", "corp")
+ .config(toml::toml! {
+ [openstack]
+ })
+ .collect();
+ let expected = Some(format!(
+ "on {} ",
+ Color::Yellow.bold().paint("☁️ corp(testproject)")
+ ));
+
+ assert_eq!(actual, expected);
+ dir.close()
+ }
+
+ #[test]
+ fn parse_broken_config() -> io::Result<()> {
+ let dir = tempfile::tempdir()?;
+ let config_path = dir.path().join("clouds.yaml");
+ let mut file = File::create(&config_path)?;
+ file.write_all(
+ b"---
+dummy_yaml
+",
+ )?;
+ let actual = ModuleRenderer::new("openstack")
+ .env("PWD", dir.path().to_str().unwrap())
+ .env("OS_CLOUD", "test")
+ .config(toml::toml! {
+ [openstack]
+ })
+ .collect();
+ let expected = Some(format!("on {} ", Color::Yellow.bold().paint("☁️ test")));
+
+ assert_eq!(actual, expected);
+ dir.close()
+ }
+}