This commit is contained in:
2025-10-17 13:48:34 +03:00
parent c7fff59f6c
commit df0b260c7b
4 changed files with 76 additions and 19 deletions

View File

@@ -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 zspatch
cargo build --release --target x86_64-unknown-linux-gnu --package zsdiff_all --bin zsdiff 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 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

View File

@@ -55,6 +55,7 @@ pub struct Metadata {
pub(crate) diff_files: Vec<String>, pub(crate) diff_files: Vec<String>,
pub hashes: HashMap<String, String>, pub hashes: HashMap<String, String>,
pub remove_files: Vec<String>, pub remove_files: Vec<String>,
pub remove_folders: Vec<String>,
} }
pub async fn get_hash(data: Vec<u8>) -> String { pub async fn get_hash(data: Vec<u8>) -> String {

View File

@@ -7,10 +7,12 @@ use std::{fs, io, time};
use utils::{Metadata, Zsdiff, get_hash}; use utils::{Metadata, Zsdiff, get_hash};
use walkdir::WalkDir; use walkdir::WalkDir;
#[derive(Debug)]
struct FileInfo { struct FileInfo {
path: String, path: String,
relative_path: String, // Without dir prefix relative_path: String, // Without dir prefix
hash: String, hash: String,
is_dir: bool,
} }
async fn walk_dir(dir: String) -> HashMap<String, FileInfo> { async fn walk_dir(dir: String) -> HashMap<String, FileInfo> {
@@ -18,33 +20,66 @@ async fn walk_dir(dir: String) -> HashMap<String, FileInfo> {
for e in WalkDir::new(&dir) { for e in WalkDir::new(&dir) {
let e = e.unwrap(); let e = e.unwrap();
let path = e.path(); 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; continue;
} }
let content = fs::read(path).unwrap(); if path.is_dir() {
let hash = get_hash(content).await; let path_str = path.display().to_string();
let path_str = path.display().to_string(); let hash = get_hash(path_str.clone().into_bytes()).await;
let file_info = FileInfo { let file_info = FileInfo {
relative_path: path_str[dir.len() + 1..].to_string(), relative_path: path_str[dir.len() + 1..].to_string(),
path: path_str, path: path_str,
hash: hash.clone(), hash: hash.clone(),
}; is_dir: true,
hash_list.entry(hash).or_insert(file_info); };
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 hash_list
} }
async fn compare_hashes(old: HashMap<String, FileInfo>, new: HashMap<String, FileInfo>) -> Zsdiff { async fn compare_hashes(old: HashMap<String, FileInfo>, new: HashMap<String, FileInfo>) -> Zsdiff {
let mut diff_files: HashMap<String, Vec<u8>> = HashMap::new(); let mut diff_files: HashMap<String, Vec<u8>> = HashMap::new();
let mut remove_files: Vec<String> = vec![]; let mut remove_files: Vec<String> = vec![];
let mut remove_folders: Vec<String> = vec![];
let mut hashes: HashMap<String, String> = HashMap::new(); let mut hashes: HashMap<String, String> = HashMap::new();
for (_, info) in &old { 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 { for (new_hash, new_fileinfo) in &new {
let old_fileinfo = old.get(new_hash); 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() { if old_fileinfo.is_none() {
let path = new_fileinfo.relative_path.clone(); let path = new_fileinfo.relative_path.clone();
@@ -62,6 +97,7 @@ async fn compare_hashes(old: HashMap<String, FileInfo>, new: HashMap<String, Fil
diff_files: diff_files.keys().cloned().collect(), diff_files: diff_files.keys().cloned().collect(),
hashes, hashes,
remove_files, remove_files,
remove_folders,
}, },
} }
} }
@@ -95,7 +131,7 @@ pub async fn zsdiff(
"Compress ratio: {:.2?}%", "Compress ratio: {:.2?}%",
size_after as f64 / size_before as f64 * 100.0 size_after as f64 / size_before as f64 * 100.0
); );
print!("Time elapsed: {:.2?}s", elapsed); print!("Time elapsed: {:.2?}", elapsed);
Ok(()) Ok(())
} }

View File

@@ -14,7 +14,13 @@ async fn create_tmp_dir(dir_name: String) -> Result<String, io::Error> {
Ok(name) Ok(name)
} }
async fn extract_files(zsdiff: &Zsdiff, filename: &String) -> Result<String, io::Error> { async fn load_file(filename: String) -> Result<Zsdiff, io::Error> {
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<String, io::Error> {
let tmp_dir_name = create_tmp_dir(filename.to_string()).await?; let tmp_dir_name = create_tmp_dir(filename.to_string()).await?;
let path = Path::new(&tmp_dir_name); let path = Path::new(&tmp_dir_name);
fs::remove_dir_all(path).ok(); 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> { async fn zspatch(filename: String, dest_dir: String) -> Result<(), io::Error> {
let filename = &format!("{}.zdiff", filename); let diff = load_file(filename.clone()).await?;
let parts = utils::decompress_parts(read(filename)?).await?;
let diff = Zsdiff::from_vec(parts).await?;
let tmp_dir_name = extract_files(&diff, filename).await?; let tmp_dir_name = extract_files(&diff, filename).await?;
let now = time::Instant::now(); let now = time::Instant::now();
for name in diff.content.keys().collect::<Vec<&String>>() { for name in diff.content.keys().collect::<Vec<&String>>() {
@@ -55,6 +59,11 @@ async fn zspatch(filename: String, dest_dir: String) -> Result<(), io::Error> {
fs::remove_file(path).ok(); 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 { for (k, hash) in diff.metadata.hashes {
let path = Path::new(&dest_dir).join(k); let path = Path::new(&dest_dir).join(k);
let content = read(path)?; let content = read(path)?;
@@ -76,6 +85,8 @@ struct Args {
#[arg(short, long)] #[arg(short, long)]
dest_dir: String, dest_dir: String,
#[arg(short, long)] #[arg(short, long)]
metadata: bool,
#[arg(short, long)]
hash_check: bool, hash_check: bool,
} }
@@ -85,5 +96,10 @@ async fn main() -> io::Result<()> {
if args.hash_check { if args.hash_check {
check_hash(args.filename.clone()).await?; 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 zspatch(args.filename, args.dest_dir).await
} }