Support for metapackages

This commit is contained in:
Wildan M 2025-07-27 21:43:54 +07:00
parent b3559d7a1d
commit 25141384b4
3 changed files with 109 additions and 39 deletions

View File

@ -1029,6 +1029,7 @@ done
}
BuildKind::Configure => "cookbook_configure".to_owned(),
BuildKind::Custom { script } => script.clone(),
BuildKind::None => "".to_owned(),
};
let command = {
@ -1075,16 +1076,12 @@ done
}
fn package(
_recipe_dir: &Path,
stage_dir: &Path,
target_dir: &Path,
name: &PackageName,
recipe: &Recipe,
auto_deps: &BTreeSet<PackageName>,
) -> Result<PathBuf, String> {
//TODO: metadata like dependencies, name, and version
let package = &recipe.package;
let secret_path = "build/id_ed25519.toml";
let public_path = "build/id_ed25519.pub.toml";
if !Path::new(secret_path).is_file() || !Path::new(public_path).is_file() {
@ -1122,33 +1119,65 @@ fn package(
)
.map_err(|err| format!("failed to create pkgar archive: {:?}", err))?;
let mut depends = package.dependencies.clone();
for dep in auto_deps.iter() {
if !depends.contains(dep) {
depends.push(dep.clone());
}
}
let stage_toml = toml::to_string(&Package {
name: name.clone(),
version: "TODO".into(),
target: env::var("TARGET")
.map_err(|err| format!("failed to read TARGET: {:?}", err))?,
depends,
})
.map_err(|err| format!("failed to serialize stage.toml: {:?}", err))?;
fs::write(target_dir.join("stage.toml"), stage_toml)
.map_err(|err| format!("failed to write stage.toml: {:?}", err))?;
package_toml(target_dir, name, recipe, auto_deps)?;
}
Ok(package_file)
}
fn package_toml(
target_dir: &Path,
name: &PackageName,
recipe: &Recipe,
auto_deps: &BTreeSet<PackageName>,
) -> Result<(), String> {
let mut depends = recipe.package.dependencies.clone();
for dep in auto_deps.iter() {
if !depends.contains(dep) {
depends.push(dep.clone());
}
}
let stage_toml = toml::to_string(&Package {
name: name.clone(),
version: "TODO".into(),
target: env::var("TARGET").map_err(|err| format!("failed to read TARGET: {:?}", err))?,
depends,
})
.map_err(|err| format!("failed to serialize stage.toml: {:?}", err))?;
fs::write(target_dir.join("stage.toml"), stage_toml)
.map_err(|err| format!("failed to write stage.toml: {:?}", err))?;
return Ok(());
}
fn cook_meta(
recipe_dir: &Path,
name: &PackageName,
recipe: &Recipe,
fetch_only: bool,
) -> Result<(), String> {
if fetch_only {
return Ok(());
}
let target_dir = create_target_dir(recipe_dir)?;
let empty_deps = BTreeSet::new();
let _package_file = package_toml(&target_dir, name, recipe, &empty_deps)
.map_err(|err| format!("failed to package: {}", err))?;
Ok(())
}
fn cook(
recipe_dir: &Path,
name: &PackageName,
recipe: &Recipe,
fetch_only: bool,
) -> Result<(), String> {
if recipe.build.kind == BuildKind::None {
return cook_meta(recipe_dir, name, recipe, fetch_only);
}
let is_offline = env::var("COOKBOOK_OFFLINE").unwrap_or("".to_string()) == "1";
let source_dir = match is_offline {
true => fetch_offline(recipe_dir, &recipe.source),
@ -1160,6 +1189,18 @@ fn cook(
return Ok(());
}
let target_dir = create_target_dir(recipe_dir)?;
let (stage_dir, auto_deps) = build(recipe_dir, &source_dir, &target_dir, name, recipe)
.map_err(|err| format!("failed to build: {}", err))?;
let _package_file = package(&stage_dir, &target_dir, name, recipe, &auto_deps)
.map_err(|err| format!("failed to package: {}", err))?;
Ok(())
}
fn create_target_dir(recipe_dir: &Path) -> Result<PathBuf, String> {
let target_parent_dir = recipe_dir.join("target");
if !target_parent_dir.is_dir() {
create_dir(&target_parent_dir)?;
@ -1168,21 +1209,7 @@ fn cook(
if !target_dir.is_dir() {
create_dir(&target_dir)?;
}
let (stage_dir, auto_deps) = build(recipe_dir, &source_dir, &target_dir, name, recipe)
.map_err(|err| format!("failed to build: {}", err))?;
let _package_file = package(
recipe_dir,
&stage_dir,
&target_dir,
name,
recipe,
&auto_deps,
)
.map_err(|err| format!("failed to package: {}", err))?;
Ok(())
Ok(target_dir)
}
fn main() {

View File

@ -46,9 +46,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let toml_src = stage_dir.with_extension("toml");
let toml_dst = repo_path.join(format!("{}.toml", recipe));
if is_newer(&pkgar_src, &pkgar_dst) {
if is_newer(&toml_src, &toml_dst) {
eprintln!("\x1b[01;38;5;155mrepo - publishing {}\x1b[0m", recipe);
fs::copy(&pkgar_src, &pkgar_dst)?;
if fs::exists(&pkgar_src)? {
fs::copy(&pkgar_src, &pkgar_dst)?;
}
fs::copy(&toml_src, &toml_dst)?;
}

View File

@ -63,6 +63,9 @@ pub enum SourceRecipe {
#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(tag = "template")]
pub enum BuildKind {
/// Will not build (for meta packages)
#[serde(rename = "none")]
None,
/// Will build and install using cargo
#[serde(rename = "cargo")]
Cargo {
@ -80,9 +83,15 @@ pub enum BuildKind {
Custom { script: String },
}
#[derive(Debug, Deserialize, PartialEq, Serialize)]
impl Default for BuildKind {
fn default() -> Self {
BuildKind::None
}
}
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
pub struct BuildRecipe {
#[serde(flatten)]
#[serde(flatten, default)]
pub kind: BuildKind,
#[serde(default)]
pub dependencies: Vec<PackageName>,
@ -100,6 +109,7 @@ pub struct Recipe {
/// Specifies how to download the source for this recipe
pub source: Option<SourceRecipe>,
/// Specifies how to build this recipe
#[serde(default)]
pub build: BuildRecipe,
/// Specifies how to package this recipe
#[serde(default)]
@ -207,6 +217,8 @@ impl CookRecipe {
#[cfg(test)]
mod tests {
use pkg::PackageName;
#[test]
fn git_cargo_recipe() {
use crate::recipe::{BuildKind, BuildRecipe, PackageRecipe, Recipe, SourceRecipe};
@ -291,4 +303,33 @@ mod tests {
}
);
}
#[test]
fn meta_recipe() {
use crate::recipe::{BuildKind, BuildRecipe, PackageRecipe, Recipe};
let recipe: Recipe = toml::from_str(
r#"
[package]
dependencies = [
"gcc13",
]
"#,
)
.unwrap();
assert_eq!(
recipe,
Recipe {
source: None,
build: BuildRecipe {
kind: BuildKind::None,
dependencies: Vec::new(),
},
package: PackageRecipe {
dependencies: vec![PackageName::new("gcc13").unwrap()],
},
}
);
}
}