Skip to content

Commit

Permalink
refactor(deps): use conflate instead of merge crate (#284)
Browse files Browse the repository at this point in the history
conflate (essentially merge 0.1.0-dev) lacks the blanket `impl<T> Merge
for Option<T>`, which was removed from version 0.1.0

```rust
impl<T> Merge for Option<T> {
    fn merge(&mut self, mut other: Self) {
        if !self.is_some() {
            *self = other.take();
        }
    }
}
```

Hence, I added the `overwrite_none` strategies where needed.

We could also add it back, for a future version, though I think there
was some decision involved, that strategies should be more explicit,
because it could be confusing for strategies being applied without
having an annotation. So I felt, I don't want to add that back to
`conflate` for now.

Fixes #258

---------

Signed-off-by: simonsan <[email protected]>
Co-authored-by: Alexander Weiss <[email protected]>
  • Loading branch information
simonsan and aawsome authored Oct 1, 2024
1 parent c24fe81 commit 5980401
Show file tree
Hide file tree
Showing 10 changed files with 75 additions and 39 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ This crate exposes a few features for controlling dependency usage:
- **cli** - Enables support for CLI features by enabling `merge` and `clap`
features. *This feature is disabled by default*.
- **merge** - Enables support for merging multiple values into one, which
enables the `merge` dependency. This is needed for parsing commandline
enables the `conflate` dependency. This is needed for parsing commandline
arguments and merging them into one (e.g. `config`). *This feature is disabled
by default*.
- **clap** - Enables a dependency on the `clap` crate and enables parsing from
Expand Down
4 changes: 2 additions & 2 deletions crates/backend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ edition = "2021"
[features]
default = ["opendal", "rest", "rclone"]
cli = ["merge", "clap"]
merge = ["dep:merge"]
merge = ["dep:conflate"]
clap = ["dep:clap"]
opendal = ["dep:opendal", "dep:rayon", "dep:tokio", "tokio/rt-multi-thread"]
rest = ["dep:reqwest", "dep:backoff"]
Expand Down Expand Up @@ -66,7 +66,7 @@ url = "2.5.2"

# cli support
clap = { version = "4.5.16", optional = true, features = ["derive", "env", "wrap_help"] }
merge = { version = "0.1.0", optional = true }
conflate = { version = "0.2.0", optional = true }

# local backend
aho-corasick = { workspace = true }
Expand Down
2 changes: 1 addition & 1 deletion crates/backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ This crate exposes a few features for controlling dependency usage:
the commandline. *This feature is disabled by default*.

- **merge** - Enables support for merging multiple values into one, which
enables the `merge` dependency. This is needed for parsing commandline
enables the `conflate` dependency. This is needed for parsing commandline
arguments and merging them into one (e.g. `config`). *This feature is disabled
by default*.

Expand Down
4 changes: 3 additions & 1 deletion crates/backend/src/choose.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use clap::ValueHint;

/// Options for a backend.
#[cfg_attr(feature = "clap", derive(clap::Parser))]
#[cfg_attr(feature = "merge", derive(merge::Merge))]
#[cfg_attr(feature = "merge", derive(conflate::Merge))]
#[derive(Clone, Default, Debug, serde::Deserialize, serde::Serialize, Setters)]
#[serde(default, rename_all = "kebab-case", deny_unknown_fields)]
#[setters(into, strip_option)]
Expand All @@ -37,13 +37,15 @@ pub struct BackendOptions {
feature = "clap",
clap(short, long, global = true, visible_alias = "repo", env = "RUSTIC_REPOSITORY", value_hint = ValueHint::DirPath)
)]
#[cfg_attr(feature = "merge", merge(strategy = conflate::option::overwrite_none))]
pub repository: Option<String>,

/// Repository to use as hot storage
#[cfg_attr(
feature = "clap",
clap(long, global = true, alias = "repository_hot", env = "RUSTIC_REPO_HOT")
)]
#[cfg_attr(feature = "merge", merge(strategy = conflate::option::overwrite_none))]
pub repo_hot: Option<String>,

/// Other options for this repository (hot and cold part)
Expand Down
4 changes: 2 additions & 2 deletions crates/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ edition = "2021"
[features]
default = []
cli = ["merge", "clap"]
merge = ["dep:merge"]
merge = ["dep:conflate"]
clap = ["dep:clap"]
webdav = ["dep:dav-server", "dep:futures"]

Expand Down Expand Up @@ -87,7 +87,7 @@ dirs = "5.0.1"

# cli support
clap = { version = "4.5.16", optional = true, features = ["derive", "env", "wrap_help"] }
merge = { version = "0.1.0", optional = true }
conflate = { version = "0.2.0", optional = true }

