| // 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(()) |
| } |
| } |