diff --git a/.github/config-schema.json b/.github/config-schema.json index 5db474c49..52f23166e 100644 --- a/.github/config-schema.json +++ b/.github/config-schema.json @@ -774,6 +774,9 @@ "kubernetes": { "default": { "context_aliases": {}, + "detect_extensions": [], + "detect_files": [], + "detect_folders": [], "disabled": true, "format": "[$symbol$context( \\($namespace\\))]($style) in ", "style": "cyan bold", @@ -1033,6 +1036,7 @@ "default": { "disabled": false, "format": "via [$symbol($username@)$stack]($style) ", + "search_upwards": true, "style": "bold 5", "symbol": " ", "version_format": "v${raw}" @@ -3404,6 +3408,27 @@ "additionalProperties": { "type": "string" } + }, + "detect_extensions": { + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "detect_files": { + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "detect_folders": { + "default": [], + "type": "array", + "items": { + "type": "string" + } } } }, @@ -3913,6 +3938,10 @@ "disabled": { "default": false, "type": "boolean" + }, + "search_upwards": { + "default": true, + "type": "boolean" } } }, diff --git a/Cargo.lock b/Cargo.lock index f1234258e..89b331023 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -270,9 +270,9 @@ dependencies = [ [[package]] name = "clap" -version = "3.2.8" +version = "3.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190814073e85d238f31ff738fcb0bf6910cedeb73376c87cd69291028966fd83" +checksum = "69c5a7f9997be616e47f0577ee38c91decb33392c5be4866494f34cdf329a9aa" dependencies = [ "atty", "bitflags", @@ -1356,9 +1356,9 @@ dependencies = [ [[package]] name = "path-slash" -version = "0.1.4" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cacbb3c4ff353b534a67fb8d7524d00229da4cb1dc8c79f4db96e375ab5b619" +checksum = "c54014ba3c1880122928735226f78b6f5bf5bd1fed15e41e92cf7aa20278ce28" [[package]] name = "pathdiff" @@ -1730,9 +1730,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.5.6" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" dependencies = [ "aho-corasick", "memchr", @@ -1741,9 +1741,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.26" +version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" [[package]] name = "remove_dir_all" @@ -1841,18 +1841,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.138" +version = "1.0.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1578c6245786b9d168c5447eeacfb96856573ca56c9d68fdcf394be134882a47" +checksum = "0171ebb889e45aa68b44aee0859b3eede84c6f5f5c228e6f140c0b2a0a46cad6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.138" +version = "1.0.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "023e9b1467aef8a10fb88f25611870ada9800ef7e22afce356bb0d2387b6f27c" +checksum = "dc1d3230c1de7932af58ad8ffbe1d784bd55efd5a9d84ac24f69c72d83543dfb" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 209471278..5672c8c6a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ notify = ["notify-rust"] [dependencies] ansi_term = "0.12.1" chrono = "0.4.19" -clap = { version = "=3.2.8", features = ["derive", "cargo", "unicode", "unstable-v4"] } +clap = { version = "=3.2.10", features = ["derive", "cargo", "unicode", "unstable-v4"] } clap_complete = "3.2.3" dirs-next = "2.0.0" dunce = "1.0.2" @@ -53,16 +53,16 @@ notify-rust = { version = "4.5.8", optional = true } once_cell = "1.13.0" open = "3.0.1" os_info = "3.4.0" -path-slash = "0.1.4" +path-slash = "0.2.0" pest = "2.1.3" pest_derive = "2.1.0" quick-xml = "0.23.0" rand = "0.8.5" rayon = "1.5.3" -regex = "1.5.6" +regex = "1.6.0" rust-ini = "0.18.0" semver = "1.0.12" -serde = { version = "1.0.138", features = ["derive"] } +serde = { version = "1.0.139", features = ["derive"] } serde_json = "1.0.82" sha-1 = "0.10.0" shadow-rs = "0.12.0" diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.ts similarity index 98% rename from docs/.vuepress/config.js rename to docs/.vuepress/config.ts index 0a425f5d5..c35f9ddf1 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.ts @@ -1,4 +1,6 @@ -const sidebar = (lang, override = {}) => +import { defineConfig, SidebarConfigArray } from "vuepress/config"; + +const sidebar = (lang, override = {}): SidebarConfigArray => [ "", // "Home", which should always have a override "guide", // README, which should always have a override @@ -23,7 +25,7 @@ const sidebar = (lang, override = {}) => return page in override ? [path, override[page]] : path; }); -module.exports = { +module.exports = defineConfig({ locales: { "/": { lang: "en-US", @@ -331,11 +333,11 @@ module.exports = { }, ], [ - "sitemap", + "vuepress-plugin-sitemap", { hostname: "https://starship.rs", }, ], ["vuepress-plugin-code-copy", true], ], -}; +}); diff --git a/docs/.vuepress/public/presets/toml/pastel-powerline.toml b/docs/.vuepress/public/presets/toml/pastel-powerline.toml index 9503dc69c..88103ae7b 100644 --- a/docs/.vuepress/public/presets/toml/pastel-powerline.toml +++ b/docs/.vuepress/public/presets/toml/pastel-powerline.toml @@ -56,69 +56,69 @@ truncation_symbol = "…/" [c] symbol = " " style = "bg:#86BBD8" -format = '[[ $symbol ($version) ](bg:#86BBD8)]($style)' +format = '[ $symbol ($version) ]($style)' [docker_context] symbol = " " style = "bg:#06969A" -format = '[[ $symbol $context ](bg:#06969A)]($style) $path' +format = '[ $symbol $context ]($style) $path' [elixir] symbol = " " style = "bg:#86BBD8" -format = '[[ $symbol ($version) ](bg:#86BBD8)]($style)' +format = '[ $symbol ($version) ]($style)' [elm] symbol = " " style = "bg:#86BBD8" -format = '[[ $symbol ($version) ](bg:#86BBD8)]($style)' +format = '[ $symbol ($version) ]($style)' [git_branch] symbol = "" style = "bg:#FCA17D" -format = '[[ $symbol $branch ](bg:#FCA17D)]($style)' +format = '[ $symbol $branch ]($style)' [git_status] style = "bg:#FCA17D" -format = '[[($all_status$ahead_behind )](bg:#FCA17D)]($style)' +format = '[$all_status$ahead_behind ]($style)' [golang] symbol = " " style = "bg:#86BBD8" -format = '[[ $symbol ($version) ](bg:#86BBD8)]($style)' +format = '[ $symbol ($version) ]($style)' [haskell] symbol = " " style = "bg:#86BBD8" -format = '[[ $symbol ($version) ](bg:#86BBD8)]($style)' +format = '[ $symbol ($version) ]($style)' [java] symbol = " " style = "bg:#86BBD8" -format = '[[ $symbol ($version) ](bg:#86BBD8)]($style)' +format = '[ $symbol ($version) ]($style)' [julia] symbol = " " style = "bg:#86BBD8" -format = '[[ $symbol ($version) ](bg:#86BBD8)]($style)' +format = '[ $symbol ($version) ]($style)' [nodejs] symbol = "" style = "bg:#86BBD8" -format = '[[ $symbol ($version) ](bg:#86BBD8)]($style)' +format = '[ $symbol ($version) ]($style)' [nim] symbol = " " style = "bg:#86BBD8" -format = '[[ $symbol ($version) ](bg:#86BBD8)]($style)' +format = '[ $symbol ($version) ]($style)' [rust] symbol = "" style = "bg:#86BBD8" -format = '[[ $symbol ($version) ](bg:#86BBD8)]($style)' +format = '[ $symbol ($version) ]($style)' [time] disabled = false time_format = "%R" # Hour:Minute Format style = "bg:#33658A" -format = '[[ ♥ $time ](bg:#33658A)]($style)' +format = '[ ♥ $time ]($style)' diff --git a/docs/config/README.md b/docs/config/README.md index 77c1927c6..7316b86dd 100644 --- a/docs/config/README.md +++ b/docs/config/README.md @@ -2084,18 +2084,25 @@ If the `$KUBECONFIG` env var is set the module will use that if not it will use This module is disabled by default. To enable it, set `disabled` to `false` in your configuration file. +When the module is enabled it will always be active, unless any of +`detect_extensions`, `detect_files` or `detect_folders` have been st in which +case the module will only be active in directories that match those conditions. + ::: ### Options -| Option | Default | Description | -| ----------------- | -------------------------------------------------- | --------------------------------------------------------------------- | -| `symbol` | `"☸ "` | A format string representing the symbol displayed before the Cluster. | -| `format` | `'[$symbol$context( \($namespace\))]($style) in '` | The format for the module. | -| `style` | `"cyan bold"` | The style for the module. | -| `context_aliases` | | Table of context aliases to display. | -| `user_aliases` | | Table of user aliases to display. | -| `disabled` | `true` | Disables the `kubernetes` module. | +| Option | Default | Description | +| ------------------- | -------------------------------------------------- | --------------------------------------------------------------------- | +| `symbol` | `"☸ "` | A format string representing the symbol displayed before the Cluster. | +| `format` | `'[$symbol$context( \($namespace\))]($style) in '` | The format for the module. | +| `style` | `"cyan bold"` | The style for the module. | +| `context_aliases` | | Table of context aliases to display. | +| `user_aliases` | | Table of user aliases to display. | +| `detect_extensions` | `[]` | Which extensions should trigger this module. | +| `detect_files` | `[]` | Which filenames should trigger this module. | +| `detect_folders` | `[]` | Which folders should trigger this modules. | +| `disabled` | `true` | Disables the `kubernetes` module. | ### Variables @@ -2127,6 +2134,16 @@ disabled = false "root/.*" = "root" ``` +Only show the module in directories that contain a `k8s` file. + +```toml +# ~/.config/starship.toml + +[kubernetes] +disabled = false +detect_files = ['k8s'] +``` + #### Regex Matching Additional to simple aliasing, `context_aliases` and `user_aliases` also supports @@ -2700,7 +2717,7 @@ If you still want to enable it, [follow the example shown below](#with-pulumi-ve By default the module will be shown if any of the following conditions are met: - The current directory contains either `Pulumi.yaml` or `Pulumi.yml` -- A parent directory contains either `Pulumi.yaml` or `Pulumi.yml` +- A parent directory contains either `Pulumi.yaml` or `Pulumi.yml` unless `search_upwards` is set to `false` ### Options @@ -2710,6 +2727,7 @@ By default the module will be shown if any of the following conditions are met: | `version_format` | `"v${raw}"` | The version format. Available vars are `raw`, `major`, `minor`, & `patch` | | `symbol` | `" "` | A format string shown before the Pulumi stack. | | `style` | `"bold 5"` | The style for the module. | +| `search_upwards` | `true` | Enable discovery of pulumi config files in parent directories. | | `disabled` | `false` | Disables the `pulumi` module. | ### Variables diff --git a/src/configs/kubernetes.rs b/src/configs/kubernetes.rs index 8e7362ea5..fde9add5b 100644 --- a/src/configs/kubernetes.rs +++ b/src/configs/kubernetes.rs @@ -11,6 +11,9 @@ pub struct KubernetesConfig<'a> { pub disabled: bool, pub context_aliases: HashMap, pub user_aliases: HashMap, + pub detect_extensions: Vec<&'a str>, + pub detect_files: Vec<&'a str>, + pub detect_folders: Vec<&'a str>, } impl<'a> Default for KubernetesConfig<'a> { @@ -22,6 +25,9 @@ impl<'a> Default for KubernetesConfig<'a> { disabled: true, context_aliases: HashMap::new(), user_aliases: HashMap::new(), + detect_extensions: vec![], + detect_files: vec![], + detect_folders: vec![], } } } diff --git a/src/configs/pulumi.rs b/src/configs/pulumi.rs index d372c900e..043cdab02 100644 --- a/src/configs/pulumi.rs +++ b/src/configs/pulumi.rs @@ -9,6 +9,7 @@ pub struct PulumiConfig<'a> { pub symbol: &'a str, pub style: &'a str, pub disabled: bool, + pub search_upwards: bool, } impl<'a> Default for PulumiConfig<'a> { @@ -19,6 +20,7 @@ impl<'a> Default for PulumiConfig<'a> { symbol: " ", style: "bold 5", disabled: false, + search_upwards: true, } } } diff --git a/src/modules/custom.rs b/src/modules/custom.rs index 7daea110f..56790f662 100644 --- a/src/modules/custom.rs +++ b/src/modules/custom.rs @@ -34,6 +34,8 @@ pub fn module<'a>(name: &str, context: &'a Context) -> Option> { } } + let mut module = Module::new(name, config.description, Some(toml_config)); + let mut is_match = context .try_begin_scan()? .set_extensions(&config.detect_extensions) @@ -46,46 +48,42 @@ pub fn module<'a>(name: &str, context: &'a Context) -> Option> { Either::First(b) => b, Either::Second(s) => exec_when(s, &config, context), }; - - if !is_match { - return None; - } } - let mut module = Module::new(name, config.description, Some(toml_config)); + if is_match { + let parsed = StringFormatter::new(config.format).and_then(|formatter| { + formatter + .map_meta(|var, _| match var { + "symbol" => Some(config.symbol), + _ => None, + }) + .map_style(|variable| match variable { + "style" => Some(Ok(config.style)), + _ => None, + }) + .map_no_escaping(|variable| match variable { + "output" => { + let output = exec_command(config.command, context, &config)?; + let trimmed = output.trim(); - let parsed = StringFormatter::new(config.format).and_then(|formatter| { - formatter - .map_meta(|var, _| match var { - "symbol" => Some(config.symbol), - _ => None, - }) - .map_style(|variable| match variable { - "style" => Some(Ok(config.style)), - _ => None, - }) - .map_no_escaping(|variable| match variable { - "output" => { - let output = exec_command(config.command, context, &config)?; - let trimmed = output.trim(); - - if trimmed.is_empty() { - None - } else { - Some(Ok(trimmed.to_string())) + if trimmed.is_empty() { + None + } else { + Some(Ok(trimmed.to_string())) + } } - } - _ => None, - }) - .parse(None, Some(context)) - }); + _ => None, + }) + .parse(None, Some(context)) + }); - match parsed { - Ok(segments) => module.set_segments(segments), - Err(error) => { - log::warn!("Error in module `custom.{}`:\n{}", name, error); - } - }; + match parsed { + Ok(segments) => module.set_segments(segments), + Err(error) => { + log::warn!("Error in module `custom.{}`:\n{}", name, error); + } + }; + } let elapsed = start.elapsed(); log::trace!("Took {:?} to compute custom module {:?}", elapsed, name); module.duration = elapsed; diff --git a/src/modules/directory.rs b/src/modules/directory.rs index 1238208d6..344be7d9b 100644 --- a/src/modules/directory.rs +++ b/src/modules/directory.rs @@ -6,6 +6,7 @@ use super::utils::path::PathExt as SPathExt; use crate::conditional_style::get_conditional_style; use indexmap::IndexMap; use path_slash::{PathBufExt, PathExt}; +use std::borrow::Cow; use std::iter::FromIterator; use std::path::{Path, PathBuf}; use unicode_segmentation::UnicodeSegmentation; @@ -64,8 +65,8 @@ pub fn module<'a>(context: &'a Context) -> Option> { let mut is_truncated = dir_string.is_some(); // the home directory if required. - let dir_string = - dir_string.unwrap_or_else(|| contract_path(display_dir, &home_dir, &home_symbol)); + let dir_string = dir_string + .unwrap_or_else(|| contract_path(display_dir, &home_dir, &home_symbol).to_string()); #[cfg(windows)] let dir_string = remove_extended_path_prefix(dir_string); @@ -90,7 +91,7 @@ pub fn module<'a>(context: &'a Context) -> Option> { let contracted_home_dir = contract_path(display_dir, &home_dir, &home_symbol); to_fish_style( config.fish_style_pwd_dir_length as usize, - contracted_home_dir, + contracted_home_dir.to_string(), &dir_string, ) } else { @@ -206,13 +207,17 @@ fn is_readonly_dir(path: &Path) -> bool { /// /// Replaces the `top_level_path` in a given `full_path` with the provided /// `top_level_replacement`. -fn contract_path(full_path: &Path, top_level_path: &Path, top_level_replacement: &str) -> String { +fn contract_path<'a>( + full_path: &'a Path, + top_level_path: &'a Path, + top_level_replacement: &'a str, +) -> Cow<'a, str> { if !full_path.normalised_starts_with(top_level_path) { return full_path.to_slash_lossy(); } if full_path.normalised_equals(top_level_path) { - return top_level_replacement.to_string(); + return Cow::from(top_level_replacement); } // Because we've done a normalised path comparison above @@ -223,12 +228,12 @@ fn contract_path(full_path: &Path, top_level_path: &Path, top_level_replacement: .strip_prefix(top_level_path.without_prefix()) .unwrap_or(full_path); - format!( + Cow::from(format!( "{replacement}{separator}{path}", replacement = top_level_replacement, separator = "/", path = sub_path.to_slash_lossy() - ) + )) } /// Contract the root component of a path based on the real path @@ -426,7 +431,7 @@ mod tests { let top_level_path = Path::new("C:\\Users\\astronaut"); let output = contract_path(full_path, top_level_path, "~"); - assert_eq!(output, "C:"); + assert_eq!(output, "C:/"); } #[test] @@ -791,7 +796,7 @@ mod tests { }) .path(&dir) .collect(); - let dir_str = dir.to_slash_lossy(); + let dir_str = dir.to_slash_lossy().to_string(); let expected = Some(format!( "{} ", Color::Cyan.bold().paint(convert_path_sep( @@ -821,7 +826,7 @@ mod tests { "{} ", Color::Cyan.bold().paint(convert_path_sep(&to_fish_style( 100, - dir.to_slash_lossy(), + dir.to_slash_lossy().to_string(), "" ))) )); @@ -872,7 +877,7 @@ mod tests { "{} ", Color::Cyan.bold().paint(convert_path_sep(&format!( "{}/thrusters/rocket", - to_fish_style(1, dir.to_slash_lossy(), "/thrusters/rocket") + to_fish_style(1, dir.to_slash_lossy().to_string(), "/thrusters/rocket") ))) )); @@ -994,7 +999,7 @@ mod tests { "{} ", Color::Cyan.bold().paint(convert_path_sep(&format!( "{}/above-repo/rocket-controls/src/meters/fuel-gauge", - to_fish_style(1, tmp_dir.path().to_slash_lossy(), "") + to_fish_style(1, tmp_dir.path().to_slash_lossy().to_string(), "") ))) )); @@ -1025,7 +1030,15 @@ mod tests { "{} ", Color::Cyan.bold().paint(convert_path_sep(&format!( "{}/rocket-controls/src/meters/fuel-gauge", - to_fish_style(1, tmp_dir.path().join("above-repo").to_slash_lossy(), "") + to_fish_style( + 1, + tmp_dir + .path() + .join("above-repo") + .to_slash_lossy() + .to_string(), + "" + ) ))) )); @@ -1200,7 +1213,7 @@ mod tests { "{} ", Color::Cyan.bold().paint(convert_path_sep(&format!( "{}/above-repo/rocket-controls-symlink/src/meters/fuel-gauge", - to_fish_style(1, tmp_dir.path().to_slash_lossy(), "") + to_fish_style(1, tmp_dir.path().to_slash_lossy().to_string(), "") ))) )); @@ -1237,7 +1250,15 @@ mod tests { "{} ", Color::Cyan.bold().paint(convert_path_sep(&format!( "{}/rocket-controls-symlink/src/meters/fuel-gauge", - to_fish_style(1, tmp_dir.path().join("above-repo").to_slash_lossy(), "") + to_fish_style( + 1, + tmp_dir + .path() + .join("above-repo") + .to_slash_lossy() + .to_string(), + "" + ) ))) )); diff --git a/src/modules/kubernetes.rs b/src/modules/kubernetes.rs index d5aa48b40..a8449a20c 100644 --- a/src/modules/kubernetes.rs +++ b/src/modules/kubernetes.rs @@ -119,6 +119,23 @@ pub fn module<'a>(context: &'a Context) -> Option> { return None; }; + // If we have some config for doing the directory scan then we use it but if we don't then we + // assume we should treat it like the module is enabled to preserve backward compatability. + let have_scan_config = !(config.detect_files.is_empty() + && config.detect_folders.is_empty() + && config.detect_extensions.is_empty()); + + let is_kube_project = context + .try_begin_scan()? + .set_files(&config.detect_files) + .set_folders(&config.detect_folders) + .set_extensions(&config.detect_extensions) + .is_match(); + + if have_scan_config && !is_kube_project { + return None; + } + let default_config_file = context.get_home()?.join(".kube").join("config"); let kube_cfg = context @@ -197,7 +214,7 @@ mod tests { use crate::test::ModuleRenderer; use ansi_term::Color; use std::env; - use std::fs::File; + use std::fs::{create_dir, File}; use std::io::{self, Write}; #[test] @@ -234,6 +251,128 @@ users: [] dir.close() } + #[test] + fn test_none_when_no_detected_files_or_folders() -> io::Result<()> { + let dir = tempfile::tempdir()?; + + let filename = dir.path().join("config"); + + let mut file = File::create(&filename)?; + file.write_all( + b" +apiVersion: v1 +clusters: [] +contexts: + - context: + cluster: test_cluster + user: test_user + name: test_context +current-context: test_context +kind: Config +preferences: {} +users: [] +", + )?; + file.sync_all()?; + + let actual = ModuleRenderer::new("kubernetes") + .path(dir.path()) + .env("KUBECONFIG", filename.to_string_lossy().as_ref()) + .config(toml::toml! { + [kubernetes] + disabled = false + detect_files = ["k8s.ext"] + detect_extensions = ["k8s"] + detect_folders = ["k8s_folder"] + }) + .collect(); + + assert_eq!(None, actual); + + dir.close() + } + + #[test] + fn test_with_detected_files_and_folder() -> io::Result<()> { + let dir = tempfile::tempdir()?; + + let filename = dir.path().join("config"); + + let mut file = File::create(&filename)?; + file.write_all( + b" +apiVersion: v1 +clusters: [] +contexts: + - context: + cluster: test_cluster + user: test_user + name: test_context +current-context: test_context +kind: Config +preferences: {} +users: [] +", + )?; + file.sync_all()?; + + let dir_with_file = tempfile::tempdir()?; + File::create(dir_with_file.path().join("k8s.ext"))?.sync_all()?; + + let actual_file = ModuleRenderer::new("kubernetes") + .path(dir_with_file.path()) + .env("KUBECONFIG", filename.to_string_lossy().as_ref()) + .config(toml::toml! { + [kubernetes] + disabled = false + detect_files = ["k8s.ext"] + detect_extensions = ["k8s"] + detect_folders = ["k8s_folder"] + }) + .collect(); + + let dir_with_ext = tempfile::tempdir()?; + File::create(dir_with_ext.path().join("test.k8s"))?.sync_all()?; + + let actual_ext = ModuleRenderer::new("kubernetes") + .path(dir_with_ext.path()) + .env("KUBECONFIG", filename.to_string_lossy().as_ref()) + .config(toml::toml! { + [kubernetes] + disabled = false + detect_files = ["k8s.ext"] + detect_extensions = ["k8s"] + detect_folders = ["k8s_folder"] + }) + .collect(); + + let dir_with_dir = tempfile::tempdir()?; + create_dir(dir_with_dir.path().join("k8s_folder"))?; + + let actual_dir = ModuleRenderer::new("kubernetes") + .path(dir_with_dir.path()) + .env("KUBECONFIG", filename.to_string_lossy().as_ref()) + .config(toml::toml! { + [kubernetes] + disabled = false + detect_files = ["k8s.ext"] + detect_extensions = ["k8s"] + detect_folders = ["k8s_folder"] + }) + .collect(); + + let expected = Some(format!( + "{} in ", + Color::Cyan.bold().paint("☸ test_context") + )); + + assert_eq!(expected, actual_file); + assert_eq!(expected, actual_ext); + assert_eq!(expected, actual_dir); + + dir.close() + } + fn base_test_ctx_alias(ctx_name: &str, config: toml::Value, expected: &str) -> io::Result<()> { let dir = tempfile::tempdir()?; diff --git a/src/modules/pulumi.rs b/src/modules/pulumi.rs index 63ef63520..5b2f975d4 100644 --- a/src/modules/pulumi.rs +++ b/src/modules/pulumi.rs @@ -31,6 +31,15 @@ pub fn module<'a>(context: &'a Context) -> Option> { let mut module = context.new_module("pulumi"); let config = PulumiConfig::try_load(module.config); + let project_file_in_cwd = context + .try_begin_scan()? + .set_files(&["Pulumi.yaml", "Pulumi.yml"]) + .is_match(); + + if !project_file_in_cwd && !config.search_upwards { + return None; + } + let project_file = find_package_file(&context.logical_dir)?; let parsed = StringFormatter::new(config.format).and_then(|formatter| { @@ -409,4 +418,47 @@ mod tests { dir.close()?; Ok(()) } + + #[test] + fn do_not_search_upwards() -> io::Result<()> { + let dir = tempfile::tempdir()?; + let child_dir = dir.path().join("child"); + std::fs::create_dir(&child_dir)?; + let yaml = File::create(dir.path().join("Pulumi.yaml"))?; + yaml.sync_all()?; + + let actual = ModuleRenderer::new("pulumi") + .path(&child_dir) + .logical_path(&child_dir) + .config(toml::toml! { + [pulumi] + format = "in [$symbol($stack)]($style) " + search_upwards = false + }) + .collect(); + let expected = None; + assert_eq!(expected, actual); + dir.close() + } + + #[test] + fn search_upwards_default() -> io::Result<()> { + let dir = tempfile::tempdir()?; + let child_dir = dir.path().join("child"); + std::fs::create_dir(&child_dir)?; + let yaml = File::create(dir.path().join("Pulumi.yaml"))?; + yaml.sync_all()?; + + let actual = ModuleRenderer::new("pulumi") + .path(&child_dir) + .logical_path(&child_dir) + .config(toml::toml! { + [pulumi] + format = "in [$symbol($stack)]($style) " + }) + .collect(); + let expected = Some(format!("in {} ", Color::Fixed(5).bold().paint(" "))); + assert_eq!(expected, actual); + dir.close() + } }