summaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2020-11-13 09:40:39 +0200
committerLars Wirzenius <liw@liw.fi>2020-11-13 11:27:21 +0200
commit38b51382e710dda515e6d0df8fdc4f0b253d9cd7 (patch)
tree5a012e63ef7aa6ae63c31f459d56631bc008b0b5 /src/cmd
parent179993f3bdd5e5d4dd728fc2a8f5d63274f95966 (diff)
downloadobnam2-38b51382e710dda515e6d0df8fdc4f0b253d9cd7.tar.gz
refactor: put all client functionality into one program
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/backup.rs21
-rw-r--r--src/cmd/list.rs13
-rw-r--r--src/cmd/mod.rs8
-rw-r--r--src/cmd/restore.rs115
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(())
+}