fix(cookbook): add runtime dependencies to repo

Signed-off-by: Anhad Singh <andypython@protonmail.com>
This commit is contained in:
Anhad Singh 2025-02-01 00:14:42 +11:00
parent 3d492f9ae3
commit bd5f5357a8
No known key found for this signature in database
GPG Key ID: 80E0357347554B89
4 changed files with 161 additions and 76 deletions

14
repo.sh
View File

@ -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`

View File

@ -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<bool> = 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<String>,
}
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<Self, String> {
//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<Vec<Self>, 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!(

View File

@ -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::<Vec<String>>();
let recipes = CookRecipe::new_recursive(&names, DEP_DEPTH, true).expect("recipe not found");
for recipe in recipes {
println!("{}", recipe.name);
}
ExitCode::SUCCESS
}

View File

@ -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<Item = &String> {
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<String> {
self.dependencies_iter().cloned().collect::<Vec<_>>()
}
/// `[package.dependencies] + [package.shared_deps]`
#[inline]
pub fn runtime_dependencies(&self) -> Vec<String> {
self.package
.dependencies
.iter()
.chain(self.package.shared_deps.iter())
.cloned()
.collect::<Vec<_>>()
}
}
pub struct CookRecipe {
pub name: String,
pub dir: PathBuf,
pub recipe: Recipe,
}
impl CookRecipe {
pub fn new(name: String) -> Result<Self, String> {
//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<Vec<Self>, 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)]