# vfs support
dav-server = { version = "0.7.0", default-features = false, optional = true }
Expand Down
27 changes: 14 additions & 13 deletions crates/core/src/backend/ignore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,82 +42,83 @@ pub struct LocalSource {

#[serde_as]
#[cfg_attr(feature = "clap", derive(clap::Parser))]
#[cfg_attr(feature = "merge", derive(merge::Merge))]
#[cfg_attr(feature = "merge", derive(conflate::Merge))]
#[derive(serde::Deserialize, serde::Serialize, Default, Clone, Copy, Debug, Setters)]
#[serde(default, rename_all = "kebab-case", deny_unknown_fields)]
#[setters(into)]
/// [`LocalSourceSaveOptions`] describes how entries from a local source will be saved in the repository.
pub struct LocalSourceSaveOptions {
/// Save access time for files and directories
#[cfg_attr(feature = "clap", clap(long))]
#[cfg_attr(feature = "merge", merge(strategy = merge::bool::overwrite_false))]
#[cfg_attr(feature = "merge", merge(strategy = conflate::bool::overwrite_false))]
pub with_atime: bool,

/// Don't save device ID for files and directories
#[cfg_attr(feature = "clap", clap(long))]
#[cfg_attr(feature = "merge", merge(strategy = merge::bool::overwrite_false))]
#[cfg_attr(feature = "merge", merge(strategy = conflate::bool::overwrite_false))]
pub ignore_devid: bool,
}

#[serde_as]
#[cfg_attr(feature = "clap", derive(clap::Parser))]
#[cfg_attr(feature = "merge", derive(merge::Merge))]
#[cfg_attr(feature = "merge", derive(conflate::Merge))]
#[derive(serde::Deserialize, serde::Serialize, Default, Clone, Debug, Setters)]
#[serde(default, rename_all = "kebab-case", deny_unknown_fields)]
#[setters(into)]
/// [`LocalSourceFilterOptions`] allow to filter a local source by various criteria.
pub struct LocalSourceFilterOptions {
/// Glob pattern to exclude/include (can be specified multiple times)
#[cfg_attr(feature = "clap", clap(long = "glob", value_name = "GLOB"))]
#[cfg_attr(feature = "merge", merge(strategy = merge::vec::overwrite_empty))]
#[cfg_attr(feature = "merge", merge(strategy = conflate::vec::overwrite_empty))]
pub globs: Vec<String>,

/// Same as --glob pattern but ignores the casing of filenames
#[cfg_attr(feature = "clap", clap(long = "iglob", value_name = "GLOB"))]
#[cfg_attr(feature = "merge", merge(strategy = merge::vec::overwrite_empty))]
#[cfg_attr(feature = "merge", merge(strategy = conflate::vec::overwrite_empty))]
pub iglobs: Vec<String>,

/// Read glob patterns to exclude/include from this file (can be specified multiple times)
#[cfg_attr(feature = "clap", clap(long = "glob-file", value_name = "FILE"))]
#[cfg_attr(feature = "merge", merge(strategy = merge::vec::overwrite_empty))]
#[cfg_attr(feature = "merge", merge(strategy = conflate::vec::overwrite_empty))]
pub glob_files: Vec<String>,

/// Same as --glob-file ignores the casing of filenames in patterns
#[cfg_attr(feature = "clap", clap(long = "iglob-file", value_name = "FILE"))]
#[cfg_attr(feature = "merge", merge(strategy = merge::vec::overwrite_empty))]
#[cfg_attr(feature = "merge", merge(strategy = conflate::vec::overwrite_empty))]
pub iglob_files: Vec<String>,

/// Ignore files based on .gitignore files
#[cfg_attr(feature = "clap", clap(long))]
#[cfg_attr(feature = "merge", merge(strategy = merge::bool::overwrite_false))]
#[cfg_attr(feature = "merge", merge(strategy = conflate::bool::overwrite_false))]
pub git_ignore: bool,

/// Do not require a git repository to apply git-ignore rule
#[cfg_attr(feature = "clap", clap(long))]
#[cfg_attr(feature = "merge", merge(strategy = merge::bool::overwrite_false))]
#[cfg_attr(feature = "merge", merge(strategy = conflate::bool::overwrite_false))]
pub no_require_git: bool,

/// Treat the provided filename like a .gitignore file (can be specified multiple times)
#[cfg_attr(
feature = "clap",
clap(long = "custom-ignorefile", value_name = "FILE")
)]
#[cfg_attr(feature = "merge", merge(strategy = merge::vec::overwrite_empty))]
#[cfg_attr(feature = "merge", merge(strategy = conflate::vec::overwrite_empty))]
pub custom_ignorefiles: Vec<String>,

/// Exclude contents of directories containing this filename (can be specified multiple times)
#[cfg_attr(feature = "clap", clap(long, value_name = "FILE"))]
#[cfg_attr(feature = "merge", merge(strategy = merge::vec::overwrite_empty))]
#[cfg_attr(feature = "merge", merge(strategy = conflate::vec::overwrite_empty))]
pub exclude_if_present: Vec<String>,

/// Exclude other file systems, don't cross filesystem boundaries and subvolumes
#[cfg_attr(feature = "clap", clap(long, short = 'x'))]
#[cfg_attr(feature = "merge", merge(strategy = merge::bool::overwrite_false))]
#[cfg_attr(feature = "merge", merge(strategy = conflate::bool::overwrite_false))]
pub one_file_system: bool,

/// Maximum size of files to be backed up. Larger files will be excluded.
#[cfg_attr(feature = "clap", clap(long, value_name = "SIZE"))]
#[serde_as(as = "Option<DisplayFromStr>")]
#[cfg_attr(feature = "merge", merge(strategy = conflate::option::overwrite_none))]
pub exclude_larger_than: Option<ByteSize>,
}

Expand Down
20 changes: 12 additions & 8 deletions crates/core/src/commands/backup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use clap::ValueHint;
/// `backup` subcommand
#[serde_as]
#[cfg_attr(feature = "clap", derive(clap::Parser))]
#[cfg_attr(feature = "merge", derive(merge::Merge))]
#[cfg_attr(feature = "merge", derive(conflate::Merge))]
#[derive(Clone, Default, Debug, Deserialize, Serialize, Setters)]
#[serde(default, rename_all = "kebab-case", deny_unknown_fields)]
#[setters(into)]
Expand All @@ -43,33 +43,35 @@ pub struct ParentOptions {
/// Group snapshots by any combination of host,label,paths,tags to find a suitable parent (default: host,label,paths)
#[cfg_attr(feature = "clap", clap(long, short = 'g', value_name = "CRITERION",))]
#[serde_as(as = "Option<DisplayFromStr>")]
#[cfg_attr(feature = "merge", merge(strategy = conflate::option::overwrite_none))]
pub group_by: Option<SnapshotGroupCriterion>,

/// Snapshot to use as parent
#[cfg_attr(
feature = "clap",
clap(long, value_name = "SNAPSHOT", conflicts_with = "force",)
)]
#[cfg_attr(feature = "merge", merge(strategy = conflate::option::overwrite_none))]
pub parent: Option<String>,

/// Skip writing of snapshot if nothing changed w.r.t. the parent snapshot.
#[cfg_attr(feature = "clap", clap(long))]
#[cfg_attr(feature = "merge", merge(strategy = merge::bool::overwrite_false))]
#[cfg_attr(feature = "merge", merge(strategy = conflate::bool::overwrite_false))]
pub skip_identical_parent: bool,

/// Use no parent, read all files
#[cfg_attr(feature = "clap", clap(long, short, conflicts_with = "parent",))]
#[cfg_attr(feature = "merge", merge(strategy = merge::bool::overwrite_false))]
#[cfg_attr(feature = "merge", merge(strategy = conflate::bool::overwrite_false))]
pub force: bool,

/// Ignore ctime changes when checking for modified files
#[cfg_attr(feature = "clap", clap(long, conflicts_with = "force",))]
#[cfg_attr(feature = "merge", merge(strategy = merge::bool::overwrite_false))]
#[cfg_attr(feature = "merge", merge(strategy = conflate::bool::overwrite_false))]
pub ignore_ctime: bool,

/// Ignore inode number changes when checking for modified files
#[cfg_attr(feature = "clap", clap(long, conflicts_with = "force",))]
#[cfg_attr(feature = "merge", merge(strategy = merge::bool::overwrite_false))]
#[cfg_attr(feature = "merge", merge(strategy = conflate::bool::overwrite_false))]
pub ignore_inode: bool,
}

Expand Down Expand Up @@ -127,7 +129,7 @@ impl ParentOptions {
}

#[cfg_attr(feature = "clap", derive(clap::Parser))]
#[cfg_attr(feature = "merge", derive(merge::Merge))]
#[cfg_attr(feature = "merge", derive(conflate::Merge))]
#[derive(Clone, Default, Debug, Deserialize, Serialize, Setters)]
#[serde(default, rename_all = "kebab-case", deny_unknown_fields)]
#[setters(into)]
Expand All @@ -144,20 +146,22 @@ pub struct BackupOptions {

/// Call the given command and use its output as stdin
#[cfg_attr(feature = "clap", clap(long, value_name = "COMMAND"))]
#[cfg_attr(feature = "merge", merge(strategy = conflate::option::overwrite_none))]
pub stdin_command: Option<CommandInput>,

/// Manually set backup path in snapshot
#[cfg_attr(feature = "clap", clap(long, value_name = "PATH", value_hint = ValueHint::DirPath))]
#[cfg_attr(feature = "merge", merge(strategy = conflate::option::overwrite_none))]
pub as_path: Option<PathBuf>,

/// Don't scan the backup source for its size - this disables ETA estimation for backup.
#[cfg_attr(feature = "clap", clap(long))]
#[cfg_attr(feature = "merge", merge(strategy = merge::bool::overwrite_false))]
#[cfg_attr(feature = "merge", merge(strategy = conflate::bool::overwrite_false))]
pub no_scan: bool,

/// Dry-run mode: Don't write any data or snapshot
#[cfg_attr(feature = "clap", clap(long))]
#[cfg_attr(feature = "merge", merge(strategy = merge::bool::overwrite_false))]
#[cfg_attr(feature = "merge", merge(strategy = conflate::bool::overwrite_false))]
pub dry_run: bool,

#[cfg_attr(feature = "clap", clap(flatten))]
Expand Down
Loading

0 comments on commit 5980401

Please sign in to comment.