use crate::{credentials::GoogleCloudUserDirectory, Error};
use serde::Deserialize;
use std::io::BufRead;
#[derive(Deserialize)]
pub struct ProfileSchema {
pub account: String,
pub project: String,
}
pub struct GoogleCloudConfigurationContext {
pub directory: GoogleCloudUserDirectory,
pub profiles: Profiles,
}
impl GoogleCloudConfigurationContext {
pub fn new() -> Result<Self, Error> {
let dir = GoogleCloudUserDirectory::new()?;
let profiles = Profiles::new(&dir)?;
Ok(Self {
directory: dir,
profiles,
})
}
}
pub struct Profiles {
inner: std::collections::HashMap<String, toml::Table>,
}
impl Profiles {
pub fn new(directory: &GoogleCloudUserDirectory) -> Result<Profiles, Error> {
let mut profiles = Profiles {
inner: std::collections::HashMap::<String, toml::Table>::new(),
};
let config = directory.get_config_default();
let contents = std::fs::read_to_string(config.as_path())
.map_err(|e| Error::FailedToLoad(format!("{} because {}", config.display(), e)))?;
parse(&mut profiles, contents.as_ref());
Ok(profiles)
}
pub fn get(&mut self, name: &str) -> Result<ProfileSchema, Error> {
let Some(core) = self.inner.remove(name) else {
return Err(Error::ProfileNotFound(name.to_string()));
};
let profile: ProfileSchema = core
.try_into()
.map_err(|e| Error::InvalidProfile(e.to_string()))?;
Ok(profile)
}
}
pub fn parse(profiles: &mut Profiles, contents: &[u8]) {
let mut lines = contents.lines();
while let Some(line) = lines.next() {
let Ok(line) = line else {
continue;
};
let name = line.trim_matches(['[', ']']);
if name.is_empty() {
continue;
}
let name = name.to_string();
let mut table = toml::Table::new();
for property in lines.by_ref() {
let Ok(property) = property else {
continue;
};
if property.is_empty() {
break;
}
let mut parts = property.split('=');
if let (Some(key), Some(value)) = (parts.next(), parts.next()) {
table.insert(
key.trim().to_string(),
toml::Value::String(value.trim().to_string()),
);
}
}
profiles.inner.insert(name, table);
}
}