feat: add revision retrieving
This commit is contained in:
@@ -10,7 +10,7 @@ pub enum ErrorKind {
|
|||||||
Io(#[from] std::io::Error),
|
Io(#[from] std::io::Error),
|
||||||
#[error("error parsing revision lockfile")]
|
#[error("error parsing revision lockfile")]
|
||||||
RevisionLock,
|
RevisionLock,
|
||||||
#[error("error reading revision lockfile at {path}")]
|
#[error("error reading revision at {path}")]
|
||||||
ReadRevision {
|
ReadRevision {
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
#[source]
|
#[source]
|
||||||
@@ -52,6 +52,8 @@ pub enum ErrorKind {
|
|||||||
#[source]
|
#[source]
|
||||||
source: std::io::Error,
|
source: std::io::Error,
|
||||||
},
|
},
|
||||||
|
#[error("error unpacking revision")]
|
||||||
|
UnpackError(#[source] std::io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Result<T> = core::result::Result<T, Error>;
|
pub type Result<T> = core::result::Result<T, Error>;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use std::io::{self, BufReader, BufWriter, Read, Write};
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::{fs, path::PathBuf};
|
use std::{fs, path::PathBuf};
|
||||||
|
|
||||||
|
use flate2::read::GzDecoder;
|
||||||
use indicatif::ProgressBar;
|
use indicatif::ProgressBar;
|
||||||
|
|
||||||
use crate::Data;
|
use crate::Data;
|
||||||
@@ -39,7 +40,7 @@ fn copy_with_progress(src: &Path, dst: &Path, progress: &ProgressBar) -> io::Res
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl StorageImpl for FSStorage {
|
impl StorageImpl for FSStorage {
|
||||||
fn get_revision(&self, app_state: Data) -> Result<usize> {
|
fn get_revision_metadata(&self, app_state: Data) -> Result<usize> {
|
||||||
let path = base_path(app_state).join(LOCKFILE_NAME);
|
let path = base_path(app_state).join(LOCKFILE_NAME);
|
||||||
let revision = match fs::read_to_string(&path) {
|
let revision = match fs::read_to_string(&path) {
|
||||||
Ok(rev) => rev.parse::<usize>().map_err(|_| Error::revision_lock())?,
|
Ok(rev) => rev.parse::<usize>().map_err(|_| Error::revision_lock())?,
|
||||||
@@ -55,15 +56,12 @@ impl StorageImpl for FSStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn store_revision(&self, app_state: Data) -> Result<()> {
|
fn store_revision(&self, app_state: Data) -> Result<()> {
|
||||||
let revision = self.get_revision(app_state.clone())?;
|
let revision = self.get_revision_metadata(app_state.clone())?;
|
||||||
let new_revision = revision + 1;
|
let new_revision = revision + 1;
|
||||||
let reporter = Reporter::new(app_state.clone());
|
let reporter = Reporter::new(app_state.clone());
|
||||||
let result = create_archive(app_state.clone(), &reporter)?;
|
let result = create_archive(app_state.clone(), &reporter)?;
|
||||||
let archive_path = match &app_state.config.sync.fs_dir {
|
let archive_path =
|
||||||
Some(dir) => PathBuf::from(shellexpand::tilde(&dir).as_ref())
|
base_path(app_state.clone()).join(&format!("revision_{revision}.tar.gz"));
|
||||||
.join(&format!("revision_{new_revision}.tar.gz")),
|
|
||||||
_ => base_path(app_state.clone()).join(&format!("revision_{new_revision}.tar.gz")),
|
|
||||||
};
|
|
||||||
|
|
||||||
match result.temp_file.persist(&archive_path) {
|
match result.temp_file.persist(&archive_path) {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
@@ -96,6 +94,44 @@ impl StorageImpl for FSStorage {
|
|||||||
tracing::debug!(revision, path = ?remove_path, "cleared revisions");
|
tracing::debug!(revision, path = ?remove_path, "cleared revisions");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn retrieve_revision(
|
||||||
|
&self,
|
||||||
|
app_state: Data,
|
||||||
|
revision: usize,
|
||||||
|
) -> Result<tar::Archive<flate2::read::GzDecoder<BufReader<std::fs::File>>>> {
|
||||||
|
let archive_path = base_path(app_state).join(&format!("revision_{revision}.tar.gz"));
|
||||||
|
|
||||||
|
let file =
|
||||||
|
fs::File::open(&archive_path).map_err(|e| Error::read_revision(e, &archive_path))?;
|
||||||
|
let buffered = BufReader::new(file);
|
||||||
|
let decoder = GzDecoder::new(buffered);
|
||||||
|
let archive = tar::Archive::new(decoder);
|
||||||
|
|
||||||
|
Ok(archive)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unpack_revision(
|
||||||
|
&self,
|
||||||
|
app_state: Data,
|
||||||
|
destination: PathBuf,
|
||||||
|
revision: usize,
|
||||||
|
) -> Result<()> {
|
||||||
|
let mut archive = self.retrieve_revision(app_state.clone(), revision)?;
|
||||||
|
let entries = archive.entries()?;
|
||||||
|
let reporter = Reporter::new(app_state);
|
||||||
|
let total_files = entries.progress_with_style
|
||||||
|
reporter.start_archive_progress(total);
|
||||||
|
|
||||||
|
for entry in entries {
|
||||||
|
let mut entry = entry?;
|
||||||
|
entry
|
||||||
|
.unpack_in(&destination)
|
||||||
|
.map_err(|e| Error::unpack_error(e))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn base_path(app_state: Data) -> PathBuf {
|
pub fn base_path(app_state: Data) -> PathBuf {
|
||||||
|
|||||||
@@ -1,12 +1,21 @@
|
|||||||
pub mod fs;
|
pub mod fs;
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::{io::BufReader, path::PathBuf};
|
||||||
|
|
||||||
|
use flate2::read::GzDecoder;
|
||||||
|
|
||||||
use crate::{Data, error::Result};
|
use crate::{Data, error::Result};
|
||||||
|
|
||||||
pub trait StorageImpl {
|
pub trait StorageImpl {
|
||||||
fn get_revision(&self, app_state: Data) -> Result<usize>;
|
fn get_revision_metadata(&self, app_state: Data) -> Result<usize>;
|
||||||
fn store_revision(&self, app_state: Data) -> Result<()>;
|
fn store_revision(&self, app_state: Data) -> Result<()>;
|
||||||
|
fn retrieve_revision(
|
||||||
|
&self,
|
||||||
|
app_state: Data,
|
||||||
|
revision: usize,
|
||||||
|
) -> Result<tar::Archive<GzDecoder<BufReader<std::fs::File>>>>;
|
||||||
|
fn unpack_revision(&self, app_state: Data, destination: PathBuf, revision: usize)
|
||||||
|
-> Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Storage {
|
pub enum Storage {
|
||||||
@@ -16,9 +25,9 @@ pub enum Storage {
|
|||||||
pub const IGNORE_FILES: [&str; 6] = ["assets", "cache", "catpacks", "logs", "meta", "metacache"];
|
pub const IGNORE_FILES: [&str; 6] = ["assets", "cache", "catpacks", "logs", "meta", "metacache"];
|
||||||
|
|
||||||
impl StorageImpl for Storage {
|
impl StorageImpl for Storage {
|
||||||
fn get_revision(&self, app_state: Data) -> Result<usize> {
|
fn get_revision_metadata(&self, app_state: Data) -> Result<usize> {
|
||||||
match self {
|
match self {
|
||||||
Self::FS(storage) => storage.get_revision(app_state),
|
Self::FS(storage) => storage.get_revision_metadata(app_state),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,6 +36,27 @@ impl StorageImpl for Storage {
|
|||||||
Self::FS(storage) => storage.store_revision(app_state),
|
Self::FS(storage) => storage.store_revision(app_state),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn retrieve_revision(
|
||||||
|
&self,
|
||||||
|
app_state: Data,
|
||||||
|
revision: usize,
|
||||||
|
) -> Result<tar::Archive<GzDecoder<BufReader<std::fs::File>>>> {
|
||||||
|
match self {
|
||||||
|
Self::FS(storage) => storage.retrieve_revision(app_state, revision),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unpack_revision(
|
||||||
|
&self,
|
||||||
|
app_state: Data,
|
||||||
|
destination: PathBuf,
|
||||||
|
revision: usize,
|
||||||
|
) -> Result<()> {
|
||||||
|
match self {
|
||||||
|
Self::FS(storage) => storage.unpack_revision(app_state, destination, revision),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_storage_from_env() -> Storage {
|
pub fn get_storage_from_env() -> Storage {
|
||||||
|
|||||||
Reference in New Issue
Block a user