use crate::cfg::{Cfg, IgnoreProp, IgnoreType, Instance};
use anyhow::Result;
use log::{debug, info};
use serde_derive::{Deserialize, Serialize};
use std::env;
use std::fs::read_to_string;
use std::path::Path;
pub(crate) const CONFIG_FILE: &str = ".je";
pub(crate) const CURRENT_VERSION: &str = env!("CARGO_PKG_VERSION");
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
pub(crate) struct Version {
#[serde(rename = "version")]
pub(crate) value: Option<String>,
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
struct Pre030Cfg {
pub(crate) ignore_properties: Vec<String>,
#[serde(rename = "profile")]
pub(crate) profiles: Vec<Instance>,
}
pub(crate) fn handle_cfg_load() -> Result<Cfg> {
debug!("loading config: {:?}{}", env::current_dir(), CONFIG_FILE);
if Path::new(CONFIG_FILE).exists() {
let version: Version = toml::from_str(&read_to_string(CONFIG_FILE)?)?;
if version.value.is_none() {
let cfg: Pre030Cfg = toml::from_str(&read_to_string(CONFIG_FILE)?)?;
Ok(convert_to_current_cfg(cfg))
} else {
Ok(toml::from_str::<Cfg>(&read_to_string(CONFIG_FILE)?)?)
}
} else {
debug!("{} config doesn't exists, loading default", CONFIG_FILE);
Ok(Cfg::default())
}
}
fn convert_to_current_cfg(cfg: Pre030Cfg) -> Cfg {
info!("adjusting configuration to a newer version");
let res = Cfg {
version: Some(CURRENT_VERSION.to_string()),
ignore_properties: adjust_ignore_props(cfg.ignore_properties),
profiles: cfg.profiles,
..Cfg::default()
};
debug!("config after adjustments: {:#?}", res);
res
}
fn adjust_ignore_props(props: Vec<String>) -> Vec<IgnoreProp> {
let mut res = Vec::new();
for prop in props {
res.push(IgnoreProp {
ignore_type: IgnoreType::Contains,
value: prop,
});
}
res
}
#[cfg(test)]
mod test {
use super::*;
use crate::cfg::{Bundle, IgnoreProp, Instance};
use crate::testutils::TestConfig;
use anyhow::Result;
#[test]
fn test_handle_cfg_load_when_config_not_exists() -> Result<()> {
let _ = pretty_env_logger::try_init();
let expected_profiles = vec![Instance::new(
"author",
"http://localhost:4502",
"admin",
"admin",
)];
let expected_ignore_props = vec![];
let expected_version = Some("0.3.0".into());
let cfg = handle_cfg_load()?;
assert_eq!(cfg.version, expected_version);
assert_eq!(cfg.ignore_properties, expected_ignore_props);
assert_eq!(cfg.profiles, expected_profiles);
Ok(())
}
#[test]
fn test_handle_cfg_load_when_config_exists_but_is_from_pre_030_version() -> Result<()> {
let _ = pretty_env_logger::try_init();
let test_config = TestConfig::new()?;
let original_cfg_content = r#"ignore_properties = ["jcr:created", "jcr:createdBy"]
[[profile]]
name = "author"
addr = "http://localhost:4502"
user = "user1"
pass = "pass1"
"#;
test_config.write_all(original_cfg_content)?;
let expected_profiles = vec![Instance::new(
"author",
"http://localhost:4502",
"user1",
"pass1",
)];
let expected_ignore_props = vec![
IgnoreProp {
ignore_type: IgnoreType::Contains,
value: "jcr:created".to_string(),
},
IgnoreProp {
ignore_type: IgnoreType::Contains,
value: "jcr:createdBy".to_string(),
},
];
let expected_version = Some("0.3.0".into());
let cfg = handle_cfg_load()?;
assert_eq!(cfg.version, expected_version);
assert_eq!(cfg.ignore_properties, expected_ignore_props);
assert_eq!(cfg.profiles, expected_profiles);
assert_eq!(original_cfg_content, test_config.read_all()?);
Ok(())
}
#[test]
fn test_handle_cfg_load_when_config_is_not_available() -> Result<()> {
let _ = pretty_env_logger::try_init();
let cfg = handle_cfg_load()?;
let expected_profiles = vec![Instance::new(
"author",
"http://localhost:4502",
"admin",
"admin",
)];
assert_eq!(cfg.ignore_properties, Vec::<IgnoreProp>::new());
assert_eq!(cfg.profiles, expected_profiles);
Ok(())
}
#[test]
fn test_instance_with_existing_profile() -> Result<()> {
let _ = pretty_env_logger::try_init();
let test_config = TestConfig::new()?;
let original_cfg_content = r#"version = "0.3.0"
ignore_properties = [{type = "contains", value = "prop1"},
{type = "contains", value = "prop2"}]
[[profile]]
name = "author"
addr = "http://localhost:4502"
user = "user1"
pass = "pass1"
"#;
test_config.write_all(original_cfg_content)?;
let expected_instance = Instance::new("author", "http://localhost:4502", "user1", "pass1");
let cfg = handle_cfg_load()?;
let instance = cfg.instance(Some(&String::from("author")));
assert_eq!(instance, expected_instance);
assert_eq!(original_cfg_content, test_config.read_all()?);
Ok(())
}
#[test]
fn test_instance_with_not_existing_profile() -> Result<()> {
let _ = pretty_env_logger::try_init();
let test_config = TestConfig::new()?;
let original_cfg_content = r#"version = "0.3.0"
ignore_properties = [{type = "contains", value = "prop1"},
{type = "contains", value = "prop2"}]
[[profile]]
name = "author"
addr = "http://localhost:4502"
user = "user1"
pass = "pass1"
"#;
test_config.write_all(original_cfg_content)?;
let default_instance = Instance::new("author", "http://localhost:4502", "admin", "admin");
let cfg = handle_cfg_load()?;
let instance = cfg.instance(Some(&String::from("not-existing")));
assert_eq!(instance, default_instance);
assert_eq!(original_cfg_content, test_config.read_all()?);
Ok(())
}
#[test]
fn test_instance_when_no_profile_was_selected() -> Result<()> {
let _ = pretty_env_logger::try_init();
let test_config = TestConfig::new()?;
let original_cfg_content = r#"version = "0.3.0"
ignore_properties = [{type = "contains", value = "prop1"},
{type = "contains", value = "prop2"}]
[[profile]]
name = "publish"
addr = "http://localhost:4503"
user = "user2"
pass = "pass2"
[[profile]]
name = "author"
addr = "http://localhost:4502"
user = "user1"
pass = "pass1"
"#;
test_config.write_all(original_cfg_content)?;
let first_instance = Instance::new("publish", "http://localhost:4503", "user2", "pass2");
let cfg = handle_cfg_load()?;
let instance = cfg.instance(None);
assert_eq!(instance, first_instance);
assert_eq!(original_cfg_content, test_config.read_all()?);
Ok(())
}
#[test]
fn test_bundles_when_bundle_defined() -> Result<()> {
let _ = pretty_env_logger::try_init();
let test_config = TestConfig::new()?;
let original_cfg_content = r#"version = "0.3.0"
ignore_properties = [{type = "contains", value = "prop1"},
{type = "contains", value = "prop2"}]
[[profile]]
name = "author"
addr = "http://localhost:4502"
user = "user1"
pass = "pass1"
[[bundle]]
name = "simple"
paths = ["file1", "file2"]
"#;
test_config.write_all(original_cfg_content)?;
let expected_bundle = Bundle::new("simple", vec!["file1", "file2"]);
let cfg = handle_cfg_load();
debug!("result: {:?}", cfg);
let cfg = handle_cfg_load()?;
let bundle = cfg.bundle(Some("simple"));
assert_eq!(expected_bundle, bundle);
assert_eq!(original_cfg_content, test_config.read_all()?);
Ok(())
}
#[test]
fn test_bundles_when_multiple_bundles_defined() -> Result<()> {
let _ = pretty_env_logger::try_init();
let test_config = TestConfig::new()?;
let original_cfg_content = r#"version = "0.3.0"
ignore_properties = [{type = "contains", value = "prop1"},
{type = "contains", value = "prop2"}]
[[profile]]
name = "author"
addr = "http://localhost:4502"
user = "user1"
pass = "pass1"
[[bundle]]
name = "simple"
paths = ["file1", "file2"]
[[bundle]]
name = "other"
paths = ["file3", "file4"]
"#;
test_config.write_all(original_cfg_content)?;
let expected_simple_bundle = Bundle::new("simple", vec!["file1", "file2"]);
let expected_other_bundle = Bundle::new("other", vec!["file3", "file4"]);
let cfg = handle_cfg_load()?;
let simple_bundle = cfg.bundle(Some("simple"));
let other_bundle = cfg.bundle(Some("other"));
assert_eq!(expected_simple_bundle, simple_bundle);
assert_eq!(expected_other_bundle, other_bundle);
assert_eq!(original_cfg_content, test_config.read_all()?);
Ok(())
}
#[test]
fn test_bundles_when_no_bundle() -> Result<()> {
let _ = pretty_env_logger::try_init();
let test_config = TestConfig::new()?;
let original_cfg_content = r#"version = "0.3.0"
ignore_properties = [{type = "contains", value = "prop1"},
{type = "contains", value = "prop2"}]
[[profile]]
name = "author"
addr = "http://localhost:4502"
user = "user1"
pass = "pass1"
"#;
test_config.write_all(original_cfg_content)?;
let expected_bundle = Bundle::default();
let cfg = handle_cfg_load()?;
let bundle = cfg.bundle(Some("not-existing"));
assert_eq!(expected_bundle, bundle);
assert_eq!(original_cfg_content, test_config.read_all()?);
Ok(())
}
#[test]
#[should_panic]
fn test_bundles_when_bundle_broken() {
let _ = pretty_env_logger::try_init();
let test_config = TestConfig::new().unwrap();
test_config
.write_all(
r#"version = "0.3.0"
ignore_properties = [{type = "contains", value = "prop1"},
{type = "contains", value = "prop2"}]
[[profile]]
name = "author"
addr = "http://localhost:4502"
user = "user1"
pass = "pass1"
[[bundle]]
paths = ["file3", "file4"]
"#,
)
.unwrap();
let _not_important = handle_cfg_load().unwrap(); }
}