From b9370e3a0486d0a12a8a4ee6cc2586c9d240eb22 Mon Sep 17 00:00:00 2001 From: Dennis Schwerdel Date: Fri, 31 Mar 2017 18:44:27 +0200 Subject: [PATCH] Default repository in ~/.zvault --- Cargo.lock | 7 +++++ Cargo.toml | 1 + src/cli/args.rs | 84 +++++++++++++++++++++++++++---------------------- src/cli/mod.rs | 6 ++++ src/main.rs | 1 + 5 files changed, 61 insertions(+), 38 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4a79239..73b4ce4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9,6 +9,7 @@ dependencies = [ "clap 2.21.2 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "fuse 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "mmap 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -130,6 +131,11 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "lazy_static" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "libc" version = "0.1.12" @@ -442,6 +448,7 @@ dependencies = [ "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" "checksum fuse 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5087262ce5b36fed6ccd4abf0a8224e48d055a2bb07fecb5605765de6f114a28" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +"checksum lazy_static 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4732c563b9a21a406565c4747daa7b46742f082911ae4753f390dc9ec7ee1a97" "checksum libc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "e32a70cf75e5846d53a673923498228bbec6a8624708a9ea5645f075d6276122" "checksum libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "88ee81885f9f04bff991e306fea7c1c60a5f0f9e409e99f6b40e3311a3363135" "checksum libsodium-sys 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "cbbc6e46017815abf8698de0ed4847fad45fd8cad2909ac38ac6de79673c1ad1" diff --git a/Cargo.toml b/Cargo.toml index 18e2382..eeb11ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ sodiumoxide = "0.0.14" filetime = "0.1" regex = "0.2" fuse = "0.3" +lazy_static = "0.2" time = "*" libc = "*" diff --git a/src/cli/args.rs b/src/cli/args.rs index 8418134..dcb9b64 100644 --- a/src/cli/args.rs +++ b/src/cli/args.rs @@ -126,16 +126,24 @@ pub enum Arguments { } -pub fn split_repo_path(repo_path: &str) -> (&str, Option<&str>, Option<&str>) { - let mut parts = repo_path.splitn(3, "::"); - let repo = parts.next().unwrap(); - let backup = parts.next(); - let inode = parts.next(); - (repo, backup, inode) -} - pub fn parse_repo_path(repo_path: &str, backup_restr: Option, path_restr: Option) -> (&str, Option<&str>, Option<&str>) { - let (repo, backup, path) = split_repo_path(repo_path); + let mut parts = repo_path.splitn(3, "::"); + let mut repo = parts.next().unwrap_or(&DEFAULT_REPOSITORY); + if repo.is_empty() { + repo = &DEFAULT_REPOSITORY; + } + 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 + } + } if let Some(restr) = backup_restr { if !restr && backup.is_some() { println!("No backup may be given here"); @@ -241,7 +249,7 @@ pub fn parse() -> Arguments { (@arg encryption: --encryption -e "generate a keypair and enable encryption") (@arg hash: --hash +takes_value "hash method to use [default: blake2]") (@arg remote: --remote -r +takes_value +required "path to the mounted remote storage") - (@arg REPO: +required "path of the repository") + (@arg REPO: "path of the repository") ) (@subcommand backup => (about: "creates a new backup") @@ -271,54 +279,54 @@ pub fn parse() -> Arguments { (@arg monthly: --monthly +takes_value "keep this number of monthly backups") (@arg yearly: --yearly +takes_value "keep this number of yearly backups") (@arg force: --force -f "actually run the prunce instead of simulating it") - (@arg REPO: +required "path of the repository") + (@arg REPO: "path of the repository") ) (@subcommand vacuum => (about: "saves space by combining and recompressing bundles") (@arg ratio: --ratio -r +takes_value "ratio in % of unused space in a bundle to rewrite that bundle") (@arg force: --force -f "actually run the vacuum instead of simulating it") - (@arg REPO: +required "path of the repository") + (@arg REPO: "path of the repository") ) (@subcommand check => (about: "checks the repository, a backup or a backup subpath") (@arg full: --full "also check file contents") - (@arg PATH: +required "repository[::backup] path") + (@arg PATH: "repository[::backup] path") ) (@subcommand list => (about: "lists backups or backup contents") - (@arg PATH: +required "repository[::backup[::subpath]] path") + (@arg PATH: "repository[::backup[::subpath]] path") ) (@subcommand mount => (about: "mount a backup for inspection") - (@arg PATH: +required "repository[::backup[::subpath]] path") + (@arg PATH: "repository[::backup[::subpath]] path") (@arg MOUNTPOINT: +required "where to mount to backup") ) (@subcommand bundlelist => (about: "lists bundles in a repository") - (@arg REPO: +required "path of the repository") + (@arg REPO: "path of the repository") ) (@subcommand bundleinfo => (about: "lists bundles in a repository") - (@arg REPO: +required "path of the repository") + (@arg REPO: "path of the repository") (@arg BUNDLE: +required "the bundle id") ) (@subcommand import => (about: "reconstruct a repository from the remote files") (@arg key: --key -k ... +takes_value "a file with a needed to read the bundles") (@arg REMOTE: +required "remote repository path") - (@arg REPO: +required "path of the local repository to create") + (@arg REPO: "path of the local repository to create") ) (@subcommand info => (about: "displays information on a repository, a backup or a path in a backup") - (@arg PATH: +required "repository[::backup[::subpath]] path") + (@arg PATH: "repository[::backup[::subpath]] path") ) (@subcommand analyze => (about: "analyze the used and reclaimable space of bundles") - (@arg REPO: +required "repository path") + (@arg REPO: "repository path") ) (@subcommand versions => (about: "display different versions of a file in all backups") - (@arg REPO: +required "repository path") + (@arg REPO: "repository path") (@arg PATH: +required "the file path") ) (@subcommand diff => @@ -328,7 +336,7 @@ pub fn parse() -> Arguments { ) (@subcommand config => (about: "changes the configuration") - (@arg REPO: +required "path of the repository") + (@arg REPO: "path of the repository") (@arg bundle_size: --bundlesize +takes_value "maximal bundle size in MiB [default: 25]") (@arg chunker: --chunker +takes_value "chunker algorithm [default: fastcdc/16]") (@arg compression: --compression -c +takes_value "compression to use [default: brotli/3]") @@ -341,7 +349,7 @@ pub fn parse() -> Arguments { ) (@subcommand addkey => (about: "adds a key to the respository") - (@arg REPO: +required "path of the repository") + (@arg REPO: "path of the repository") (@arg generate: --generate -g "generate a new key") (@arg set_default: --default -d "set this key as default") (@arg FILE: +takes_value "the file containing the keypair") @@ -357,7 +365,7 @@ pub fn parse() -> Arguments { ) ).get_matches(); if let Some(args) = args.subcommand_matches("init") { - let (repository, _backup, _inode) = parse_repo_path(args.value_of("REPO").unwrap(), Some(false), Some(false)); + let (repository, _backup, _inode) = parse_repo_path(args.value_of("REPO").unwrap_or(""), Some(false), Some(false)); return Arguments::Init { bundle_size: (parse_num(args.value_of("bundle_size").unwrap_or(&DEFAULT_BUNDLE_SIZE.to_string()), "Bundle size") * 1024 * 1024) as usize, chunker: parse_chunker(args.value_of("chunker").unwrap_or(DEFAULT_CHUNKER)), @@ -400,7 +408,7 @@ pub fn parse() -> Arguments { } } if let Some(args) = args.subcommand_matches("prune") { - let (repository, _backup, _inode) = parse_repo_path(args.value_of("REPO").unwrap(), Some(false), Some(false)); + let (repository, _backup, _inode) = parse_repo_path(args.value_of("REPO").unwrap_or(""), Some(false), Some(false)); return Arguments::Prune { repo_path: repository.to_string(), prefix: args.value_of("prefix").unwrap_or("").to_string(), @@ -412,7 +420,7 @@ pub fn parse() -> Arguments { } } if let Some(args) = args.subcommand_matches("vacuum") { - let (repository, _backup, _inode) = parse_repo_path(args.value_of("REPO").unwrap(), Some(false), Some(false)); + let (repository, _backup, _inode) = parse_repo_path(args.value_of("REPO").unwrap_or(""), Some(false), Some(false)); return Arguments::Vacuum { repo_path: repository.to_string(), force: args.is_present("force"), @@ -420,7 +428,7 @@ pub fn parse() -> Arguments { } } if let Some(args) = args.subcommand_matches("check") { - let (repository, backup, inode) = parse_repo_path(args.value_of("PATH").unwrap(), None, None); + let (repository, backup, inode) = parse_repo_path(args.value_of("PATH").unwrap_or(""), None, None); return Arguments::Check { repo_path: repository.to_string(), backup_name: backup.map(|v| v.to_string()), @@ -429,7 +437,7 @@ pub fn parse() -> Arguments { } } if let Some(args) = args.subcommand_matches("list") { - let (repository, backup, inode) = parse_repo_path(args.value_of("PATH").unwrap(), None, None); + let (repository, backup, inode) = parse_repo_path(args.value_of("PATH").unwrap_or(""), None, None); return Arguments::List { repo_path: repository.to_string(), backup_name: backup.map(|v| v.to_string()), @@ -437,20 +445,20 @@ pub fn parse() -> Arguments { } } if let Some(args) = args.subcommand_matches("bundlelist") { - let (repository, _backup, _inode) = parse_repo_path(args.value_of("REPO").unwrap(), Some(false), Some(false)); + let (repository, _backup, _inode) = parse_repo_path(args.value_of("REPO").unwrap_or(""), Some(false), Some(false)); return Arguments::BundleList { repo_path: repository.to_string(), } } if let Some(args) = args.subcommand_matches("bundleinfo") { - let (repository, _backup, _inode) = parse_repo_path(args.value_of("REPO").unwrap(), Some(false), Some(false)); + let (repository, _backup, _inode) = parse_repo_path(args.value_of("REPO").unwrap_or(""), Some(false), Some(false)); return Arguments::BundleInfo { repo_path: repository.to_string(), bundle_id: parse_bundle_id(args.value_of("BUNDLE").unwrap()) } } if let Some(args) = args.subcommand_matches("info") { - let (repository, backup, inode) = parse_repo_path(args.value_of("PATH").unwrap(), None, None); + let (repository, backup, inode) = parse_repo_path(args.value_of("PATH").unwrap_or(""), None, None); return Arguments::Info { repo_path: repository.to_string(), backup_name: backup.map(|v| v.to_string()), @@ -458,7 +466,7 @@ pub fn parse() -> Arguments { } } if let Some(args) = args.subcommand_matches("mount") { - let (repository, backup, inode) = parse_repo_path(args.value_of("PATH").unwrap(), None, None); + let (repository, backup, inode) = parse_repo_path(args.value_of("PATH").unwrap_or(""), None, None); return Arguments::Mount { repo_path: repository.to_string(), backup_name: backup.map(|v| v.to_string()), @@ -467,7 +475,7 @@ pub fn parse() -> Arguments { } } if let Some(args) = args.subcommand_matches("versions") { - let (repository, _backup, _inode) = parse_repo_path(args.value_of("REPO").unwrap(), Some(false), Some(false)); + let (repository, _backup, _inode) = parse_repo_path(args.value_of("REPO").unwrap_or(""), Some(false), Some(false)); return Arguments::Versions { repo_path: repository.to_string(), path: args.value_of("PATH").unwrap().to_string() @@ -482,17 +490,17 @@ pub fn parse() -> Arguments { inode_old: inode_old.map(|v| v.to_string()), repo_path_new: repository_new.to_string(), backup_name_new: backup_new.unwrap().to_string(), - inode_new: inode_new.map(|v| v.to_string()), + inode_new: inode_new.map(|v| v.to_string()), } } if let Some(args) = args.subcommand_matches("analyze") { - let (repository, _backup, _inode) = parse_repo_path(args.value_of("REPO").unwrap(), Some(false), Some(false)); + let (repository, _backup, _inode) = parse_repo_path(args.value_of("REPO").unwrap_or(""), Some(false), Some(false)); return Arguments::Analyze { repo_path: repository.to_string() } } if let Some(args) = args.subcommand_matches("import") { - let (repository, _backup, _inode) = parse_repo_path(args.value_of("REPO").unwrap(), Some(false), Some(false)); + let (repository, _backup, _inode) = parse_repo_path(args.value_of("REPO").unwrap_or(""), Some(false), Some(false)); return Arguments::Import { repo_path: repository.to_string(), remote_path: args.value_of("REMOTE").unwrap().to_string(), @@ -500,7 +508,7 @@ pub fn parse() -> Arguments { } } if let Some(args) = args.subcommand_matches("config") { - let (repository, _backup, _inode) = parse_repo_path(args.value_of("REPO").unwrap(), Some(false), Some(false)); + let (repository, _backup, _inode) = parse_repo_path(args.value_of("REPO").unwrap_or(""), Some(false), Some(false)); return Arguments::Config { bundle_size: args.value_of("bundle_size").map(|v| (parse_num(v, "Bundle size") * 1024 * 1024) as usize), chunker: args.value_of("chunker").map(|v| parse_chunker(v)), @@ -522,7 +530,7 @@ pub fn parse() -> Arguments { } } if let Some(args) = args.subcommand_matches("addkey") { - let (repository, _backup, _inode) = parse_repo_path(args.value_of("REPO").unwrap(), Some(false), Some(false)); + let (repository, _backup, _inode) = parse_repo_path(args.value_of("REPO").unwrap_or(""), Some(false), Some(false)); let generate = args.is_present("generate"); if !generate && !args.is_present("FILE") { println!("Without --generate, a file containing the key pair must be given"); diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 02a266c..e6b61d0 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -12,6 +12,7 @@ use std::collections::HashMap; use std::fmt::Display; use std::io::{BufReader, BufRead}; use std::fs::File; +use std::env; use self::args::Arguments; @@ -21,6 +22,11 @@ pub const DEFAULT_HASH: &'static str = "blake2"; pub const DEFAULT_COMPRESSION: &'static str = "brotli/3"; pub const DEFAULT_BUNDLE_SIZE: usize = 25; pub const DEFAULT_VACUUM_RATIO: usize = 50; +lazy_static! { + pub static ref DEFAULT_REPOSITORY: String = { + env::home_dir().unwrap().join(".zvault").to_string_lossy().to_string() + }; +} fn checked(result: Result, msg: &'static str) -> T { diff --git a/src/main.rs b/src/main.rs index c964ae7..b15062f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,6 +17,7 @@ extern crate sodiumoxide; extern crate ansi_term; extern crate filetime; extern crate regex; +#[macro_use] extern crate lazy_static; extern crate fuse; extern crate time; extern crate libc;