diff options
author | Lars Wirzenius <liw@liw.fi> | 2020-11-13 09:40:39 +0200 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2020-11-13 11:27:21 +0200 |
commit | 38b51382e710dda515e6d0df8fdc4f0b253d9cd7 (patch) | |
tree | 5a012e63ef7aa6ae63c31f459d56631bc008b0b5 /src/cmd | |
parent | 179993f3bdd5e5d4dd728fc2a8f5d63274f95966 (diff) | |
download | obnam2-38b51382e710dda515e6d0df8fdc4f0b253d9cd7.tar.gz |
refactor: put all client functionality into one program
Diffstat (limited to 'src/cmd')
-rw-r--r-- | src/cmd/backup.rs | 21 | ||||
-rw-r--r-- | src/cmd/list.rs | 13 | ||||
-rw-r--r-- | src/cmd/mod.rs | 8 | ||||
-rw-r--r-- | src/cmd/restore.rs | 115 |
4 files changed, 157 insertions, 0 deletions
diff --git a/src/cmd/backup.rs b/src/cmd/backup.rs new file mode 100644 index 0000000..308eafb --- /dev/null +++ b/src/cmd/backup.rs @@ -0,0 +1,21 @@ +use crate::client::{BackupClient, ClientConfig}; +use crate::fsiter::FsIterator; +use crate::generation::Generation; +use std::path::Path; + +pub fn backup(config: &Path, buffer_size: usize) -> anyhow::Result<()> { + let config = ClientConfig::read_config(config)?; + let client = BackupClient::new(&config.server_name, config.server_port)?; + + { + let mut gen = Generation::create(&config.dbname)?; + gen.insert_iter(FsIterator::new(&config.root).map(|entry| match entry { + Err(err) => Err(err), + Ok(entry) => client.upload_filesystem_entry(entry, buffer_size), + }))?; + } + let gen_id = client.upload_generation(&config.dbname, buffer_size)?; + println!("gen id: {}", gen_id); + + Ok(()) +} diff --git a/src/cmd/list.rs b/src/cmd/list.rs new file mode 100644 index 0000000..1972144 --- /dev/null +++ b/src/cmd/list.rs @@ -0,0 +1,13 @@ +use crate::client::{BackupClient, ClientConfig}; +use std::path::Path; + +pub fn list(config: &Path) -> anyhow::Result<()> { + let config = ClientConfig::read_config(&config)?; + let client = BackupClient::new(&config.server_name, config.server_port)?; + + for gen_id in client.list_generations()? { + println!("{}", gen_id); + } + + Ok(()) +} diff --git a/src/cmd/mod.rs b/src/cmd/mod.rs new file mode 100644 index 0000000..ca5ff42 --- /dev/null +++ b/src/cmd/mod.rs @@ -0,0 +1,8 @@ +mod backup; +pub use backup::backup; + +mod list; +pub use list::list; + +pub mod restore; +pub use restore::restore; diff --git a/src/cmd/restore.rs b/src/cmd/restore.rs new file mode 100644 index 0000000..6e2690c --- /dev/null +++ b/src/cmd/restore.rs @@ -0,0 +1,115 @@ +use crate::client::BackupClient; +use crate::fsentry::{FilesystemEntry, FilesystemKind}; +use crate::generation::Generation; +use log::{debug, info}; +//use obnam::chunkmeta::ChunkMeta; +use serde::Deserialize; +use std::fs::File; +use std::io::prelude::*; +use std::path::{Path, PathBuf}; +use structopt::StructOpt; + +pub fn restore(config: &Path, gen_id: &str, dbname: &Path, to: &Path) -> anyhow::Result<()> { + let config = Config::read_config(&config).unwrap(); + + let client = BackupClient::new(&config.server_name, config.server_port)?; + let gen_chunk = client.fetch_generation(&gen_id)?; + debug!("gen: {:?}", gen_chunk); + { + let mut dbfile = File::create(&dbname)?; + for id in gen_chunk.chunk_ids() { + let chunk = client.fetch_chunk(id)?; + dbfile.write_all(chunk.data())?; + } + } + info!("downloaded generation to {}", dbname.display()); + + let gen = Generation::open(&dbname)?; + for (fileid, entry) in gen.files()? { + restore_generation(&client, &gen, fileid, entry, &to)?; + } + + Ok(()) +} + +#[derive(Debug, StructOpt)] +#[structopt(name = "obnam-backup", about = "Simplistic backup client")] +struct Opt { + #[structopt(parse(from_os_str))] + config: PathBuf, + + #[structopt()] + gen_id: String, + + #[structopt(parse(from_os_str))] + dbname: PathBuf, + + #[structopt(parse(from_os_str))] + to: PathBuf, +} + +#[derive(Debug, Deserialize, Clone)] +pub struct Config { + pub server_name: String, + pub server_port: u16, +} + +impl Config { + pub fn read_config(filename: &Path) -> anyhow::Result<Config> { + let config = std::fs::read_to_string(filename)?; + let config: Config = serde_yaml::from_str(&config)?; + Ok(config) + } +} + +fn restore_generation( + client: &BackupClient, + gen: &Generation, + fileid: u64, + entry: FilesystemEntry, + to: &Path, +) -> anyhow::Result<()> { + println!("restoring {}:{}", fileid, entry.path().display()); + + let path = if entry.path().is_absolute() { + entry.path().strip_prefix("/")? + } else { + entry.path() + }; + let to = to.join(path); + debug!(" to: {}", to.display()); + + match entry.kind() { + FilesystemKind::Regular => restore_regular(client, &gen, &to, fileid, &entry)?, + FilesystemKind::Directory => restore_directory(&to)?, + } + Ok(()) +} + +fn restore_directory(path: &Path) -> anyhow::Result<()> { + debug!("restoring directory {}", path.display()); + std::fs::create_dir_all(path)?; + Ok(()) +} + +fn restore_regular( + client: &BackupClient, + gen: &Generation, + path: &Path, + fileid: u64, + _entry: &FilesystemEntry, +) -> anyhow::Result<()> { + debug!("restoring regular {}", path.display()); + let parent = path.parent().unwrap(); + debug!(" mkdir {}", parent.display()); + std::fs::create_dir_all(parent)?; + { + let mut file = std::fs::File::create(path)?; + for chunkid in gen.chunkids(fileid)? { + let chunk = client.fetch_chunk(&chunkid)?; + file.write_all(chunk.data())?; + } + } + debug!("restored regular {}", path.display()); + Ok(()) +} |