diff options
author | Lars Wirzenius <liw@liw.fi> | 2021-04-10 09:02:27 +0300 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2021-04-10 10:29:27 +0300 |
commit | e13ef6a773755e8eed4d0fb1e55f3bd80a6c5cfd (patch) | |
tree | 0ef79cad97789850efc5fcfe8073dd120b8473d7 | |
parent | f3ed6ba027dbb410161970c4a706192885d92a3d (diff) | |
download | obnam2-e13ef6a773755e8eed4d0fb1e55f3bd80a6c5cfd.tar.gz |
refactor: move ClientConfig into its own module
-rw-r--r-- | src/backup_run.rs | 3 | ||||
-rw-r--r-- | src/bin/obnam.rs | 2 | ||||
-rw-r--r-- | src/client.rs | 122 | ||||
-rw-r--r-- | src/cmd/backup.rs | 3 | ||||
-rw-r--r-- | src/cmd/get_chunk.rs | 2 | ||||
-rw-r--r-- | src/cmd/init.rs | 2 | ||||
-rw-r--r-- | src/cmd/list.rs | 3 | ||||
-rw-r--r-- | src/cmd/list_files.rs | 2 | ||||
-rw-r--r-- | src/cmd/restore.rs | 2 | ||||
-rw-r--r-- | src/cmd/show_config.rs | 2 | ||||
-rw-r--r-- | src/cmd/show_gen.rs | 2 | ||||
-rw-r--r-- | src/config.rs | 122 | ||||
-rw-r--r-- | src/error.rs | 3 | ||||
-rw-r--r-- | src/lib.rs | 1 |
14 files changed, 140 insertions, 131 deletions
diff --git a/src/backup_run.rs b/src/backup_run.rs index e9d094d..e966855 100644 --- a/src/backup_run.rs +++ b/src/backup_run.rs @@ -1,7 +1,8 @@ use crate::backup_progress::BackupProgress; use crate::backup_reason::Reason; use crate::chunkid::ChunkId; -use crate::client::{BackupClient, ClientConfig, ClientError}; +use crate::client::{BackupClient, ClientError}; +use crate::config::ClientConfig; use crate::error::ObnamError; use crate::fsentry::FilesystemEntry; use crate::fsiter::{FsIterError, FsIterResult}; diff --git a/src/bin/obnam.rs b/src/bin/obnam.rs index bb0cbdb..10048a3 100644 --- a/src/bin/obnam.rs +++ b/src/bin/obnam.rs @@ -2,10 +2,10 @@ use directories_next::ProjectDirs; use log::{debug, error, info, LevelFilter}; use log4rs::append::file::FileAppender; use log4rs::config::{Appender, Config, Logger, Root}; -use obnam::client::ClientConfig; use obnam::cmd::{ backup, get_chunk, init, list, list_files, restore, show_config, show_generation, }; +use obnam::config::ClientConfig; use std::path::{Path, PathBuf}; use structopt::StructOpt; diff --git a/src/client.rs b/src/client.rs index 37bfe91..1b33372 100644 --- a/src/client.rs +++ b/src/client.rs @@ -4,136 +4,18 @@ use crate::chunk::{GenerationChunk, GenerationChunkError}; use crate::chunker::{Chunker, ChunkerError}; use crate::chunkid::ChunkId; use crate::chunkmeta::ChunkMeta; +use crate::config::ClientConfig; use crate::fsentry::{FilesystemEntry, FilesystemKind}; use crate::generation::{FinishedGeneration, LocalGeneration, LocalGenerationError}; use crate::genlist::GenerationList; -use crate::passwords::{passwords_filename, PasswordError, Passwords}; -use bytesize::MIB; use chrono::{DateTime, Local}; use log::{debug, error, info, trace}; use reqwest::blocking::Client; -use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::fs::File; use std::io::prelude::*; -use std::path::{Path, PathBuf}; - -const DEFAULT_CHUNK_SIZE: usize = MIB as usize; -const DEVNULL: &str = "/dev/null"; - -#[derive(Debug, Deserialize, Clone)] -#[serde(deny_unknown_fields)] -struct TentativeClientConfig { - server_url: String, - verify_tls_cert: Option<bool>, - chunk_size: Option<usize>, - roots: Vec<PathBuf>, - log: Option<PathBuf>, - encrypt: Option<bool>, -} - -#[derive(Debug, Serialize, Clone)] -pub enum ClientConfig { - Plain(ClientConfigWithoutPasswords), - WithPasswords(ClientConfigWithoutPasswords, Passwords), -} - -impl ClientConfig { - pub fn read_without_passwords(filename: &Path) -> Result<Self, ClientConfigError> { - let config = ClientConfigWithoutPasswords::read_config(filename)?; - Ok(ClientConfig::Plain(config)) - } - - pub fn read_with_passwords(filename: &Path) -> Result<Self, ClientConfigError> { - let config = ClientConfigWithoutPasswords::read_config(filename)?; - if config.encrypt { - let passwords = Passwords::load(&passwords_filename(filename)) - .map_err(ClientConfigError::PasswordsMissing)?; - Ok(ClientConfig::WithPasswords(config, passwords)) - } else { - Ok(ClientConfig::Plain(config)) - } - } - - pub fn config(&self) -> &ClientConfigWithoutPasswords { - match self { - Self::Plain(config) => &config, - Self::WithPasswords(config, _) => &config, - } - } -} - -#[derive(Debug, Serialize, Clone)] -pub struct ClientConfigWithoutPasswords { - pub server_url: String, - pub verify_tls_cert: bool, - pub chunk_size: usize, - pub roots: Vec<PathBuf>, - pub log: PathBuf, - pub encrypt: bool, -} - -#[derive(Debug, thiserror::Error)] -pub enum ClientConfigError { - #[error("server_url is empty")] - ServerUrlIsEmpty, - - #[error("No backup roots in config; at least one is needed")] - NoBackupRoot, - - #[error("server URL doesn't use https: {0}")] - NotHttps(String), - - #[error("No passwords are set: you may need to run 'obnam init': {0}")] - PasswordsMissing(PasswordError), - - #[error(transparent)] - IoError(#[from] std::io::Error), - - #[error(transparent)] - SerdeYamlError(#[from] serde_yaml::Error), -} - -pub type ClientConfigResult<T> = Result<T, ClientConfigError>; - -impl ClientConfigWithoutPasswords { - pub fn read_config(filename: &Path) -> ClientConfigResult<Self> { - trace!("read_config: filename={:?}", filename); - let config = std::fs::read_to_string(filename)?; - let tentative: TentativeClientConfig = serde_yaml::from_str(&config)?; - - let encrypt = tentative.encrypt.or(Some(false)).unwrap(); - - let config = Self { - server_url: tentative.server_url, - roots: tentative.roots, - verify_tls_cert: tentative.verify_tls_cert.or(Some(false)).unwrap(), - chunk_size: tentative.chunk_size.or(Some(DEFAULT_CHUNK_SIZE)).unwrap(), - log: tentative - .log - .or_else(|| Some(PathBuf::from(DEVNULL))) - .unwrap(), - encrypt, - }; - - config.check()?; - Ok(config) - } - - fn check(&self) -> Result<(), ClientConfigError> { - if self.server_url.is_empty() { - return Err(ClientConfigError::ServerUrlIsEmpty); - } - if !self.server_url.starts_with("https://") { - return Err(ClientConfigError::NotHttps(self.server_url.to_string())); - } - if self.roots.is_empty() { - return Err(ClientConfigError::NoBackupRoot); - } - Ok(()) - } -} +use std::path::Path; #[derive(Debug, thiserror::Error)] pub enum ClientError { diff --git a/src/cmd/backup.rs b/src/cmd/backup.rs index bd36a3a..1091241 100644 --- a/src/cmd/backup.rs +++ b/src/cmd/backup.rs @@ -1,7 +1,8 @@ use crate::backup_progress::BackupProgress; use crate::backup_run::{BackupError, IncrementalBackup, InitialBackup}; use crate::chunkid::ChunkId; -use crate::client::{BackupClient, ClientConfig}; +use crate::client::BackupClient; +use crate::config::ClientConfig; use crate::error::ObnamError; use crate::fsiter::FsIterator; use crate::generation::NascentGeneration; diff --git a/src/cmd/get_chunk.rs b/src/cmd/get_chunk.rs index 385c4d5..c9d640e 100644 --- a/src/cmd/get_chunk.rs +++ b/src/cmd/get_chunk.rs @@ -1,6 +1,6 @@ use crate::chunkid::ChunkId; use crate::client::BackupClient; -use crate::client::ClientConfig; +use crate::config::ClientConfig; use crate::error::ObnamError; use std::io::{stdout, Write}; diff --git a/src/cmd/init.rs b/src/cmd/init.rs index f0ddb69..fb8a6af 100644 --- a/src/cmd/init.rs +++ b/src/cmd/init.rs @@ -1,4 +1,4 @@ -use crate::client::ClientConfigWithoutPasswords; +use crate::config::ClientConfigWithoutPasswords; use crate::error::ObnamError; use crate::passwords::{passwords_filename, Passwords}; use std::path::Path; diff --git a/src/cmd/list.rs b/src/cmd/list.rs index a3f059b..f48512b 100644 --- a/src/cmd/list.rs +++ b/src/cmd/list.rs @@ -1,4 +1,5 @@ -use crate::client::{BackupClient, ClientConfig}; +use crate::client::BackupClient; +use crate::config::ClientConfig; use crate::error::ObnamError; pub fn list(config: &ClientConfig) -> Result<(), ObnamError> { diff --git a/src/cmd/list_files.rs b/src/cmd/list_files.rs index 71b0d68..d490e85 100644 --- a/src/cmd/list_files.rs +++ b/src/cmd/list_files.rs @@ -1,6 +1,6 @@ use crate::backup_reason::Reason; use crate::client::BackupClient; -use crate::client::ClientConfig; +use crate::config::ClientConfig; use crate::error::ObnamError; use crate::fsentry::{FilesystemEntry, FilesystemKind}; use tempfile::NamedTempFile; diff --git a/src/cmd/restore.rs b/src/cmd/restore.rs index 183f207..c2cbb7f 100644 --- a/src/cmd/restore.rs +++ b/src/cmd/restore.rs @@ -1,6 +1,6 @@ use crate::backup_reason::Reason; -use crate::client::ClientConfig; use crate::client::{BackupClient, ClientError}; +use crate::config::ClientConfig; use crate::error::ObnamError; use crate::fsentry::{FilesystemEntry, FilesystemKind}; use crate::generation::{LocalGeneration, LocalGenerationError}; diff --git a/src/cmd/show_config.rs b/src/cmd/show_config.rs index 8acd1c8..88ee9ec 100644 --- a/src/cmd/show_config.rs +++ b/src/cmd/show_config.rs @@ -1,4 +1,4 @@ -use crate::client::ClientConfig; +use crate::config::ClientConfig; use crate::error::ObnamError; pub fn show_config(config: &ClientConfig) -> Result<(), ObnamError> { diff --git a/src/cmd/show_gen.rs b/src/cmd/show_gen.rs index 143aed6..5b786cf 100644 --- a/src/cmd/show_gen.rs +++ b/src/cmd/show_gen.rs @@ -1,5 +1,5 @@ use crate::client::BackupClient; -use crate::client::ClientConfig; +use crate::config::ClientConfig; use crate::error::ObnamError; use crate::fsentry::FilesystemKind; use indicatif::HumanBytes; diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..41ddcd6 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,122 @@ +use crate::passwords::{passwords_filename, PasswordError, Passwords}; + +use bytesize::MIB; +use log::{error, trace}; +use serde::{Deserialize, Serialize}; +use std::path::{Path, PathBuf}; + +const DEFAULT_CHUNK_SIZE: usize = MIB as usize; +const DEVNULL: &str = "/dev/null"; + +#[derive(Debug, Deserialize, Clone)] +#[serde(deny_unknown_fields)] +struct TentativeClientConfig { + server_url: String, + verify_tls_cert: Option<bool>, + chunk_size: Option<usize>, + roots: Vec<PathBuf>, + log: Option<PathBuf>, + encrypt: Option<bool>, +} + +#[derive(Debug, Serialize, Clone)] +pub enum ClientConfig { + Plain(ClientConfigWithoutPasswords), + WithPasswords(ClientConfigWithoutPasswords, Passwords), +} + +impl ClientConfig { + pub fn read_without_passwords(filename: &Path) -> Result<Self, ClientConfigError> { + let config = ClientConfigWithoutPasswords::read_config(filename)?; + Ok(ClientConfig::Plain(config)) + } + + pub fn read_with_passwords(filename: &Path) -> Result<Self, ClientConfigError> { + let config = ClientConfigWithoutPasswords::read_config(filename)?; + if config.encrypt { + let passwords = Passwords::load(&passwords_filename(filename)) + .map_err(ClientConfigError::PasswordsMissing)?; + Ok(ClientConfig::WithPasswords(config, passwords)) + } else { + Ok(ClientConfig::Plain(config)) + } + } + + pub fn config(&self) -> &ClientConfigWithoutPasswords { + match self { + Self::Plain(config) => &config, + Self::WithPasswords(config, _) => &config, + } + } +} + +#[derive(Debug, Serialize, Clone)] +pub struct ClientConfigWithoutPasswords { + pub server_url: String, + pub verify_tls_cert: bool, + pub chunk_size: usize, + pub roots: Vec<PathBuf>, + pub log: PathBuf, + pub encrypt: bool, +} + +#[derive(Debug, thiserror::Error)] +pub enum ClientConfigError { + #[error("server_url is empty")] + ServerUrlIsEmpty, + + #[error("No backup roots in config; at least one is needed")] + NoBackupRoot, + + #[error("server URL doesn't use https: {0}")] + NotHttps(String), + + #[error("No passwords are set: you may need to run 'obnam init': {0}")] + PasswordsMissing(PasswordError), + + #[error(transparent)] + IoError(#[from] std::io::Error), + + #[error(transparent)] + SerdeYamlError(#[from] serde_yaml::Error), +} + +pub type ClientConfigResult<T> = Result<T, ClientConfigError>; + +impl ClientConfigWithoutPasswords { + pub fn read_config(filename: &Path) -> ClientConfigResult<Self> { + trace!("read_config: filename={:?}", filename); + let config = std::fs::read_to_string(filename)?; + let tentative: TentativeClientConfig = serde_yaml::from_str(&config)?; + + let encrypt = tentative.encrypt.or(Some(false)).unwrap(); + + let config = Self { + server_url: tentative.server_url, + roots: tentative.roots, + verify_tls_cert: tentative.verify_tls_cert.or(Some(false)).unwrap(), + chunk_size: tentative.chunk_size.or(Some(DEFAULT_CHUNK_SIZE)).unwrap(), + log: tentative + .log + .or_else(|| Some(PathBuf::from(DEVNULL))) + .unwrap(), + encrypt, + }; + + config.check()?; + Ok(config) + } + + fn check(&self) -> Result<(), ClientConfigError> { + if self.server_url.is_empty() { + return Err(ClientConfigError::ServerUrlIsEmpty); + } + if !self.server_url.starts_with("https://") { + return Err(ClientConfigError::NotHttps(self.server_url.to_string())); + } + if self.roots.is_empty() { + return Err(ClientConfigError::NoBackupRoot); + } + Ok(()) + } +} diff --git a/src/error.rs b/src/error.rs index 454bba6..8241d5d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,6 +1,7 @@ use crate::backup_run::BackupError; -use crate::client::{ClientConfigError, ClientError}; +use crate::client::ClientError; use crate::cmd::restore::RestoreError; +use crate::config::ClientConfigError; use crate::generation::{LocalGenerationError, NascentError}; use crate::genlist::GenerationListError; use crate::passwords::PasswordError; @@ -9,6 +9,7 @@ pub mod chunkid; pub mod chunkmeta; pub mod client; pub mod cmd; +pub mod config; pub mod error; pub mod fsentry; pub mod fsiter; |