blob: 696857eb6c07e35bc3160901197817e92096bfd8 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use {
crate::config::api::ConfigLevel,
anyhow::{anyhow, Error},
serde::{Deserialize, Serialize},
std::{
collections::HashMap,
fmt,
fs::{File, OpenOptions},
io::{BufReader, BufWriter, Read, Write},
},
};
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Environment {
pub user: Option<String>,
pub build: Option<HashMap<String, String>>,
pub global: Option<String>,
}
impl Environment {
fn load_from_reader<R: Read>(reader: R) -> Result<Self, Error> {
match serde_json::from_reader::<R, Environment>(reader) {
Ok(value) => Ok(value),
Err(e) => Err(anyhow!("Could not initialize configuration environment {}", e)),
}
}
fn save_to_writer<W: Write>(&self, writer: W) -> Result<(), Error> {
match serde_json::to_writer_pretty(writer, &self) {
Err(e) => Err(anyhow!("Could not write config environment file: {}", e)),
Ok(_) => Ok(()),
}
}
pub(crate) fn try_load(file: Option<String>) -> Self {
match file {
Some(f) => {
let reader = Environment::reader(&f);
if reader.is_err() {
Self { user: None, build: None, global: None }
} else {
match Environment::load_from_reader(reader.expect("environment file reader")) {
Ok(env) => env,
Err(e) => {
log::error!("Error loading environment: {}", e);
Self { user: None, build: None, global: None }
}
}
}
}
None => Self { user: None, build: None, global: None },
}
}
pub fn load(file: &str) -> Result<Self, Error> {
Environment::load_from_reader(Environment::reader(file)?)
}
fn reader(path: &str) -> Result<BufReader<File>, Error> {
match File::open(path) {
Ok(f) => Ok(BufReader::new(f)),
Err(e) => Err(anyhow!("Could not open file {}", e)),
}
}
fn writer(path: &str) -> Result<BufWriter<File>, Error> {
let file = OpenOptions::new().write(true).truncate(true).create(true).open(path);
match file {
Ok(f) => Ok(BufWriter::new(f)),
Err(e) => Err(anyhow!("Could not open file {}", e)),
}
}
pub fn save(&self, file: &str) -> Result<(), Error> {
self.save_to_writer(Environment::writer(file)?)
}
fn display_user(&self) -> String {
match self.user.as_ref() {
Some(u) => format!(" User: {}\n", u),
None => format!(" User: none\n"),
}
}
fn display_build(&self) -> String {
let mut res = format!(" Build:");
match self.build.as_ref() {
Some(m) => {
if m.is_empty() {
res.push_str(&format!(" none\n"));
}
res.push_str(&format!("\n"));
for (key, val) in m.iter() {
res.push_str(&format!(" {} => {}\n", key, val));
}
}
None => {
res.push_str(&format!(" none\n"));
}
}
res
}
fn display_global(&self) -> String {
match self.global.as_ref() {
Some(g) => format!(" Global: {}\n", g),
None => format!(" Global: none\n"),
}
}
pub fn display(&self, level: &Option<ConfigLevel>) -> String {
match level {
Some(l) => match l {
ConfigLevel::User => self.display_user(),
ConfigLevel::Build => self.display_build(),
ConfigLevel::Global => self.display_global(),
ConfigLevel::Defaults => "".to_string(),
},
None => {
let mut res = format!("\nEnvironment:\n");
res.push_str(&self.display_user());
res.push_str(&self.display_build());
res.push_str(&self.display_global());
res
}
}
}
}
impl fmt::Display for Environment {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "{}", self.display(&None))
}
}
////////////////////////////////////////////////////////////////////////////////
// tests
#[cfg(test)]
mod test {
use super::*;
const ENVIRONMENT: &'static str = r#"
{
"user": "/tmp/user.json",
"build": {
"/tmp/build/1": "/tmp/build/1/build.json"
},
"global": "/tmp/global.json"
}"#;
#[test]
fn test_loading_and_saving_environment() -> Result<(), Error> {
let mut env_file = String::from(ENVIRONMENT);
let environment = Environment::load_from_reader(BufReader::new(env_file.as_bytes()))?;
let mut env_file_out = String::new();
unsafe {
environment.save_to_writer(BufWriter::new(env_file_out.as_mut_vec()))?;
}
// Remove whitespace
env_file.retain(|c| !c.is_whitespace());
env_file_out.retain(|c| !c.is_whitespace());
assert_eq!(env_file, env_file_out);
Ok(())
}
}