124 lines
3.8 KiB
Rust
124 lines
3.8 KiB
Rust
use std::{
|
|
fs,
|
|
path::{Path, PathBuf},
|
|
};
|
|
|
|
use anyhow::Context;
|
|
use sha2::{Digest, Sha256};
|
|
|
|
use crate::recipe::{OutputPackage, Recipe};
|
|
|
|
pub struct Layout<'a> {
|
|
pub root: &'a Path,
|
|
pub arch: &'a str,
|
|
}
|
|
|
|
impl<'a> Layout<'a> {
|
|
pub fn new(root: &'a Path, arch: &'a str) -> Self {
|
|
Self { root, arch }
|
|
}
|
|
|
|
pub fn source_cache_dir(&self) -> PathBuf {
|
|
self.root.join("build/cache/sources")
|
|
}
|
|
|
|
pub fn source_cache_path(&self, key: &str) -> PathBuf {
|
|
self.source_cache_dir().join(key)
|
|
}
|
|
|
|
pub fn source_workdir(&self, recipe: &Recipe) -> PathBuf {
|
|
self.root.join("build/sources").join(recipe.slug())
|
|
}
|
|
|
|
pub fn build_workdir(&self, recipe: &Recipe) -> PathBuf {
|
|
self.root.join("build/builds").join(recipe.slug())
|
|
}
|
|
|
|
pub fn host_install_dir(&self, recipe: &Recipe) -> PathBuf {
|
|
self.root.join("build/host-pkgs").join(recipe.slug())
|
|
}
|
|
|
|
pub fn host_install_root(&self, recipe: &Recipe) -> PathBuf {
|
|
self.root.join("build/host-pkgs").join(recipe.slug())
|
|
}
|
|
|
|
pub fn apk_path(&self, recipe: &Recipe, output: &OutputPackage) -> PathBuf {
|
|
self.root.join("build/pkgs").join(self.arch).join(format!(
|
|
"{}-{}-r{}.apk",
|
|
output.name(),
|
|
recipe.version(),
|
|
recipe.revision()
|
|
))
|
|
}
|
|
|
|
pub fn source_stamp(&self, recipe: &Recipe, kind: &str) -> PathBuf {
|
|
self.root
|
|
.join("build/sources")
|
|
.join(format!("{}.{kind}", recipe.slug()))
|
|
}
|
|
|
|
pub fn recipe_task_stamp(&self, recipe: &Recipe, kind: &str) -> PathBuf {
|
|
self.root
|
|
.join("build/tasks")
|
|
.join(format!("{}.{kind}", recipe.slug()))
|
|
}
|
|
|
|
pub fn output_task_stamp(&self, output: &OutputPackage, kind: &str) -> PathBuf {
|
|
self.root
|
|
.join("build/tasks")
|
|
.join(format!("{}.{kind}", output.key().replace(':', "-")))
|
|
}
|
|
|
|
pub fn recipe_fingerprint(&self, recipe: &Recipe) -> anyhow::Result<String> {
|
|
let mut hasher = Sha256::new();
|
|
hasher.update(self.arch.as_bytes());
|
|
hasher.update(recipe.key().as_bytes());
|
|
hasher.update(recipe.version().as_bytes());
|
|
hasher.update(recipe.revision().to_le_bytes());
|
|
hasher.update(
|
|
fs::read(recipe.path())
|
|
.with_context(|| format!("reading recipe {}", recipe.path().display()))?,
|
|
);
|
|
for (name, source) in recipe.sources().entries() {
|
|
hasher.update(name.unwrap_or("").as_bytes());
|
|
hasher.update(source.url().as_bytes());
|
|
hasher.update(source.cache_key().as_bytes());
|
|
}
|
|
for patch in self.recipe_patches(recipe)? {
|
|
hasher.update(patch.display().to_string().as_bytes());
|
|
hasher
|
|
.update(fs::read(&patch).with_context(|| format!("reading {}", patch.display()))?);
|
|
}
|
|
Ok(hex::encode(hasher.finalize()))
|
|
}
|
|
|
|
pub fn output_fingerprint(
|
|
&self,
|
|
recipe: &Recipe,
|
|
output: &OutputPackage,
|
|
) -> anyhow::Result<String> {
|
|
let mut hasher = Sha256::new();
|
|
hasher.update(self.recipe_fingerprint(recipe)?.as_bytes());
|
|
hasher.update(output.key().as_bytes());
|
|
Ok(hex::encode(hasher.finalize()))
|
|
}
|
|
|
|
pub fn recipe_has_patches(&self, recipe: &Recipe) -> anyhow::Result<bool> {
|
|
Ok(!self.recipe_patches(recipe)?.is_empty())
|
|
}
|
|
|
|
pub fn recipe_patches(&self, recipe: &Recipe) -> anyhow::Result<Vec<PathBuf>> {
|
|
let Some(data_dir) = recipe.data_dir() else {
|
|
return Ok(Vec::new());
|
|
};
|
|
let patches_dir = data_dir.join("patches");
|
|
let mut out = Vec::new();
|
|
for (_, source) in recipe.sources().entries() {
|
|
for name in source.patches() {
|
|
out.push(patches_dir.join(name));
|
|
}
|
|
}
|
|
Ok(out)
|
|
}
|
|
}
|