Skip to content

Instantly share code, notes, and snippets.

@murilobsd
Last active May 26, 2024 00:26
Show Gist options
  • Save murilobsd/684c5dbf5bc413aa43912c9f9e2bda19 to your computer and use it in GitHub Desktop.
Save murilobsd/684c5dbf5bc413aa43912c9f9e2bda19 to your computer and use it in GitHub Desktop.
[package]
name = "vorpal"
version = "0.1.0"
edition = "2021"
[dependencies]
walkdir = "2.3.2"
ignore = "0.4.18"
sha2 = "0.10.2"
fs_extra = "1.2.0"
anyhow = "1.0.68"
rayon = "1.5.3"
fn main() -> anyhow::Result<()> {
let src_dir = ".";
let dst_base_dir = "/tmp/zumba";
let name = "zumba";
paastel::build(src_dir, dst_base_dir, name)?;
Ok(())
}
use std::fs;
use std::path::{Path, PathBuf};
use anyhow::{Context, Result};
use ignore::WalkBuilder;
use rayon::prelude::*;
use sha2::{Digest, Sha256};
pub fn build<P: AsRef<Path>>(
src_dir: P,
dst_base_dir: P,
name: &str,
) -> Result<()> {
// Liste os arquivos e gere o hash concatenado
let (files_to_copy, concatenated_hash) =
list_files_and_generate_hash(src_dir.as_ref())?;
// Verifique se o diretório de destino já existe
let dst_dir = dst_base_dir
.as_ref()
.join(format!("{name}-{concatenated_hash}"));
if dst_dir.exists() {
println!("O diretório de destino '{}' já existe!", dst_dir.display());
return Ok(());
}
// Crie o diretório de destino e copie os arquivos mantendo a hierarquia
std::fs::create_dir_all(&dst_dir)
.context("Falha ao criar diretório de destino")?;
copy_files_with_hierarchy(&files_to_copy, src_dir.as_ref(), &dst_dir)?;
println!("Arquivos copiados para o diretório '{}'", dst_dir.display());
Ok(())
}
fn list_files_and_generate_hash(
src_dir: &Path,
) -> Result<(Vec<PathBuf>, String)> {
let files_to_copy: Vec<PathBuf> = WalkBuilder::new(src_dir)
.build()
.filter_map(|entry| {
let entry = entry.ok()?;
if entry.file_type().is_some()
&& entry.file_type().unwrap().is_file()
{
Some(entry.path().to_path_buf())
} else {
None
}
})
.collect();
let mut file_hashes: Vec<String> = files_to_copy
.par_iter()
.map(hash_file)
.collect::<Result<Vec<String>>>()?;
// Ordena os hashes dos arquivos
file_hashes.sort();
// Concatena os hashes em uma única string
let concatenated_hash = generate_hash_from_hashes(&file_hashes)?;
Ok((files_to_copy, concatenated_hash))
}
fn copy_files_with_hierarchy(
files_to_copy: &[PathBuf],
src_dir: &Path,
dst_dir: &Path,
) -> Result<()> {
files_to_copy.par_iter().try_for_each(|file| {
let relative_path = file
.strip_prefix(src_dir)
.context("Falha ao obter caminho relativo")?;
let dst_file = dst_dir.join(relative_path);
if let Some(parent) = dst_file.parent() {
fs::create_dir_all(parent)
.context("Falha ao criar diretório pai no destino")?;
}
fs::copy(file, dst_file).context("Falha ao copiar arquivo")?;
Ok::<(), anyhow::Error>(())
})?;
Ok(())
}
fn hash_file<P: AsRef<Path>>(path: P) -> Result<String> {
let mut file =
fs::File::open(&path).context("Falha ao abrir arquivo para hash")?;
let mut hasher = Sha256::new();
std::io::copy(&mut file, &mut hasher)
.context("Falha ao ler arquivo para hash")?;
let hash = hasher.finalize();
Ok(format!("{:x}", hash))
}
fn generate_hash_from_hashes(hashes: &[String]) -> Result<String> {
let mut hasher = Sha256::new();
for hash in hashes {
hasher.update(hash.as_bytes());
}
let final_hash = hasher.finalize();
Ok(format!("{:x}", final_hash))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment