diff --git a/Makefile b/Makefile index 8508c8f..c8c87d6 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,9 @@ -build: +all: build-linux build-win + +build-linux: cargo build --release --target x86_64-unknown-linux-gnu --package zsdiff_all --bin zspatch cargo build --release --target x86_64-unknown-linux-gnu --package zsdiff_all --bin zsdiff + +build-win: cargo build --release --target x86_64-pc-windows-gnu --package zsdiff_all --bin zspatch - cargo build --release --target x86_64-pc-windows-gnu --package zsdiff_all --bin zsdiff + cargo build --release --target x86_64-pc-windows-gnu --package zsdiff_all --bin zsdiff \ No newline at end of file diff --git a/src/utils.rs b/src/utils.rs index 12500e5..bcacfff 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -55,6 +55,7 @@ pub struct Metadata { pub(crate) diff_files: Vec, pub hashes: HashMap, pub remove_files: Vec, + pub remove_folders: Vec, } pub async fn get_hash(data: Vec) -> String { diff --git a/src/zsdiff.rs b/src/zsdiff.rs index 4e8e36a..42e966b 100644 --- a/src/zsdiff.rs +++ b/src/zsdiff.rs @@ -7,10 +7,12 @@ use std::{fs, io, time}; use utils::{Metadata, Zsdiff, get_hash}; use walkdir::WalkDir; +#[derive(Debug)] struct FileInfo { path: String, relative_path: String, // Without dir prefix hash: String, + is_dir: bool, } async fn walk_dir(dir: String) -> HashMap { @@ -18,33 +20,66 @@ async fn walk_dir(dir: String) -> HashMap { for e in WalkDir::new(&dir) { let e = e.unwrap(); let path = e.path(); - if path.is_dir() { + println!( + "Path: {}, {}", + path.display(), + path.display().to_string().eq(&dir) + ); + if path.display().to_string().eq(&dir) { continue; } - let content = fs::read(path).unwrap(); - let hash = get_hash(content).await; - let path_str = path.display().to_string(); - let file_info = FileInfo { - relative_path: path_str[dir.len() + 1..].to_string(), - path: path_str, - hash: hash.clone(), - }; - hash_list.entry(hash).or_insert(file_info); + if path.is_dir() { + let path_str = path.display().to_string(); + let hash = get_hash(path_str.clone().into_bytes()).await; + let file_info = FileInfo { + relative_path: path_str[dir.len() + 1..].to_string(), + path: path_str, + hash: hash.clone(), + is_dir: true, + }; + hash_list.entry(hash).or_insert(file_info); + } else { + let content = fs::read(path).unwrap(); + let hash = get_hash(content).await; + let path_str = path.display().to_string(); + let file_info = FileInfo { + relative_path: path_str[dir.len() + 1..].to_string(), + path: path_str, + hash: hash.clone(), + is_dir: false, + }; + hash_list.entry(hash).or_insert(file_info); + } } + println!("{:?}", hash_list); hash_list } async fn compare_hashes(old: HashMap, new: HashMap) -> Zsdiff { let mut diff_files: HashMap> = HashMap::new(); let mut remove_files: Vec = vec![]; + let mut remove_folders: Vec = vec![]; let mut hashes: HashMap = HashMap::new(); for (_, info) in &old { - remove_files.push(info.relative_path.clone()); + if info.is_dir { + remove_folders.push(info.relative_path.clone()); + } else { + remove_files.push(info.relative_path.clone()); + } } for (new_hash, new_fileinfo) in &new { let old_fileinfo = old.get(new_hash); - remove_files.retain(|filename| !filename.eq(&new_fileinfo.relative_path)); + if new_fileinfo.is_dir { + remove_folders.retain(|filename| !filename.eq(&new_fileinfo.relative_path)); + } else { + remove_files.retain(|filename| !filename.eq(&new_fileinfo.relative_path)); + } + + if new_fileinfo.is_dir { + println!("{}", new_fileinfo.is_dir); + continue; + } if old_fileinfo.is_none() { let path = new_fileinfo.relative_path.clone(); @@ -62,6 +97,7 @@ async fn compare_hashes(old: HashMap, new: HashMap Result { Ok(name) } -async fn extract_files(zsdiff: &Zsdiff, filename: &String) -> Result { +async fn load_file(filename: String) -> Result { + let filename = &format!("{}.zdiff", filename); + let parts = utils::decompress_parts(read(filename)?).await?; + Ok(Zsdiff::from_vec(parts).await?) +} + +async fn extract_files(zsdiff: &Zsdiff, filename: String) -> Result { let tmp_dir_name = create_tmp_dir(filename.to_string()).await?; let path = Path::new(&tmp_dir_name); fs::remove_dir_all(path).ok(); @@ -38,9 +44,7 @@ async fn check_hash(filename: String) -> Result<(), io::Error> { } async fn zspatch(filename: String, dest_dir: String) -> Result<(), io::Error> { - let filename = &format!("{}.zdiff", filename); - let parts = utils::decompress_parts(read(filename)?).await?; - let diff = Zsdiff::from_vec(parts).await?; + let diff = load_file(filename.clone()).await?; let tmp_dir_name = extract_files(&diff, filename).await?; let now = time::Instant::now(); for name in diff.content.keys().collect::>() { @@ -55,6 +59,11 @@ async fn zspatch(filename: String, dest_dir: String) -> Result<(), io::Error> { fs::remove_file(path).ok(); } + for folder in diff.metadata.remove_folders { + let path = Path::new(&dest_dir).join(folder); + fs::remove_dir_all(path).ok(); + } + for (k, hash) in diff.metadata.hashes { let path = Path::new(&dest_dir).join(k); let content = read(path)?; @@ -76,6 +85,8 @@ struct Args { #[arg(short, long)] dest_dir: String, #[arg(short, long)] + metadata: bool, + #[arg(short, long)] hash_check: bool, } @@ -85,5 +96,10 @@ async fn main() -> io::Result<()> { if args.hash_check { check_hash(args.filename.clone()).await?; } + if args.metadata { + let diff = load_file(args.filename).await?; + println!("{}", serde_json::to_string(&diff.metadata)?); + return Ok(()); + } zspatch(args.filename, args.dest_dir).await }