Merge branch 'master' into conditional-style

This commit is contained in:
Filip Bachul 2022-11-28 23:10:22 +01:00
commit ba15c18c15
7 changed files with 621 additions and 100 deletions

View File

@ -41,7 +41,7 @@
"plugins": [
"https://github.com/dprint/dprint-plugin-typescript/releases/download/0.78.0/plugin.wasm",
"https://github.com/dprint/dprint-plugin-json/releases/download/0.16.0/plugin.wasm",
"https://github.com/dprint/dprint-plugin-markdown/releases/download/0.14.1/plugin.wasm",
"https://github.com/dprint/dprint-plugin-markdown/releases/download/0.14.2/plugin.wasm",
"https://github.com/dprint/dprint-plugin-toml/releases/download/0.5.4/plugin.wasm"
]
}

35
Cargo.lock generated
View File

@ -575,9 +575,9 @@ dependencies = [
[[package]]
name = "digest"
version = "0.10.3"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506"
checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
dependencies = [
"block-buffer 0.10.2",
"crypto-common",
@ -1031,9 +1031,9 @@ dependencies = [
[[package]]
name = "git-features"
version = "0.24.0"
version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d795b325f589a50a00d834ffe278b1cc1c11a667016ac71941bce13a260c4ba9"
checksum = "d7bdbe755d2129bc609437b6b18af1116f146128dda6070c15c0aa50201ac17c"
dependencies = [
"crc32fast",
"crossbeam-channel",
@ -1046,7 +1046,7 @@ dependencies = [
"parking_lot",
"prodash",
"quick-error",
"sha1 0.10.1",
"sha1 0.10.5",
"sha1_smol",
"walkdir",
]
@ -2101,7 +2101,7 @@ checksum = "57959b91f0a133f89a68be874a5c88ed689c19cd729ecdb5d762ebf16c64d662"
dependencies = [
"once_cell",
"pest",
"sha1 0.10.1",
"sha1 0.10.5",
]
[[package]]
@ -2268,9 +2268,9 @@ dependencies = [
[[package]]
name = "prodash"
version = "21.0.0"
version = "21.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d27f6a3ef883aaea624a6ad91c88452e5df05430a79fd880c12673a7bc1648d6"
checksum = "7e13d7bd38cdab08b3a8b780cedcc54238c84fdca4084eb188807b308bcf11e6"
dependencies = [
"bytesize",
"human_format",
@ -2632,17 +2632,6 @@ dependencies = [
"syn",
]
[[package]]
name = "sha-1"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f"
dependencies = [
"cfg-if 1.0.0",
"cpufeatures",
"digest 0.10.3",
]
[[package]]
name = "sha1"
version = "0.6.1"
@ -2654,13 +2643,13 @@ dependencies = [
[[package]]
name = "sha1"
version = "0.10.1"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c77f4e7f65455545c2153c1253d25056825e77ee2533f0e41deb65a93a34852f"
checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
dependencies = [
"cfg-if 1.0.0",
"cpufeatures",
"digest 0.10.3",
"digest 0.10.6",
"sha1-asm",
]
@ -2817,7 +2806,7 @@ dependencies = [
"semver 1.0.14",
"serde",
"serde_json",
"sha-1",
"sha1 0.10.5",
"shadow-rs",
"shell-words",
"starship-battery",

View File

@ -48,7 +48,7 @@ clap_complete = "4.0.6"
dirs-next = "2.0.0"
dunce = "1.0.3"
gethostname = "0.4.0"
git-features = { version = "0.24.0", optional = true }
git-features = { version = "0.24.1", optional = true }
# default feature restriction addresses https://github.com/starship/starship/issues/4251
git-repository = { version = "0.29.0", default-features = false, features = ["max-performance-safe"] }
indexmap = { version = "1.9.2", features = ["serde"] }
@ -73,7 +73,7 @@ rust-ini = "0.18.0"
semver = "1.0.14"
serde = { version = "1.0.147", features = ["derive"] }
serde_json = "1.0.89"
sha-1 = "0.10.0"
sha1 = "0.10.5"
shadow-rs = { version = "0.18.0", default-features = false }
# battery is optional (on by default) because the crate doesn't currently build for Termux
# see: https://github.com/svartalf/rust-battery/issues/33

View File

@ -439,7 +439,7 @@ Enterprise_Naming_Scheme-voidstars = 'void**'
## Azure
The `azure` module shows the current Azure Subscription. This is based on showing the name of the default subscription, as defined in the `~/.azure/azureProfile.json` file.
The `azure` module shows the current Azure Subscription. This is based on showing the name of the default subscription or the username, as defined in the `~/.azure/azureProfile.json` file.
### Options
@ -450,7 +450,9 @@ The `azure` module shows the current Azure Subscription. This is based on showin
| `style` | `'blue bold'` | The style used in the format. |
| `disabled` | `true` | Disables the `azure` module. |
### Example
### Examples
#### Display Subscription Name
```toml
# ~/.config/starship.toml
@ -462,6 +464,18 @@ symbol = 'ﴃ '
style = 'blue bold'
```
#### Display Username
```toml
# ~/.config/starship.toml
[azure]
disabled = false
format = "on [$symbol($username)]($style) "
symbol = "ﴃ "
style = "blue bold"
```
## Battery
The `battery` module shows how charged the device's battery is and its current charging status.

View File

@ -63,7 +63,7 @@ fn get_creds<'a>(context: &Context, config: &'a OnceCell<Option<Ini>>) -> Option
// Get the section for a given profile name in the config file.
fn get_profile_config<'a>(
config: &'a Ini,
profile: &Option<Profile>,
profile: Option<&Profile>,
) -> Option<&'a ini::Properties> {
match profile {
Some(profile) => config.section(Some(format!("profile {profile}"))),
@ -74,11 +74,11 @@ fn get_profile_config<'a>(
// Get the section for a given profile name in the credentials file.
fn get_profile_creds<'a>(
config: &'a Ini,
profile: &Option<Profile>,
profile: Option<&Profile>,
) -> Option<&'a ini::Properties> {
match profile {
None => config.section(Some("default")),
_ => config.section(profile.as_ref()),
_ => config.section(profile),
}
}
@ -88,7 +88,7 @@ fn get_aws_region_from_config(
aws_config: &AwsConfigFile,
) -> Option<Region> {
let config = get_config(context, aws_config)?;
let section = get_profile_config(config, aws_profile)?;
let section = get_profile_config(config, aws_profile.as_ref())?;
section.get("region").map(std::borrow::ToOwned::to_owned)
}
@ -118,7 +118,7 @@ fn get_aws_profile_and_region(
fn get_credentials_duration(
context: &Context,
aws_profile: &Option<String>,
aws_profile: Option<&Profile>,
aws_creds: &AwsCredsFile,
) -> Option<i64> {
let expiration_env_vars = ["AWS_SESSION_EXPIRATION", "AWSUME_EXPIRATION"];
@ -150,18 +150,35 @@ fn alias_name(name: Option<String>, aliases: &HashMap<String, &str>) -> Option<S
fn has_credential_process_or_sso(
context: &Context,
aws_profile: &Option<Profile>,
aws_profile: Option<&Profile>,
aws_config: &AwsConfigFile,
aws_creds: &AwsCredsFile,
) -> Option<bool> {
let config = get_config(context, aws_config)?;
let credentials = get_creds(context, aws_creds);
let section = get_profile_config(config, aws_profile)?;
Some(section.contains_key("credential_process") || section.contains_key("sso_start_url"))
let empty_section = ini::Properties::new();
// We use the aws_profile here because `get_profile_config()` treats None
// as "special" and falls back to the "[default]"; otherwise this tries
// to look up "[profile default]" which doesn't exist
let config_section = get_profile_config(config, aws_profile).or(Some(&empty_section))?;
let credential_section = match credentials {
Some(credentials) => get_profile_creds(credentials, aws_profile),
None => None,
};
Some(
config_section.contains_key("credential_process")
|| config_section.contains_key("sso_start_url")
|| credential_section?.contains_key("credential_process")
|| credential_section?.contains_key("sso_start_url"),
)
}
fn has_defined_credentials(
context: &Context,
aws_profile: &Option<Profile>,
aws_profile: Option<&Profile>,
aws_creds: &AwsCredsFile,
) -> Option<bool> {
let valid_env_vars = [
@ -197,14 +214,15 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
// only display if credential_process is defined or has valid credentials
if !config.force_display
&& !has_credential_process_or_sso(context, &aws_profile, &aws_config).unwrap_or(false)
&& !has_defined_credentials(context, &aws_profile, &aws_creds).unwrap_or(false)
&& !has_credential_process_or_sso(context, aws_profile.as_ref(), &aws_config, &aws_creds)
.unwrap_or(false)
&& !has_defined_credentials(context, aws_profile.as_ref(), &aws_creds).unwrap_or(false)
{
return None;
}
let duration = {
get_credentials_duration(context, &aws_profile, &aws_creds).map(|duration| {
get_credentials_duration(context, aws_profile.as_ref(), &aws_creds).map(|duration| {
if duration > 0 {
render_time((duration * 1000) as u128, false)
} else {
@ -899,6 +917,44 @@ credential_process = /opt/bin/awscreds-retriever
dir.close()
}
#[test]
fn credential_process_set_in_credentials() -> io::Result<()> {
let dir = tempfile::tempdir()?;
let config_path = dir.path().join("config");
let credential_path = dir.path().join("credentials");
let mut file = File::create(&config_path)?;
file.write_all(
"[default]
region = ap-northeast-2
"
.as_bytes(),
)?;
let mut file = File::create(&credential_path)?;
file.write_all(
"[default]
credential_process = /opt/bin/awscreds-for-tests
"
.as_bytes(),
)?;
let actual = ModuleRenderer::new("aws")
.env("AWS_CONFIG_FILE", config_path.to_string_lossy().as_ref())
.env(
"AWS_CREDENTIALS_FILE",
credential_path.to_string_lossy().as_ref(),
)
.collect();
let expected = Some(format!(
"on {}",
Color::Yellow.bold().paint("☁️ (ap-northeast-2) ")
));
assert_eq!(expected, actual);
dir.close()
}
#[test]
fn sso_set() -> io::Result<()> {
let dir = tempfile::tempdir()?;

View File

@ -1,15 +1,32 @@
use std::fs::File;
use std::io::{BufReader, Read};
use std::path::{Path, PathBuf};
use serde::{Deserialize, Serialize};
use std::fs;
use std::path::PathBuf;
use super::{Context, Module, ModuleConfig};
type JValue = serde_json::Value;
use crate::configs::azure::AzureConfig;
use crate::formatter::StringFormatter;
type SubscriptionName = String;
#[derive(Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
struct AzureProfile {
installation_id: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
subscriptions: Vec<Subscription>,
}
#[derive(Serialize, Deserialize, Clone)]
struct User {
name: String,
}
#[derive(Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
struct Subscription {
name: String,
user: User,
is_default: bool,
}
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
let mut module = context.new_module("azure");
@ -19,11 +36,14 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
return None;
};
let subscription_name: Option<SubscriptionName> = get_azure_subscription_name(context);
if subscription_name.is_none() {
log::info!("Could not find Azure subscription name");
let subscription: Option<Subscription> = get_azure_profile_info(context);
if subscription.is_none() {
log::info!("Could not find Subscriptions in azureProfile.json");
return None;
};
}
let subscription = subscription.unwrap();
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
formatter
@ -36,7 +56,8 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
_ => None,
})
.map(|variable| match variable {
"subscription" => Some(Ok(subscription_name.as_ref().unwrap())),
"subscription" => Some(Ok(&subscription.name)),
"username" => Some(Ok(&subscription.user.name)),
_ => None,
})
.parse(None, Some(context))
@ -53,24 +74,24 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
Some(module)
}
fn get_azure_subscription_name(context: &Context) -> Option<SubscriptionName> {
fn get_azure_profile_info(context: &Context) -> Option<Subscription> {
let mut config_path = get_config_file_location(context)?;
config_path.push("azureProfile.json");
let parsed_json = parse_json(&config_path)?;
let subscriptions = parsed_json.get("subscriptions")?.as_array()?;
let subscription_name = subscriptions.iter().find_map(|s| {
if s.get("isDefault")? == true {
Some(s.get("name")?.as_str()?.to_string())
} else {
None
let azure_profile = load_azure_profile(&config_path)?;
azure_profile
.subscriptions
.into_iter()
.find(|s| s.is_default)
}
});
if subscription_name.is_some() {
subscription_name
fn load_azure_profile(config_path: &PathBuf) -> Option<AzureProfile> {
let json_data = fs::read_to_string(config_path).ok()?;
let sanitized_json_data = json_data.strip_prefix('\u{feff}').unwrap_or(&json_data);
if let Ok(azure_profile) = serde_json::from_str::<AzureProfile>(sanitized_json_data) {
Some(azure_profile)
} else {
log::info!("Could not find subscription name");
log::info!("Failed to parse azure profile.");
None
}
}
@ -86,27 +107,9 @@ fn get_config_file_location(context: &Context) -> Option<PathBuf> {
})
}
fn parse_json(json_file_path: &Path) -> Option<JValue> {
let mut buffer: Vec<u8> = Vec::new();
let json_file = File::open(json_file_path).ok()?;
let mut reader = BufReader::new(json_file);
reader.read_to_end(&mut buffer).ok()?;
let bytes = buffer.as_mut_slice();
let decodedbuffer = bytes.strip_prefix(&[239, 187, 191]).unwrap_or(bytes);
if let Ok(parsed_json) = serde_json::from_slice(decodedbuffer) {
Some(parsed_json)
} else {
log::info!("Failed to parse json");
None
}
}
#[cfg(test)]
mod tests {
use crate::modules::azure::parse_json;
use crate::modules::azure::load_azure_profile;
use crate::test::ModuleRenderer;
use ini::Ini;
use nu_ansi_term::Color;
@ -154,6 +157,7 @@ mod tests {
"name": "user@domain.com",
"type": "user"
},
"isDefault": false,
"tenantId": "a4e1bb4b-5330-2d50-339d-b9674d3a87bc",
"environmentName": "AzureCloud",
"homeTenantId": "a4e1bb4b-5330-2d50-339d-b9674d3a87bc",
@ -194,6 +198,424 @@ mod tests {
dir.close()
}
#[test]
fn user_name_set_correctly() -> io::Result<()> {
let dir = tempfile::tempdir()?;
let azure_profile_contents = r#"{
"installationId": "3deacd2a-b9db-77e1-aa42-23e2f8dfffc3",
"subscriptions": [
{
"id": "f568c543-d12e-de0b-3d85-69843598b565",
"name": "Subscription 2",
"state": "Enabled",
"user": {
"name": "user@domain.com",
"type": "user"
},
"isDefault": false,
"tenantId": "0e8a15ec-b0f5-d355-7062-8ece54c59aee",
"environmentName": "AzureCloud",
"homeTenantId": "0e8a15ec-b0f5-d355-7062-8ece54c59aee",
"managedByTenants": []
},
{
"id": "d4442d26-ea6d-46c4-07cb-4f70b8ae5465",
"name": "Subscription 3",
"state": "Enabled",
"user": {
"name": "user@domain.com",
"type": "user"
},
"isDefault": false,
"tenantId": "a4e1bb4b-5330-2d50-339d-b9674d3a87bc",
"environmentName": "AzureCloud",
"homeTenantId": "a4e1bb4b-5330-2d50-339d-b9674d3a87bc",
"managedByTenants": []
},
{
"id": "f3935dc9-92b5-9a93-da7b-42c325d86939",
"name": "Subscription 1",
"state": "Enabled",
"user": {
"name": "user@domain.com",
"type": "user"
},
"isDefault": true,
"tenantId": "f0273a19-7779-e40a-00a1-53b8331b3bb6",
"environmentName": "AzureCloud",
"homeTenantId": "f0273a19-7779-e40a-00a1-53b8331b3bb6",
"managedByTenants": []
}
]
}
"#;
generate_test_config(&dir, azure_profile_contents)?;
let dir_path = &dir.path().to_string_lossy();
let actual = ModuleRenderer::new("azure")
.config(toml::toml! {
[azure]
format = "on [$symbol($username)]($style)"
disabled = false
})
.env("AZURE_CONFIG_DIR", dir_path.as_ref())
.collect();
let expected = Some(format!(
"on {}",
Color::Blue.bold().paint("ﴃ user@domain.com")
));
assert_eq!(actual, expected);
dir.close()
}
#[test]
fn subscription_name_empty() -> io::Result<()> {
let dir = tempfile::tempdir()?;
let azure_profile_contents = r#"{
"installationId": "3deacd2a-b9db-77e1-aa42-23e2f8dfffc3",
"subscriptions": [
{
"id": "f568c543-d12e-de0b-3d85-69843598b565",
"name": "Subscription 2",
"state": "Enabled",
"user": {
"name": "user@domain.com",
"type": "user"
},
"isDefault": false,
"tenantId": "0e8a15ec-b0f5-d355-7062-8ece54c59aee",
"environmentName": "AzureCloud",
"homeTenantId": "0e8a15ec-b0f5-d355-7062-8ece54c59aee",
"managedByTenants": []
},
{
"id": "d4442d26-ea6d-46c4-07cb-4f70b8ae5465",
"name": "Subscription 3",
"state": "Enabled",
"user": {
"name": "user@domain.com",
"type": "user"
},
"isDefault": false,
"tenantId": "a4e1bb4b-5330-2d50-339d-b9674d3a87bc",
"environmentName": "AzureCloud",
"homeTenantId": "a4e1bb4b-5330-2d50-339d-b9674d3a87bc",
"managedByTenants": []
},
{
"id": "f3935dc9-92b5-9a93-da7b-42c325d86939",
"name": "",
"state": "Enabled",
"user": {
"name": "user@domain.com",
"type": "user"
},
"isDefault": true,
"tenantId": "f0273a19-7779-e40a-00a1-53b8331b3bb6",
"environmentName": "AzureCloud",
"homeTenantId": "f0273a19-7779-e40a-00a1-53b8331b3bb6",
"managedByTenants": []
}
]
}
"#;
generate_test_config(&dir, azure_profile_contents)?;
let dir_path = &dir.path().to_string_lossy();
let actual = ModuleRenderer::new("azure")
.config(toml::toml! {
[azure]
format = "on [$symbol($subscription:$username)]($style)"
disabled = false
})
.env("AZURE_CONFIG_DIR", dir_path.as_ref())
.collect();
let expected = Some(format!(
"on {}",
Color::Blue.bold().paint("ﴃ :user@domain.com")
));
assert_eq!(actual, expected);
dir.close()
}
#[test]
fn user_name_empty() -> io::Result<()> {
let dir = tempfile::tempdir()?;
let azure_profile_contents = r#"{
"installationId": "3deacd2a-b9db-77e1-aa42-23e2f8dfffc3",
"subscriptions": [
{
"id": "f568c543-d12e-de0b-3d85-69843598b565",
"name": "Subscription 2",
"state": "Enabled",
"user": {
"name": "user@domain.com",
"type": "user"
},
"isDefault": false,
"tenantId": "0e8a15ec-b0f5-d355-7062-8ece54c59aee",
"environmentName": "AzureCloud",
"homeTenantId": "0e8a15ec-b0f5-d355-7062-8ece54c59aee",
"managedByTenants": []
},
{
"id": "d4442d26-ea6d-46c4-07cb-4f70b8ae5465",
"name": "Subscription 3",
"state": "Enabled",
"user": {
"name": "user@domain.com",
"type": "user"
},
"isDefault": false,
"tenantId": "a4e1bb4b-5330-2d50-339d-b9674d3a87bc",
"environmentName": "AzureCloud",
"homeTenantId": "a4e1bb4b-5330-2d50-339d-b9674d3a87bc",
"managedByTenants": []
},
{
"id": "f3935dc9-92b5-9a93-da7b-42c325d86939",
"name": "Subscription 1",
"state": "Enabled",
"user": {
"name": "",
"type": "user"
},
"isDefault": true,
"tenantId": "f0273a19-7779-e40a-00a1-53b8331b3bb6",
"environmentName": "AzureCloud",
"homeTenantId": "f0273a19-7779-e40a-00a1-53b8331b3bb6",
"managedByTenants": []
}
]
}
"#;
generate_test_config(&dir, azure_profile_contents)?;
let dir_path = &dir.path().to_string_lossy();
let actual = ModuleRenderer::new("azure")
.config(toml::toml! {
[azure]
format = "on [$symbol($subscription:$username)]($style)"
disabled = false
})
.env("AZURE_CONFIG_DIR", dir_path.as_ref())
.collect();
let expected = Some(format!(
"on {}",
Color::Blue.bold().paint("ﴃ Subscription 1:")
));
assert_eq!(actual, expected);
dir.close()
}
#[test]
fn user_name_missing_from_profile() -> io::Result<()> {
let dir = tempfile::tempdir()?;
let azure_profile_contents = r#"{
"installationId": "3deacd2a-b9db-77e1-aa42-23e2f8dfffc3",
"subscriptions": [
{
"id": "f568c543-d12e-de0b-3d85-69843598b565",
"name": "Subscription 2",
"state": "Enabled",
"user": {
"type": "user"
},
"isDefault": false,
"tenantId": "0e8a15ec-b0f5-d355-7062-8ece54c59aee",
"environmentName": "AzureCloud",
"homeTenantId": "0e8a15ec-b0f5-d355-7062-8ece54c59aee",
"managedByTenants": []
},
{
"id": "d4442d26-ea6d-46c4-07cb-4f70b8ae5465",
"name": "Subscription 3",
"state": "Enabled",
"user": {
"name": "user@domain.com",
"type": "user"
},
"isDefault": false,
"tenantId": "a4e1bb4b-5330-2d50-339d-b9674d3a87bc",
"environmentName": "AzureCloud",
"homeTenantId": "a4e1bb4b-5330-2d50-339d-b9674d3a87bc",
"managedByTenants": []
},
{
"id": "f3935dc9-92b5-9a93-da7b-42c325d86939",
"name": "Subscription 1",
"state": "Enabled",
"user": {
"name": "",
"type": "user"
},
"isDefault": true,
"tenantId": "f0273a19-7779-e40a-00a1-53b8331b3bb6",
"environmentName": "AzureCloud",
"homeTenantId": "f0273a19-7779-e40a-00a1-53b8331b3bb6",
"managedByTenants": []
}
]
}
"#;
generate_test_config(&dir, azure_profile_contents)?;
let dir_path = &dir.path().to_string_lossy();
let actual = ModuleRenderer::new("azure")
.config(toml::toml! {
[azure]
format = "on [$symbol($subscription:$username)]($style)"
disabled = false
})
.env("AZURE_CONFIG_DIR", dir_path.as_ref())
.collect();
let expected = None;
assert_eq!(actual, expected);
dir.close()
}
#[test]
fn subscription_name_missing_from_profile() -> io::Result<()> {
let dir = tempfile::tempdir()?;
let azure_profile_contents = r#"{
"installationId": "3deacd2a-b9db-77e1-aa42-23e2f8dfffc3",
"subscriptions": [
{
"id": "f568c543-d12e-de0b-3d85-69843598b565",
"name": "Subscription 2",
"state": "Enabled",
"user": {
"name": "user@domain.com",
"type": "user"
},
"isDefault": false,
"tenantId": "0e8a15ec-b0f5-d355-7062-8ece54c59aee",
"environmentName": "AzureCloud",
"homeTenantId": "0e8a15ec-b0f5-d355-7062-8ece54c59aee",
"managedByTenants": []
},
{
"id": "d4442d26-ea6d-46c4-07cb-4f70b8ae5465",
"name": "Subscription 3",
"state": "Enabled",
"user": {
"name": "user@domain.com",
"type": "user"
},
"isDefault": false,
"tenantId": "a4e1bb4b-5330-2d50-339d-b9674d3a87bc",
"environmentName": "AzureCloud",
"homeTenantId": "a4e1bb4b-5330-2d50-339d-b9674d3a87bc",
"managedByTenants": []
},
{
"id": "f3935dc9-92b5-9a93-da7b-42c325d86939",
"state": "Enabled",
"user": {
"name": "user@domain.com",
"type": "user"
},
"isDefault": true,
"tenantId": "f0273a19-7779-e40a-00a1-53b8331b3bb6",
"environmentName": "AzureCloud",
"homeTenantId": "f0273a19-7779-e40a-00a1-53b8331b3bb6",
"managedByTenants": []
}
]
}
"#;
generate_test_config(&dir, azure_profile_contents)?;
let dir_path = &dir.path().to_string_lossy();
let actual = ModuleRenderer::new("azure")
.config(toml::toml! {
[azure]
format = "on [$symbol($subscription:$username)]($style)"
disabled = false
})
.env("AZURE_CONFIG_DIR", dir_path.as_ref())
.collect();
let expected = None;
assert_eq!(actual, expected);
dir.close()
}
#[test]
fn subscription_name_and_username_found() -> io::Result<()> {
let dir = tempfile::tempdir()?;
let azure_profile_contents = r#"{
"installationId": "3deacd2a-b9db-77e1-aa42-23e2f8dfffc3",
"subscriptions": [
{
"id": "f568c543-d12e-de0b-3d85-69843598b565",
"name": "Subscription 2",
"state": "Enabled",
"user": {
"name": "user@domain.com",
"type": "user"
},
"isDefault": false,
"tenantId": "0e8a15ec-b0f5-d355-7062-8ece54c59aee",
"environmentName": "AzureCloud",
"homeTenantId": "0e8a15ec-b0f5-d355-7062-8ece54c59aee",
"managedByTenants": []
},
{
"id": "d4442d26-ea6d-46c4-07cb-4f70b8ae5465",
"name": "Subscription 3",
"state": "Enabled",
"user": {
"name": "user@domain.com",
"type": "user"
},
"isDefault": false,
"tenantId": "a4e1bb4b-5330-2d50-339d-b9674d3a87bc",
"environmentName": "AzureCloud",
"homeTenantId": "a4e1bb4b-5330-2d50-339d-b9674d3a87bc",
"managedByTenants": []
},
{
"id": "f3935dc9-92b5-9a93-da7b-42c325d86939",
"name": "Subscription 1",
"state": "Enabled",
"user": {
"name": "user@domain.com",
"type": "user"
},
"isDefault": true,
"tenantId": "f0273a19-7779-e40a-00a1-53b8331b3bb6",
"environmentName": "AzureCloud",
"homeTenantId": "f0273a19-7779-e40a-00a1-53b8331b3bb6",
"managedByTenants": []
}
]
}
"#;
generate_test_config(&dir, azure_profile_contents)?;
let dir_path = &dir.path().to_string_lossy();
let actual = ModuleRenderer::new("azure")
.config(toml::toml! {
[azure]
format = "on [$symbol($subscription:$username)]($style)"
disabled = false
})
.env("AZURE_CONFIG_DIR", dir_path.as_ref())
.collect();
let expected = Some(format!(
"on {}",
Color::Blue.bold().paint("ﴃ Subscription 1:user@domain.com")
));
assert_eq!(actual, expected);
dir.close()
}
#[test]
fn subscription_azure_profile_empty() -> io::Result<()> {
let dir = tempfile::tempdir()?;
@ -203,6 +625,7 @@ mod tests {
.with_section(Some("AzureCloud"))
.set("subscription", "f3935dc9-92b5-9a93-da7b-42c325d86939");
//let azure_profile_contents = "\u{feff}{\"installationId\": \"2652263e-40f8-11ed-ae3b-367ddada549c\", \"subscriptions\": []}";
let azure_profile_contents = r#"{
"installationId": "3deacd2a-b9db-77e1-aa42-23e2f8dfffc3",
"subscriptions": []
@ -223,6 +646,48 @@ mod tests {
dir.close()
}
#[test]
fn azure_profile_with_leading_char() -> io::Result<()> {
let dir = tempfile::tempdir()?;
let bom = vec![239, 187, 191];
let mut bom_str = String::from_utf8(bom).unwrap();
let json_str =
r#"{"installationId": "3deacd2a-b9db-77e1-aa42-23e2f8dfffc3", "subscriptions": []}"#;
bom_str.push_str(json_str);
let dir_path_no_bom = save_string_to_file(&dir, bom_str, String::from("bom.json"))?;
let sanitized_json = load_azure_profile(&dir_path_no_bom).unwrap();
assert_eq!(
sanitized_json.installation_id,
"3deacd2a-b9db-77e1-aa42-23e2f8dfffc3"
);
assert!(sanitized_json.subscriptions.is_empty());
dir.close()
}
#[test]
fn azure_profile_without_leading_char() -> io::Result<()> {
let dir = tempfile::tempdir()?;
let json_str =
r#"{"installationId": "3deacd2a-b9db-77e1-aa42-23e2f8dfffc3", "subscriptions": []}"#;
let dir_path_no_bom =
save_string_to_file(&dir, json_str.to_string(), String::from("bom.json"))?;
let sanitized_json = load_azure_profile(&dir_path_no_bom).unwrap();
assert_eq!(
sanitized_json.installation_id,
"3deacd2a-b9db-77e1-aa42-23e2f8dfffc3"
);
assert!(sanitized_json.subscriptions.is_empty());
dir.close()
}
#[test]
fn files_missing() -> io::Result<()> {
let dir = tempfile::tempdir()?;
@ -237,22 +702,6 @@ mod tests {
dir.close()
}
#[test]
fn json_parsing() -> io::Result<()> {
let dir = tempfile::tempdir()?;
let bom = vec![239, 187, 191];
let mut bom_str = String::from_utf8(bom).unwrap();
let json_str = r#"{"testKey": "testValue"}"#;
bom_str.push_str(json_str);
let dir_path_no_bom = save_string_to_file(&dir, bom_str, String::from("bom.json"))?;
let parsed_json = parse_json(&dir_path_no_bom).unwrap();
assert_eq!(parsed_json.get("testKey").unwrap(), "testValue");
dir.close()
}
fn save_string_to_file(
dir: &TempDir,
contents: String,

View File

@ -48,13 +48,14 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
}
});
Some(undistract_me(module, &config, elapsed))
Some(undistract_me(module, &config, context, elapsed))
}
#[cfg(not(feature = "notify"))]
fn undistract_me<'a, 'b>(
module: Module<'a>,
_config: &'b CmdDurationConfig,
_context: &'a Context,
_elapsed: u128,
) -> Module<'a> {
module
@ -64,12 +65,24 @@ fn undistract_me<'a, 'b>(
fn undistract_me<'a, 'b>(
module: Module<'a>,
config: &'b CmdDurationConfig,
context: &'a Context,
elapsed: u128,
) -> Module<'a> {
use notify_rust::{Notification, Timeout};
use nu_ansi_term::{unstyle, AnsiStrings};
if config.show_notifications && config.min_time_to_notify as u128 <= elapsed {
if cfg!(target_os = "linux") {
let in_graphical_session = ["DISPLAY", "WAYLAND_DISPLAY", "MIR_SOCKET"]
.iter()
.find_map(|&var| context.get_env(var).filter(|val| !val.is_empty()))
.is_some();
if !in_graphical_session {
return module;
};
}
let body = format!(
"Command execution {}",
unstyle(&AnsiStrings(&module.ansi_strings()))