diff --git a/Cargo.lock b/Cargo.lock index 38ab7a5e7..756092339 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -633,9 +633,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.22" +version = "1.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0" +checksum = "812acba72f0a070b003d3697490d2b55b837230ae7c6c6497f05cc2ddbb8d938" dependencies = [ "jobserver", "libc", @@ -687,9 +687,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.18" +version = "4.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3" +checksum = "7be5744db7978a28d9df86a214130d106a89ce49644cbc4e3f0c22c3fba30615" dependencies = [ "clap_builder", "clap_derive", @@ -697,9 +697,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.18" +version = "4.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b" +checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b" dependencies = [ "anstream", "anstyle", @@ -800,6 +800,28 @@ dependencies = [ "triomphe", ] +[[package]] +name = "conflate" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06f57b4959992e02db0da86fcb4b0c80dc112d31b823de27f61576b1c809bc45" +dependencies = [ + "conflate_derive", + "num-traits", +] + +[[package]] +name = "conflate_derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9395ace5316656ca6a778aa2c28ab0c4ea2c94a8f7dc942898c20be9b7a9a4b9" +dependencies = [ + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.79", +] + [[package]] name = "console" version = "0.15.8" @@ -1749,7 +1771,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.5.0", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -1772,6 +1794,12 @@ dependencies = [ "allocator-api2", ] +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" + [[package]] name = "headers" version = "0.3.9" @@ -1929,9 +1957,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" @@ -2015,7 +2043,7 @@ dependencies = [ "hyper 1.4.1", "hyper-util", "rustls 0.23.13", - "rustls-native-certs 0.8.0", + "rustls-native-certs", "rustls-pki-types", "tokio", "tokio-rustls", @@ -2116,12 +2144,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.0", "serde", ] @@ -2419,28 +2447,6 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" -[[package]] -name = "merge" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10bbef93abb1da61525bbc45eeaff6473a41907d19f8f9aa5168d214e10693e9" -dependencies = [ - "merge_derive", - "num-traits", -] - -[[package]] -name = "merge_derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "209d075476da2e63b4b29e72a2ef627b840589588e71400a25e3565c4f849d07" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "mimalloc" version = "0.1.43" @@ -3168,27 +3174,25 @@ dependencies = [ ] [[package]] -name = "proc-macro-error" -version = "1.0.4" +name = "proc-macro-error-attr2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" dependencies = [ - "proc-macro-error-attr", "proc-macro2", "quote", - "syn 1.0.109", - "version_check", ] [[package]] -name = "proc-macro-error-attr" -version = "1.0.4" +name = "proc-macro-error2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" dependencies = [ + "proc-macro-error-attr2", "proc-macro2", "quote", - "version_check", + "syn 2.0.79", ] [[package]] @@ -3417,9 +3421,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "355ae415ccd3a04315d3f8246e86d67689ea74d88d915576e1589a351062a13b" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ "bitflags", ] @@ -3518,9 +3522,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.7" +version = "0.12.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" +checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" dependencies = [ "base64 0.22.1", "bytes", @@ -3542,8 +3546,8 @@ dependencies = [ "pin-project-lite", "quinn", "rustls 0.23.13", - "rustls-native-certs 0.7.3", - "rustls-pemfile 2.1.3", + "rustls-native-certs", + "rustls-pemfile 2.2.0", "rustls-pki-types", "serde", "serde_json", @@ -3712,6 +3716,7 @@ dependencies = [ "clap", "clap_complete", "comfy-table", + "conflate", "convert_case", "crossterm 0.28.1", "dav-server", @@ -3728,7 +3733,6 @@ dependencies = [ "jemallocator-global", "libc", "log", - "merge", "mimalloc", "once_cell", "open", @@ -3759,9 +3763,9 @@ dependencies = [ [[package]] name = "rustic_backend" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28c795aff2332a69ba31fb6cc91237db3eb88d5d0d160177522ba49a21dd5911" +checksum = "79360c30ad274ce29e0c298f845a0e3633bae546a5f93c594c8cb78ed81bfe28" dependencies = [ "aho-corasick", "anyhow", @@ -3769,13 +3773,13 @@ dependencies = [ "bytes", "bytesize", "clap", + "conflate", "derive_setters", "displaydoc", "hex", "humantime", "itertools", "log", - "merge", "opendal", "rand", "rayon", @@ -3793,9 +3797,9 @@ dependencies = [ [[package]] name = "rustic_core" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "666cbd4da5ab6060f77326e73c13fe2d5043c95161393e913b910aecbdc894d0" +checksum = "35ff53869f5837bda488b441c71461a15652169814cd682dca1a96de4e7e0364" dependencies = [ "aes256ctr_poly1305aes", "anyhow", @@ -3806,6 +3810,7 @@ dependencies = [ "cachedir", "chrono", "clap", + "conflate", "crossbeam-channel", "dav-server", "derivative", @@ -3826,7 +3831,6 @@ dependencies = [ "integer-sqrt", "itertools", "log", - "merge", "nix", "pariter", "path-dedot", @@ -3851,9 +3855,9 @@ dependencies = [ [[package]] name = "rustic_testing" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2d7a4df7a49ee8b7cff95fbfa85e7cf6f478f96d472322a2ab3a02575b9cfa5" +checksum = "3362016d877cd9a671933b346c3b2c714115d723c0460ded7babaae483e91596" dependencies = [ "aho-corasick", "anyhow", @@ -3903,19 +3907,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "rustls-native-certs" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" -dependencies = [ - "openssl-probe", - "rustls-pemfile 2.1.3", - "rustls-pki-types", - "schannel", - "security-framework", -] - [[package]] name = "rustls-native-certs" version = "0.8.0" @@ -3923,7 +3914,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcaf18a4f2be7326cd874a5fa579fae794320a0f388d365dca7e480e55f83f8a" dependencies = [ "openssl-probe", - "rustls-pemfile 2.1.3", + "rustls-pemfile 2.2.0", "rustls-pki-types", "schannel", "security-framework", @@ -3940,11 +3931,10 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.3" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" dependencies = [ - "base64 0.22.1", "rustls-pki-types", ] @@ -4189,15 +4179,15 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.9.0" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" +checksum = "9720086b3357bcb44fce40117d769a4d068c70ecfa190850a980a71755f66fcc" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.5.0", + "indexmap 2.6.0", "serde", "serde_derive", "serde_json", @@ -4207,9 +4197,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.9.0" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" +checksum = "5f1abbfe725f27678f4663bcacb75a83e829fd464c25d78dd038a3a29e307cec" dependencies = [ "darling", "proc-macro2", @@ -4572,12 +4562,12 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef" dependencies = [ "rustix", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -4793,7 +4783,7 @@ version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.5.0", + "indexmap 2.6.0", "serde", "serde_spanned", "toml_datetime", diff --git a/Cargo.toml b/Cargo.toml index 48e81dfbc..853c01cc7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,8 +41,8 @@ rustdoc-args = ["--document-private-items", "--generate-link-to-definition"] [dependencies] abscissa_core = { version = "0.7.0", default-features = false, features = ["application"] } -rustic_backend = { version = "0.3.0", features = ["cli"] } -rustic_core = { version = "0.4.0", features = ["cli"] } +rustic_backend = { version = "0.4.0", features = ["cli"] } +rustic_core = { version = "0.5.0", features = ["cli"] } # allocators jemallocator-global = { version = "0.3.2", optional = true } @@ -69,7 +69,7 @@ thiserror = "1" # serialization serde = { version = "1", features = ["serde_derive"] } serde_json = "1" -serde_with = { version = "3.9", features = ["base64"] } +serde_with = { version = "3.10", features = ["base64"] } # other dependencies aho-corasick = "1.1.3" @@ -85,6 +85,7 @@ bytesize = "1" cached = "0.53.1" clap = { version = "4", features = ["derive", "env", "wrap_help"] } clap_complete = "4" +conflate = "0.2" convert_case = "0.6.0" dialoguer = "0.11.0" directories = "5" @@ -94,8 +95,7 @@ human-panic = "2.0.1" humantime = "2" indicatif = "0.17" itertools = "0.13" -merge = "0.1" -once_cell = "1.19" +once_cell = "1.20" open = "5.1.2" self_update = { version = "0.41", default-features = false, optional = true, features = ["rustls", "archive-tar", "compression-flate2"] } toml = "0.8" @@ -109,12 +109,12 @@ pretty_assertions = "1.4" quickcheck = "1" quickcheck_macros = "1" rstest = "0.23" -rustic_testing = "0.2.1" -tempfile = "3.12" +rustic_testing = "0.2.2" +tempfile = "3.13" toml = "0.8" [target.'cfg(not(windows))'.dependencies] -libc = "0.2.158" +libc = "0.2.159" # cargo-binstall support # https://github.com/cargo-bins/cargo-binstall/blob/HEAD/SUPPORT.md [package.metadata.binstall] diff --git a/src/commands/backup.rs b/src/commands/backup.rs index ae07e1cd6..8c3e56a95 100644 --- a/src/commands/backup.rs +++ b/src/commands/backup.rs @@ -12,8 +12,8 @@ use abscissa_core::{Command, Runnable, Shutdown}; use anyhow::{bail, Context, Result}; use clap::ValueHint; use comfy_table::Cell; +use conflate::Merge; use log::{debug, info, warn}; -use merge::Merge; use serde::{Deserialize, Serialize}; use serde_with::serde_as; @@ -47,10 +47,12 @@ pub struct BackupCmd { /// Start the given command and use its output as stdin #[clap(long, value_name = "COMMAND")] + #[merge(strategy=conflate::option::overwrite_none)] stdin_command: Option, /// Manually set backup path in snapshot #[clap(long, value_name = "PATH", value_hint = ValueHint::DirPath)] + #[merge(strategy=conflate::option::overwrite_none)] as_path: Option, /// Ignore save options @@ -60,27 +62,27 @@ pub struct BackupCmd { /// Don't scan the backup source for its size - this disables ETA estimation for backup. #[clap(long)] - #[merge(strategy = merge::bool::overwrite_false)] + #[merge(strategy=conflate::bool::overwrite_false)] pub no_scan: bool, /// Output generated snapshot in json format #[clap(long)] - #[merge(strategy = merge::bool::overwrite_false)] + #[merge(strategy=conflate::bool::overwrite_false)] json: bool, /// Show detailed information about generated snapshot #[clap(long, conflicts_with = "json")] - #[merge(strategy = merge::bool::overwrite_false)] + #[merge(strategy=conflate::bool::overwrite_false)] long: bool, /// Don't show any output #[clap(long, conflicts_with_all = ["json", "long"])] - #[merge(strategy = merge::bool::overwrite_false)] + #[merge(strategy=conflate::bool::overwrite_false)] quiet: bool, /// Initialize repository, if it doesn't exist yet #[clap(long)] - #[merge(strategy = merge::bool::overwrite_false)] + #[merge(strategy=conflate::bool::overwrite_false)] init: bool, /// Parent processing options diff --git a/src/commands/copy.rs b/src/commands/copy.rs index c905adef4..7dd309cdf 100644 --- a/src/commands/copy.rs +++ b/src/commands/copy.rs @@ -7,8 +7,8 @@ use crate::{ }; use abscissa_core::{config::Override, Command, FrameworkError, Runnable, Shutdown}; use anyhow::{bail, Result}; +use conflate::Merge; use log::{error, info, log, Level}; -use merge::Merge; use serde::{Deserialize, Serialize}; use rustic_core::{CopySnapshot, Id, KeyOptions}; @@ -30,7 +30,7 @@ pub struct CopyCmd { /// Target repository (can be specified multiple times) #[clap(long = "target", value_name = "TARGET")] - #[merge(strategy = merge::vec::overwrite_empty)] + #[merge(strategy=conflate::vec::overwrite_empty)] targets: Vec, /// Key options (when using --init) diff --git a/src/commands/forget.rs b/src/commands/forget.rs index 30b0c23b4..2e7d2e339 100644 --- a/src/commands/forget.rs +++ b/src/commands/forget.rs @@ -10,7 +10,7 @@ use abscissa_core::{Command, FrameworkError, Runnable}; use anyhow::Result; use chrono::Local; -use merge::Merge; +use conflate::Merge; use serde::{Deserialize, Serialize}; use serde_with::{serde_as, DisplayFromStr}; @@ -70,11 +70,12 @@ pub struct ForgetOptions { /// Group snapshots by any combination of host,label,paths,tags (default: "host,label,paths") #[clap(long, short = 'g', value_name = "CRITERION")] #[serde_as(as = "Option")] + #[merge(strategy=conflate::option::overwrite_none)] group_by: Option, /// Also prune the repository #[clap(long)] - #[merge(strategy = merge::bool::overwrite_false)] + #[merge(strategy=conflate::bool::overwrite_false)] prune: bool, /// Snapshot filter options diff --git a/src/commands/key.rs b/src/commands/key.rs index d3726c0d2..2c1cd87c2 100644 --- a/src/commands/key.rs +++ b/src/commands/key.rs @@ -65,12 +65,10 @@ impl AddCmd { let repo = open_repository(&config.repository)?; // create new Repository options which just contain password information - let pass_opts = RepositoryOptions { - password: self.new_password.clone(), - password_file: self.new_password_file.clone(), - password_command: self.new_password_command.clone(), - ..Default::default() - }; + let mut pass_opts = RepositoryOptions::default(); + pass_opts.password = self.new_password.clone(); + pass_opts.password_file = self.new_password_file.clone(); + pass_opts.password_command = self.new_password_command.clone(); let pass = pass_opts .evaluate_password() diff --git a/src/commands/tui/restore.rs b/src/commands/tui/restore.rs index 56e630884..a2dbef439 100644 --- a/src/commands/tui/restore.rs +++ b/src/commands/tui/restore.rs @@ -53,11 +53,11 @@ impl<'a, P: ProgressBars, S: IndexedFull> Restore<'a, P, S> { } self.dest = dest; let dest = LocalDestination::new(&self.dest, true, !self.node.is_dir())?; + // for restore, always recurse into tree - let ls_opts = LsOptions { - recursive: true, - ..Default::default() - }; + let mut ls_opts = LsOptions::default(); + ls_opts.recursive = true; + let ls = self.repo.ls(&self.node, &ls_opts)?; let plan = self.repo.prepare_restore(&self.opts, ls, &dest, dry_run)?; @@ -68,14 +68,14 @@ impl<'a, P: ProgressBars, S: IndexedFull> Restore<'a, P, S> { // restore using the plan // // Note: This currently runs `prepare_restore` again and doesn't use `plan` - // TODO: Fix when restore is changed such that `prepare_restore` is always dry_run and all modification is don in `restore` + // TODO: Fix when restore is changed such that `prepare_restore` is always dry_run and all modification is done in `restore` fn restore(&self, _plan: RestorePlan) -> Result<()> { let dest = LocalDestination::new(&self.dest, true, !self.node.is_dir())?; + // for restore, always recurse into tree - let ls_opts = LsOptions { - recursive: true, - ..Default::default() - }; + let mut ls_opts = LsOptions::default(); + ls_opts.recursive = true; + let ls = self.repo.ls(&self.node, &ls_opts)?; let plan = self .repo diff --git a/src/commands/webdav.rs b/src/commands/webdav.rs index 1923549b5..84a3289a7 100644 --- a/src/commands/webdav.rs +++ b/src/commands/webdav.rs @@ -8,8 +8,8 @@ use std::{net::ToSocketAddrs, str::FromStr}; use crate::{commands::open_repository_indexed, status_err, Application, RusticConfig, RUSTIC_APP}; use abscissa_core::{config::Override, Command, FrameworkError, Runnable, Shutdown}; use anyhow::{anyhow, Result}; +use conflate::Merge; use dav_server::{warp::dav_handler, DavHandler}; -use merge::Merge; use serde::{Deserialize, Serialize}; use rustic_core::vfs::{FilePolicy, IdenticalSnapshot, Latest, Vfs}; @@ -19,27 +19,32 @@ use rustic_core::vfs::{FilePolicy, IdenticalSnapshot, Latest, Vfs}; pub struct WebDavCmd { /// Address to bind the webdav server to. [default: "localhost:8000"] #[clap(long, value_name = "ADDRESS")] + #[merge(strategy=conflate::option::overwrite_none)] address: Option, /// The path template to use for snapshots. {id}, {id_long}, {time}, {username}, {hostname}, {label}, {tags}, {backup_start}, {backup_end} are replaced. [default: "[{hostname}]/[{label}]/{time}"] #[clap(long)] + #[merge(strategy=conflate::option::overwrite_none)] path_template: Option, /// The time template to use to display times in the path template. See https://docs.rs/chrono/latest/chrono/format/strftime/index.html for format options. [default: "%Y-%m-%d_%H-%M-%S"] #[clap(long)] + #[merge(strategy=conflate::option::overwrite_none)] time_template: Option, /// Use symlinks. This may not be supported by all WebDAV clients #[clap(long)] - #[merge(strategy = merge::bool::overwrite_false)] + #[merge(strategy=conflate::bool::overwrite_false)] symlinks: bool, /// How to handle access to files. [default: "forbidden" for hot/cold repositories, else "read"] #[clap(long)] + #[merge(strategy=conflate::option::overwrite_none)] file_access: Option, /// Specify directly which snapshot/path to serve #[clap(value_name = "SNAPSHOT[:PATH]")] + #[merge(strategy=conflate::option::overwrite_none)] snapshot_path: Option, } diff --git a/src/config.rs b/src/config.rs index 4be98a5e3..13a706b51 100644 --- a/src/config.rs +++ b/src/config.rs @@ -12,10 +12,10 @@ use abscissa_core::config::Config; use abscissa_core::path::AbsPathBuf; use abscissa_core::FrameworkError; use clap::{Parser, ValueHint}; +use conflate::Merge; use directories::ProjectDirs; use itertools::Itertools; use log::Level; -use merge::Merge; use rustic_backend::BackendOptions; use rustic_core::RepositoryOptions; use serde::{Deserialize, Serialize}; @@ -136,21 +136,22 @@ pub struct GlobalOptions { value_name = "PROFILE", env = "RUSTIC_USE_PROFILE" )] - #[merge(strategy = merge::vec::append)] + #[merge(strategy=conflate::vec::append)] pub use_profiles: Vec, /// Only show what would be done without modifying anything. Does not affect read-only commands. #[clap(long, short = 'n', global = true, env = "RUSTIC_DRY_RUN")] - #[merge(strategy = merge::bool::overwrite_false)] + #[merge(strategy=conflate::bool::overwrite_false)] pub dry_run: bool, /// Check if index matches pack files and read pack headers if neccessary #[clap(long, global = true, env = "RUSTIC_CHECK_INDEX")] - #[merge(strategy = merge::bool::overwrite_false)] + #[merge(strategy=conflate::bool::overwrite_false)] pub check_index: bool, /// Use this log level [default: info] #[clap(long, global = true, env = "RUSTIC_LOG_LEVEL")] + #[merge(strategy=conflate::option::overwrite_none)] pub log_level: Option, /// Write log messages to the given file instead of printing them. @@ -159,6 +160,7 @@ pub struct GlobalOptions { /// /// Warnings and errors are still additionally printed unless they are ignored by `--log-level` #[clap(long, global = true, env = "RUSTIC_LOG_FILE", value_name = "LOGFILE", value_hint = ValueHint::FilePath)] + #[merge(strategy=conflate::option::overwrite_none)] pub log_file: Option, /// Settings to customize progress bars @@ -168,16 +170,10 @@ pub struct GlobalOptions { /// List of environment variables to set (only in config file) #[clap(skip)] - #[merge(strategy = extend)] + #[merge(strategy = conflate::hashmap::ignore)] pub env: HashMap, } -/// Extend the contents of a [`HashMap`] with the contents of another -/// [`HashMap`] with the same key and value types. -fn extend(left: &mut HashMap, right: HashMap) { - left.extend(right); -} - /// Get the paths to the config file /// /// # Arguments diff --git a/src/config/progress_options.rs b/src/config/progress_options.rs index cfb41cea5..fcb201e99 100644 --- a/src/config/progress_options.rs +++ b/src/config/progress_options.rs @@ -5,7 +5,7 @@ use std::{borrow::Cow, fmt::Write, time::Duration}; use indicatif::{HumanDuration, ProgressBar, ProgressState, ProgressStyle}; use clap::Parser; -use merge::Merge; +use conflate::Merge; use serde::{Deserialize, Serialize}; use serde_with::{serde_as, DisplayFromStr}; @@ -19,7 +19,7 @@ use rustic_core::{Progress, ProgressBars}; pub struct ProgressOptions { /// Don't show any progress bar #[clap(long, global = true, env = "RUSTIC_NO_PROGRESS")] - #[merge(strategy=merge::bool::overwrite_false)] + #[merge(strategy=conflate::bool::overwrite_false)] pub no_progress: bool, /// Interval to update progress bars @@ -31,6 +31,7 @@ pub struct ProgressOptions { conflicts_with = "no_progress" )] #[serde_as(as = "Option")] + #[merge(strategy=conflate::option::overwrite_none)] pub progress_interval: Option, } diff --git a/src/filtering.rs b/src/filtering.rs index e2ae651f4..c4c3327e8 100644 --- a/src/filtering.rs +++ b/src/filtering.rs @@ -5,6 +5,7 @@ use rustic_core::{repofile::SnapshotFile, StringList}; use std::{error::Error, str::FromStr}; use cached::proc_macro::cached; +use conflate::Merge; use rhai::{serde::to_dynamic, Dynamic, Engine, FnPtr, AST}; use serde::{Deserialize, Serialize}; use serde_with::{serde_as, DisplayFromStr}; @@ -55,34 +56,35 @@ impl SnapshotFn { } #[serde_as] -#[derive(Clone, Default, Debug, Serialize, Deserialize, merge::Merge, clap::Parser)] +#[derive(Clone, Default, Debug, Serialize, Deserialize, Merge, clap::Parser)] #[serde(default, rename_all = "kebab-case", deny_unknown_fields)] pub struct SnapshotFilter { /// Hostname to filter (can be specified multiple times) #[clap(long = "filter-host", global = true, value_name = "HOSTNAME")] - #[merge(strategy=merge::vec::overwrite_empty)] + #[merge(strategy=conflate::vec::overwrite_empty)] filter_hosts: Vec, /// Label to filter (can be specified multiple times) #[clap(long = "filter-label", global = true, value_name = "LABEL")] - #[merge(strategy=merge::vec::overwrite_empty)] + #[merge(strategy=conflate::vec::overwrite_empty)] filter_labels: Vec, /// Path list to filter (can be specified multiple times) #[clap(long, global = true, value_name = "PATH[,PATH,..]")] #[serde_as(as = "Vec")] - #[merge(strategy=merge::vec::overwrite_empty)] + #[merge(strategy=conflate::vec::overwrite_empty)] filter_paths: Vec, /// Tag list to filter (can be specified multiple times) #[clap(long, global = true, value_name = "TAG[,TAG,..]")] #[serde_as(as = "Vec")] - #[merge(strategy=merge::vec::overwrite_empty)] + #[merge(strategy=conflate::vec::overwrite_empty)] filter_tags: Vec, /// Function to filter snapshots #[clap(long, global = true, value_name = "FUNC")] #[serde_as(as = "Option")] + #[merge(strategy=conflate::option::overwrite_none)] filter_fn: Option, }