diff options
author | Lars Wirzenius <liw@liw.fi> | 2021-08-02 07:12:18 +0000 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2021-08-02 07:12:18 +0000 |
commit | 8c2f79fa3cecadd8e7d7f74df6938b25c81c5e9e (patch) | |
tree | b25ed37fcfb2f8805a5b298b5ba09b80922a3c11 | |
parent | 4c6206a2cb1f8c1efba9fd08a4d6b4fa7d09a6dc (diff) | |
parent | 1962cdaebc71bec28861635784e0b41deac98060 (diff) | |
download | obnam2-8c2f79fa3cecadd8e7d7f74df6938b25c81c5e9e.tar.gz |
Merge branch 'resolve' into 'main'
add "obnam resolve"
Closes #118 and #135
See merge request obnam/obnam!171
-rw-r--r-- | obnam.md | 2 | ||||
-rw-r--r-- | src/backup_progress.rs | 3 | ||||
-rw-r--r-- | src/backup_run.rs | 8 | ||||
-rw-r--r-- | src/bin/obnam.rs | 3 | ||||
-rw-r--r-- | src/client.rs | 16 | ||||
-rw-r--r-- | src/cmd/list_files.rs | 2 | ||||
-rw-r--r-- | src/cmd/mod.rs | 1 | ||||
-rw-r--r-- | src/cmd/resolve.rs | 33 | ||||
-rw-r--r-- | src/cmd/restore.rs | 4 | ||||
-rw-r--r-- | src/cmd/show_gen.rs | 2 | ||||
-rw-r--r-- | src/generation.rs | 34 | ||||
-rw-r--r-- | src/genlist.rs | 10 |
12 files changed, 92 insertions, 26 deletions
@@ -1278,6 +1278,8 @@ when I run obnam backup then backup generation is GEN when I run obnam list then generation list contains <GEN> +when I run obnam resolve latest +then generation list contains <GEN> when I invoke obnam restore <GEN> rest given a manifest of the directory live restored in rest in rest.yaml then manifests live.yaml and rest.yaml match diff --git a/src/backup_progress.rs b/src/backup_progress.rs index fd07978..30b6228 100644 --- a/src/backup_progress.rs +++ b/src/backup_progress.rs @@ -1,3 +1,4 @@ +use crate::generation::GenId; use indicatif::{ProgressBar, ProgressStyle}; use std::path::Path; @@ -58,7 +59,7 @@ impl BackupProgress { Self { progress } } - pub fn download_generation(gen_id: &str) -> Self { + pub fn download_generation(gen_id: &GenId) -> Self { let progress = ProgressBar::new(0); let parts = vec!["{msg}", "elapsed: {elapsed}", "{spinner}"]; progress.set_style(ProgressStyle::default_bar().template(&parts.join("\n"))); diff --git a/src/backup_run.rs b/src/backup_run.rs index dee1d11..3b107bb 100644 --- a/src/backup_run.rs +++ b/src/backup_run.rs @@ -6,7 +6,9 @@ use crate::config::ClientConfig; use crate::error::ObnamError; use crate::fsentry::FilesystemEntry; use crate::fsiter::{AnnotatedFsEntry, FsIterError, FsIterator}; -use crate::generation::{LocalGeneration, LocalGenerationError, NascentError, NascentGeneration}; +use crate::generation::{ + GenId, LocalGeneration, LocalGenerationError, NascentError, NascentGeneration, +}; use crate::policy::BackupPolicy; use log::{info, warn}; use std::path::{Path, PathBuf}; @@ -72,7 +74,7 @@ impl<'a> BackupRun<'a> { pub fn start( &mut self, - genid: Option<&str>, + genid: Option<&GenId>, oldname: &Path, ) -> Result<LocalGeneration, ObnamError> { match genid { @@ -94,7 +96,7 @@ impl<'a> BackupRun<'a> { fn fetch_previous_generation( &self, - genid: &str, + genid: &GenId, oldname: &Path, ) -> Result<LocalGeneration, ObnamError> { let progress = BackupProgress::download_generation(genid); diff --git a/src/bin/obnam.rs b/src/bin/obnam.rs index 29de2eb..b2d5683 100644 --- a/src/bin/obnam.rs +++ b/src/bin/obnam.rs @@ -9,6 +9,7 @@ use obnam::cmd::get_chunk::GetChunk; use obnam::cmd::init::Init; use obnam::cmd::list::List; use obnam::cmd::list_files::ListFiles; +use obnam::cmd::resolve::Resolve; use obnam::cmd::restore::Restore; use obnam::cmd::show_config::ShowConfig; use obnam::cmd::show_gen::ShowGeneration; @@ -44,6 +45,7 @@ fn main_program() -> anyhow::Result<()> { Command::List(x) => x.run(&config), Command::ShowGeneration(x) => x.run(&config), Command::ListFiles(x) => x.run(&config), + Command::Resolve(x) => x.run(&config), Command::Restore(x) => x.run(&config), Command::GetChunk(x) => x.run(&config), Command::Config(x) => x.run(&config), @@ -102,6 +104,7 @@ enum Command { ListFiles(ListFiles), Restore(Restore), ShowGeneration(ShowGeneration), + Resolve(Resolve), GetChunk(GetChunk), Config(ShowConfig), EncryptChunk(EncryptChunk), diff --git a/src/client.rs b/src/client.rs index ca0104f..c655bb2 100644 --- a/src/client.rs +++ b/src/client.rs @@ -6,7 +6,7 @@ use crate::chunkmeta::ChunkMeta; use crate::cipher::{CipherEngine, CipherError}; use crate::config::{ClientConfig, ClientConfigError}; use crate::fsentry::{FilesystemEntry, FilesystemKind}; -use crate::generation::{FinishedGeneration, LocalGeneration, LocalGenerationError}; +use crate::generation::{FinishedGeneration, GenId, LocalGeneration, LocalGenerationError}; use crate::genlist::GenerationList; use chrono::{DateTime, Local}; @@ -101,16 +101,15 @@ impl AsyncBackupClient { self.chunk_client.fetch_chunk(chunk_id).await } - async fn fetch_generation_chunk(&self, gen_id: &str) -> Result<GenerationChunk, ClientError> { - let chunk_id = ChunkId::recreate(gen_id); - let chunk = self.fetch_chunk(&chunk_id).await?; + async fn fetch_generation_chunk(&self, gen_id: &GenId) -> Result<GenerationChunk, ClientError> { + let chunk = self.fetch_chunk(gen_id.as_chunk_id()).await?; let gen = GenerationChunk::from_data_chunk(&chunk)?; Ok(gen) } pub async fn fetch_generation( &self, - gen_id: &str, + gen_id: &GenId, dbname: &Path, ) -> Result<LocalGeneration, ClientError> { let gen = self.fetch_generation_chunk(gen_id).await?; @@ -323,16 +322,15 @@ impl BackupClient { self.chunk_client.fetch_chunk(chunk_id) } - fn fetch_generation_chunk(&self, gen_id: &str) -> Result<GenerationChunk, ClientError> { - let chunk_id = ChunkId::recreate(gen_id); - let chunk = self.fetch_chunk(&chunk_id)?; + fn fetch_generation_chunk(&self, gen_id: &GenId) -> Result<GenerationChunk, ClientError> { + let chunk = self.fetch_chunk(gen_id.as_chunk_id())?; let gen = GenerationChunk::from_data_chunk(&chunk)?; Ok(gen) } pub fn fetch_generation( &self, - gen_id: &str, + gen_id: &GenId, dbname: &Path, ) -> Result<LocalGeneration, ClientError> { let gen = self.fetch_generation_chunk(gen_id)?; diff --git a/src/cmd/list_files.rs b/src/cmd/list_files.rs index e511327..bdec55b 100644 --- a/src/cmd/list_files.rs +++ b/src/cmd/list_files.rs @@ -25,7 +25,7 @@ impl ListFiles { let client = AsyncBackupClient::new(config)?; let genlist = client.list_generations().await?; - let gen_id: String = genlist.resolve(&self.gen_id)?; + let gen_id = genlist.resolve(&self.gen_id)?; let gen = client.fetch_generation(&gen_id, temp.path()).await?; for file in gen.files()?.iter()? { diff --git a/src/cmd/mod.rs b/src/cmd/mod.rs index 7313a05..502ec5d 100644 --- a/src/cmd/mod.rs +++ b/src/cmd/mod.rs @@ -5,6 +5,7 @@ pub mod get_chunk; pub mod init; pub mod list; pub mod list_files; +pub mod resolve; pub mod restore; pub mod show_config; pub mod show_gen; diff --git a/src/cmd/resolve.rs b/src/cmd/resolve.rs new file mode 100644 index 0000000..9b36445 --- /dev/null +++ b/src/cmd/resolve.rs @@ -0,0 +1,33 @@ +use crate::client::AsyncBackupClient; +use crate::config::ClientConfig; +use crate::error::ObnamError; +use structopt::StructOpt; +use tokio::runtime::Runtime; + +#[derive(Debug, StructOpt)] +pub struct Resolve { + generation: String, +} + +impl Resolve { + pub fn run(&self, config: &ClientConfig) -> Result<(), ObnamError> { + let rt = Runtime::new()?; + rt.block_on(self.run_async(config)) + } + + async fn run_async(&self, config: &ClientConfig) -> Result<(), ObnamError> { + let client = AsyncBackupClient::new(config)?; + let generations = client.list_generations().await?; + + match generations.resolve(&self.generation) { + Err(err) => { + return Err(err.into()); + } + Ok(gen_id) => { + println!("{}", gen_id.as_chunk_id()); + } + }; + + Ok(()) + } +} diff --git a/src/cmd/restore.rs b/src/cmd/restore.rs index c770501..e03f3de 100644 --- a/src/cmd/restore.rs +++ b/src/cmd/restore.rs @@ -40,8 +40,8 @@ impl Restore { let client = AsyncBackupClient::new(config)?; let genlist = client.list_generations().await?; - let gen_id: String = genlist.resolve(&self.gen_id)?; - info!("generation id is {}", gen_id); + let gen_id = genlist.resolve(&self.gen_id)?; + info!("generation id is {}", gen_id.as_chunk_id()); let gen = client.fetch_generation(&gen_id, temp.path()).await?; info!("restoring {} files", gen.file_count()?); diff --git a/src/cmd/show_gen.rs b/src/cmd/show_gen.rs index 8df26c2..fb7e1bd 100644 --- a/src/cmd/show_gen.rs +++ b/src/cmd/show_gen.rs @@ -24,7 +24,7 @@ impl ShowGeneration { let client = AsyncBackupClient::new(config)?; let genlist = client.list_generations().await?; - let gen_id: String = genlist.resolve(&self.gen_id)?; + let gen_id = genlist.resolve(&self.gen_id)?; let gen = client.fetch_generation(&gen_id, temp.path()).await?; let mut files = gen.files()?; let mut files = files.iter()?; diff --git a/src/generation.rs b/src/generation.rs index 25fc14d..5412ae7 100644 --- a/src/generation.rs +++ b/src/generation.rs @@ -4,11 +4,37 @@ use crate::chunkid::ChunkId; use crate::fsentry::FilesystemEntry; use log::debug; use rusqlite::Connection; +use std::fmt; use std::path::{Path, PathBuf}; /// An identifier for a file in a generation. type FileId = i64; +/// An identifier for a generation. +#[derive(Debug, Clone)] +pub struct GenId { + id: ChunkId, +} + +impl GenId { + pub fn from_chunk_id(id: ChunkId) -> Self { + Self { id } + } + + pub fn as_chunk_id(&self) -> &ChunkId { + &self.id + } +} + +impl fmt::Display for GenId { + /// Format an identifier for display. + /// + /// The output can be parsed to re-created an identical identifier. + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.id) + } +} + /// A nascent backup generation. /// /// A nascent generation is one that is being prepared. It isn't @@ -97,21 +123,21 @@ impl NascentGeneration { /// A generation is finished when it's on the server. It can be restored. #[derive(Debug, Clone)] pub struct FinishedGeneration { - id: ChunkId, + id: GenId, ended: String, } impl FinishedGeneration { pub fn new(id: &str, ended: &str) -> Self { - let id = id.parse().unwrap(); // this never fails + let id = GenId::from_chunk_id(id.parse().unwrap()); // this never fails Self { id, ended: ended.to_string(), } } - pub fn id(&self) -> ChunkId { - self.id.clone() + pub fn id(&self) -> &GenId { + &self.id } pub fn ended(&self) -> &str { diff --git a/src/genlist.rs b/src/genlist.rs index 21f558c..a81a997 100644 --- a/src/genlist.rs +++ b/src/genlist.rs @@ -1,5 +1,5 @@ use crate::chunkid::ChunkId; -use crate::generation::FinishedGeneration; +use crate::generation::{FinishedGeneration, GenId}; pub struct GenerationList { list: Vec<FinishedGeneration>, @@ -22,17 +22,17 @@ impl GenerationList { self.list.iter() } - pub fn resolve(&self, genref: &str) -> Result<String, GenerationListError> { + pub fn resolve(&self, genref: &str) -> Result<GenId, GenerationListError> { let gen = if self.list.is_empty() { None } else if genref == "latest" { let i = self.list.len() - 1; Some(self.list[i].clone()) } else { - let genref: ChunkId = genref.parse().unwrap(); + let genref = GenId::from_chunk_id(genref.parse().unwrap()); let hits: Vec<FinishedGeneration> = self .iter() - .filter(|gen| gen.id() == genref) + .filter(|gen| gen.id().as_chunk_id() == genref.as_chunk_id()) .cloned() .collect(); if hits.len() == 1 { @@ -45,7 +45,7 @@ impl GenerationList { None => Err(GenerationListError::UnknownGeneration(ChunkId::recreate( genref, ))), - Some(gen) => Ok(gen.id().to_string()), + Some(gen) => Ok(gen.id().clone()), } } } |