From bd5f5357a814cbd8d9e8b3fd6a39190c8dd1e9f5 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Sat, 1 Feb 2025 00:14:42 +1100 Subject: [PATCH] fix(cookbook): add runtime dependencies to repo Signed-off-by: Anhad Singh --- repo.sh | 14 +++++ src/bin/cook.rs | 93 +++++++------------------------- src/bin/runtime_deps_of.rs | 25 +++++++++ src/recipe.rs | 105 ++++++++++++++++++++++++++++++++++++- 4 files changed, 161 insertions(+), 76 deletions(-) create mode 100644 src/bin/runtime_deps_of.rs diff --git a/repo.sh b/repo.sh index 202cef3b8..6d866519e 100755 --- a/repo.sh +++ b/repo.sh @@ -27,6 +27,9 @@ then recipes="$(target/release/list_recipes)" fi +# All $recipes that are in the new TOML format. +toml_recipes="" + for recipe in $recipes do recipe_path=`target/release/find_recipe $recipe` @@ -39,6 +42,7 @@ do if [ -e "${COOKBOOK_RECIPE}/recipe.toml" ] then + toml_recipes+=" $recipe" target/release/cook "$recipe" continue fi @@ -89,6 +93,16 @@ mkdir -p "$REPO" APPSTREAM_SOURCES=() +# Currently, we only support runtime dependencies for recipes in the new TOML +# format. Runtime dependencies include both `[package.dependencies]` and +# [`package.shared_deps`]. +# +# The following adds the package dependencies of the recipes to the repo as +# well. +# +# TODO(?): All of this script can be moved into `cook.rs`. +recipes="$recipes $(target/release/runtime_deps_of $toml_recipes)" + for recipe in $recipes do recipe_path=`target/release/find_recipe $recipe` diff --git a/src/bin/cook.rs b/src/bin/cook.rs index ff9345ada..648123492 100644 --- a/src/bin/cook.rs +++ b/src/bin/cook.rs @@ -1,5 +1,5 @@ use cookbook::blake3::blake3_progress; -use cookbook::recipe::{BuildKind, PackageRecipe, Recipe, SourceRecipe}; +use cookbook::recipe::{BuildKind, CookRecipe, PackageRecipe, Recipe, SourceRecipe}; use cookbook::recipe_find::recipe_find; use std::{ env, fs, @@ -14,7 +14,11 @@ use walkdir::{DirEntry, WalkDir}; fn should_build_shared() -> bool { use std::sync::OnceLock; static YES: OnceLock = OnceLock::new(); - *YES.get_or_init(|| env::var("COOKBOOK_PREFER_STATIC").expect("COOKBOOK_PREFER_STATIC").is_empty()) + *YES.get_or_init(|| { + env::var("COOKBOOK_PREFER_STATIC") + .expect("COOKBOOK_PREFER_STATIC") + .is_empty() + }) } fn remove_all(path: &Path) -> Result<(), String> { @@ -761,7 +765,10 @@ done command }; - let full_script = format!("{}\n{}\n{}\n{}", pre_script, SHARED_PRESCRIPT, script, post_script); + let full_script = format!( + "{}\n{}\n{}\n{}", + pre_script, SHARED_PRESCRIPT, script, post_script + ); run_command_stdin(command, full_script.as_bytes())?; // Move stage.tmp to stage atomically @@ -826,7 +833,12 @@ fn package( depends: Vec, } let depends = if should_build_shared() { - package.dependencies.iter().chain(package.shared_deps.iter()).cloned().collect() + package + .dependencies + .iter() + .chain(package.shared_deps.iter()) + .cloned() + .collect() } else { package.dependencies.clone() }; @@ -835,7 +847,7 @@ fn package( version: "TODO".into(), target: env::var("TARGET") .map_err(|err| format!("failed to read TARGET: {:?}", err))?, - depends + depends, }) .map_err(|err| format!("failed to serialize stage.toml: {:?}", err))?; fs::write(target_dir.join("stage.toml"), stage_toml) @@ -871,75 +883,6 @@ fn cook(recipe_dir: &Path, name: &str, recipe: &Recipe, fetch_only: bool) -> Res Ok(()) } -pub struct CookRecipe { - name: String, - dir: PathBuf, - recipe: Recipe, -} - -impl CookRecipe { - pub fn new(name: String) -> Result { - //TODO: sanitize recipe name? - let dir = recipe_find(&name, Path::new("recipes"))?; - if dir.is_none() { - return Err(format!("failed to find recipe directory '{}'", name)); - } - let dir = dir.unwrap(); - let file = dir.join("recipe.toml"); - if !file.is_file() { - return Err(format!("failed to find recipe file '{}'", file.display())); - } - - let toml = fs::read_to_string(&file).map_err(|err| { - format!( - "failed to read recipe file '{}': {}\n{:#?}", - file.display(), - err, - err - ) - })?; - - let recipe: Recipe = toml::from_str(&toml).map_err(|err| { - format!( - "failed to parse recipe file '{}': {}\n{:#?}", - file.display(), - err, - err - ) - })?; - - Ok(Self { name, dir, recipe }) - } - - //TODO: make this more efficient, smarter, and not return duplicates - pub fn new_recursive(names: &[String], recursion: usize) -> Result, String> { - if recursion == 0 { - return Err(format!( - "recursion limit while processing build dependencies: {:#?}", - names - )); - } - - let mut recipes = Vec::new(); - for name in names { - let recipe = Self::new(name.clone())?; - - let dependencies = - Self::new_recursive(&recipe.recipe.dependencies(), recursion - 1).map_err( - |err| format!("{}: failed on loading build dependencies:\n{}", name, err), - )?; - - for dependency in dependencies { - recipes.push(dependency); - } - - recipes.push(recipe); - } - - Ok(recipes) - } -} - fn main() { let mut matching = true; let mut dry_run = false; @@ -956,7 +899,7 @@ fn main() { } } - let recipes = match CookRecipe::new_recursive(&recipe_names, 16) { + let recipes = match CookRecipe::new_recursive(&recipe_names, 16, false) { Ok(ok) => ok, Err(err) => { eprintln!( diff --git a/src/bin/runtime_deps_of.rs b/src/bin/runtime_deps_of.rs new file mode 100644 index 000000000..7edc25ba2 --- /dev/null +++ b/src/bin/runtime_deps_of.rs @@ -0,0 +1,25 @@ +use cookbook::recipe::CookRecipe; +use std::{env::args, process::ExitCode}; + +/// Same as `cookbook/src/bin/cook.rs`. +const DEP_DEPTH: usize = 16; + +fn usage() { + eprintln!("Usage: pkg_deps_of package1 [package2 ...]"); +} + +fn main() -> ExitCode { + if args().len() < 2 { + usage(); + return ExitCode::FAILURE; + } + + let names = args().skip(1).collect::>(); + let recipes = CookRecipe::new_recursive(&names, DEP_DEPTH, true).expect("recipe not found"); + + for recipe in recipes { + println!("{}", recipe.name); + } + + ExitCode::SUCCESS +} diff --git a/src/recipe.rs b/src/recipe.rs index 1ba061794..eb73239c0 100644 --- a/src/recipe.rs +++ b/src/recipe.rs @@ -1,5 +1,12 @@ +use std::{ + fs, + path::{Path, PathBuf}, +}; + use serde::{Deserialize, Serialize}; +use crate::recipe_find::recipe_find; + /// Specifies how to download the source for a recipe #[derive(Debug, Deserialize, PartialEq, Serialize)] #[serde(untagged)] @@ -97,13 +104,109 @@ pub struct Recipe { impl Recipe { #[inline] pub fn dependencies_iter(&self) -> impl Iterator { - self.build.dependencies.iter().chain(self.package.shared_deps.iter()) + self.build + .dependencies + .iter() + .chain(self.package.shared_deps.iter()) } + /// `[build.dependencies] + [package.shared_deps]` #[inline] pub fn dependencies(&self) -> Vec { self.dependencies_iter().cloned().collect::>() } + + /// `[package.dependencies] + [package.shared_deps]` + #[inline] + pub fn runtime_dependencies(&self) -> Vec { + self.package + .dependencies + .iter() + .chain(self.package.shared_deps.iter()) + .cloned() + .collect::>() + } +} + +pub struct CookRecipe { + pub name: String, + pub dir: PathBuf, + pub recipe: Recipe, +} + +impl CookRecipe { + pub fn new(name: String) -> Result { + //TODO: sanitize recipe name? + let dir = recipe_find(&name, Path::new("recipes"))?; + if dir.is_none() { + return Err(format!("failed to find recipe directory '{}'", name)); + } + let dir = dir.unwrap(); + let file = dir.join("recipe.toml"); + if !file.is_file() { + return Err(format!("failed to find recipe file '{}'", file.display())); + } + + let toml = fs::read_to_string(&file).map_err(|err| { + format!( + "failed to read recipe file '{}': {}\n{:#?}", + file.display(), + err, + err + ) + })?; + + let recipe: Recipe = toml::from_str(&toml).map_err(|err| { + format!( + "failed to parse recipe file '{}': {}\n{:#?}", + file.display(), + err, + err + ) + })?; + + Ok(Self { name, dir, recipe }) + } + + //TODO: make this more efficient, smarter, and not return duplicates + pub fn new_recursive( + names: &[String], + recursion: usize, + runtime_deps_only: bool, + ) -> Result, String> { + if recursion == 0 { + return Err(format!( + "recursion limit while processing build dependencies: {:#?}", + names + )); + } + + let mut recipes = Vec::new(); + for name in names { + let recipe = Self::new(name.clone())?; + let all_deps = recipe.recipe.dependencies(); + let runtime_deps = recipe.recipe.runtime_dependencies(); + + let dependencies = Self::new_recursive( + if runtime_deps_only { + &runtime_deps + } else { + &all_deps + }, + recursion - 1, + runtime_deps_only, + ) + .map_err(|err| format!("{}: failed on loading build dependencies:\n{}", name, err))?; + + for dependency in dependencies { + recipes.push(dependency); + } + + recipes.push(recipe); + } + + Ok(recipes) + } } #[cfg(test)]