use std::collections::HashMap;
use std::path::PathBuf;
use std::str::FromStr;
use chrono::DateTime;
use ini::Ini;
use once_cell::unsync::OnceCell;
use super::{Context, Module, ModuleConfig};
use crate::configs::aws::AwsConfig;
use crate::formatter::StringFormatter;
use crate::utils::render_time;
type Profile = String;
type Region = String;
type AwsConfigFile = OnceCell<Option<Ini>>;
type AwsCredsFile = OnceCell<Option<Ini>>;
fn get_credentials_file_path(context: &Context) -> Option<PathBuf> {
context
.get_env("AWS_SHARED_CREDENTIALS_FILE")
.or_else(|| context.get_env("AWS_CREDENTIALS_FILE"))
.and_then(|path| PathBuf::from_str(&path).ok())
.or_else(|| {
let mut home = context.get_home()?;
home.push(".aws/credentials");
Some(home)
})
}
fn get_config_file_path(context: &Context) -> Option<PathBuf> {
context
.get_env("AWS_CONFIG_FILE")
.and_then(|path| PathBuf::from_str(&path).ok())
.or_else(|| {
let mut home = context.get_home()?;
home.push(".aws/config");
Some(home)
})
}
// Initialize the AWS config file once
fn get_config<'a>(context: &Context, config: &'a OnceCell<Option<Ini>>) -> Option<&'a Ini> {
config
.get_or_init(|| {
let path = get_config_file_path(context)?;
Ini::load_from_file(path).ok()
})
.as_ref()
}
// Initialize the AWS credentials file once
fn get_creds<'a>(context: &Context, config: &'a OnceCell<Option<Ini>>) -> Option<&'a Ini> {
config
.get_or_init(|| {
let path = get_credentials_file_path(context)?;
Ini::load_from_file(path).ok()
})
.as_ref()
}
// Get the section for a given profile name in the config file.
fn get_profile_config<'a>(
config: &'a Ini,
profile: &Option<Profile>,
) -> Option<&'a ini::Properties> {
match profile {
Some(profile) => config.section(Some(format!("profile {profile}"))),
None => config.section(Some("default")),
}
}
// Get the section for a given profile name in the credentials file.
fn get_profile_creds<'a>(
config: &'a Ini,
profile: &Option<Profile>,
) -> Option<&'a ini::Properties> {
match profile {
None => config.section(Some("default")),
_ => config.section(profile.as_ref()),
}
}
fn get_aws_region_from_config(
context: &Context,
aws_profile: &Option<Profile>,
aws_config: &AwsConfigFile,
) -> Option<Region> {
let config = get_config(context, aws_config)?;
let section = get_profile_config(config, aws_profile)?;
section.get("region").map(std::borrow::ToOwned::to_owned)
}
fn get_aws_profile_and_region(
context: &Context,
aws_config: &AwsConfigFile,
) -> (Option<Profile>, Option<Region>) {
let profile_env_vars = ["AWSU_PROFILE", "AWS_VAULT", "AWSUME_PROFILE", "AWS_PROFILE"];
let region_env_vars = ["AWS_REGION", "AWS_DEFAULT_REGION"];
let profile = profile_env_vars
.iter()
.find_map(|env_var| context.get_env(env_var));
let region = region_env_vars
.iter()
.find_map(|env_var| context.get_env(env_var));
match (profile, region) {
(Some(p), Some(r)) => (Some(p), Some(r)),
(None, Some(r)) => (None, Some(r)),
(Some(p), None) => (
Some(p.