diff --git a/src/config.rs b/src/config.rs index 80434c9..ac0d3cf 100644 --- a/src/config.rs +++ b/src/config.rs @@ -7,8 +7,11 @@ pub(crate) mod hooks; pub(crate) mod progress_options; -use std::fmt::Debug; -use std::{collections::HashMap, path::PathBuf}; +use std::{ + collections::BTreeMap, + fmt::{self, Display, Formatter}, + path::PathBuf, +}; use abscissa_core::{config::Config, path::AbsPathBuf, FrameworkError}; use anyhow::Result; @@ -83,6 +86,15 @@ pub struct RusticConfig { pub webdav: Option, } +impl Display for RusticConfig { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let config = toml::to_string_pretty(self) + .unwrap_or_else(|_| "".to_string()); + + write!(f, "{config}",) + } +} + impl RusticConfig { /// Merge a profile into the current config by reading the corresponding config file. /// Also recursively merge all profiles given within this config file. @@ -176,8 +188,8 @@ pub struct GlobalOptions { /// List of environment variables to set (only in config file) #[clap(skip)] - #[merge(strategy = conflate::hashmap::append_or_ignore)] - pub env: HashMap, + #[merge(strategy = conflate::btreemap::append_or_ignore)] + pub env: BTreeMap, } /// Get the paths to the config file @@ -245,7 +257,7 @@ fn get_global_config_path() -> Option { #[cfg(test)] mod tests { use super::*; - use insta::assert_debug_snapshot; + use insta::{assert_debug_snapshot, assert_snapshot}; #[test] fn test_default_config_passes() { @@ -253,4 +265,35 @@ mod tests { assert_debug_snapshot!(config); } + + #[test] + fn test_default_config_display_passes() { + let config = RusticConfig::default(); + + assert_snapshot!(config); + } + + #[test] + fn test_global_env_roundtrip_passes() { + let mut config = RusticConfig::default(); + + for i in 0..10 { + let _ = config + .global + .env + .insert(format!("KEY{}", i), format!("VALUE{}", i)); + } + + let serialized = toml::to_string(&config).unwrap(); + + // Check Serialization + assert_snapshot!(serialized); + + let deserialized: RusticConfig = toml::from_str(&serialized).unwrap(); + // Check Deserialization and Display + assert_snapshot!(deserialized); + + // Check Debug + assert_debug_snapshot!(deserialized); + } } diff --git a/src/snapshots/rustic_rs__config__tests__default_config_display_passes.snap b/src/snapshots/rustic_rs__config__tests__default_config_display_passes.snap new file mode 100644 index 0000000..28132de --- /dev/null +++ b/src/snapshots/rustic_rs__config__tests__default_config_display_passes.snap @@ -0,0 +1,89 @@ +--- +source: src/config.rs +expression: config +--- +[global] +use-profiles = [] +dry-run = false +check-index = false +no-progress = false + +[global.hooks] +run-before = [] +run-after = [] +run-failed = [] +run-finally = [] + +[global.env] + +[repository] +no-cache = false +warm-up = false + +[repository.options] + +[repository.options-hot] + +[repository.options-cold] + +[repository.hooks] +run-before = [] +run-after = [] +run-failed = [] +run-finally = [] + +[snapshot-filter] +filter-hosts = [] +filter-labels = [] +filter-paths = [] +filter-paths-exact = [] +filter-tags = [] +filter-tags-exact = [] + +[backup] +stdin-filename = "" +with-atime = false +ignore-devid = false +no-scan = false +json = false +long = false +quiet = false +init = false +skip-identical-parent = false +force = false +ignore-ctime = false +ignore-inode = false +globs = [] +iglobs = [] +glob-files = [] +iglob-files = [] +git-ignore = false +no-require-git = false +custom-ignorefiles = [] +exclude-if-present = [] +one-file-system = false +tags = [] +delete-never = false +snapshots = [] +sources = [] + +[backup.hooks] +run-before = [] +run-after = [] +run-failed = [] +run-finally = [] + +[copy] +targets = [] + +[forget] +prune = false +filter-hosts = [] +filter-labels = [] +filter-paths = [] +filter-paths-exact = [] +filter-tags = [] +filter-tags-exact = [] + +[webdav] +symlinks = false diff --git a/src/snapshots/rustic_rs__config__tests__global_env_roundtrip_passes-2.snap b/src/snapshots/rustic_rs__config__tests__global_env_roundtrip_passes-2.snap new file mode 100644 index 0000000..5002206 --- /dev/null +++ b/src/snapshots/rustic_rs__config__tests__global_env_roundtrip_passes-2.snap @@ -0,0 +1,99 @@ +--- +source: src/config.rs +expression: deserialized +--- +[global] +use-profiles = [] +dry-run = false +check-index = false +no-progress = false + +[global.hooks] +run-before = [] +run-after = [] +run-failed = [] +run-finally = [] + +[global.env] +KEY0 = "VALUE0" +KEY1 = "VALUE1" +KEY2 = "VALUE2" +KEY3 = "VALUE3" +KEY4 = "VALUE4" +KEY5 = "VALUE5" +KEY6 = "VALUE6" +KEY7 = "VALUE7" +KEY8 = "VALUE8" +KEY9 = "VALUE9" + +[repository] +no-cache = false +warm-up = false + +[repository.options] + +[repository.options-hot] + +[repository.options-cold] + +[repository.hooks] +run-before = [] +run-after = [] +run-failed = [] +run-finally = [] + +[snapshot-filter] +filter-hosts = [] +filter-labels = [] +filter-paths = [] +filter-paths-exact = [] +filter-tags = [] +filter-tags-exact = [] + +[backup] +stdin-filename = "" +with-atime = false +ignore-devid = false +no-scan = false +json = false +long = false +quiet = false +init = false +skip-identical-parent = false +force = false +ignore-ctime = false +ignore-inode = false +globs = [] +iglobs = [] +glob-files = [] +iglob-files = [] +git-ignore = false +no-require-git = false +custom-ignorefiles = [] +exclude-if-present = [] +one-file-system = false +tags = [] +delete-never = false +snapshots = [] +sources = [] + +[backup.hooks] +run-before = [] +run-after = [] +run-failed = [] +run-finally = [] + +[copy] +targets = [] + +[forget] +prune = false +filter-hosts = [] +filter-labels = [] +filter-paths = [] +filter-paths-exact = [] +filter-tags = [] +filter-tags-exact = [] + +[webdav] +symlinks = false diff --git a/src/snapshots/rustic_rs__config__tests__global_env_roundtrip_passes-3.snap b/src/snapshots/rustic_rs__config__tests__global_env_roundtrip_passes-3.snap new file mode 100644 index 0000000..4cfdd06 --- /dev/null +++ b/src/snapshots/rustic_rs__config__tests__global_env_roundtrip_passes-3.snap @@ -0,0 +1,206 @@ +--- +source: src/config.rs +expression: deserialized +--- +RusticConfig { + global: GlobalOptions { + use_profiles: [], + dry_run: false, + check_index: false, + log_level: None, + log_file: None, + progress_options: ProgressOptions { + no_progress: false, + progress_interval: None, + }, + hooks: Hooks { + run_before: [], + run_after: [], + run_failed: [], + run_finally: [], + context: "", + }, + env: { + "KEY0": "VALUE0", + "KEY1": "VALUE1", + "KEY2": "VALUE2", + "KEY3": "VALUE3", + "KEY4": "VALUE4", + "KEY5": "VALUE5", + "KEY6": "VALUE6", + "KEY7": "VALUE7", + "KEY8": "VALUE8", + "KEY9": "VALUE9", + }, + }, + repository: AllRepositoryOptions { + be: BackendOptions { + repository: None, + repo_hot: None, + options: {}, + options_hot: {}, + options_cold: {}, + }, + repo: RepositoryOptions { + password: None, + password_file: None, + password_command: None, + no_cache: false, + cache_dir: None, + warm_up: false, + warm_up_command: None, + warm_up_wait: None, + }, + hooks: Hooks { + run_before: [], + run_after: [], + run_failed: [], + run_finally: [], + context: "", + }, + }, + snapshot_filter: SnapshotFilter { + filter_hosts: [], + filter_labels: [], + filter_paths: [], + filter_paths_exact: [], + filter_tags: [], + filter_tags_exact: [], + filter_after: None, + filter_before: None, + filter_size: None, + filter_size_added: None, + filter_fn: None, + }, + backup: BackupCmd { + cli_sources: [], + stdin_filename: "", + stdin_command: None, + as_path: None, + ignore_save_opts: LocalSourceSaveOptions { + with_atime: false, + ignore_devid: false, + }, + no_scan: false, + json: false, + long: false, + quiet: false, + init: false, + parent_opts: ParentOptions { + group_by: None, + parent: None, + skip_identical_parent: false, + force: false, + ignore_ctime: false, + ignore_inode: false, + }, + ignore_filter_opts: LocalSourceFilterOptions { + globs: [], + iglobs: [], + glob_files: [], + iglob_files: [], + git_ignore: false, + no_require_git: false, + custom_ignorefiles: [], + exclude_if_present: [], + one_file_system: false, + exclude_larger_than: None, + }, + snap_opts: SnapshotOptions { + label: None, + tags: [], + description: None, + description_from: None, + time: None, + delete_never: false, + delete_after: None, + host: None, + command: None, + }, + key_opts: KeyOptions { + hostname: None, + username: None, + with_created: false, + }, + config_opts: ConfigOptions { + set_compression: None, + set_version: None, + set_append_only: None, + set_treepack_size: None, + set_treepack_size_limit: None, + set_treepack_growfactor: None, + set_datapack_size: None, + set_datapack_growfactor: None, + set_datapack_size_limit: None, + set_min_packsize_tolerate_percent: None, + set_max_packsize_tolerate_percent: None, + set_extra_verify: None, + }, + hooks: Hooks { + run_before: [], + run_after: [], + run_failed: [], + run_finally: [], + context: "", + }, + snapshots: [], + sources: [], + }, + copy: CopyCmd { + ids: [], + init: false, + targets: [], + key_opts: KeyOptions { + hostname: None, + username: None, + with_created: false, + }, + }, + forget: ForgetOptions { + group_by: None, + prune: false, + filter: SnapshotFilter { + filter_hosts: [], + filter_labels: [], + filter_paths: [], + filter_paths_exact: [], + filter_tags: [], + filter_tags_exact: [], + filter_after: None, + filter_before: None, + filter_size: None, + filter_size_added: None, + filter_fn: None, + }, + keep: KeepOptions { + keep_tags: [], + keep_ids: [], + keep_last: None, + keep_hourly: None, + keep_daily: None, + keep_weekly: None, + keep_monthly: None, + keep_quarter_yearly: None, + keep_half_yearly: None, + keep_yearly: None, + keep_within: None, + keep_within_hourly: None, + keep_within_daily: None, + keep_within_weekly: None, + keep_within_monthly: None, + keep_within_quarter_yearly: None, + keep_within_half_yearly: None, + keep_within_yearly: None, + keep_none: false, + }, + }, + mount: None, + webdav: WebDavCmd { + address: None, + path_template: None, + time_template: None, + symlinks: false, + file_access: None, + snapshot_path: None, + }, +} diff --git a/src/snapshots/rustic_rs__config__tests__global_env_roundtrip_passes.snap b/src/snapshots/rustic_rs__config__tests__global_env_roundtrip_passes.snap new file mode 100644 index 0000000..6c1e84f --- /dev/null +++ b/src/snapshots/rustic_rs__config__tests__global_env_roundtrip_passes.snap @@ -0,0 +1,99 @@ +--- +source: src/config.rs +expression: serialized +--- +[global] +use-profiles = [] +dry-run = false +check-index = false +no-progress = false + +[global.hooks] +run-before = [] +run-after = [] +run-failed = [] +run-finally = [] + +[global.env] +KEY0 = "VALUE0" +KEY1 = "VALUE1" +KEY2 = "VALUE2" +KEY3 = "VALUE3" +KEY4 = "VALUE4" +KEY5 = "VALUE5" +KEY6 = "VALUE6" +KEY7 = "VALUE7" +KEY8 = "VALUE8" +KEY9 = "VALUE9" + +[repository] +no-cache = false +warm-up = false + +[repository.options] + +[repository.options-hot] + +[repository.options-cold] + +[repository.hooks] +run-before = [] +run-after = [] +run-failed = [] +run-finally = [] + +[snapshot-filter] +filter-hosts = [] +filter-labels = [] +filter-paths = [] +filter-paths-exact = [] +filter-tags = [] +filter-tags-exact = [] + +[backup] +stdin-filename = "" +with-atime = false +ignore-devid = false +no-scan = false +json = false +long = false +quiet = false +init = false +skip-identical-parent = false +force = false +ignore-ctime = false +ignore-inode = false +globs = [] +iglobs = [] +glob-files = [] +iglob-files = [] +git-ignore = false +no-require-git = false +custom-ignorefiles = [] +exclude-if-present = [] +one-file-system = false +tags = [] +delete-never = false +snapshots = [] +sources = [] + +[backup.hooks] +run-before = [] +run-after = [] +run-failed = [] +run-finally = [] + +[copy] +targets = [] + +[forget] +prune = false +filter-hosts = [] +filter-labels = [] +filter-paths = [] +filter-paths-exact = [] +filter-tags = [] +filter-tags-exact = [] + +[webdav] +symlinks = false