From 4af66f418b6837b6441b4e8eaf2d8ede585238b9 Mon Sep 17 00:00:00 2001 From: diogo464 Date: Mon, 11 Aug 2025 11:51:39 +0100 Subject: snapshot --- src/main.rs | 74 ++++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 59 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 3a8e5f9..00091e6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,7 +10,7 @@ use std::{ time::SystemTime, }; -use clap::{Args, Parser, Subcommand}; +use clap::{Args, Parser, Subcommand, ValueEnum}; use sha2::Digest; use slotmap::SlotMap; @@ -77,7 +77,7 @@ pub fn blob_path(store: &BlobStore, blob_id: &BlobId) -> PathBuf { path } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ValueEnum)] pub enum ImportMode { Move, Copy, @@ -103,7 +103,13 @@ pub fn blob_import_file( std::fs::rename(file_path, blob_path)?; } ImportMode::Copy => { - todo!() + let blob_tmp_path = { + let mut p = blob_path.clone(); + p.set_file_name(format!("{blob_id}.tmp")); + p + }; + std::fs::copy(file_path, &blob_tmp_path)?; + std::fs::rename(&blob_tmp_path, blob_path)?; } ImportMode::HardLink => match std::fs::hard_link(file_path, blob_path) { Ok(()) => {} @@ -315,6 +321,12 @@ impl DrivePath { Self(components) } + pub fn join(&self, path: DrivePath) -> DrivePath { + let mut components = self.0.clone(); + components.extend(path.0); + Self(components) + } + pub fn components(&self) -> &[DrivePathComponent] { self.0.as_slice() } @@ -349,7 +361,11 @@ impl FromStr for DrivePath { fn from_str(s: &str) -> Result { let mut components = Vec::default(); - for unchecked_component in s.trim().trim_matches('/').split('/') { + for unchecked_component in s.trim_matches('/').split('/') { + if unchecked_component.is_empty() { + continue; + } + match unchecked_component.parse() { Ok(component) => components.push(component), Err(err) => { @@ -773,6 +789,9 @@ struct LsArgs { #[clap(short, long)] recursive: bool, + #[clap(long)] + relative: bool, + path: Option, } @@ -781,12 +800,18 @@ struct ImportArgs { #[clap(flatten)] common: CliCommon, + #[clap(long)] + mode: ImportMode, + #[clap(long)] timestamp: Option, #[clap(long)] email: String, + #[clap(long, default_value = "/")] + destination: DrivePath, + path: PathBuf, } @@ -921,8 +946,8 @@ fn cmd_ls(args: LsArgs) { let mut fs = Fs::default(); let ops = common_read_log_file(&args.common); ops.iter().for_each(|op| apply(&mut fs, op).unwrap()); - let node_id = match args.path { - Some(path) => find_node(&fs, &path), + let node_id = match &args.path { + Some(path) => find_node(&fs, path), None => Some(fs.root), }; if let Some(node_id) = node_id { @@ -930,7 +955,11 @@ fn cmd_ls(args: LsArgs) { &mut writer, &fs, node_id, - Default::default(), + if args.relative { + Default::default() + } else { + args.path.unwrap_or_default() + }, args.recursive, true, ); @@ -958,12 +987,14 @@ fn write_node( .unwrap(); } FsNodeKind::Directory => { - writeln!( - writer, - "{}\tdir\t{}\t-\t-\t{}", - path, node.lastmod, node.author - ) - .unwrap(); + if !recurse { + writeln!( + writer, + "{}\tdir\t{}\t-\t-\t{}", + path, node.lastmod, node.author + ) + .unwrap(); + } if recursive || recurse { for (child_comp, child_id) in node.children.iter() { let child_path = path.push(child_comp.clone()); @@ -1007,6 +1038,7 @@ fn cmd_import(args: ImportArgs) { let store = BlobStore::new("blobs"); let timestamp = args.timestamp.unwrap_or_else(get_timestamp); let root = args.path.canonicalize().unwrap(); + let import_mode = args.mode; let files = Queue::from(collect_all_file_paths(&root)); let num_threads = std::thread::available_parallelism().unwrap().get(); @@ -1016,13 +1048,15 @@ fn cmd_import(args: ImportArgs) { let email = args.email.clone(); let files = files.clone(); let store = store.clone(); + let destination = args.destination.clone(); let handle = std::thread::spawn(move || { let mut ops = Vec::default(); while let Some(file) = files.pop() { let rel = file.strip_prefix(&root).unwrap(); - let drive_path = rel.to_str().unwrap().parse::().unwrap(); + let drive_path = + destination.join(rel.to_str().unwrap().parse::().unwrap()); let blob_id = blob_hash_file(&file).unwrap(); - blob_import_file(&store, ImportMode::HardLink, &blob_id, &file).unwrap(); + blob_import_file(&store, import_mode, &blob_id, &file).unwrap(); let blob_size = blob_size(&store, &blob_id).unwrap(); let op = Operation { header: OperationHeader { @@ -1152,3 +1186,13 @@ fn get_next_revision(ops: &[Operation]) -> u64 { None => 0, } } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn parse_drive_path() { + let p = "/".parse::().unwrap(); + } +} -- cgit