Add minitar test files; Remove creator and item modules;

This commit is contained in:
Nathan Fisher 2023-04-03 18:29:11 -04:00
parent 1e7d73bc28
commit ee52bfb462
8 changed files with 3 additions and 240 deletions

2
.gitignore vendored
View File

@ -1,3 +1,3 @@
/target
/Cargo.lock
test
tags

View File

@ -1,143 +0,0 @@
use {
crate::{Entry, Item, Package, Plist, Specs},
rayon::prelude::{IntoParallelRefIterator, ParallelIterator},
std::{
borrow::BorrowMut,
env,
error::Error,
fs::{self, File},
io::{self, Write},
path::{Path, PathBuf},
sync::{
atomic::{AtomicUsize, Ordering},
mpsc::Sender,
Mutex,
},
},
walkdir::WalkDir,
zstd::Encoder,
};
pub enum Message {
MemberAdded(String),
Success(String),
Failure(String),
}
pub struct Creator {
path: PathBuf,
entries: Vec<PathBuf>,
specs: Specs,
}
impl Creator {
pub fn new(path: &Path, specs: Specs) -> Result<Self, io::Error> {
let d = env::current_dir()?;
env::set_current_dir(path)?;
let path = path.to_path_buf();
let entries = WalkDir::new(".")
.into_iter()
.filter(Result::is_ok)
.map(|x| x.unwrap().path().to_path_buf())
.collect::<Vec<_>>();
env::set_current_dir(d)?;
Ok(Self {
path,
entries,
specs,
})
}
pub fn from_list(list: &[&str], specs: Specs) -> Result<Self, io::Error> {
let entries = list.iter().map(|x| Path::new(x).to_path_buf()).collect();
Ok(Self {
path: env::current_dir().unwrap_or(Path::new("/").to_path_buf()),
entries,
specs,
})
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn create(self, outdir: &Path, sender: Sender<Message>) -> Result<(), Box<dyn Error>> {
let d = env::current_dir()?;
let plist = Mutex::new(Plist::default());
let totalsize: AtomicUsize = 0.into();
let fullname = format!(
"{}-{}_{}",
&self.specs.name, self.specs.version, self.specs.release
);
if !outdir.exists() {
fs::create_dir_all(outdir)?;
}
let outdir = outdir.canonicalize()?;
let mut archive = outdir.clone();
archive.push(&fullname);
archive.set_extension("tar.zst");
let fd = File::create(&archive)?;
let writer = Mutex::new(Encoder::new(fd, 0)?);
let sender = Mutex::new(sender);
env::set_current_dir(&self.path)?;
self.entries
.par_iter()
.filter(|x| x.as_path() != Path::new("."))
.for_each(|x| {
let sender = sender.lock().unwrap().clone();
if let Ok(item) = Item::try_create(x.as_path()) {
if let Entry::File {
path: _,
sha256sum: _,
mode: _,
size,
} = &item.entry
{
totalsize.fetch_add(*size, Ordering::Release);
}
let path = match item.entry.clone() {
Entry::File {
path,
sha256sum: _,
mode: _,
size: _,
}
| Entry::Link { path, target: _ }
| Entry::Directory { path, mode: _ } => path,
};
plist.lock().unwrap().borrow_mut().entries.push(item.entry);
match writer.lock().unwrap().borrow_mut().write_all(&item.data) {
Ok(_) => sender
.send(Message::MemberAdded(format!("{}", path.display())))
.expect("couldn't send message"),
Err(e) => sender
.send(Message::Failure(format!("{e}")))
.expect("couldn't send message"),
}
} else {
sender
.send(Message::Failure(format!(
"Could not process DirEntry for {}",
x.display()
)))
.expect("could not send message");
}
});
let mut package: Package = self.specs.into();
package.size = totalsize.into_inner();
let plist = plist.into_inner()?;
package.plist = plist;
let node = package.save_ron_and_create_tar_node(&outdir)?;
let mut writer = writer.into_inner()?;
writer.write_all(&node.to_vec()?)?;
let _fd = writer.finish()?;
let sender = sender.into_inner()?;
sender.send(Message::Success(format!("{} saved", archive.display())))?;
env::set_current_dir(d)?;
Ok(())
}
}

View File

@ -1,91 +0,0 @@
use crate::Entry;
use sha2::{Digest, Sha256};
use std::{
error::Error,
ffi::OsStr,
fmt::Write,
fs,
io::Read,
os::unix::fs::MetadataExt,
path::{Path, PathBuf},
};
use crate::tar::{Node, Owner};
#[derive(Clone, Debug)]
pub struct Item {
pub entry: Entry,
pub data: Vec<u8>,
}
impl Item {
pub fn try_create(path: &Path) -> Result<Self, Box<dyn Error>> {
let path = fix_path(path);
let meta = fs::metadata(&path)?;
let filename = format!("{}", path.display());
let owner = Some(Owner::default());
if meta.is_file() {
let mut data = vec![];
let mut fd = fs::File::open(path)?;
let path = PathBuf::from(&filename);
let size = fd.read_to_end(&mut data)?;
let mut sha256sum = String::new();
let mut hasher = Sha256::new();
hasher.update(&data);
let res = hasher.finalize();
for c in res {
write!(sha256sum, "{c:02x}")?;
}
let mode = meta.mode();
Ok(Self {
entry: Entry::File {
path,
sha256sum,
mode,
size,
},
data: Node::read_data_to_tar(&data, &filename, &meta, owner)?.to_vec()?,
})
} else if meta.is_dir() {
let mode = meta.mode();
let path = PathBuf::from(&filename);
Ok(Self {
entry: Entry::Directory { path, mode },
data: Node::read_data_to_tar(&[0; 0], &filename, &meta, owner)?.to_vec()?,
})
} else if meta.is_symlink() {
let target = fs::read_link(path)?;
let path = PathBuf::from(&filename);
Ok(Self {
entry: Entry::Link { path, target },
data: Node::read_data_to_tar(&[0; 0], &filename, &meta, owner)?.to_vec()?,
})
} else {
unreachable!();
}
}
}
fn fix_path(path: &Path) -> PathBuf {
let path = if let Ok(p) = path.strip_prefix("./") {
p
} else {
path
};
if path.is_file() || path.is_symlink() {
match path.ancestors().last().and_then(Path::to_str) {
Some("etc" | "var") => {
let ext = if let Some(x) = path.extension().and_then(OsStr::to_str) {
format!("{x}.new")
} else {
"new".to_string()
};
let mut path = path.to_path_buf();
path.set_extension(ext);
path
}
_ => path.to_path_buf(),
}
} else {
path.to_path_buf()
}
}

View File

@ -1,13 +1,9 @@
pub mod tar;
mod creator;
mod item;
mod package;
mod plist;
mod version;
pub use {
creator::{Creator, Message},
item::Item,
package::{Dependency, Package, Specs},
plist::*,
version::*,

View File

@ -85,7 +85,7 @@ impl Package {
to_string_pretty(self, cfg)
}
pub(crate) fn save_ron_and_create_tar_node(
pub fn save_ron_and_create_tar_node(
&self,
outdir: &Path,
) -> Result<Node, Box<dyn Error>> {

BIN
test/1.tar Normal file

Binary file not shown.

1
test/1.txt Normal file
View File

@ -0,0 +1 @@
This is a test file.

BIN
test/2.tar Normal file

Binary file not shown.