Merge branch 'reuse-pkgutils-package-struct' into 'master'

Move struct Package to redox-pkg

See merge request redox-os/cookbook!521
This commit is contained in:
Jeremy Soller 2025-07-05 09:19:36 -06:00
commit 006ac4b73a
10 changed files with 98 additions and 174 deletions

19
Cargo.lock generated
View File

@ -1830,6 +1830,22 @@ dependencies = [
"toml 0.8.19",
]
[[package]]
name = "redox-pkg"
version = "0.2.5"
dependencies = [
"anyhow",
"ignore",
"pkgar 0.1.15",
"pkgar-core 0.1.15",
"pkgar-keys 0.1.15",
"reqwest",
"serde",
"serde_derive",
"thiserror 1.0.69",
"toml 0.8.19",
]
[[package]]
name = "redox-scheme"
version = "0.2.4"
@ -1851,6 +1867,7 @@ dependencies = [
"pkgar 0.1.17",
"pkgar-core 0.1.17",
"pkgar-keys 0.1.17",
"redox-pkg 0.2.5",
"redoxer",
"serde",
"tempfile",
@ -1876,7 +1893,7 @@ dependencies = [
"pkgar-core 0.1.15",
"pkgar-keys 0.1.15",
"rand",
"redox-pkg",
"redox-pkg 0.2.4",
"redox_liner",
"redox_syscall",
"redoxfs",

View File

@ -27,6 +27,7 @@ pbr = "1.0.2"
pkgar = { path = "pkgar/pkgar" }
pkgar-core = { path = "pkgar/pkgar-core" }
pkgar-keys = { path = "pkgar/pkgar-keys" }
redox-pkg = { git = "https://gitlab.redox-os.org/redox-os/pkgutils" }
redoxer = "0.2"
serde = { version = "=1.0.197", features = ["derive"] }
termion = "4"

View File

@ -1,8 +1,9 @@
use cookbook::blake3::blake3_progress;
use cookbook::package::StageToml;
use cookbook::recipe::{BuildKind, CookRecipe, Recipe, SourceRecipe};
use cookbook::recipe_find::recipe_find;
use pkg::package::Package;
use pkg::{recipes, PackageName};
use std::collections::VecDeque;
use std::convert::TryInto;
use std::{
collections::BTreeSet,
env, fs,
@ -15,6 +16,8 @@ use std::{
use termion::{color, style};
use walkdir::{DirEntry, WalkDir};
use cookbook::WALK_DEPTH;
fn remove_all(path: &Path) -> Result<(), String> {
if path.is_dir() {
fs::remove_dir_all(path)
@ -504,7 +507,10 @@ fi"#,
Ok(source_dir)
}
fn auto_deps(stage_dir: &Path, dep_pkgars: &BTreeSet<(String, PathBuf)>) -> BTreeSet<String> {
fn auto_deps(
stage_dir: &Path,
dep_pkgars: &BTreeSet<(PackageName, PathBuf)>,
) -> BTreeSet<PackageName> {
let mut paths = BTreeSet::new();
let mut visited = BTreeSet::new();
// Base directories may need to be updated for packages that place binaries in odd locations.
@ -571,7 +577,12 @@ fn auto_deps(stage_dir: &Path, dep_pkgars: &BTreeSet<(String, PathBuf)>) -> BTre
if let Ok(relative_path) = path.strip_prefix(stage_dir) {
eprintln!("DEBUG: {} needs {}", relative_path.display(), name);
}
needed.insert(name.to_string());
if let Ok(name) = PackageName::new(name) {
needed.insert(name);
} else {
// AFAICT this shouldn't ever happen.
eprintln!("ERROR: `{name}` is an invalid package name; please report");
}
}
}
}
@ -623,18 +634,17 @@ fn build(
recipe_dir: &Path,
source_dir: &Path,
target_dir: &Path,
name: &str,
name: &PackageName,
recipe: &Recipe,
) -> Result<(PathBuf, BTreeSet<String>), String> {
) -> Result<(PathBuf, BTreeSet<PackageName>), String> {
let mut dep_pkgars = BTreeSet::new();
for dependency in recipe.build.dependencies.iter() {
//TODO: sanitize name
let dependency_dir = recipe_find(dependency);
let dependency_dir = recipes::find(dependency.as_str());
if dependency_dir.is_none() {
return Err(format!("failed to find recipe directory '{}'", dependency));
}
dep_pkgars.insert((
dependency.to_string(),
dependency.clone(),
dependency_dir
.unwrap()
.join("target")
@ -992,7 +1002,7 @@ done
command.arg("bash").arg("-ex");
command.current_dir(&cookbook_build);
command.env("COOKBOOK_BUILD", &cookbook_build);
command.env("COOKBOOK_NAME", name);
command.env("COOKBOOK_NAME", name.as_str());
command.env("COOKBOOK_RECIPE", &cookbook_recipe);
command.env("COOKBOOK_REDOXER", &cookbook_redoxer);
command.env("COOKBOOK_ROOT", &cookbook_root);
@ -1022,9 +1032,9 @@ fn package(
_recipe_dir: &Path,
stage_dir: &Path,
target_dir: &Path,
name: &str,
name: &PackageName,
recipe: &Recipe,
auto_deps: &BTreeSet<String>,
auto_deps: &BTreeSet<PackageName>,
) -> Result<PathBuf, String> {
//TODO: metadata like dependencies, name, and version
let package = &recipe.package;
@ -1072,8 +1082,8 @@ fn package(
depends.push(dep.clone());
}
}
let stage_toml = toml::to_string(&StageToml {
name: name.into(),
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))?,
@ -1087,7 +1097,12 @@ fn package(
Ok(package_file)
}
fn cook(recipe_dir: &Path, name: &str, recipe: &Recipe, fetch_only: bool) -> Result<(), String> {
fn cook(
recipe_dir: &Path,
name: &PackageName,
recipe: &Recipe,
fetch_only: bool,
) -> Result<(), String> {
let source_dir =
fetch(recipe_dir, &recipe.source).map_err(|err| format!("failed to fetch: {}", err))?;
@ -1104,7 +1119,7 @@ fn cook(recipe_dir: &Path, name: &str, recipe: &Recipe, fetch_only: bool) -> Res
create_dir(&target_dir)?;
}
let (stage_dir, auto_deps) = build(recipe_dir, &source_dir, &target_dir, name, &recipe)
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(
@ -1112,7 +1127,7 @@ fn cook(recipe_dir: &Path, name: &str, recipe: &Recipe, fetch_only: bool) -> Res
&stage_dir,
&target_dir,
name,
&recipe,
recipe,
&auto_deps,
)
.map_err(|err| format!("failed to package: {}", err))?;
@ -1134,12 +1149,12 @@ fn main() {
"--with-package-deps" if matching => with_package_deps = true,
"--fetch-only" if matching => fetch_only = true,
"-q" | "--quiet" if matching => quiet = true,
_ => recipe_names.push(arg),
_ => recipe_names.push(arg.try_into().expect("Invalid package name")),
}
}
if with_package_deps {
recipe_names = match CookRecipe::get_package_deps_recursive(&recipe_names, 16) {
recipe_names = match CookRecipe::get_package_deps_recursive(&recipe_names, WALK_DEPTH) {
Ok(ok) => ok,
Err(err) => {
eprintln!(
@ -1155,7 +1170,7 @@ fn main() {
};
}
let recipes = match CookRecipe::new_recursive(&recipe_names, 16) {
let recipes = match CookRecipe::new_recursive(&recipe_names, WALK_DEPTH) {
Ok(ok) => ok,
Err(err) => {
eprintln!(

View File

@ -1,7 +1,7 @@
use cookbook::recipe_find::recipe_find;
use std::env::args;
use std::process::exit;
// use clap::Parser;
use pkg::recipes;
fn usage() {
println!("Usage: find_recipe recipe_name");
@ -12,14 +12,14 @@ fn main() {
exit(2);
}
let recipe_name = &args().last().unwrap();
match recipe_find(recipe_name) {
match recipes::find(recipe_name) {
Some(path) => {
println!("{}", path.display());
exit(0);
},
}
None => {
eprintln!("recipe {} not found", recipe_name);
exit(1);
eprintln!("recipe {} not found", recipe_name);
exit(1);
}
}
}

View File

@ -1,13 +1,13 @@
use cookbook::recipe_find::list_recipes;
use std::process::exit;
// use clap::Parser;
use pkg::recipes;
fn main() {
let print_short = std::env::args()
.nth(1)
.map_or(false, |a| a == "-s" || a == "--short");
let result = list_recipes(Default::default());
let result = recipes::list("");
if result.is_empty() {
eprintln!("recipes not found");
exit(1);

View File

@ -1,12 +1,14 @@
use cookbook::package::StageToml;
use std::{env::args, process::ExitCode};
/// Same as `cookbook/src/bin/cook.rs`.
const DEP_DEPTH: usize = 16;
use pkg::package::Package;
use cookbook::WALK_DEPTH;
fn main() -> ExitCode {
let names = args().skip(1).collect::<Vec<String>>();
let packages = StageToml::new_recursive(&names, DEP_DEPTH).expect("package not found");
// TODO: Ugly vec
let names: Vec<&str> = names.iter().map(|s| s.as_str()).collect();
let packages = Package::new_recursive(&names, WALK_DEPTH).expect("package not found");
for package in packages {
println!("{}", package.name);

View File

@ -1,6 +1,7 @@
pub mod blake3;
pub mod package;
pub mod recipe;
pub mod recipe_find;
mod progress_bar;
/// Default for maximum number of levels to descend down dependencies tree.
pub const WALK_DEPTH: usize = 16;

View File

@ -1,77 +0,0 @@
use std::{env, fs};
use crate::recipe_find::recipe_find;
//TODO: share struct with pkgutils?
#[derive(PartialEq, serde::Deserialize, serde::Serialize)]
pub struct StageToml {
pub name: String,
pub version: String,
pub target: String,
pub depends: Vec<String>,
}
impl StageToml {
pub fn new(name: String) -> Result<Self, String> {
//TODO: sanitize recipe name?
let dir = recipe_find(&name);
if dir.is_none() {
return Err(format!("failed to find recipe directory '{}'", name));
}
let dir = dir.unwrap();
let target =
env::var("TARGET").map_err(|err| format!("failed to read TARGET: {:?}", err))?;
let file = dir.join("target").join(target).join("stage.toml");
if !file.is_file() {
return Err(format!("failed to find package file '{}'", file.display()));
}
let toml = fs::read_to_string(&file).map_err(|err| {
format!(
"failed to read package file '{}': {}\n{:#?}",
file.display(),
err,
err
)
})?;
toml::from_str(&toml).map_err(|err| {
format!(
"failed to parse package file '{}': {}\n{:#?}",
file.display(),
err,
err
)
})
}
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 packages = Vec::new();
for name in names {
let package = Self::new(name.clone())?;
let dependencies = Self::new_recursive(&package.depends, recursion - 1)
.map_err(|err| format!("{}: failed on loading dependencies:\n{}", name, err))?;
for dependency in dependencies {
if !packages.contains(&dependency) {
packages.push(dependency);
}
}
if !packages.contains(&package) {
packages.push(package);
}
}
Ok(packages)
}
}

View File

@ -1,12 +1,8 @@
use std::{
fs,
path::PathBuf,
};
use std::{convert::TryInto, fs, path::PathBuf};
use pkg::{recipes, PackageName};
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)]
@ -83,19 +79,19 @@ pub struct BuildRecipe {
#[serde(flatten)]
pub kind: BuildKind,
#[serde(default)]
pub dependencies: Vec<String>,
pub dependencies: Vec<PackageName>,
}
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
pub struct PackageRecipe {
#[serde(default)]
pub dependencies: Vec<String>,
pub dependencies: Vec<PackageName>,
}
/// Everything required to build a Redox package
#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub struct Recipe {
/// Specifies how to donload the source for this recipe
/// Specifies how to download the source for this recipe
pub source: Option<SourceRecipe>,
/// Specifies how to build this recipe
pub build: BuildRecipe,
@ -106,15 +102,17 @@ pub struct Recipe {
#[derive(Debug, PartialEq)]
pub struct CookRecipe {
pub name: String,
pub name: PackageName,
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);
pub fn new(name: &str) -> Result<Self, String> {
let name: PackageName = name
.try_into()
.map_err(|e| format!("Invalid package name: {e}"))?;
let dir = recipes::find(name.as_str());
if dir.is_none() {
return Err(format!("failed to find recipe directory '{}'", name));
}
@ -142,10 +140,11 @@ impl CookRecipe {
)
})?;
let dir = dir.to_path_buf();
Ok(Self { name, dir, recipe })
}
pub fn new_recursive(names: &[String], recursion: usize) -> Result<Vec<Self>, String> {
pub fn new_recursive(names: &[PackageName], recursion: usize) -> Result<Vec<Self>, String> {
if recursion == 0 {
return Err(format!(
"recursion limit while processing build dependencies: {:#?}",
@ -155,7 +154,7 @@ impl CookRecipe {
let mut recipes = Vec::new();
for name in names {
let recipe = Self::new(name.clone())?;
let recipe = Self::new(name.as_str())?;
let dependencies =
Self::new_recursive(&recipe.recipe.build.dependencies, recursion - 1).map_err(
@ -176,7 +175,10 @@ impl CookRecipe {
Ok(recipes)
}
pub fn get_package_deps_recursive(names: &[String], recursion: usize) -> Result<Vec<String>, String> {
pub fn get_package_deps_recursive(
names: &[PackageName],
recursion: usize,
) -> Result<Vec<PackageName>, String> {
if recursion == 0 {
return Err(format!(
"recursion limit while processing package dependencies: {:#?}",
@ -184,14 +186,15 @@ impl CookRecipe {
));
}
let mut recipes = Vec::new();
let mut recipes: Vec<PackageName> = Vec::new();
for name in names {
let recipe = Self::new(name.clone())?;
let recipe = Self::new(name.as_str())?;
let dependencies =
Self::get_package_deps_recursive(&recipe.recipe.package.dependencies, recursion - 1).map_err(
|err| format!("{}: failed on loading package dependencies:\n{}", name, err),
)?;
let dependencies = Self::get_package_deps_recursive(
&recipe.recipe.package.dependencies,
recursion - 1,
)
.map_err(|err| format!("{}: failed on loading package dependencies:\n{}", name, err))?;
for dependency in dependencies {
if !recipes.contains(&dependency) {
@ -199,7 +202,7 @@ impl CookRecipe {
}
}
if !recipes.contains(&name) {
if !recipes.contains(name) {
recipes.push(name.clone());
}
}

View File

@ -1,38 +0,0 @@
use std::collections::HashMap;
use std::ffi::OsStr;
use std::path::PathBuf;
use std::sync::LazyLock;
static RECIPE_PATHS: LazyLock<HashMap<String, PathBuf>> = LazyLock::new(|| {
let mut recipe_paths = HashMap::new();
for entry_res in ignore::Walk::new("recipes") {
let entry = entry_res.unwrap();
if entry.file_name() == OsStr::new("recipe.sh") || entry.file_name() == OsStr::new("recipe.toml") {
let recipe_file = entry.path();
let Some(recipe_dir) = recipe_file.parent() else { continue };
let Some(recipe_name) = recipe_dir.file_name().and_then(|x| x.to_str()) else { continue };
if let Some(other_dir) = recipe_paths.insert(recipe_name.to_string(), recipe_dir.to_path_buf()) {
panic!(
"recipe {} has two or more entries {:?}, {:?}",
recipe_name,
other_dir,
recipe_dir
);
}
}
}
recipe_paths
});
pub fn recipe_find(recipe: &str) -> Option<PathBuf> {
RECIPE_PATHS.get(recipe).cloned()
}
pub fn list_recipes(prefix: PathBuf) -> Vec<PathBuf> {
let mut recipes = Vec::<PathBuf>::new();
for (_name, path) in RECIPE_PATHS.iter() {
recipes.push(prefix.join(path));
}
recipes.sort();
recipes
}