Almost fully implement restore

This commit is contained in:
Josh Hansen 2023-09-28 00:12:49 -07:00
parent b99f8d50fc
commit 75eab354c8
5 changed files with 117 additions and 37 deletions

11
Cargo.lock generated
View file

@ -427,6 +427,7 @@ dependencies = [
"lazy_static",
"nom",
"path-absolutize",
"reflink",
"rustyline",
"serde",
"serde_json",
@ -741,6 +742,16 @@ dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "reflink"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc585ec28b565b4c28977ce8363a6636cedc280351ba25a7915f6c9f37f68cbe"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "regex"
version = "1.9.5"

View file

@ -22,6 +22,7 @@ ghee-lang = { path = "lang" }
lazy_static = "1.4.0"
nom = "7.1.3"
path-absolutize = "3.1.1"
reflink = "0.1.3"
rustyline = "12.0.0"
serde = { version = "1.0.163", features = ["derive"] }
serde_json = "1.0.96"

View file

@ -229,16 +229,16 @@ pub enum Commands {
},
Restore {
#[arg(help = "Paths to get restore", required = true)]
#[arg(help = "Paths to restore", required = true)]
paths: Vec<PathBuf>,
#[arg(
short,
long,
help = "Delete paths not present in most recent commit; defaults to true",
default_value_t = true
help = "Keep paths not present in most recent commit; defaults to false",
default_value_t = false
)]
delete: bool,
keep: bool,
#[arg(long, help = "Process paths nonrecursively; defaults to false")]
flat: bool,

View file

@ -247,14 +247,14 @@ fn run_command(cmd: &Commands) {
Commands::Restore {
paths,
delete,
keep,
flat,
verbose,
} => {
let new_file_handling = if *delete {
NewFileHandling::Delete
let new_file_handling = if *keep {
NewFileHandling::Keep
} else {
NewFileHandling::Ignore
NewFileHandling::Delete
};
restore(paths, !*flat, *verbose, new_file_handling)
.unwrap_or_else(|e| panic!("Error restoring paths {:?}: {}", paths, e));

View file

@ -1,8 +1,14 @@
use std::{env::current_dir, path::PathBuf};
use std::{
env::current_dir,
fs::{remove_dir, remove_file},
path::PathBuf,
};
use anyhow::Result;
use path_absolutize::Absolutize;
use reflink::reflink_or_copy;
use thiserror::Error;
use walkdir::WalkDir;
use crate::{
containing_table_info,
@ -11,7 +17,7 @@ use crate::{
};
pub enum NewFileHandling {
Ignore,
Keep,
Delete,
}
@ -45,37 +51,99 @@ pub fn restore(
let snapshot_path = table_snapshot_path(table_path, uuid);
let max_depth = if recursive { usize::MAX } else { 0 };
for path in paths {
let abs_path = path.absolutize().unwrap().to_path_buf();
for entry in WalkDir::new(path).max_depth(max_depth).into_iter() {
let entry = entry?;
if !abs_path
.to_str()
.unwrap()
.starts_with(table_path.to_str().unwrap())
{
return Err(RestoreErr::PathNotContainedByTable {
path: path.clone(),
table_path: table_path.clone(),
let path = entry.path().to_path_buf();
println!("path: {}", path.display());
let abs_path = path.absolutize().unwrap().to_path_buf();
if !abs_path
.to_str()
.unwrap()
.starts_with(table_path.to_str().unwrap())
{
return Err(RestoreErr::PathNotContainedByTable {
path: path.clone(),
table_path: table_path.clone(),
}
.into());
}
let rel_path = abs_path.relativize(table_path)?;
let snapshot_file_path = {
let mut p = snapshot_path.clone();
p.push(&rel_path);
p
}
.absolutize()
.unwrap()
.to_path_buf();
println!("snapshot_file_path: {}", snapshot_file_path.display());
if abs_path.exists() {
if snapshot_file_path.exists() {
// Both paths exist
// Now handle files vs directories
if snapshot_file_path.is_dir() {
if abs_path.is_dir() {
// do nothing - both paths are directories
} else {
// Replace file with directory
remove_file(&abs_path)?;
copy_dir(&snapshot_file_path, &abs_path)?;
//TODO copy entire tree of snapshot_file_path to abs_path
// create_dir(&abs_path)?;
}
} else {
// Snapshot is file
// Copy over working either way
//TODO Do we need to remove before `reflink_or_copy`ing over?
if abs_path.is_dir() {
remove_dir(&abs_path)?;
} else {
remove_file(&abs_path)?;
}
reflink_or_copy(&snapshot_file_path, abs_path)?;
if verbose {
println!("r{}", path.display());
}
}
} else {
// working exists; snapshot doesn't
match new_file_handling {
NewFileHandling::Delete => {
remove_file(abs_path)?;
if verbose {
println!("-{}", path.display());
}
}
NewFileHandling::Keep => { /* do nothing, obvvvvvsly */ }
}
}
} else {
if snapshot_file_path.exists() {
// snapshot exists; working doesn't
reflink_or_copy(&snapshot_file_path, abs_path)?;
if verbose {
println!("r{}", path.display());
}
} else {
// neither working nor snapshot exists
eprintln!(
"WTF? {} exists neither in working directory nor in most recent commit",
rel_path.display()
);
}
}
.into());
}
let rel_path = abs_path.relativize(table_path)?;
let snapshot_file_path = {
let mut p = snapshot_path.clone();
p.push(rel_path);
p
}
.absolutize()
.unwrap()
.to_path_buf();
println!(
"Comparing {} to {}",
path.display(),
snapshot_file_path.display()
);
}
Ok(())