diff --git a/Cargo.lock b/Cargo.lock index 00792606..d52cb2bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", diff --git a/Cargo.toml b/Cargo.toml index c5aa5b09..9376f661 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/src/bin/cook.rs b/src/bin/cook.rs index 23ad0cdd..c8fc1ddd 100644 --- a/src/bin/cook.rs +++ b/src/bin/cook.rs @@ -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 { +fn auto_deps( + stage_dir: &Path, + dep_pkgars: &BTreeSet<(PackageName, PathBuf)>, +) -> BTreeSet { 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> { +) -> Result<(PathBuf, BTreeSet), 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, + auto_deps: &BTreeSet, ) -> Result { //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!( diff --git a/src/bin/find_recipe.rs b/src/bin/find_recipe.rs index 92b8ec05..8765b4eb 100644 --- a/src/bin/find_recipe.rs +++ b/src/bin/find_recipe.rs @@ -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); } } } diff --git a/src/bin/list_recipes.rs b/src/bin/list_recipes.rs index 81f88e47..59a30df1 100644 --- a/src/bin/list_recipes.rs +++ b/src/bin/list_recipes.rs @@ -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); diff --git a/src/bin/pkg_deps.rs b/src/bin/pkg_deps.rs index 657b3039..757a0ffe 100644 --- a/src/bin/pkg_deps.rs +++ b/src/bin/pkg_deps.rs @@ -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::>(); - 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); diff --git a/src/lib.rs b/src/lib.rs index 78e3b9a1..2892e8c9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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; diff --git a/src/package.rs b/src/package.rs deleted file mode 100644 index c86a610f..00000000 --- a/src/package.rs +++ /dev/null @@ -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, -} - -impl StageToml { - pub fn new(name: String) -> Result { - //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, 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) - } -} diff --git a/src/recipe.rs b/src/recipe.rs index 456f6097..5d66b224 100644 --- a/src/recipe.rs +++ b/src/recipe.rs @@ -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, + pub dependencies: Vec, } #[derive(Debug, Default, Deserialize, PartialEq, Serialize)] pub struct PackageRecipe { #[serde(default)] - pub dependencies: Vec, + pub dependencies: Vec, } /// 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, /// 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 { - //TODO: sanitize recipe name? - let dir = recipe_find(&name); + pub fn new(name: &str) -> Result { + 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, String> { + pub fn new_recursive(names: &[PackageName], recursion: usize) -> Result, 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, String> { + pub fn get_package_deps_recursive( + names: &[PackageName], + recursion: usize, + ) -> Result, 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 = 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()); } } diff --git a/src/recipe_find.rs b/src/recipe_find.rs deleted file mode 100644 index b0cedcbd..00000000 --- a/src/recipe_find.rs +++ /dev/null @@ -1,38 +0,0 @@ -use std::collections::HashMap; -use std::ffi::OsStr; -use std::path::PathBuf; -use std::sync::LazyLock; - -static RECIPE_PATHS: LazyLock> = 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 { - RECIPE_PATHS.get(recipe).cloned() -} - -pub fn list_recipes(prefix: PathBuf) -> Vec { - let mut recipes = Vec::::new(); - for (_name, path) in RECIPE_PATHS.iter() { - recipes.push(prefix.join(path)); - } - recipes.sort(); - recipes -}