pub mod builtin;
pub mod commands;
pub mod manifest;
pub mod resolver;
pub mod store;
pub type PkgResult<T> = Result<T, PkgError>;
#[derive(Debug)]
pub enum PkgError {
Io(String),
Manifest(String),
Resolve(String),
Unknown(String),
Other(String),
}
impl std::fmt::Display for PkgError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PkgError::Io(s)
| PkgError::Manifest(s)
| PkgError::Resolve(s)
| PkgError::Unknown(s)
| PkgError::Other(s) => write!(f, "{}", s),
}
}
}
impl From<std::io::Error> for PkgError {
fn from(e: std::io::Error) -> Self {
PkgError::Io(e.to_string())
}
}
pub fn store_integrity(root: &std::path::Path) -> PkgResult<String> {
use sha2::{Digest, Sha256};
let mut hasher = Sha256::new();
let mut entries: Vec<std::path::PathBuf> = Vec::new();
fn walk(
root: &std::path::Path,
cur: &std::path::Path,
out: &mut Vec<std::path::PathBuf>,
) -> PkgResult<()> {
for entry in std::fs::read_dir(cur)? {
let entry = entry?;
let path = entry.path();
let meta = entry.metadata()?;
if meta.is_dir() && !meta.file_type().is_symlink() {
walk(root, &path, out)?;
} else {
out.push(path.strip_prefix(root).unwrap_or(&path).to_path_buf());
}
}
Ok(())
}
walk(root, root, &mut entries)?;
entries.sort();
for rel in &entries {
let abs = root.join(rel);
let meta = std::fs::symlink_metadata(&abs)?;
let rel_s = rel.to_string_lossy();
if meta.file_type().is_symlink() {
let target = std::fs::read_link(&abs)?;
hasher.update(rel_s.as_bytes());
hasher.update(b"\0L\0");
hasher.update(target.to_string_lossy().as_bytes());
hasher.update(b"\n");
} else if meta.is_file() {
let bytes = std::fs::read(&abs)?;
hasher.update(rel_s.as_bytes());
hasher.update(b"\0F\0");
hasher.update(bytes.len().to_string().as_bytes());
hasher.update(b"\n");
hasher.update(&bytes);
hasher.update(b"\n");
}
}
Ok(format!("sha256-{:x}", hasher.finalize()))
}