mirror of
https://github.com/rustic-rs/rustic.git
synced 2025-10-26 11:18:51 +00:00
Update to clap v4
This commit is contained in:
parent
48570016e9
commit
10db248507
151
Cargo.lock
generated
151
Cargo.lock
generated
@ -75,6 +75,55 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e579a7752471abc2a8268df8b20005e3eadd975f585398f17efcfd8d4927371"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is-terminal",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
|
||||
dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bcd8291a340dd8ac70e18878bc4501dd7b4ff970cfa21c207d36ece51ea88fd"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.70"
|
||||
@ -87,17 +136,6 @@ version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi 0.1.19",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
@ -258,51 +296,55 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "3.2.23"
|
||||
version = "4.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5"
|
||||
checksum = "9b802d85aaf3a1cdb02b224ba472ebdea62014fccfcb269b95a4d76443b5ee5a"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
"clap_lex",
|
||||
"indexmap",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14a1a858f532119338887a4b8e1af9c60de8249cd7bafd68036a489e261e37b6"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"bitflags",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
"termcolor",
|
||||
"textwrap",
|
||||
"terminal_size",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_complete"
|
||||
version = "3.2.5"
|
||||
version = "4.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f7a2e0a962c45ce25afce14220bc24f9dade0a1787f185cecf96bfba7847cd8"
|
||||
checksum = "01c22dcfb410883764b29953103d9ef7bb8fe21b3fa1158bc99986c2067294bd"
|
||||
dependencies = [
|
||||
"clap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "3.2.18"
|
||||
version = "4.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65"
|
||||
checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"syn 2.0.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.2.4"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
|
||||
dependencies = [
|
||||
"os_str_bytes",
|
||||
]
|
||||
checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1"
|
||||
|
||||
[[package]]
|
||||
name = "codespan-reporting"
|
||||
@ -314,6 +356,12 @@ dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||
|
||||
[[package]]
|
||||
name = "comfy-table"
|
||||
version = "6.1.4"
|
||||
@ -932,15 +980,6 @@ version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.2.6"
|
||||
@ -1175,6 +1214,18 @@ version = "2.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f"
|
||||
|
||||
[[package]]
|
||||
name = "is-terminal"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f"
|
||||
dependencies = [
|
||||
"hermit-abi 0.3.1",
|
||||
"io-lifetimes",
|
||||
"rustix",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.5"
|
||||
@ -1413,12 +1464,6 @@ version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267"
|
||||
|
||||
[[package]]
|
||||
name = "owo-colors"
|
||||
version = "3.5.0"
|
||||
@ -2302,10 +2347,14 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.16.0"
|
||||
name = "terminal_size"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
|
||||
checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237"
|
||||
dependencies = [
|
||||
"rustix",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
@ -2573,6 +2622,12 @@ dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
|
||||
@ -70,8 +70,8 @@ semver = "1"
|
||||
dirs = "5"
|
||||
cachedir = "0.3"
|
||||
# commands
|
||||
clap = { version = "3", features = ["derive", "env"] }
|
||||
clap_complete = "3.2.4"
|
||||
clap = { version = "4", features = ["derive", "env", "wrap_help"] }
|
||||
clap_complete = "4"
|
||||
directories = "5"
|
||||
nom = "7"
|
||||
toml = "0.7"
|
||||
|
||||
@ -3,5 +3,7 @@ Changes in version x.x.x:
|
||||
Breaking changes:
|
||||
|
||||
Bugs fixed:
|
||||
- restore: Warm-up options given by the command line didn't work. This has been fixed.
|
||||
|
||||
New features:
|
||||
- Updated to clap v4
|
||||
|
||||
@ -46,42 +46,42 @@ pub struct LocalSourceOptions {
|
||||
ignore_devid: bool,
|
||||
|
||||
/// Glob pattern to exclude/include (can be specified multiple times)
|
||||
#[clap(long, help_heading = "EXCLUDE OPTIONS")]
|
||||
#[clap(long, help_heading = "Exclude options")]
|
||||
#[merge(strategy = merge::vec::overwrite_empty)]
|
||||
glob: Vec<String>,
|
||||
|
||||
/// Same as --glob pattern but ignores the casing of filenames
|
||||
#[clap(long, value_name = "GLOB", help_heading = "EXCLUDE OPTIONS")]
|
||||
#[clap(long, value_name = "GLOB", help_heading = "Exclude options")]
|
||||
#[merge(strategy = merge::vec::overwrite_empty)]
|
||||
iglob: Vec<String>,
|
||||
|
||||
/// Read glob patterns to exclude/include from this file (can be specified multiple times)
|
||||
#[clap(long, value_name = "FILE", help_heading = "EXCLUDE OPTIONS")]
|
||||
#[clap(long, value_name = "FILE", help_heading = "Exclude options")]
|
||||
#[merge(strategy = merge::vec::overwrite_empty)]
|
||||
glob_file: Vec<String>,
|
||||
|
||||
/// Same as --glob-file ignores the casing of filenames in patterns
|
||||
#[clap(long, value_name = "FILE", help_heading = "EXCLUDE OPTIONS")]
|
||||
#[clap(long, value_name = "FILE", help_heading = "Exclude options")]
|
||||
#[merge(strategy = merge::vec::overwrite_empty)]
|
||||
iglob_file: Vec<String>,
|
||||
|
||||
/// Ignore files based on .gitignore files
|
||||
#[clap(long, help_heading = "EXCLUDE OPTIONS")]
|
||||
#[clap(long, help_heading = "Exclude options")]
|
||||
#[merge(strategy = merge::bool::overwrite_false)]
|
||||
git_ignore: bool,
|
||||
|
||||
/// Exclude contents of directories containing this filename (can be specified multiple times)
|
||||
#[clap(long, value_name = "FILE", help_heading = "EXCLUDE OPTIONS")]
|
||||
#[clap(long, value_name = "FILE", help_heading = "Exclude options")]
|
||||
#[merge(strategy = merge::vec::overwrite_empty)]
|
||||
exclude_if_present: Vec<String>,
|
||||
|
||||
/// Exclude other file systems, don't cross filesystem boundaries and subvolumes
|
||||
#[clap(long, short = 'x', help_heading = "EXCLUDE OPTIONS")]
|
||||
#[clap(long, short = 'x', help_heading = "Exclude options")]
|
||||
#[merge(strategy = merge::bool::overwrite_false)]
|
||||
one_file_system: bool,
|
||||
|
||||
/// Maximum size of files to be backuped. Larger files will be excluded.
|
||||
#[clap(long, value_name = "SIZE", help_heading = "EXCLUDE OPTIONS")]
|
||||
#[clap(long, value_name = "SIZE", help_heading = "Exclude options")]
|
||||
#[serde_as(as = "Option<DisplayFromStr>")]
|
||||
exclude_larger_than: Option<ByteSize>,
|
||||
}
|
||||
|
||||
@ -109,19 +109,19 @@ impl IntoIterator for Tree {
|
||||
#[derive(Default, Clone, Parser)]
|
||||
pub struct TreeStreamerOptions {
|
||||
/// Glob pattern to exclude/include (can be specified multiple times)
|
||||
#[clap(long, help_heading = "EXCLUDE OPTIONS")]
|
||||
#[clap(long, help_heading = "Exclude options")]
|
||||
glob: Vec<String>,
|
||||
|
||||
/// Same as --glob pattern but ignores the casing of filenames
|
||||
#[clap(long, value_name = "GLOB", help_heading = "EXCLUDE OPTIONS")]
|
||||
#[clap(long, value_name = "GLOB", help_heading = "Exclude options")]
|
||||
iglob: Vec<String>,
|
||||
|
||||
/// Read glob patterns to exclude/include from this file (can be specified multiple times)
|
||||
#[clap(long, value_name = "FILE", help_heading = "EXCLUDE OPTIONS")]
|
||||
#[clap(long, value_name = "FILE", help_heading = "Exclude options")]
|
||||
glob_file: Vec<String>,
|
||||
|
||||
/// Same as --glob-file ignores the casing of filenames in patterns
|
||||
#[clap(long, value_name = "FILE", help_heading = "EXCLUDE OPTIONS")]
|
||||
#[clap(long, value_name = "FILE", help_heading = "Exclude options")]
|
||||
iglob_file: Vec<String>,
|
||||
}
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ use std::str::FromStr;
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use chrono::Local;
|
||||
use clap::{AppSettings, Parser};
|
||||
use clap::Parser;
|
||||
use log::*;
|
||||
use merge::Merge;
|
||||
use path_dedot::ParseDot;
|
||||
@ -20,13 +20,14 @@ use crate::repofile::{
|
||||
use crate::repository::OpenRepository;
|
||||
|
||||
#[derive(Clone, Default, Parser, Deserialize, Merge)]
|
||||
#[clap(global_setting(AppSettings::DeriveDisplayOrder))]
|
||||
#[serde(default, rename_all = "kebab-case", deny_unknown_fields)]
|
||||
#[serde(default, rename_all = "kebab-case")]
|
||||
pub(super) struct Opts {
|
||||
/// Output generated snapshot in json format
|
||||
#[clap(long)]
|
||||
#[merge(strategy = merge::bool::overwrite_false)]
|
||||
json: bool,
|
||||
/// Backup source (can be specified multiple times), use - for stdin. If no source is given, uses all
|
||||
/// sources defined in the config file
|
||||
#[clap(value_name = "SOURCE")]
|
||||
#[merge(skip)]
|
||||
#[serde(skip)]
|
||||
cli_sources: Vec<String>,
|
||||
|
||||
/// Do not upload or write any data, just show what would be done
|
||||
#[clap(long, short = 'n')]
|
||||
@ -34,25 +35,48 @@ pub(super) struct Opts {
|
||||
dry_run: bool,
|
||||
|
||||
/// Group snapshots by any combination of host,label,paths,tags to find a suitable parent (default: host,label,paths)
|
||||
#[clap(long, short = 'g', value_name = "CRITERION")]
|
||||
#[clap(
|
||||
long,
|
||||
short = 'g',
|
||||
value_name = "CRITERION",
|
||||
help_heading = "Options for parent processing"
|
||||
)]
|
||||
group_by: Option<SnapshotGroupCriterion>,
|
||||
|
||||
/// Snapshot to use as parent
|
||||
#[clap(long, value_name = "SNAPSHOT", conflicts_with = "force")]
|
||||
#[clap(
|
||||
long,
|
||||
value_name = "SNAPSHOT",
|
||||
conflicts_with = "force",
|
||||
help_heading = "Options for parent processing"
|
||||
)]
|
||||
parent: Option<String>,
|
||||
|
||||
/// Use no parent, read all files
|
||||
#[clap(long, short, conflicts_with = "parent")]
|
||||
#[clap(
|
||||
long,
|
||||
short,
|
||||
conflicts_with = "parent",
|
||||
help_heading = "Options for parent processing"
|
||||
)]
|
||||
#[merge(strategy = merge::bool::overwrite_false)]
|
||||
force: bool,
|
||||
|
||||
/// Ignore ctime changes when checking for modified files
|
||||
#[clap(long, conflicts_with = "force")]
|
||||
#[clap(
|
||||
long,
|
||||
conflicts_with = "force",
|
||||
help_heading = "Options for parent processing"
|
||||
)]
|
||||
#[merge(strategy = merge::bool::overwrite_false)]
|
||||
ignore_ctime: bool,
|
||||
|
||||
/// Ignore inode number changes when checking for modified files
|
||||
#[clap(long, conflicts_with = "force")]
|
||||
#[clap(
|
||||
long,
|
||||
conflicts_with = "force",
|
||||
help_heading = "Options for parent processing"
|
||||
)]
|
||||
#[merge(strategy = merge::bool::overwrite_false)]
|
||||
ignore_inode: bool,
|
||||
|
||||
@ -65,20 +89,18 @@ pub(super) struct Opts {
|
||||
#[clap(long, value_name = "PATH")]
|
||||
as_path: Option<PathBuf>,
|
||||
|
||||
#[clap(flatten)]
|
||||
#[serde(flatten)]
|
||||
snap_opts: SnapshotOptions,
|
||||
|
||||
#[clap(flatten)]
|
||||
#[serde(flatten)]
|
||||
ignore_opts: LocalSourceOptions,
|
||||
|
||||
/// Backup source (can be specified multiple times), use - for stdin. If no source is given, uses all
|
||||
/// sources defined in the config file
|
||||
#[clap(value_name = "SOURCE")]
|
||||
#[merge(skip)]
|
||||
#[serde(skip)]
|
||||
cli_sources: Vec<String>,
|
||||
#[clap(flatten, next_help_heading = "Snapshot options")]
|
||||
#[serde(flatten)]
|
||||
snap_opts: SnapshotOptions,
|
||||
|
||||
/// Output generated snapshot in json format
|
||||
#[clap(long)]
|
||||
#[merge(strategy = merge::bool::overwrite_false)]
|
||||
json: bool,
|
||||
|
||||
// This is a hack to support serde(deny_unknown_fields) for deserializing the backup options from TOML
|
||||
// while still being able to use [[backup.sources]] in the config file.
|
||||
|
||||
@ -43,12 +43,15 @@ struct IdOpt {
|
||||
|
||||
#[derive(Parser)]
|
||||
struct TreeOpts {
|
||||
#[clap(flatten, help_heading = "SNAPSHOT FILTER OPTIONS (when using latest)")]
|
||||
filter: SnapshotFilter,
|
||||
|
||||
/// Snapshot/path of the tree to display
|
||||
#[clap(value_name = "SNAPSHOT[:PATH]")]
|
||||
snap: String,
|
||||
|
||||
#[clap(
|
||||
flatten,
|
||||
next_help_heading = "Snapshot filter options (when using latest)"
|
||||
)]
|
||||
filter: SnapshotFilter,
|
||||
}
|
||||
|
||||
pub(super) fn execute(repo: OpenRepository, opts: Opts, config_file: RusticConfig) -> Result<()> {
|
||||
|
||||
@ -24,7 +24,7 @@ use crate::repository::OpenRepository;
|
||||
#[derive(Parser)]
|
||||
pub(super) struct Opts {
|
||||
/// Don't verify the data saved in the cache
|
||||
#[clap(long, conflicts_with = "no-cache")]
|
||||
#[clap(long, conflicts_with = "no_cache")]
|
||||
trust_cache: bool,
|
||||
|
||||
/// Read all data blobs
|
||||
|
||||
@ -5,6 +5,7 @@ use clap_complete::{generate, shells, Generator};
|
||||
|
||||
#[derive(Parser)]
|
||||
pub(super) struct Opts {
|
||||
/// Shell to generate completions for
|
||||
#[clap(value_enum)]
|
||||
sh: Variant,
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use anyhow::{bail, Result};
|
||||
use bytesize::ByteSize;
|
||||
use clap::{AppSettings, Parser};
|
||||
use clap::Parser;
|
||||
|
||||
use crate::backend::{DecryptBackend, DecryptWriteBackend};
|
||||
use crate::repofile::ConfigFile;
|
||||
@ -40,7 +40,6 @@ pub(super) fn execute(mut repo: OpenRepository, opts: Opts) -> Result<()> {
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[clap(global_setting(AppSettings::DeriveDisplayOrder))]
|
||||
pub(super) struct ConfigOpts {
|
||||
/// Set compression level. Allowed levels are 1 to 22 and -1 to -7, see <https://facebook.github.io/zstd/>.
|
||||
/// Note that 0 equals to no compression
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use clap::{AppSettings, Parser};
|
||||
use clap::Parser;
|
||||
use log::*;
|
||||
use rayon::prelude::*;
|
||||
|
||||
@ -13,22 +13,20 @@ use crate::repofile::{Id, SnapshotFile, SnapshotFilter};
|
||||
use crate::repository::{OpenRepository, Repository, RepositoryOptions};
|
||||
|
||||
#[derive(Parser)]
|
||||
#[clap(global_setting(AppSettings::DeriveDisplayOrder))]
|
||||
pub(super) struct Opts {
|
||||
/// Snapshots to copy. If none is given, use filter options to filter from all snapshots.
|
||||
#[clap(value_name = "ID")]
|
||||
ids: Vec<String>,
|
||||
|
||||
/// Don't copy any snapshot, only show what would be done
|
||||
#[clap(long, short = 'n')]
|
||||
dry_run: bool,
|
||||
|
||||
#[clap(
|
||||
flatten,
|
||||
help_heading = "SNAPSHOT FILTER OPTIONS (if no snapshot is given)"
|
||||
next_help_heading = "Snapshot filter options (if no snapshot is given)"
|
||||
)]
|
||||
filter: SnapshotFilter,
|
||||
|
||||
/// Snapshots to copy. If none is given, use filter to filter from all
|
||||
/// snapshots.
|
||||
#[clap(value_name = "ID")]
|
||||
ids: Vec<String>,
|
||||
}
|
||||
|
||||
pub(super) fn execute(
|
||||
|
||||
@ -15,12 +15,6 @@ use crate::repository::OpenRepository;
|
||||
|
||||
#[derive(Parser)]
|
||||
pub(super) struct Opts {
|
||||
#[clap(flatten)]
|
||||
ignore_opts: LocalSourceOptions,
|
||||
|
||||
#[clap(flatten, help_heading = "SNAPSHOT FILTER OPTIONS (when using latest)")]
|
||||
filter: SnapshotFilter,
|
||||
|
||||
/// Reference snapshot/path
|
||||
#[clap(value_name = "SNAPSHOT1[:PATH1]")]
|
||||
snap1: String,
|
||||
@ -36,6 +30,15 @@ pub(super) struct Opts {
|
||||
/// don't check for different file contents
|
||||
#[clap(long)]
|
||||
no_content: bool,
|
||||
|
||||
#[clap(flatten)]
|
||||
ignore_opts: LocalSourceOptions,
|
||||
|
||||
#[clap(
|
||||
flatten,
|
||||
next_help_heading = "Snapshot filter options (when using latest)"
|
||||
)]
|
||||
filter: SnapshotFilter,
|
||||
}
|
||||
|
||||
pub(super) fn execute(
|
||||
|
||||
@ -12,12 +12,15 @@ use super::{progress_counter, RusticConfig};
|
||||
|
||||
#[derive(Parser)]
|
||||
pub(super) struct Opts {
|
||||
#[clap(flatten, help_heading = "SNAPSHOT FILTER OPTIONS (when using latest)")]
|
||||
filter: SnapshotFilter,
|
||||
|
||||
/// file from snapshot to dump
|
||||
#[clap(value_name = "SNAPSHOT[:PATH]")]
|
||||
snap: String,
|
||||
|
||||
#[clap(
|
||||
flatten,
|
||||
next_help_heading = "Snapshot filter options (when using latest)"
|
||||
)]
|
||||
filter: SnapshotFilter,
|
||||
}
|
||||
|
||||
pub(super) fn execute(
|
||||
|
||||
@ -2,7 +2,7 @@ use std::str::FromStr;
|
||||
|
||||
use anyhow::Result;
|
||||
use chrono::{DateTime, Datelike, Duration, Local, Timelike};
|
||||
use clap::{AppSettings, Parser};
|
||||
use clap::Parser;
|
||||
use derivative::Derivative;
|
||||
use merge::Merge;
|
||||
use serde::Deserialize;
|
||||
@ -16,41 +16,44 @@ use crate::repofile::{
|
||||
use crate::repository::OpenRepository;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[clap(global_setting(AppSettings::DeriveDisplayOrder))]
|
||||
pub(super) struct Opts {
|
||||
/// Snapshots to forget. If none is given, use filter options to filter from all snapshots
|
||||
#[clap(value_name = "ID")]
|
||||
ids: Vec<String>,
|
||||
|
||||
#[clap(flatten)]
|
||||
config: ConfigOpts,
|
||||
|
||||
/// Also prune the repository
|
||||
#[clap(long)]
|
||||
prune: bool,
|
||||
|
||||
#[clap(flatten, help_heading = "PRUNE OPTIONS (only when used with --prune)")]
|
||||
#[clap(
|
||||
flatten,
|
||||
next_help_heading = "PRUNE OPTIONS (only when used with --prune)"
|
||||
)]
|
||||
prune_opts: prune::Opts,
|
||||
|
||||
/// Don't remove anything, only show what would be done
|
||||
#[clap(skip)]
|
||||
dry_run: bool,
|
||||
|
||||
/// Snapshots to forget
|
||||
ids: Vec<String>,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Default, Parser, Deserialize, Merge)]
|
||||
#[clap(global_setting(AppSettings::DeriveDisplayOrder))]
|
||||
#[serde(default, rename_all = "kebab-case", deny_unknown_fields)]
|
||||
#[serde(default, rename_all = "kebab-case")]
|
||||
struct ConfigOpts {
|
||||
/// 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<DisplayFromStr>")]
|
||||
group_by: Option<SnapshotGroupCriterion>,
|
||||
|
||||
#[clap(flatten, help_heading = "SNAPSHOT FILTER OPTIONS")]
|
||||
/// Also prune the repository
|
||||
#[clap(long)]
|
||||
#[merge(strategy = merge::bool::overwrite_false)]
|
||||
prune: bool,
|
||||
|
||||
#[clap(flatten, next_help_heading = "Snapshot filter options")]
|
||||
#[serde(flatten)]
|
||||
filter: SnapshotFilter,
|
||||
|
||||
#[clap(flatten, help_heading = "RETENTION OPTIONS")]
|
||||
#[clap(flatten, next_help_heading = "Retention options")]
|
||||
#[serde(flatten)]
|
||||
keep: KeepOptions,
|
||||
}
|
||||
@ -153,7 +156,7 @@ pub(super) fn execute(
|
||||
}
|
||||
}
|
||||
|
||||
if opts.prune {
|
||||
if opts.config.prune {
|
||||
prune::execute(repo, opts.prune_opts, forget_snaps)?;
|
||||
}
|
||||
|
||||
|
||||
@ -92,8 +92,8 @@ pub fn warm_up_wait(
|
||||
packs: impl ExactSizeIterator<Item = Id>,
|
||||
wait: bool,
|
||||
) -> Result<()> {
|
||||
if repo.opts.warm_up_command.is_some() {
|
||||
warm_up_command(packs, repo.opts.warm_up_command.as_ref().unwrap())?;
|
||||
if let Some(command) = &repo.opts.warm_up_command {
|
||||
warm_up_command(packs, command)?;
|
||||
} else if repo.opts.warm_up {
|
||||
warm_up(&repo.be, packs)?;
|
||||
}
|
||||
|
||||
@ -13,10 +13,10 @@ use crate::repofile::{ConfigFile, KeyFile};
|
||||
|
||||
#[derive(Parser)]
|
||||
pub(super) struct Opts {
|
||||
#[clap(flatten, help_heading = "KEY OPTIONS")]
|
||||
#[clap(flatten, next_help_heading = "Key options")]
|
||||
key_opts: KeyOpts,
|
||||
|
||||
#[clap(flatten, help_heading = "CONFIG OPTIONS")]
|
||||
#[clap(flatten, next_help_heading = "Config options")]
|
||||
config_opts: ConfigOpts,
|
||||
}
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@ use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::{AppSettings, Parser, Subcommand};
|
||||
use clap::{Parser, Subcommand};
|
||||
use rpassword::{prompt_password, read_password_from_bufread};
|
||||
|
||||
use crate::backend::{FileType, WriteBackend};
|
||||
@ -18,11 +18,11 @@ pub(super) struct Opts {
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum Command {
|
||||
/// Add a new key to the repository
|
||||
Add(AddOpts),
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[clap(global_setting(AppSettings::DeriveDisplayOrder))]
|
||||
pub(crate) struct AddOpts {
|
||||
/// File from which to read the new password
|
||||
#[clap(long)]
|
||||
@ -33,7 +33,6 @@ pub(crate) struct AddOpts {
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[clap(global_setting(AppSettings::DeriveDisplayOrder))]
|
||||
pub(crate) struct KeyOpts {
|
||||
/// Set 'hostname' in public key information
|
||||
#[clap(long)]
|
||||
|
||||
@ -9,7 +9,7 @@ use crate::repository::OpenRepository;
|
||||
#[derive(Parser)]
|
||||
pub(super) struct Opts {
|
||||
/// File type to list
|
||||
#[clap(possible_values=["blobs", "index", "packs", "snapshots", "keys"])]
|
||||
#[clap(value_parser=["blobs", "index", "packs", "snapshots", "keys"])]
|
||||
tpe: String,
|
||||
}
|
||||
|
||||
|
||||
@ -11,19 +11,22 @@ use crate::repository::OpenRepository;
|
||||
|
||||
#[derive(Parser)]
|
||||
pub(super) struct Opts {
|
||||
#[clap(flatten, help_heading = "SNAPSHOT FILTER OPTIONS (when using latest)")]
|
||||
filter: SnapshotFilter,
|
||||
/// Snapshot/path to list
|
||||
#[clap(value_name = "SNAPSHOT[:PATH]")]
|
||||
snap: String,
|
||||
|
||||
/// recursively list the dir (default when no PATH is given)
|
||||
#[clap(long)]
|
||||
recursive: bool,
|
||||
|
||||
#[clap(
|
||||
flatten,
|
||||
next_help_heading = "Snapshot filter options (when using latest)"
|
||||
)]
|
||||
filter: SnapshotFilter,
|
||||
|
||||
#[clap(flatten)]
|
||||
streamer_opts: TreeStreamerOptions,
|
||||
|
||||
/// Snapshot/path to list
|
||||
#[clap(value_name = "SNAPSHOT[:PATH]")]
|
||||
snap: String,
|
||||
}
|
||||
|
||||
pub(super) fn execute(
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use anyhow::Result;
|
||||
use chrono::Local;
|
||||
use clap::{AppSettings, Parser};
|
||||
use clap::Parser;
|
||||
use log::*;
|
||||
|
||||
use crate::backend::{DecryptWriteBackend, FileType};
|
||||
@ -13,8 +13,11 @@ use super::helpers::{progress_counter, progress_spinner};
|
||||
use super::rustic_config::RusticConfig;
|
||||
|
||||
#[derive(Default, Parser)]
|
||||
#[clap(global_setting(AppSettings::DeriveDisplayOrder))]
|
||||
pub(super) struct Opts {
|
||||
/// Snapshots to merge. If none is given, use filter options to filter from all snapshots.
|
||||
#[clap(value_name = "ID")]
|
||||
ids: Vec<String>,
|
||||
|
||||
/// Output generated snapshot in json format
|
||||
#[clap(long)]
|
||||
json: bool,
|
||||
@ -23,15 +26,11 @@ pub(super) struct Opts {
|
||||
#[clap(long)]
|
||||
delete: bool,
|
||||
|
||||
#[clap(flatten)]
|
||||
#[clap(flatten, next_help_heading = "Snapshot options")]
|
||||
snap_opts: SnapshotOptions,
|
||||
|
||||
#[clap(flatten, help_heading = "SNAPSHOT FILTER OPTIONS")]
|
||||
#[clap(flatten, next_help_heading = "Snapshot filter options")]
|
||||
filter: SnapshotFilter,
|
||||
|
||||
/// Snapshots to merge. If none is given, use filter to filter from all snapshots.
|
||||
#[clap(value_name = "ID")]
|
||||
ids: Vec<String>,
|
||||
}
|
||||
|
||||
pub(super) fn execute(
|
||||
|
||||
@ -40,24 +40,25 @@ mod tag;
|
||||
use rustic_config::RusticConfig;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[clap(about, name="rustic", version = option_env!("PROJECT_VERSION").unwrap_or(env!("CARGO_PKG_VERSION")))]
|
||||
#[clap(about, version, name="rustic", version = option_env!("PROJECT_VERSION").unwrap_or(env!("CARGO_PKG_VERSION")))]
|
||||
struct Opts {
|
||||
#[clap(flatten, help_heading = "GLOBAL OPTIONS")]
|
||||
global: GlobalOpts,
|
||||
|
||||
#[clap(flatten, help_heading = "REPOSITORY OPTIONS")]
|
||||
repository: RepositoryOptions,
|
||||
|
||||
/// Config profile to use. This parses the file `<PROFILE>.toml` in the config directory.
|
||||
#[clap(
|
||||
short = 'P',
|
||||
long,
|
||||
value_name = "PROFILE",
|
||||
global = true,
|
||||
default_value = "rustic"
|
||||
default_value = "rustic",
|
||||
help_heading = "Global options"
|
||||
)]
|
||||
config_profile: String,
|
||||
|
||||
#[clap(flatten, next_help_heading = "Global options")]
|
||||
global: GlobalOpts,
|
||||
|
||||
#[clap(flatten, next_help_heading = "Repository options")]
|
||||
repository: RepositoryOptions,
|
||||
|
||||
#[clap(subcommand)]
|
||||
command: Command,
|
||||
}
|
||||
@ -87,7 +88,7 @@ struct GlobalOpts {
|
||||
global = true,
|
||||
env = "RUSTIC_PROGRESS_INTERVAL",
|
||||
value_name = "DURATION",
|
||||
conflicts_with = "no-progress"
|
||||
conflicts_with = "no_progress"
|
||||
)]
|
||||
#[serde_as(as = "Option<DisplayFromStr>")]
|
||||
progress_interval: Option<humantime::Duration>,
|
||||
@ -110,11 +111,10 @@ enum Command {
|
||||
/// Check the repository
|
||||
Check(check::Opts),
|
||||
|
||||
/// Copy snapshots to another repository
|
||||
/// Copy snapshots to other repositories. Note: The target repositories must be given in the config file!
|
||||
Copy(copy::Opts),
|
||||
|
||||
/// Compare two snapshots/paths
|
||||
///
|
||||
/// Note that the exclude options only apply for comparison with a local path
|
||||
Diff(diff::Opts),
|
||||
|
||||
@ -167,12 +167,12 @@ pub fn execute() -> Result<()> {
|
||||
|
||||
// get global options from command line / env and config file
|
||||
let config_file = RusticConfig::new(&args.config_profile)?;
|
||||
let mut opts = args.global;
|
||||
config_file.merge_into("global", &mut opts)?;
|
||||
let mut gopts = args.global;
|
||||
config_file.merge_into("global", &mut gopts)?;
|
||||
|
||||
// start logger
|
||||
let level_filter = opts.log_level.unwrap_or(LevelFilter::Info);
|
||||
match opts.log_file {
|
||||
let level_filter = gopts.log_level.unwrap_or(LevelFilter::Info);
|
||||
match gopts.log_file {
|
||||
None => TermLogger::init(
|
||||
level_filter,
|
||||
ConfigBuilder::new()
|
||||
@ -199,12 +199,12 @@ pub fn execute() -> Result<()> {
|
||||
])?,
|
||||
}
|
||||
|
||||
if opts.no_progress {
|
||||
if gopts.no_progress {
|
||||
let mut no_progress = NO_PROGRESS.lock().unwrap();
|
||||
*no_progress = true;
|
||||
}
|
||||
|
||||
if let Some(duration) = opts.progress_interval {
|
||||
if let Some(duration) = gopts.progress_interval {
|
||||
let mut interval = PROGRESS_INTERVAL.lock().unwrap();
|
||||
*interval = *duration;
|
||||
}
|
||||
@ -263,3 +263,9 @@ pub fn execute() -> Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verify_cli() {
|
||||
use clap::CommandFactory;
|
||||
Opts::command().debug_assert()
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ use std::sync::{Arc, Mutex};
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use bytesize::ByteSize;
|
||||
use chrono::{DateTime, Duration, Local};
|
||||
use clap::{AppSettings, Parser};
|
||||
use clap::Parser;
|
||||
use derive_more::Add;
|
||||
use itertools::Itertools;
|
||||
use log::*;
|
||||
@ -24,7 +24,7 @@ use crate::repofile::{HeaderEntry, IndexBlob, IndexFile, IndexPack, SnapshotFile
|
||||
use crate::repository::OpenRepository;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[clap(global_setting(AppSettings::DeriveDisplayOrder))]
|
||||
#[group(id = "prune_opts")]
|
||||
pub(super) struct Opts {
|
||||
/// Don't remove anything, only show what would be done
|
||||
#[clap(long, short = 'n')]
|
||||
@ -59,7 +59,7 @@ pub(super) struct Opts {
|
||||
|
||||
/// Repack packs containing uncompressed blobs. This cannot be used with --fast-repack.
|
||||
/// Implies --max-unused=0.
|
||||
#[clap(long, conflicts_with = "fast-repack")]
|
||||
#[clap(long, conflicts_with = "fast_repack")]
|
||||
repack_uncompressed: bool,
|
||||
|
||||
/// Only repack packs which are cacheable [default: true for a hot/cold repository, else false]
|
||||
@ -139,6 +139,7 @@ pub(super) fn execute(repo: OpenRepository, opts: Opts, ignore_snaps: Vec<Id>) -
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
enum LimitOption {
|
||||
Size(ByteSize),
|
||||
Percentage(u64),
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::{AppSettings, Parser, Subcommand};
|
||||
use clap::{Parser, Subcommand};
|
||||
use log::*;
|
||||
|
||||
use crate::backend::{
|
||||
@ -46,9 +46,8 @@ struct IndexOpts {
|
||||
}
|
||||
|
||||
#[derive(Default, Parser)]
|
||||
#[clap(global_setting(AppSettings::DeriveDisplayOrder))]
|
||||
struct SnapOpts {
|
||||
#[clap(flatten, help_heading = "SNAPSHOT FILTER OPTIONS")]
|
||||
#[clap(flatten, next_help_heading = "Snapshot filter options")]
|
||||
filter: SnapshotFilter,
|
||||
|
||||
/// Only show what would be repaired
|
||||
|
||||
@ -4,9 +4,9 @@ use std::io::Read;
|
||||
use std::num::NonZeroU32;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use chrono::{DateTime, Local, Utc};
|
||||
use clap::{AppSettings, Parser};
|
||||
use clap::Parser;
|
||||
use derive_getters::Dissolve;
|
||||
use ignore::{DirEntry, WalkBuilder};
|
||||
use log::*;
|
||||
@ -24,20 +24,21 @@ use crate::repofile::{SnapshotFile, SnapshotFilter};
|
||||
use crate::repository::OpenRepository;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[clap(global_setting(AppSettings::DeriveDisplayOrder))]
|
||||
pub(super) struct Opts {
|
||||
#[clap(flatten, help_heading = "SNAPSHOT FILTER OPTIONS (when using latest)")]
|
||||
filter: SnapshotFilter,
|
||||
/// Snapshot/path to restore
|
||||
#[clap(value_name = "SNAPSHOT[:PATH]")]
|
||||
snap: String,
|
||||
|
||||
/// Restore destination
|
||||
#[clap(value_name = "DESTINATION")]
|
||||
dest: String,
|
||||
|
||||
/// Dry-run: don't restore, only show what would be done
|
||||
#[clap(long, short = 'n')]
|
||||
dry_run: bool,
|
||||
|
||||
#[clap(flatten)]
|
||||
streamer_opts: TreeStreamerOptions,
|
||||
|
||||
/// Remove all files/dirs in destination which are not contained in snapshot.
|
||||
/// WARNING: Use with care, maybe first try this first with --dry-run?
|
||||
/// WARNING: Use with care, maybe first try this with --dry-run?
|
||||
#[clap(long)]
|
||||
delete: bool,
|
||||
|
||||
@ -46,32 +47,21 @@ pub(super) struct Opts {
|
||||
numeric_id: bool,
|
||||
|
||||
/// Don't restore ownership (user/group)
|
||||
#[clap(long, conflicts_with = "numeric-id")]
|
||||
#[clap(long, conflicts_with = "numeric_id")]
|
||||
no_ownership: bool,
|
||||
|
||||
/// Warm up needed data pack files by only requesting them without processing
|
||||
#[clap(long)]
|
||||
warm_up: bool,
|
||||
|
||||
/// Always read and verify existing files (don't trust correct modification time and file size)
|
||||
#[clap(long)]
|
||||
verify_existing: bool,
|
||||
|
||||
/// Warm up needed data pack files by running the command with %id replaced by pack id
|
||||
#[clap(long, conflicts_with = "warm-up")]
|
||||
warm_up_command: Option<String>,
|
||||
#[clap(flatten)]
|
||||
streamer_opts: TreeStreamerOptions,
|
||||
|
||||
/// Duration (e.g. 10m) to wait after warm up before doing the actual restore
|
||||
#[clap(long, value_name = "DURATION", conflicts_with = "dry-run")]
|
||||
warm_up_wait: Option<humantime::Duration>,
|
||||
|
||||
/// Snapshot/path to restore
|
||||
#[clap(value_name = "SNAPSHOT[:PATH]")]
|
||||
snap: String,
|
||||
|
||||
/// Restore destination
|
||||
#[clap(value_name = "DESTINATION")]
|
||||
dest: String,
|
||||
#[clap(
|
||||
flatten,
|
||||
next_help_heading = "Snapshot filter options (when using latest)"
|
||||
)]
|
||||
filter: SnapshotFilter,
|
||||
}
|
||||
|
||||
pub(super) fn execute(
|
||||
@ -82,13 +72,6 @@ pub(super) fn execute(
|
||||
let be = &repo.dbe;
|
||||
config_file.merge_into("snapshot-filter", &mut opts.filter)?;
|
||||
|
||||
if let Some(command) = &opts.warm_up_command {
|
||||
if !command.contains("%id") {
|
||||
bail!("warm-up command must contain %id!");
|
||||
}
|
||||
info!("using warm-up command {command}");
|
||||
}
|
||||
|
||||
let (id, path) = opts.snap.split_once(':').unwrap_or((&opts.snap, ""));
|
||||
let snap = SnapshotFile::from_str(be, id, |sn| sn.matches(&opts.filter), progress_counter(""))?;
|
||||
|
||||
|
||||
@ -14,8 +14,9 @@ use crate::repository::OpenRepository;
|
||||
|
||||
#[derive(Parser)]
|
||||
pub(super) struct Opts {
|
||||
#[clap(flatten, help_heading = "SNAPSHOT FILTER OPTIONS")]
|
||||
filter: SnapshotFilter,
|
||||
/// Snapshots to show. If none is given, use filter options to filter from all snapshots
|
||||
#[clap(value_name = "ID")]
|
||||
ids: Vec<String>,
|
||||
|
||||
/// Group snapshots by any combination of host,label,paths,tags
|
||||
#[clap(
|
||||
@ -38,9 +39,8 @@ pub(super) struct Opts {
|
||||
#[clap(long, conflicts_with_all = &["long", "json"])]
|
||||
all: bool,
|
||||
|
||||
/// Snapshots to show
|
||||
#[clap(value_name = "ID")]
|
||||
ids: Vec<String>,
|
||||
#[clap(flatten, next_help_heading = "Snapshot filter options")]
|
||||
filter: SnapshotFilter,
|
||||
}
|
||||
|
||||
pub(super) fn execute(
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use anyhow::Result;
|
||||
use chrono::{Duration, Local};
|
||||
use clap::{AppSettings, Parser};
|
||||
use clap::Parser;
|
||||
|
||||
use super::{progress_counter, RusticConfig};
|
||||
use crate::backend::{DecryptWriteBackend, FileType};
|
||||
@ -9,15 +9,19 @@ use crate::repofile::{DeleteOption, SnapshotFile, SnapshotFilter, StringList};
|
||||
use crate::repository::OpenRepository;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[clap(global_setting(AppSettings::DeriveDisplayOrder))]
|
||||
pub(super) struct Opts {
|
||||
/// Snapshots to change tags. If none is given, use filter to filter from all
|
||||
/// snapshots.
|
||||
#[clap(value_name = "ID")]
|
||||
ids: Vec<String>,
|
||||
|
||||
/// Don't change any snapshot, only show which would be modified
|
||||
#[clap(long, short = 'n')]
|
||||
dry_run: bool,
|
||||
|
||||
#[clap(
|
||||
flatten,
|
||||
help_heading = "SNAPSHOT FILTER OPTIONS (if no snapshot is given)"
|
||||
next_help_heading = "Snapshot filter options (if no snapshot is given)"
|
||||
)]
|
||||
filter: SnapshotFilter,
|
||||
|
||||
@ -26,12 +30,12 @@ pub(super) struct Opts {
|
||||
long,
|
||||
value_name = "TAG[,TAG,..]",
|
||||
conflicts_with = "remove",
|
||||
help_heading = "TAG OPTIONS"
|
||||
help_heading = "Tag options"
|
||||
)]
|
||||
add: Vec<StringList>,
|
||||
|
||||
/// Tags to remove (can be specified multiple times)
|
||||
#[clap(long, value_name = "TAG[,TAG,..]", help_heading = "TAG OPTIONS")]
|
||||
#[clap(long, value_name = "TAG[,TAG,..]", help_heading = "Tag options")]
|
||||
remove: Vec<StringList>,
|
||||
|
||||
/// Tag list to set (can be specified multiple times)
|
||||
@ -39,34 +43,29 @@ pub(super) struct Opts {
|
||||
long,
|
||||
value_name = "TAG[,TAG,..]",
|
||||
conflicts_with = "remove",
|
||||
help_heading = "TAG OPTIONS"
|
||||
help_heading = "Tag options"
|
||||
)]
|
||||
set: Vec<StringList>,
|
||||
|
||||
/// Remove any delete mark
|
||||
#[clap(
|
||||
long,
|
||||
conflicts_with_all = &["set-delete-never", "set-delete-after"],
|
||||
help_heading = "DELETE MARK OPTIONS"
|
||||
conflicts_with_all = &["set_delete_never", "set_delete_after"],
|
||||
help_heading = "Delete mark options"
|
||||
)]
|
||||
remove_delete: bool,
|
||||
|
||||
/// Mark snapshot as uneraseable
|
||||
#[clap(
|
||||
long,
|
||||
conflicts_with = "set-delete-after",
|
||||
help_heading = "DELETE MARK OPTIONS"
|
||||
conflicts_with = "set_delete_after",
|
||||
help_heading = "Delete mark options"
|
||||
)]
|
||||
set_delete_never: bool,
|
||||
|
||||
/// Mark snapshot to be deleted after given duration (e.g. 10d)
|
||||
#[clap(long, value_name = "DURATION", help_heading = "DELETE MARK OPTIONS")]
|
||||
#[clap(long, value_name = "DURATION", help_heading = "Delete mark options")]
|
||||
set_delete_after: Option<humantime::Duration>,
|
||||
|
||||
/// Snapshots to change tags. If none is given, use filter to filter from all
|
||||
/// snapshots.
|
||||
#[clap(value_name = "ID")]
|
||||
ids: Vec<String>,
|
||||
}
|
||||
|
||||
pub(super) fn execute(
|
||||
|
||||
@ -5,7 +5,7 @@ use std::{cmp::Ordering, fmt::Display};
|
||||
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use chrono::{DateTime, Duration, Local};
|
||||
use clap::{AppSettings, Parser};
|
||||
use clap::Parser;
|
||||
use derivative::Derivative;
|
||||
use dunce::canonicalize;
|
||||
use gethostname::gethostname;
|
||||
@ -25,7 +25,6 @@ use crate::repository::parse_command;
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Clone, Default, Parser, Deserialize, Merge)]
|
||||
#[clap(global_setting(AppSettings::DeriveDisplayOrder))]
|
||||
#[serde(default, rename_all = "kebab-case", deny_unknown_fields)]
|
||||
pub struct SnapshotOptions {
|
||||
/// Label snapshot with given label
|
||||
@ -47,7 +46,7 @@ pub struct SnapshotOptions {
|
||||
description_from: Option<PathBuf>,
|
||||
|
||||
/// Mark snapshot as uneraseable
|
||||
#[clap(long, conflicts_with = "delete-after")]
|
||||
#[clap(long, conflicts_with = "delete_after")]
|
||||
#[merge(strategy = merge::bool::overwrite_false)]
|
||||
delete_never: bool,
|
||||
|
||||
@ -420,6 +419,7 @@ impl Ord for SnapshotFile {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct SnapshotFn(FnPtr, AST);
|
||||
impl FromStr for SnapshotFn {
|
||||
type Err = anyhow::Error;
|
||||
|
||||
@ -49,7 +49,6 @@ pub struct RepositoryOptions {
|
||||
short,
|
||||
long,
|
||||
global = true,
|
||||
parse(from_os_str),
|
||||
env = "RUSTIC_PASSWORD_FILE",
|
||||
conflicts_with = "password"
|
||||
)]
|
||||
@ -60,7 +59,7 @@ pub struct RepositoryOptions {
|
||||
long,
|
||||
global = true,
|
||||
env = "RUSTIC_PASSWORD_COMMAND",
|
||||
conflicts_with_all = &["password", "password-file"],
|
||||
conflicts_with_all = &["password", "password_file"],
|
||||
)]
|
||||
password_command: Option<String>,
|
||||
|
||||
@ -73,8 +72,7 @@ pub struct RepositoryOptions {
|
||||
#[clap(
|
||||
long,
|
||||
global = true,
|
||||
parse(from_os_str),
|
||||
conflicts_with = "no-cache",
|
||||
conflicts_with = "no_cache",
|
||||
env = "RUSTIC_CACHE_DIR"
|
||||
)]
|
||||
cache_dir: Option<PathBuf>,
|
||||
@ -85,7 +83,7 @@ pub struct RepositoryOptions {
|
||||
pub(crate) warm_up: bool,
|
||||
|
||||
/// Warm up needed data pack files by running the command with %id replaced by pack id
|
||||
#[clap(long, global = true, conflicts_with = "warm-up")]
|
||||
#[clap(long, global = true, conflicts_with = "warm_up")]
|
||||
pub(crate) warm_up_command: Option<String>,
|
||||
|
||||
/// Duration (e.g. 10m) to wait after warm up
|
||||
@ -149,6 +147,13 @@ impl Repository {
|
||||
None => bail!("No repository given. Please use the --repository option."),
|
||||
};
|
||||
|
||||
if let Some(command) = &opts.warm_up_command {
|
||||
if !command.contains("%id") {
|
||||
bail!("warm-up command must contain %id!");
|
||||
}
|
||||
info!("using warm-up command {command}");
|
||||
}
|
||||
|
||||
let be_hot = opts
|
||||
.repo_hot
|
||||
.as_ref()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user