zvault/src/cli/args.rs

947 lines
38 KiB
Rust
Raw Normal View History

2017-07-21 09:21:59 +00:00
use prelude::*;
2017-03-22 08:19:16 +00:00
use super::*;
2017-03-16 19:05:58 +00:00
2017-05-17 07:43:14 +00:00
use std::path::{Path, PathBuf};
2018-02-19 22:31:58 +00:00
use log;
2017-04-05 10:41:39 +00:00
use clap::{App, AppSettings, Arg, SubCommand};
2017-03-16 19:05:58 +00:00
2018-02-19 21:30:59 +00:00
#[allow(option_option)]
2017-03-16 19:05:58 +00:00
pub enum Arguments {
Init {
2017-05-17 07:43:14 +00:00
repo_path: PathBuf,
2017-03-16 19:05:58 +00:00
bundle_size: usize,
chunker: ChunkerType,
2017-03-17 10:03:07 +00:00
compression: Option<Compression>,
2017-03-18 16:22:11 +00:00
encryption: bool,
2017-03-22 13:10:42 +00:00
hash: HashMethod,
2017-03-22 13:42:27 +00:00
remote_path: String
2017-03-16 19:05:58 +00:00
},
Backup {
2017-05-17 07:43:14 +00:00
repo_path: PathBuf,
2017-03-16 19:05:58 +00:00
backup_name: String,
src_path: String,
2017-03-20 21:24:53 +00:00
full: bool,
2017-03-24 08:26:55 +00:00
reference: Option<String>,
2017-03-24 10:00:20 +00:00
same_device: bool,
excludes: Vec<String>,
2017-03-26 18:33:32 +00:00
excludes_from: Option<String>,
2017-04-03 13:18:06 +00:00
no_default_excludes: bool,
tar: bool
2017-03-16 19:05:58 +00:00
},
Restore {
2017-05-17 07:43:14 +00:00
repo_path: PathBuf,
2017-03-16 19:05:58 +00:00
backup_name: String,
inode: Option<String>,
2017-04-03 13:18:06 +00:00
dst_path: String,
tar: bool
2017-03-16 19:05:58 +00:00
},
2017-03-17 11:58:22 +00:00
Remove {
2017-05-17 07:43:14 +00:00
repo_path: PathBuf,
2017-03-17 11:58:22 +00:00
backup_name: String,
2017-04-13 12:10:11 +00:00
inode: Option<String>,
force: bool
2017-03-17 11:58:22 +00:00
},
2018-03-08 14:20:20 +00:00
Duplicates {
repo_path: PathBuf,
backup_name: String,
inode: Option<String>,
min_size: u64
},
2017-03-20 14:38:33 +00:00
Prune {
2017-05-17 07:43:14 +00:00
repo_path: PathBuf,
2017-03-20 14:38:33 +00:00
prefix: String,
2017-04-07 16:57:49 +00:00
daily: usize,
weekly: usize,
monthly: usize,
yearly: usize,
2017-03-20 17:11:03 +00:00
force: bool
2017-03-20 14:38:33 +00:00
},
2017-03-17 11:58:22 +00:00
Vacuum {
2017-05-17 07:43:14 +00:00
repo_path: PathBuf,
2017-03-20 13:03:29 +00:00
ratio: f32,
force: bool,
combine: bool
2017-03-17 11:58:22 +00:00
},
2017-03-16 19:05:58 +00:00
Check {
2017-05-17 07:43:14 +00:00
repo_path: PathBuf,
2017-03-16 19:05:58 +00:00
backup_name: Option<String>,
inode: Option<String>,
bundles: bool,
bundle_data: bool,
2017-04-12 18:19:21 +00:00
index: bool,
repair: bool
2017-03-16 19:05:58 +00:00
},
List {
2017-05-17 07:43:14 +00:00
repo_path: PathBuf,
2017-03-16 19:05:58 +00:00
backup_name: Option<String>,
inode: Option<String>
},
Info {
2017-05-17 07:43:14 +00:00
repo_path: PathBuf,
2017-03-16 19:05:58 +00:00
backup_name: Option<String>,
inode: Option<String>
},
2018-03-08 14:20:20 +00:00
Statistics {
2018-03-06 23:36:44 +00:00
repo_path: PathBuf
},
2017-05-17 05:35:41 +00:00
Copy {
2017-05-17 07:43:14 +00:00
repo_path_src: PathBuf,
2017-05-17 05:35:41 +00:00
backup_name_src: String,
2017-05-17 07:43:14 +00:00
repo_path_dst: PathBuf,
2017-07-21 09:21:59 +00:00
backup_name_dst: String
2017-05-17 05:35:41 +00:00
},
2017-03-26 09:34:16 +00:00
Mount {
2017-05-17 07:43:14 +00:00
repo_path: PathBuf,
2017-03-26 09:34:16 +00:00
backup_name: Option<String>,
inode: Option<String>,
mount_point: String
},
2017-07-21 09:21:59 +00:00
Versions { repo_path: PathBuf, path: String },
2017-03-29 21:24:26 +00:00
Diff {
2017-05-17 07:43:14 +00:00
repo_path_old: PathBuf,
2017-03-29 21:24:26 +00:00
backup_name_old: String,
inode_old: Option<String>,
2017-05-17 07:43:14 +00:00
repo_path_new: PathBuf,
2017-03-29 21:24:26 +00:00
backup_name_new: String,
inode_new: Option<String>
},
2017-07-21 09:21:59 +00:00
Analyze { repo_path: PathBuf },
BundleList { repo_path: PathBuf },
2017-03-24 11:52:01 +00:00
BundleInfo {
2017-05-17 07:43:14 +00:00
repo_path: PathBuf,
2017-03-24 11:52:01 +00:00
bundle_id: BundleId
},
2017-03-17 11:58:22 +00:00
Import {
2017-05-17 07:43:14 +00:00
repo_path: PathBuf,
2017-03-22 16:28:45 +00:00
remote_path: String,
key_files: Vec<String>
2017-03-17 11:58:22 +00:00
},
2017-03-26 18:33:32 +00:00
Config {
2017-05-17 07:43:14 +00:00
repo_path: PathBuf,
2017-03-18 16:22:11 +00:00
bundle_size: Option<usize>,
chunker: Option<ChunkerType>,
compression: Option<Option<Compression>>,
encryption: Option<Option<PublicKey>>,
hash: Option<HashMethod>
},
GenKey {
2017-05-08 13:11:07 +00:00
file: Option<String>,
password: Option<String>
2017-03-18 16:22:11 +00:00
},
AddKey {
2017-05-17 07:43:14 +00:00
repo_path: PathBuf,
2017-03-22 16:28:45 +00:00
file: Option<String>,
2017-05-08 13:11:07 +00:00
password: Option<String>,
2017-03-18 16:22:11 +00:00
set_default: bool
},
2017-03-16 19:05:58 +00:00
AlgoTest {
2017-03-17 10:03:07 +00:00
file: String,
bundle_size: usize,
chunker: ChunkerType,
compression: Option<Compression>,
2017-03-18 16:22:11 +00:00
encrypt: bool,
2017-03-17 10:03:07 +00:00
hash: HashMethod
2017-03-16 19:05:58 +00:00
}
}
2017-05-17 07:43:14 +00:00
fn convert_repo_path(mut path_str: &str) -> PathBuf {
if path_str.is_empty() {
path_str = "default";
}
let path = Path::new(path_str);
if path.is_absolute() {
path.to_path_buf()
} else {
ZVAULT_FOLDER.join("repos").join(path)
2017-03-31 16:44:27 +00:00
}
2017-05-17 07:43:14 +00:00
}
2017-07-21 09:21:59 +00:00
fn parse_repo_path(
repo_path: &str,
existing: bool,
backup_restr: Option<bool>,
path_restr: Option<bool>,
) -> Result<(PathBuf, Option<&str>, Option<&str>), String> {
2017-05-17 07:43:14 +00:00
let mut parts = repo_path.splitn(3, "::");
let repo = convert_repo_path(parts.next().unwrap_or(""));
if existing && !repo.join("config.yaml").exists() {
2018-02-24 12:19:51 +00:00
return Err(tr!("The specified repository does not exist").to_string());
2017-04-07 09:05:28 +00:00
}
2017-05-17 07:43:14 +00:00
if !existing && repo.exists() {
2018-02-24 12:19:51 +00:00
return Err(tr!("The specified repository already exists").to_string());
2017-04-07 09:05:28 +00:00
}
2017-03-31 16:44:27 +00:00
let mut backup = parts.next();
if let Some(val) = backup {
if val.is_empty() {
backup = None
}
}
let mut path = parts.next();
if let Some(val) = path {
if val.is_empty() {
path = None
}
}
2017-03-26 09:34:16 +00:00
if let Some(restr) = backup_restr {
if !restr && backup.is_some() {
2018-02-24 12:19:51 +00:00
return Err(tr!("No backup may be given here").to_string());
2017-03-26 09:34:16 +00:00
}
if restr && backup.is_none() {
2018-02-24 12:19:51 +00:00
return Err(tr!("A backup must be specified").to_string());
2017-03-26 09:34:16 +00:00
}
}
if let Some(restr) = path_restr {
if !restr && path.is_some() {
2018-02-24 12:19:51 +00:00
return Err(tr!("No subpath may be given here").to_string());
2017-03-26 09:34:16 +00:00
}
if restr && path.is_none() {
2018-02-24 12:19:51 +00:00
return Err(tr!("A subpath must be specified").to_string());
2017-03-26 09:34:16 +00:00
}
}
2017-04-03 13:18:06 +00:00
Ok((repo, backup, path))
2017-03-26 09:34:16 +00:00
}
2017-07-21 09:21:59 +00:00
#[allow(unknown_lints, needless_pass_by_value)]
fn validate_repo_path(
repo_path: String,
existing: bool,
backup_restr: Option<bool>,
path_restr: Option<bool>,
) -> Result<(), String> {
2017-04-07 09:05:28 +00:00
parse_repo_path(&repo_path, existing, backup_restr, path_restr).map(|_| ())
}
2018-03-08 14:20:20 +00:00
fn parse_filesize(num: &str) -> Result<u64, String> {
let (num, suffix) = if num.len() > 0 {
num.split_at(num.len() - 1)
} else {
(num, "b")
};
let factor = match suffix {
"b" | "B" => 1,
"k" | "K" => 1024,
"m" | "M" => 1024*1024,
"g" | "G" => 1024*1024*1024,
"t" | "T" => 1024*1024*1024*1024,
_ => return Err(tr!("Unknown suffix").to_string())
};
let num = try!(parse_num(num));
Ok(num * factor)
}
#[allow(unknown_lints, needless_pass_by_value)]
fn validate_filesize(val: String) -> Result<(), String> {
parse_filesize(&val).map(|_| ())
}
2017-04-07 09:05:28 +00:00
fn parse_num(num: &str) -> Result<u64, String> {
2017-03-17 10:03:07 +00:00
if let Ok(num) = num.parse::<u64>() {
2017-04-03 13:18:06 +00:00
Ok(num)
2017-03-17 10:03:07 +00:00
} else {
2018-02-24 12:19:51 +00:00
Err(tr!("Must be a number").to_string())
2017-03-17 10:03:07 +00:00
}
}
2017-07-21 09:21:59 +00:00
#[allow(unknown_lints, needless_pass_by_value)]
2017-04-07 09:05:28 +00:00
fn validate_num(val: String) -> Result<(), String> {
parse_num(&val).map(|_| ())
}
fn parse_chunker(val: &str) -> Result<ChunkerType, String> {
2017-03-18 16:22:11 +00:00
if let Ok(chunker) = ChunkerType::from_string(val) {
2017-04-03 13:18:06 +00:00
Ok(chunker)
2017-03-17 10:03:07 +00:00
} else {
2018-02-24 12:19:51 +00:00
Err(tr!("Invalid chunker method/size").to_string())
2017-03-17 10:03:07 +00:00
}
}
2017-07-21 09:21:59 +00:00
#[allow(unknown_lints, needless_pass_by_value)]
2017-04-07 09:05:28 +00:00
fn validate_chunker(val: String) -> Result<(), String> {
parse_chunker(&val).map(|_| ())
}
fn parse_compression(val: &str) -> Result<Option<Compression>, String> {
2017-03-17 10:03:07 +00:00
if val == "none" {
2017-07-21 09:21:59 +00:00
return Ok(None);
2017-03-17 10:03:07 +00:00
}
if let Ok(compression) = Compression::from_string(val) {
2017-04-03 13:18:06 +00:00
Ok(Some(compression))
2017-03-17 10:03:07 +00:00
} else {
2018-02-24 12:19:51 +00:00
Err(tr!("Invalid compression method/level").to_string())
2017-03-17 10:03:07 +00:00
}
}
2017-07-21 09:21:59 +00:00
#[allow(unknown_lints, needless_pass_by_value)]
2017-04-07 09:05:28 +00:00
fn validate_compression(val: String) -> Result<(), String> {
parse_compression(&val).map(|_| ())
}
fn parse_public_key(val: &str) -> Result<Option<PublicKey>, String> {
if val.to_lowercase() == "none" {
return Ok(None);
}
2017-03-18 16:22:11 +00:00
let bytes = match parse_hex(val) {
Ok(bytes) => bytes,
Err(_) => {
2018-02-24 12:19:51 +00:00
return Err(tr!("Invalid hexadecimal").to_string());
2017-03-18 16:22:11 +00:00
}
};
if let Some(key) = PublicKey::from_slice(&bytes) {
2017-04-07 09:05:28 +00:00
Ok(Some(key))
2017-03-18 16:22:11 +00:00
} else {
2018-02-24 12:19:51 +00:00
return Err(tr!("Invalid key").to_string());
2017-03-18 16:22:11 +00:00
}
}
2017-07-21 09:21:59 +00:00
#[allow(unknown_lints, needless_pass_by_value)]
2017-04-07 09:05:28 +00:00
fn validate_public_key(val: String) -> Result<(), String> {
parse_public_key(&val).map(|_| ())
}
fn parse_hash(val: &str) -> Result<HashMethod, String> {
2017-03-18 16:22:11 +00:00
if let Ok(hash) = HashMethod::from(val) {
2017-04-03 13:18:06 +00:00
Ok(hash)
2017-03-17 10:03:07 +00:00
} else {
2018-02-24 12:19:51 +00:00
Err(tr!("Invalid hash method").to_string())
2017-03-17 10:03:07 +00:00
}
}
2017-07-21 09:21:59 +00:00
#[allow(unknown_lints, needless_pass_by_value)]
2017-04-07 09:05:28 +00:00
fn validate_hash(val: String) -> Result<(), String> {
parse_hash(&val).map(|_| ())
}
2017-04-03 13:18:06 +00:00
fn parse_bundle_id(val: &str) -> Result<BundleId, ErrorCode> {
2017-03-24 11:52:01 +00:00
if let Ok(hash) = Hash::from_string(val) {
2017-04-03 13:18:06 +00:00
Ok(BundleId(hash))
2017-03-24 11:52:01 +00:00
} else {
2018-02-24 12:19:51 +00:00
tr_error!("Invalid bundle id: {}", val);
2017-04-03 13:18:06 +00:00
Err(ErrorCode::InvalidArgs)
2017-03-24 11:52:01 +00:00
}
}
2017-07-21 09:21:59 +00:00
#[allow(unknown_lints, needless_pass_by_value)]
2017-04-07 09:05:28 +00:00
fn validate_existing_path(val: String) -> Result<(), String> {
if !Path::new(&val).exists() {
2018-02-24 12:19:51 +00:00
Err(tr!("Path does not exist").to_string())
2017-04-07 09:05:28 +00:00
} else {
Ok(())
}
}
2017-07-21 09:21:59 +00:00
#[allow(unknown_lints, needless_pass_by_value)]
2017-05-11 07:45:55 +00:00
fn validate_existing_path_or_stdio(val: String) -> Result<(), String> {
if val != "-" && !Path::new(&val).exists() {
2018-02-24 12:19:51 +00:00
Err(tr!("Path does not exist").to_string())
2017-05-11 07:45:55 +00:00
} else {
Ok(())
}
}
2017-04-07 09:05:28 +00:00
2017-07-21 09:21:59 +00:00
#[allow(unknown_lints, cyclomatic_complexity)]
2018-02-19 22:31:58 +00:00
pub fn parse() -> Result<(log::Level, Arguments), ErrorCode> {
2018-02-24 12:19:51 +00:00
let args = App::new("zvault")
.version(crate_version!())
.author(crate_authors!(",\n"))
.about(crate_description!())
2017-04-07 16:57:49 +00:00
.settings(&[AppSettings::VersionlessSubcommands, AppSettings::SubcommandRequiredElseHelp])
.global_settings(&[AppSettings::AllowMissingPositional, AppSettings::UnifiedHelpMessage, AppSettings::ColoredHelp, AppSettings::ColorAuto])
2018-02-24 12:19:51 +00:00
.arg(Arg::from_usage("-v --verbose")
.help(tr!("Print more information"))
.global(true)
.multiple(true)
.max_values(3)
.takes_value(false))
.arg(Arg::from_usage("-q --quiet")
.help(tr!("Print less information"))
.global(true)
.conflicts_with("verbose"))
.subcommand(SubCommand::with_name("init")
.about(tr!("Initialize a new repository"))
.arg(Arg::from_usage("[bundle_size] --bundle-size [SIZE]")
.help(tr!("Set the target bundle size in MiB"))
.default_value(DEFAULT_BUNDLE_SIZE_STR)
.validator(validate_num))
.arg(Arg::from_usage("--chunker [CHUNKER]")
.help(tr!("Set the chunker algorithm and target chunk size"))
.default_value(DEFAULT_CHUNKER)
.validator(validate_chunker))
.arg(Arg::from_usage("-c --compression [COMPRESSION]")
.help(tr!("Set the compression method and level"))
.default_value(DEFAULT_COMPRESSION)
.validator(validate_compression))
.arg(Arg::from_usage("-e --encrypt")
.help(tr!("Generate a keypair and enable encryption")))
.arg(Arg::from_usage("--hash [HASH]")
.help(tr!("Set the hash method'"))
.default_value(DEFAULT_HASH)
.validator(validate_hash))
.arg(Arg::from_usage("-r --remote <REMOTE>")
.help(tr!("Set the path to the mounted remote storage"))
2017-04-07 09:05:28 +00:00
.validator(validate_existing_path))
2018-02-24 12:19:51 +00:00
.arg(Arg::from_usage("<REPO>")
.help(tr!("The path for the new repository"))
2017-04-07 16:57:49 +00:00
.validator(|val| validate_repo_path(val, false, Some(false), Some(false)))))
2018-02-24 12:19:51 +00:00
.subcommand(SubCommand::with_name("backup")
.about(tr!("Create a new backup"))
.arg(Arg::from_usage("--full")
.help(tr!("Create a full backup without using a reference")))
.arg(Arg::from_usage("[reference] --ref [REF]")
.help(tr!("Base the new backup on this reference"))
2017-04-07 09:05:28 +00:00
.conflicts_with("full"))
2018-02-24 12:19:51 +00:00
.arg(Arg::from_usage("[cross_device] -x --xdev")
.help(tr!("Allow to cross filesystem boundaries")))
.arg(Arg::from_usage("-e --exclude [PATTERN]...")
.help(tr!("Exclude this path or file pattern")))
.arg(Arg::from_usage("[excludes_from] --excludes-from [FILE]")
.help(tr!("Read the list of excludes from this file")))
.arg(Arg::from_usage("[no_default_excludes] --no-default-excludes")
.help(tr!("Do not load the default excludes file")))
.arg(Arg::from_usage("--tar")
.help(tr!("Read the source data from a tar file"))
2017-04-07 09:05:28 +00:00
.conflicts_with_all(&["reference", "exclude", "excludes_from"]))
2018-02-24 12:19:51 +00:00
.arg(Arg::from_usage("<SRC>")
.help(tr!("Source path to backup"))
2017-05-11 07:45:55 +00:00
.validator(validate_existing_path_or_stdio))
2018-02-24 12:19:51 +00:00
.arg(Arg::from_usage("<BACKUP>")
.help(tr!("Backup path, [repository]::backup"))
2017-04-07 09:05:28 +00:00
.validator(|val| validate_repo_path(val, true, Some(true), Some(false)))))
2018-02-24 12:19:51 +00:00
.subcommand(SubCommand::with_name("restore")
.about(tr!("Restore a backup or subtree"))
.arg(Arg::from_usage("--tar")
.help(tr!("Restore in form of a tar file")))
.arg(Arg::from_usage("<BACKUP>")
.help(tr!("The backup/subtree path, [repository]::backup[::subtree]"))
2017-04-07 09:05:28 +00:00
.validator(|val| validate_repo_path(val, true, Some(true), None)))
2018-02-24 12:19:51 +00:00
.arg(Arg::from_usage("<DST>")
.help(tr!("Destination path for backup"))))
.subcommand(SubCommand::with_name("remove")
.aliases(&["rm", "delete", "del"])
.about(tr!("Remove a backup or a subtree"))
.arg(Arg::from_usage("-f --force")
.help(tr!("Remove multiple backups in a backup folder")))
.arg(Arg::from_usage("<BACKUP>")
.help(tr!("The backup/subtree path, [repository]::backup[::subtree]"))
2017-04-07 09:05:28 +00:00
.validator(|val| validate_repo_path(val, true, Some(true), None))))
2018-02-24 12:19:51 +00:00
.subcommand(SubCommand::with_name("prune")
.about(tr!("Remove backups based on age"))
.arg(Arg::from_usage("-p --prefix [PREFIX]")
.help(tr!("Only consider backups starting with this prefix")))
.arg(Arg::from_usage("-d --daily [NUM]")
.help(tr!("Keep this number of daily backups"))
.default_value("0")
.validator(validate_num))
.arg(Arg::from_usage("-w --weekly [NUM]")
.help(tr!("Keep this number of weekly backups"))
.default_value("0")
.validator(validate_num))
.arg(Arg::from_usage("-m --monthly [NUM]")
.help(tr!("Keep this number of monthly backups"))
.default_value("0")
.validator(validate_num))
.arg(Arg::from_usage("-y --yearly [NUM]")
.help(tr!("Keep this number of yearly backups"))
.default_value("0")
.validator(validate_num))
.arg(Arg::from_usage("-f --force")
.help(tr!("Actually run the prune instead of simulating it")))
.arg(Arg::from_usage("<REPO>")
.help(tr!("Path of the repository"))
2017-04-07 09:05:28 +00:00
.validator(|val| validate_repo_path(val, true, Some(false), Some(false)))))
2018-02-24 12:19:51 +00:00
.subcommand(SubCommand::with_name("vacuum")
.about(tr!("Reclaim space by rewriting bundles"))
.arg(Arg::from_usage("-r --ratio [NUM]")
.help(tr!("Ratio in % of unused space in a bundle to rewrite that bundle"))
2017-04-07 09:05:28 +00:00
.default_value(DEFAULT_VACUUM_RATIO_STR).validator(validate_num))
2018-02-24 12:19:51 +00:00
.arg(Arg::from_usage("--combine")
.help(tr!("Combine small bundles into larger ones")))
.arg(Arg::from_usage("-f --force")
.help(tr!("Actually run the vacuum instead of simulating it")))
.arg(Arg::from_usage("<REPO>")
.help(tr!("Path of the repository"))
2017-04-07 09:05:28 +00:00
.validator(|val| validate_repo_path(val, true, Some(false), Some(false)))))
2018-02-24 12:19:51 +00:00
.subcommand(SubCommand::with_name("check")
.about(tr!("Check the repository, a backup or a backup subtree"))
.arg(Arg::from_usage("-b --bundles")
.help(tr!("Check the bundles")))
.arg(Arg::from_usage("[bundle_data] --bundle-data")
.help(tr!("Check bundle contents (slow)"))
.requires("bundles")
.alias("data"))
.arg(Arg::from_usage("-i --index")
.help(tr!("Check the chunk index")))
.arg(Arg::from_usage("-r --repair")
.help(tr!("Try to repair errors")))
.arg(Arg::from_usage("<PATH>")
.help(tr!("Path of the repository/backup/subtree, [repository][::backup[::subtree]]"))
2017-04-07 09:05:28 +00:00
.validator(|val| validate_repo_path(val, true, None, None))))
2018-02-24 12:19:51 +00:00
.subcommand(SubCommand::with_name("list")
.alias("ls")
.about(tr!("List backups or backup contents"))
.arg(Arg::from_usage("<PATH>")
.help(tr!("Path of the repository/backup/subtree, [repository][::backup[::subtree]]"))
2017-04-07 09:05:28 +00:00
.validator(|val| validate_repo_path(val, true, None, None))))
2018-02-24 12:19:51 +00:00
.subcommand(SubCommand::with_name("mount")
.about(tr!("Mount the repository, a backup or a subtree"))
.arg(Arg::from_usage("<PATH>")
.help(tr!("Path of the repository/backup/subtree, [repository][::backup[::subtree]]"))
2017-04-07 09:05:28 +00:00
.validator(|val| validate_repo_path(val, true, None, None)))
2018-02-24 12:19:51 +00:00
.arg(Arg::from_usage("<MOUNTPOINT>")
.help(tr!("Existing mount point"))
2017-04-07 09:05:28 +00:00
.validator(validate_existing_path)))
2018-02-24 12:19:51 +00:00
.subcommand(SubCommand::with_name("bundlelist")
.about(tr!("List bundles in a repository"))
.arg(Arg::from_usage("<REPO>")
.help(tr!("Path of the repository"))
2017-04-07 09:05:28 +00:00
.validator(|val| validate_repo_path(val, true, Some(false), Some(false)))))
2018-03-08 14:20:20 +00:00
.subcommand(SubCommand::with_name("statistics")
.alias("stats")
2018-03-06 23:36:44 +00:00
.about(tr!("Display statistics on a repository"))
.arg(Arg::from_usage("<REPO>")
.help(tr!("Path of the repository"))
.validator(|val| validate_repo_path(val, true, Some(false), Some(false)))))
2018-02-24 12:19:51 +00:00
.subcommand(SubCommand::with_name("bundleinfo")
.about(tr!("Display information on a bundle"))
.arg(Arg::from_usage("<REPO>")
.help(tr!("Path of the repository"))
2017-04-07 09:05:28 +00:00
.validator(|val| validate_repo_path(val, true, Some(false), Some(false))))
2018-02-24 12:19:51 +00:00
.arg(Arg::from_usage("<BUNDLE>")
.help(tr!("Id of the bundle"))))
.subcommand(SubCommand::with_name("import")
.about(tr!("Reconstruct a repository from the remote storage"))
.arg(Arg::from_usage("-k --key [FILE]...")
.help(tr!("Key file needed to read the bundles")))
.arg(Arg::from_usage("<REMOTE>")
.help(tr!("Remote repository path"))
2017-04-07 09:05:28 +00:00
.validator(validate_existing_path))
2018-02-24 12:19:51 +00:00
.arg(Arg::from_usage("<REPO>")
.help(tr!("The path for the new repository"))
2017-04-07 09:05:28 +00:00
.validator(|val| validate_repo_path(val, false, Some(false), Some(false)))))
2018-02-24 12:19:51 +00:00
.subcommand(SubCommand::with_name("info")
.about(tr!("Display information on a repository, a backup or a subtree"))
.arg(Arg::from_usage("<PATH>")
.help(tr!("Path of the repository/backup/subtree, [repository][::backup[::subtree]]"))
2017-04-07 09:05:28 +00:00
.validator(|val| validate_repo_path(val, true, None, None))))
2018-02-24 12:19:51 +00:00
.subcommand(SubCommand::with_name("analyze")
.about(tr!("Analyze the used and reclaimable space of bundles"))
.arg(Arg::from_usage("<REPO>")
.help(tr!("Path of the repository"))
2017-04-07 09:05:28 +00:00
.validator(|val| validate_repo_path(val, true, Some(false), Some(false)))))
2018-02-24 12:19:51 +00:00
.subcommand(SubCommand::with_name("versions")
.about(tr!("Find different versions of a file in all backups"))
.arg(Arg::from_usage("<REPO>")
.help(tr!("Path of the repository"))
2017-04-07 09:05:28 +00:00
.validator(|val| validate_repo_path(val, true, Some(false), Some(false))))
2018-02-24 12:19:51 +00:00
.arg(Arg::from_usage("<PATH>")
.help(tr!("Path of the file"))))
.subcommand(SubCommand::with_name("diff")
.about(tr!("Display differences between two backup versions"))
.arg(Arg::from_usage("<OLD>")
.help(tr!("Old version, [repository]::backup[::subpath]"))
2017-04-07 09:05:28 +00:00
.validator(|val| validate_repo_path(val, true, Some(true), None)))
2018-02-24 12:19:51 +00:00
.arg(Arg::from_usage("<NEW>")
.help(tr!("New version, [repository]::backup[::subpath]"))
2017-04-07 09:05:28 +00:00
.validator(|val| validate_repo_path(val, true, Some(true), None))))
2018-03-08 14:20:20 +00:00
.subcommand(SubCommand::with_name("duplicates")
.aliases(&["dups"])
.about(tr!("Find duplicate files in a backup"))
.arg(Arg::from_usage("[min_size] --min-size [SIZE]")
.help(tr!("Set the minimum file size"))
.default_value(DEFAULT_DUPLICATES_MIN_SIZE_STR)
.validator(validate_filesize))
.arg(Arg::from_usage("<BACKUP>")
.help(tr!("The backup/subtree path, [repository]::backup[::subtree]"))
.validator(|val| validate_repo_path(val, true, Some(true), None))))
2018-02-24 12:19:51 +00:00
.subcommand(SubCommand::with_name("copy")
.alias("cp")
.about(tr!("Create a copy of a backup"))
.arg(Arg::from_usage("<SRC>")
.help(tr!("Existing backup, [repository]::backup"))
2017-05-17 05:35:41 +00:00
.validator(|val| validate_repo_path(val, true, Some(true), Some(false))))
2018-02-24 12:19:51 +00:00
.arg(Arg::from_usage("<DST>")
.help(tr!("Destination backup, [repository]::backup"))
2017-05-17 05:35:41 +00:00
.validator(|val| validate_repo_path(val, true, Some(true), Some(false)))))
2018-02-24 12:19:51 +00:00
.subcommand(SubCommand::with_name("config")
.about(tr!("Display or change the configuration"))
.arg(Arg::from_usage("[bundle_size] --bundle-size [SIZE]")
.help(tr!("Set the target bundle size in MiB"))
2017-04-07 09:05:28 +00:00
.validator(validate_num))
2018-02-24 12:19:51 +00:00
.arg(Arg::from_usage("--chunker [CHUNKER]")
.help(tr!("Set the chunker algorithm and target chunk size"))
2017-04-07 09:05:28 +00:00
.validator(validate_chunker))
2018-02-24 12:19:51 +00:00
.arg(Arg::from_usage("-c --compression [COMPRESSION]")
.help(tr!("Set the compression method and level"))
2017-04-07 09:05:28 +00:00
.validator(validate_compression))
2018-02-24 12:19:51 +00:00
.arg(Arg::from_usage("-e --encryption [PUBLIC_KEY]")
.help(tr!("The public key to use for encryption"))
2017-04-07 09:05:28 +00:00
.validator(validate_public_key))
2018-02-24 12:19:51 +00:00
.arg(Arg::from_usage("--hash [HASH]")
.help(tr!("Set the hash method"))
2017-04-07 09:05:28 +00:00
.validator(validate_hash))
2018-02-24 12:19:51 +00:00
.arg(Arg::from_usage("<REPO>")
.help(tr!("Path of the repository"))
2017-04-07 09:05:28 +00:00
.validator(|val| validate_repo_path(val, true, Some(false), Some(false)))))
2018-02-24 12:19:51 +00:00
.subcommand(SubCommand::with_name("genkey")
.about(tr!("Generate a new key pair"))
.arg(Arg::from_usage("-p --password [PASSWORD]")
.help(tr!("Derive the key pair from the given password")))
.arg(Arg::from_usage("[FILE]")
.help(tr!("Destination file for the keypair"))))
.subcommand(SubCommand::with_name("addkey")
.about(tr!("Add a key pair to the repository"))
.arg(Arg::from_usage("-g --generate")
.help(tr!("Generate a new key pair"))
2017-05-11 07:36:44 +00:00
.conflicts_with("FILE"))
2018-02-24 12:19:51 +00:00
.arg(Arg::from_usage("[set_default] --default -d")
.help(tr!("Set the key pair as default")))
.arg(Arg::from_usage("-p --password [PASSWORD]")
.help(tr!("Derive the key pair from the given password"))
2017-05-11 07:36:44 +00:00
.requires("generate"))
2018-02-24 12:19:51 +00:00
.arg(Arg::from_usage("[FILE]")
.help(tr!("File containing the keypair"))
2017-05-11 07:36:44 +00:00
.validator(validate_existing_path))
2018-02-24 12:19:51 +00:00
.arg(Arg::from_usage("<REPO>")
.help(tr!("Path of the repository"))
2017-05-11 07:36:44 +00:00
.validator(|val| validate_repo_path(val, true, Some(false), Some(false)))))
2018-02-24 12:19:51 +00:00
.subcommand(SubCommand::with_name("algotest")
.about(tr!("Test a specific algorithm combination"))
.arg(Arg::from_usage("[bundle_size] --bundle-size [SIZE]")
.help(tr!("Set the target bundle size in MiB"))
.default_value(DEFAULT_BUNDLE_SIZE_STR)
.validator(validate_num))
.arg(Arg::from_usage("--chunker [CHUNKER]")
.help(tr!("Set the chunker algorithm and target chunk size"))
.default_value(DEFAULT_CHUNKER)
.validator(validate_chunker))
2018-02-24 12:55:24 +00:00
.arg(Arg::from_usage("-c --compression [COMPRESSION]")
.help(tr!("Set the compression method and level"))
2018-02-24 12:19:51 +00:00
.default_value(DEFAULT_COMPRESSION)
.validator(validate_compression))
.arg(Arg::from_usage("-e --encrypt")
.help(tr!("Generate a keypair and enable encryption")))
.arg(Arg::from_usage("--hash [HASH]")
.help(tr!("Set the hash method"))
.default_value(DEFAULT_HASH)
.validator(validate_hash))
.arg(Arg::from_usage("<FILE>")
.help(tr!("File with test data"))
2017-04-07 09:05:28 +00:00
.validator(validate_existing_path))).get_matches();
2017-07-21 09:21:59 +00:00
let verbose_count = args.subcommand()
.1
.map(|m| m.occurrences_of("verbose"))
.unwrap_or(0) + args.occurrences_of("verbose");
let quiet_count = args.subcommand()
.1
.map(|m| m.occurrences_of("quiet"))
.unwrap_or(0) + args.occurrences_of("quiet");
let log_level = match 1 + verbose_count - quiet_count {
2018-02-19 22:31:58 +00:00
0 => log::Level::Warn,
1 => log::Level::Info,
2 => log::Level::Debug,
_ => log::Level::Trace,
2017-04-09 10:04:28 +00:00
};
let args = match args.subcommand() {
2017-04-07 16:57:49 +00:00
("init", Some(args)) => {
2017-07-21 09:21:59 +00:00
let (repository, _backup, _inode) = parse_repo_path(
args.value_of("REPO").unwrap(),
false,
Some(false),
Some(false)
).unwrap();
2017-04-09 10:04:28 +00:00
Arguments::Init {
2017-07-21 09:21:59 +00:00
bundle_size: (parse_num(args.value_of("bundle_size").unwrap()).unwrap() *
1024 * 1024) as usize,
2017-04-07 16:57:49 +00:00
chunker: parse_chunker(args.value_of("chunker").unwrap()).unwrap(),
compression: parse_compression(args.value_of("compression").unwrap()).unwrap(),
encryption: args.is_present("encrypt"),
hash: parse_hash(args.value_of("hash").unwrap()).unwrap(),
2017-05-17 07:43:14 +00:00
repo_path: repository,
2017-04-07 16:57:49 +00:00
remote_path: args.value_of("remote").unwrap().to_string()
2017-04-09 10:04:28 +00:00
}
2017-07-21 09:21:59 +00:00
}
2017-04-07 16:57:49 +00:00
("backup", Some(args)) => {
2017-07-21 09:21:59 +00:00
let (repository, backup, _inode) = parse_repo_path(
args.value_of("BACKUP").unwrap(),
true,
Some(true),
Some(false)
).unwrap();
2017-04-09 10:04:28 +00:00
Arguments::Backup {
2017-05-17 07:43:14 +00:00
repo_path: repository,
2017-04-07 16:57:49 +00:00
backup_name: backup.unwrap().to_string(),
full: args.is_present("full"),
same_device: !args.is_present("cross_device"),
2017-07-21 09:21:59 +00:00
excludes: args.values_of("exclude")
.map(|v| v.map(|k| k.to_string()).collect())
.unwrap_or_else(|| vec![]),
2017-04-07 16:57:49 +00:00
excludes_from: args.value_of("excludes_from").map(|v| v.to_string()),
src_path: args.value_of("SRC").unwrap().to_string(),
reference: args.value_of("reference").map(|v| v.to_string()),
no_default_excludes: args.is_present("no_default_excludes"),
tar: args.is_present("tar")
2017-04-09 10:04:28 +00:00
}
2017-07-21 09:21:59 +00:00
}
2017-04-07 16:57:49 +00:00
("restore", Some(args)) => {
2017-07-21 09:21:59 +00:00
let (repository, backup, inode) =
parse_repo_path(args.value_of("BACKUP").unwrap(), true, Some(true), None).unwrap();
2017-04-09 10:04:28 +00:00
Arguments::Restore {
2017-05-17 07:43:14 +00:00
repo_path: repository,
2017-04-07 16:57:49 +00:00
backup_name: backup.unwrap().to_string(),
inode: inode.map(|v| v.to_string()),
dst_path: args.value_of("DST").unwrap().to_string(),
tar: args.is_present("tar")
2017-04-09 10:04:28 +00:00
}
2017-07-21 09:21:59 +00:00
}
2017-04-07 16:57:49 +00:00
("remove", Some(args)) => {
2017-07-21 09:21:59 +00:00
let (repository, backup, inode) =
parse_repo_path(args.value_of("BACKUP").unwrap(), true, Some(true), None).unwrap();
2017-04-09 10:04:28 +00:00
Arguments::Remove {
2017-05-17 07:43:14 +00:00
repo_path: repository,
2017-04-07 16:57:49 +00:00
backup_name: backup.unwrap().to_string(),
2017-04-13 12:10:11 +00:00
inode: inode.map(|v| v.to_string()),
force: args.is_present("force")
2017-04-09 10:04:28 +00:00
}
2017-07-21 09:21:59 +00:00
}
2017-04-07 16:57:49 +00:00
("prune", Some(args)) => {
2017-07-21 09:21:59 +00:00
let (repository, _backup, _inode) = parse_repo_path(
args.value_of("REPO").unwrap(),
true,
Some(false),
Some(false)
).unwrap();
2017-04-09 10:04:28 +00:00
Arguments::Prune {
2017-05-17 07:43:14 +00:00
repo_path: repository,
2017-04-07 16:57:49 +00:00
prefix: args.value_of("prefix").unwrap_or("").to_string(),
force: args.is_present("force"),
daily: parse_num(args.value_of("daily").unwrap()).unwrap() as usize,
weekly: parse_num(args.value_of("weekly").unwrap()).unwrap() as usize,
monthly: parse_num(args.value_of("monthly").unwrap()).unwrap() as usize,
yearly: parse_num(args.value_of("yearly").unwrap()).unwrap() as usize
2017-04-09 10:04:28 +00:00
}
2017-07-21 09:21:59 +00:00
}
2017-04-07 16:57:49 +00:00
("vacuum", Some(args)) => {
2017-07-21 09:21:59 +00:00
let (repository, _backup, _inode) = parse_repo_path(
args.value_of("REPO").unwrap(),
true,
Some(false),
Some(false)
).unwrap();
2017-04-09 10:04:28 +00:00
Arguments::Vacuum {
2017-05-17 07:43:14 +00:00
repo_path: repository,
2017-04-07 16:57:49 +00:00
force: args.is_present("force"),
combine: args.is_present("combine"),
2017-04-07 16:57:49 +00:00
ratio: parse_num(args.value_of("ratio").unwrap()).unwrap() as f32 / 100.0
2017-04-09 10:04:28 +00:00
}
2017-07-21 09:21:59 +00:00
}
2017-04-07 16:57:49 +00:00
("check", Some(args)) => {
2017-07-21 09:21:59 +00:00
let (repository, backup, inode) =
parse_repo_path(args.value_of("PATH").unwrap(), true, None, None).unwrap();
2017-04-09 10:04:28 +00:00
Arguments::Check {
2017-05-17 07:43:14 +00:00
repo_path: repository,
2017-04-07 16:57:49 +00:00
backup_name: backup.map(|v| v.to_string()),
inode: inode.map(|v| v.to_string()),
bundles: args.is_present("bundles"),
bundle_data: args.is_present("bundle_data"),
2017-04-12 18:19:21 +00:00
index: args.is_present("index"),
repair: args.is_present("repair")
2017-04-09 10:04:28 +00:00
}
2017-07-21 09:21:59 +00:00
}
2017-04-07 16:57:49 +00:00
("list", Some(args)) => {
2017-07-21 09:21:59 +00:00
let (repository, backup, inode) =
parse_repo_path(args.value_of("PATH").unwrap(), true, None, None).unwrap();
2017-04-09 10:04:28 +00:00
Arguments::List {
2017-05-17 07:43:14 +00:00
repo_path: repository,
2017-04-07 16:57:49 +00:00
backup_name: backup.map(|v| v.to_string()),
inode: inode.map(|v| v.to_string())
2017-04-09 10:04:28 +00:00
}
2017-07-21 09:21:59 +00:00
}
2017-04-07 16:57:49 +00:00
("bundlelist", Some(args)) => {
2017-07-21 09:21:59 +00:00
let (repository, _backup, _inode) = parse_repo_path(
args.value_of("REPO").unwrap(),
true,
Some(false),
Some(false)
).unwrap();
Arguments::BundleList { repo_path: repository }
}
2017-04-07 16:57:49 +00:00
("bundleinfo", Some(args)) => {
2017-07-21 09:21:59 +00:00
let (repository, _backup, _inode) = parse_repo_path(
args.value_of("REPO").unwrap(),
true,
Some(false),
Some(false)
).unwrap();
2017-04-09 10:04:28 +00:00
Arguments::BundleInfo {
2017-05-17 07:43:14 +00:00
repo_path: repository,
2017-04-07 16:57:49 +00:00
bundle_id: try!(parse_bundle_id(args.value_of("BUNDLE").unwrap()))
2017-04-09 10:04:28 +00:00
}
2017-07-21 09:21:59 +00:00
}
2017-04-07 16:57:49 +00:00
("info", Some(args)) => {
2017-07-21 09:21:59 +00:00
let (repository, backup, inode) =
parse_repo_path(args.value_of("PATH").unwrap(), true, None, None).unwrap();
2017-04-09 10:04:28 +00:00
Arguments::Info {
2017-05-17 07:43:14 +00:00
repo_path: repository,
2017-04-07 16:57:49 +00:00
backup_name: backup.map(|v| v.to_string()),
inode: inode.map(|v| v.to_string())
2017-04-09 10:04:28 +00:00
}
2017-07-21 09:21:59 +00:00
}
2018-03-08 14:20:20 +00:00
("statistics", Some(args)) => {
2018-03-06 23:36:44 +00:00
let (repository, _backup, _inode) = parse_repo_path(
args.value_of("REPO").unwrap(),
true,
Some(false),
Some(false)
).unwrap();
2018-03-08 14:20:20 +00:00
Arguments::Statistics { repo_path: repository }
2018-03-06 23:36:44 +00:00
}
2017-05-17 05:35:41 +00:00
("copy", Some(args)) => {
2017-07-21 09:21:59 +00:00
let (repository_src, backup_src, _inode) =
parse_repo_path(args.value_of("SRC").unwrap(), true, Some(true), Some(false))
.unwrap();
let (repository_dst, backup_dst, _inode) =
parse_repo_path(args.value_of("DST").unwrap(), true, Some(true), Some(false))
.unwrap();
2017-05-17 05:35:41 +00:00
Arguments::Copy {
2017-05-17 07:43:14 +00:00
repo_path_src: repository_src,
2017-05-17 05:35:41 +00:00
backup_name_src: backup_src.unwrap().to_string(),
2017-05-17 07:43:14 +00:00
repo_path_dst: repository_dst,
2017-07-21 09:21:59 +00:00
backup_name_dst: backup_dst.unwrap().to_string()
2017-05-17 05:35:41 +00:00
}
2017-07-21 09:21:59 +00:00
}
2017-04-07 16:57:49 +00:00
("mount", Some(args)) => {
2017-07-21 09:21:59 +00:00
let (repository, backup, inode) =
parse_repo_path(args.value_of("PATH").unwrap(), true, None, None).unwrap();
2017-04-09 10:04:28 +00:00
Arguments::Mount {
2017-05-17 07:43:14 +00:00
repo_path: repository,
2017-04-07 16:57:49 +00:00
backup_name: backup.map(|v| v.to_string()),
inode: inode.map(|v| v.to_string()),
mount_point: args.value_of("MOUNTPOINT").unwrap().to_string()
2017-04-09 10:04:28 +00:00
}
2017-07-21 09:21:59 +00:00
}
2017-04-07 16:57:49 +00:00
("versions", Some(args)) => {
2017-07-21 09:21:59 +00:00
let (repository, _backup, _inode) = parse_repo_path(
args.value_of("REPO").unwrap(),
true,
Some(false),
Some(false)
).unwrap();
2017-04-09 10:04:28 +00:00
Arguments::Versions {
2017-05-17 07:43:14 +00:00
repo_path: repository,
2017-04-07 16:57:49 +00:00
path: args.value_of("PATH").unwrap().to_string()
2017-04-09 10:04:28 +00:00
}
2017-07-21 09:21:59 +00:00
}
2017-04-07 16:57:49 +00:00
("diff", Some(args)) => {
2017-07-21 09:21:59 +00:00
let (repository_old, backup_old, inode_old) =
parse_repo_path(args.value_of("OLD").unwrap(), true, Some(true), None).unwrap();
let (repository_new, backup_new, inode_new) =
parse_repo_path(args.value_of("NEW").unwrap(), true, Some(true), None).unwrap();
2017-04-09 10:04:28 +00:00
Arguments::Diff {
2017-05-17 07:43:14 +00:00
repo_path_old: repository_old,
2017-04-07 16:57:49 +00:00
backup_name_old: backup_old.unwrap().to_string(),
inode_old: inode_old.map(|v| v.to_string()),
2017-05-17 07:43:14 +00:00
repo_path_new: repository_new,
2017-04-07 16:57:49 +00:00
backup_name_new: backup_new.unwrap().to_string(),
2017-07-21 09:21:59 +00:00
inode_new: inode_new.map(|v| v.to_string())
2017-04-09 10:04:28 +00:00
}
2017-07-21 09:21:59 +00:00
}
2017-04-07 16:57:49 +00:00
("analyze", Some(args)) => {
2017-07-21 09:21:59 +00:00
let (repository, _backup, _inode) = parse_repo_path(
args.value_of("REPO").unwrap(),
true,
Some(false),
Some(false)
).unwrap();
Arguments::Analyze { repo_path: repository }
}
2017-04-07 16:57:49 +00:00
("import", Some(args)) => {
2017-07-21 09:21:59 +00:00
let (repository, _backup, _inode) = parse_repo_path(
args.value_of("REPO").unwrap(),
false,
Some(false),
Some(false)
).unwrap();
2017-04-09 10:04:28 +00:00
Arguments::Import {
2017-05-17 07:43:14 +00:00
repo_path: repository,
2017-04-07 16:57:49 +00:00
remote_path: args.value_of("REMOTE").unwrap().to_string(),
2017-07-21 09:21:59 +00:00
key_files: args.values_of("key")
.map(|v| v.map(|k| k.to_string()).collect())
.unwrap_or_else(|| vec![])
2017-04-09 10:04:28 +00:00
}
2017-07-21 09:21:59 +00:00
}
2018-03-08 14:20:20 +00:00
("duplicates", Some(args)) => {
let (repository, backup, inode) =
parse_repo_path(args.value_of("BACKUP").unwrap(), true, Some(true), None).unwrap();
Arguments::Duplicates {
repo_path: repository,
backup_name: backup.unwrap().to_string(),
inode: inode.map(|v| v.to_string()),
min_size: args.value_of("min_size").map(|v| {
parse_filesize(v).unwrap()
}).unwrap()
}
}
2017-04-07 16:57:49 +00:00
("config", Some(args)) => {
2017-07-21 09:21:59 +00:00
let (repository, _backup, _inode) = parse_repo_path(
args.value_of("REPO").unwrap(),
true,
Some(false),
Some(false)
).unwrap();
2017-04-09 10:04:28 +00:00
Arguments::Config {
2017-07-21 09:21:59 +00:00
bundle_size: args.value_of("bundle_size").map(|v| {
parse_num(v).unwrap() as usize * 1024 * 1024
}),
2017-04-07 16:57:49 +00:00
chunker: args.value_of("chunker").map(|v| parse_chunker(v).unwrap()),
2017-07-21 09:21:59 +00:00
compression: args.value_of("compression").map(|v| {
parse_compression(v).unwrap()
}),
encryption: args.value_of("encryption").map(
|v| parse_public_key(v).unwrap()
),
2017-04-07 16:57:49 +00:00
hash: args.value_of("hash").map(|v| parse_hash(v).unwrap()),
2017-07-21 09:21:59 +00:00
repo_path: repository
2017-04-09 10:04:28 +00:00
}
2017-07-21 09:21:59 +00:00
}
2017-04-07 16:57:49 +00:00
("genkey", Some(args)) => {
2017-04-09 10:04:28 +00:00
Arguments::GenKey {
2017-05-08 13:11:07 +00:00
file: args.value_of("FILE").map(|v| v.to_string()),
password: args.value_of("password").map(|v| v.to_string())
2017-04-09 10:04:28 +00:00
}
2017-07-21 09:21:59 +00:00
}
2017-04-07 16:57:49 +00:00
("addkey", Some(args)) => {
2017-07-21 09:21:59 +00:00
let (repository, _backup, _inode) = parse_repo_path(
args.value_of("REPO").unwrap(),
true,
Some(false),
Some(false)
).unwrap();
2017-04-09 10:04:28 +00:00
Arguments::AddKey {
2017-05-17 07:43:14 +00:00
repo_path: repository,
2017-04-07 16:57:49 +00:00
set_default: args.is_present("set_default"),
2017-05-08 13:11:07 +00:00
password: args.value_of("password").map(|v| v.to_string()),
2017-04-07 16:57:49 +00:00
file: args.value_of("FILE").map(|v| v.to_string())
2017-04-09 10:04:28 +00:00
}
2017-07-21 09:21:59 +00:00
}
2017-04-07 16:57:49 +00:00
("algotest", Some(args)) => {
2017-04-09 10:04:28 +00:00
Arguments::AlgoTest {
2017-07-21 09:21:59 +00:00
bundle_size: (parse_num(args.value_of("bundle_size").unwrap()).unwrap() *
1024 * 1024) as usize,
2017-04-07 16:57:49 +00:00
chunker: parse_chunker(args.value_of("chunker").unwrap()).unwrap(),
compression: parse_compression(args.value_of("compression").unwrap()).unwrap(),
encrypt: args.is_present("encrypt"),
hash: parse_hash(args.value_of("hash").unwrap()).unwrap(),
2017-07-21 09:21:59 +00:00
file: args.value_of("FILE").unwrap().to_string()
2017-04-09 10:04:28 +00:00
}
2017-07-21 09:21:59 +00:00
}
2017-04-07 16:57:49 +00:00
_ => {
2018-02-24 12:19:51 +00:00
tr_error!("No subcommand given");
2017-07-21 09:21:59 +00:00
return Err(ErrorCode::InvalidArgs);
2017-04-07 16:57:49 +00:00
}
2017-04-09 10:04:28 +00:00
};
Ok((log_level, args))
2017-03-17 06:15:19 +00:00
}