recipe: basic recipe parsing
This commit is contained in:
@@ -13,8 +13,8 @@ source = tarball(
|
||||
def configure(ctx):
|
||||
ctx.run(
|
||||
ctx.source_dir / "configure",
|
||||
"--prefix=" + cfg.prefix,
|
||||
"--target=" + cfg.target_triple,
|
||||
"--prefix=" + options.prefix,
|
||||
"--target=" + options.target_triple,
|
||||
"--with-sysroot=" + ctx.sysroot_dir,
|
||||
"--with-pic",
|
||||
"--enable-cet",
|
||||
@@ -31,9 +31,9 @@ def configure(ctx):
|
||||
# gprofng's libcollector relies on glibc-specific internals.
|
||||
"--disable-gprofng",
|
||||
env = {
|
||||
"CFLAGS": cfg.host_cflags,
|
||||
"CXXFLAGS": cfg.host_cxxflags,
|
||||
"LDFLAGS": cfg.host_ldflags,
|
||||
"CFLAGS": options.host_cflags,
|
||||
"CXXFLAGS": options.host_cxxflags,
|
||||
"LDFLAGS": options.host_ldflags,
|
||||
})
|
||||
|
||||
_, build, install = autotools()
|
||||
|
||||
@@ -12,7 +12,7 @@ source = tarball(
|
||||
|
||||
def build(ctx):
|
||||
ctx.run("cp", "-rp", ctx.source_dir / ".", ctx.build_dir)
|
||||
ctx.run("make", "headers_install", "ARCH=" + cfg.target_arch)
|
||||
ctx.run("make", "headers_install", "ARCH=" + options.target_arch)
|
||||
ctx.run("find", ctx.build_dir / "usr" / "include", "-type", "f", "!", "-name", "*.h", "-delete")
|
||||
|
||||
def install(ctx):
|
||||
|
||||
+4
-2
@@ -81,14 +81,16 @@ pub fn run() -> anyhow::Result<()> {
|
||||
};
|
||||
|
||||
let mut container_manager = ContainerManager::new(container_runtime);
|
||||
let mut recipes = RecipeSet::default();
|
||||
let mut recipes = RecipeSet::new(&config);
|
||||
|
||||
recipes.load_recipes(
|
||||
&root_path.join(config.recipes_dir()),
|
||||
&root_path.join(config.host_recipes_dir()),
|
||||
)?;
|
||||
|
||||
println!("{:?}", recipes);
|
||||
for (name, recipe) in recipes.packages.iter() {
|
||||
println!("{name}: {:#?}", recipe);
|
||||
}
|
||||
|
||||
match cli.command {
|
||||
Command::Fetch(_) => {}
|
||||
|
||||
+4
-1
@@ -8,11 +8,14 @@ use starlark::{
|
||||
use std::path::Path as StdPath;
|
||||
|
||||
mod config;
|
||||
mod recipe;
|
||||
mod types;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
pub use config::*;
|
||||
#[allow(unused_imports)]
|
||||
pub use recipe::*;
|
||||
#[allow(unused_imports)]
|
||||
pub use types::*;
|
||||
|
||||
pub fn eval_files(
|
||||
@@ -29,7 +32,7 @@ pub fn eval_files(
|
||||
}
|
||||
|
||||
if let Some(config) = config {
|
||||
module.set("cfg", module.heap().alloc(config.clone()));
|
||||
module.set("options", module.heap().alloc(config.clone()));
|
||||
}
|
||||
|
||||
let mut paths = path.to_vec();
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
use allocative::Allocative;
|
||||
use starlark::{
|
||||
environment::GlobalsBuilder, starlark_module, starlark_simple_value, values::StarlarkValue,
|
||||
};
|
||||
use starlark_derive::{NoSerialize, ProvidesStaticType, starlark_value};
|
||||
|
||||
use crate::recipe::Source;
|
||||
|
||||
#[derive(Debug, Clone, Allocative, NoSerialize, ProvidesStaticType)]
|
||||
pub struct TarballSource {
|
||||
url: String,
|
||||
sha256: String,
|
||||
strip_components: u32,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for TarballSource {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "tarball")
|
||||
}
|
||||
}
|
||||
|
||||
starlark_simple_value!(TarballSource);
|
||||
|
||||
#[starlark_value(type = "tarball")]
|
||||
impl<'v> StarlarkValue<'v> for TarballSource {}
|
||||
|
||||
impl Source for TarballSource {}
|
||||
|
||||
#[derive(Debug, Clone, Allocative, NoSerialize, ProvidesStaticType)]
|
||||
pub struct Metadata {
|
||||
maintainer: Option<String>,
|
||||
description: Option<String>,
|
||||
license: Option<String>,
|
||||
website: Option<String>,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Metadata {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "metadata")
|
||||
}
|
||||
}
|
||||
|
||||
starlark_simple_value!(Metadata);
|
||||
|
||||
#[starlark_value(type = "metadata")]
|
||||
impl<'v> StarlarkValue<'v> for Metadata {}
|
||||
|
||||
#[starlark_module]
|
||||
pub fn recipe_globals(b: &mut GlobalsBuilder) {
|
||||
fn tarball(
|
||||
#[starlark(require = named)] url: &str,
|
||||
#[starlark(require = named)] sha256: &str,
|
||||
#[starlark(require = named, default = 0)] strip_components: u32,
|
||||
) -> anyhow::Result<TarballSource> {
|
||||
Ok(TarballSource {
|
||||
url: url.to_string(),
|
||||
sha256: sha256.to_string(),
|
||||
strip_components,
|
||||
})
|
||||
}
|
||||
|
||||
fn meta(
|
||||
#[starlark(require = named)] maintainer: Option<&str>,
|
||||
#[starlark(require = named)] description: Option<&str>,
|
||||
#[starlark(require = named)] license: Option<&str>,
|
||||
#[starlark(require = named)] website: Option<&str>,
|
||||
) -> anyhow::Result<Metadata> {
|
||||
Ok(Metadata {
|
||||
maintainer: maintainer.map(|x| x.to_string()),
|
||||
description: description.map(|x| x.to_string()),
|
||||
license: license.map(|x| x.to_string()),
|
||||
website: website.map(|x| x.to_string()),
|
||||
})
|
||||
}
|
||||
}
|
||||
+52
-47
@@ -23,23 +23,23 @@ pub enum PlanError {
|
||||
CycleDetected,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum PlanKey<'a> {
|
||||
SourceFetch(&'a SourceRecipe),
|
||||
SourcePatch(&'a SourceRecipe),
|
||||
SourcePrepare(&'a SourceRecipe),
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum PlanKey {
|
||||
SourceFetch(String),
|
||||
SourcePatch(String),
|
||||
SourcePrepare(String),
|
||||
|
||||
ToolConfigure(&'a ToolRecipe),
|
||||
ToolBuild(&'a ToolRecipe),
|
||||
ToolInstall(&'a ToolRecipe),
|
||||
ToolConfigure(String),
|
||||
ToolBuild(String),
|
||||
ToolInstall(String),
|
||||
|
||||
PkgConfigure(&'a PackageRecipe),
|
||||
PkgBuild(&'a PackageRecipe),
|
||||
PkgInstall(&'a PackageRecipe),
|
||||
PkgPackage(&'a PackageRecipe),
|
||||
PkgConfigure(String),
|
||||
PkgBuild(String),
|
||||
PkgInstall(String),
|
||||
PkgPackage(String),
|
||||
}
|
||||
|
||||
impl<'a> PlanKey<'a> {
|
||||
impl PlanKey {
|
||||
fn weight(&self) -> i8 {
|
||||
match self {
|
||||
PlanKey::SourceFetch(_) => 0,
|
||||
@@ -55,67 +55,72 @@ impl<'a> PlanKey<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn dependencies(
|
||||
&self,
|
||||
recipes: &'a RecipeSet,
|
||||
) -> Result<SmallVec<[PlanKey<'a>; 8]>, PlanError> {
|
||||
fn dependencies(&self, recipes: &RecipeSet) -> Result<SmallVec<[PlanKey; 8]>, PlanError> {
|
||||
match self {
|
||||
PlanKey::SourceFetch(_) => Ok(smallvec![]),
|
||||
PlanKey::SourcePatch(recipe) => Ok(smallvec![PlanKey::SourceFetch(recipe)]),
|
||||
PlanKey::SourcePrepare(recipe) => Ok(smallvec![PlanKey::SourcePatch(recipe)]),
|
||||
PlanKey::SourcePatch(recipe) => Ok(smallvec![PlanKey::SourceFetch(recipe.clone())]),
|
||||
PlanKey::SourcePrepare(recipe) => Ok(smallvec![PlanKey::SourcePatch(recipe.clone())]),
|
||||
PlanKey::ToolConfigure(recipe) => {
|
||||
let recipe = recipes
|
||||
.tool(recipe)
|
||||
.ok_or(PlanError::MissingTool(recipe.clone()))?;
|
||||
|
||||
let source_deps = recipe.sources.iter().map(|name| {
|
||||
recipes
|
||||
.source(name)
|
||||
.map(PlanKey::SourcePrepare)
|
||||
.ok_or(PlanError::MissingSource(name.clone()))
|
||||
.map(|_| PlanKey::SourcePrepare(name.to_string()))
|
||||
.ok_or(PlanError::MissingSource(name.to_string()))
|
||||
});
|
||||
|
||||
let tool_deps = recipe.tools_wanted.iter().map(|name| {
|
||||
recipes
|
||||
.tool(name)
|
||||
.map(PlanKey::ToolInstall)
|
||||
.ok_or(PlanError::MissingTool(name.clone()))
|
||||
.map(|_| PlanKey::ToolInstall(name.to_string()))
|
||||
.ok_or(PlanError::MissingTool(name.to_string()))
|
||||
});
|
||||
|
||||
let pkg_deps = recipe.pkgs_wanted.iter().map(|name| {
|
||||
recipes
|
||||
.package(name)
|
||||
.map(PlanKey::PkgPackage)
|
||||
.ok_or(PlanError::MissingPackage(name.clone()))
|
||||
.map(|_| PlanKey::PkgPackage(name.to_string()))
|
||||
.ok_or(PlanError::MissingPackage(name.to_string()))
|
||||
});
|
||||
|
||||
source_deps.chain(tool_deps).chain(pkg_deps).collect()
|
||||
}
|
||||
PlanKey::ToolBuild(recipe) => Ok(smallvec![PlanKey::ToolConfigure(recipe)]),
|
||||
PlanKey::ToolInstall(recipe) => Ok(smallvec![PlanKey::ToolBuild(recipe)]),
|
||||
PlanKey::ToolBuild(recipe) => Ok(smallvec![PlanKey::ToolConfigure(recipe.clone())]),
|
||||
PlanKey::ToolInstall(recipe) => Ok(smallvec![PlanKey::ToolBuild(recipe.clone())]),
|
||||
PlanKey::PkgConfigure(recipe) => {
|
||||
let recipe = recipes
|
||||
.package(recipe)
|
||||
.ok_or(PlanError::MissingPackage(recipe.clone()))?;
|
||||
|
||||
let source_deps = recipe.sources.iter().map(|name| {
|
||||
recipes
|
||||
.source(name)
|
||||
.map(PlanKey::SourcePrepare)
|
||||
.ok_or(PlanError::MissingSource(name.clone()))
|
||||
.map(|_| PlanKey::SourcePrepare(name.to_string()))
|
||||
.ok_or(PlanError::MissingSource(name.to_string()))
|
||||
});
|
||||
|
||||
let tool_deps = recipe.tools_wanted.iter().map(|name| {
|
||||
recipes
|
||||
.tool(name)
|
||||
.map(PlanKey::ToolInstall)
|
||||
.ok_or(PlanError::MissingTool(name.clone()))
|
||||
.map(|_| PlanKey::ToolInstall(name.to_string()))
|
||||
.ok_or(PlanError::MissingTool(name.to_string()))
|
||||
});
|
||||
|
||||
let pkg_deps = recipe.pkgs_wanted.iter().map(|name| {
|
||||
recipes
|
||||
.package(name)
|
||||
.map(PlanKey::PkgPackage)
|
||||
.ok_or(PlanError::MissingPackage(name.clone()))
|
||||
.map(|_| PlanKey::PkgPackage(name.to_string()))
|
||||
.ok_or(PlanError::MissingPackage(name.to_string()))
|
||||
});
|
||||
|
||||
source_deps.chain(tool_deps).chain(pkg_deps).collect()
|
||||
}
|
||||
PlanKey::PkgBuild(recipe) => Ok(smallvec![PlanKey::PkgConfigure(recipe)]),
|
||||
PlanKey::PkgInstall(recipe) => Ok(smallvec![PlanKey::PkgBuild(recipe)]),
|
||||
PlanKey::PkgPackage(recipe) => Ok(smallvec![PlanKey::PkgInstall(recipe)]),
|
||||
PlanKey::PkgBuild(recipe) => Ok(smallvec![PlanKey::PkgConfigure(recipe.clone())]),
|
||||
PlanKey::PkgInstall(recipe) => Ok(smallvec![PlanKey::PkgBuild(recipe.clone())]),
|
||||
PlanKey::PkgPackage(recipe) => Ok(smallvec![PlanKey::PkgInstall(recipe.clone())]),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,8 +130,8 @@ impl<'a> PlanKey<'a> {
|
||||
}
|
||||
|
||||
pub struct Plan<'a> {
|
||||
recipes: &'a RecipeSet,
|
||||
wanted: HashSet<PlanKey<'a>>,
|
||||
recipes: &'a RecipeSet<'a>,
|
||||
wanted: HashSet<PlanKey>,
|
||||
}
|
||||
|
||||
impl<'a> Plan<'a> {
|
||||
@@ -137,12 +142,12 @@ impl<'a> Plan<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_wanted(&mut self, key: PlanKey<'a>) {
|
||||
pub fn add_wanted(&mut self, key: PlanKey) {
|
||||
self.wanted.insert(key);
|
||||
}
|
||||
|
||||
pub fn steps(&self) -> Result<Vec<PlanKey<'a>>, PlanError> {
|
||||
let mut stack: Vec<_> = self.wanted.iter().copied().collect();
|
||||
pub fn steps(&self) -> Result<Vec<PlanKey>, PlanError> {
|
||||
let mut stack: Vec<_> = self.wanted.iter().cloned().collect();
|
||||
let mut graph: DiGraph<_, ()> = DiGraph::new();
|
||||
let mut nodes = HashMap::new();
|
||||
|
||||
@@ -150,18 +155,18 @@ impl<'a> Plan<'a> {
|
||||
let node_idx = match nodes.get(&node) {
|
||||
Some(&idx) => idx,
|
||||
None => {
|
||||
let idx = graph.add_node(node);
|
||||
nodes.insert(node, idx);
|
||||
let idx = graph.add_node(node.clone());
|
||||
nodes.insert(node.clone(), idx);
|
||||
idx
|
||||
}
|
||||
};
|
||||
|
||||
for dep in node.dependencies(self.recipes)?.iter().copied() {
|
||||
for dep in node.dependencies(self.recipes)? {
|
||||
let dep_idx = match nodes.get(&dep) {
|
||||
Some(&idx) => idx,
|
||||
None => {
|
||||
let idx = graph.add_node(dep);
|
||||
nodes.insert(dep, idx);
|
||||
let idx = graph.add_node(dep.clone());
|
||||
nodes.insert(dep.clone(), idx);
|
||||
stack.push(dep);
|
||||
idx
|
||||
}
|
||||
@@ -195,7 +200,7 @@ impl<'a> Plan<'a> {
|
||||
let mut result = Vec::with_capacity(graph.node_count());
|
||||
|
||||
while let Some((_, idx)) = heap.pop() {
|
||||
result.push(graph[idx]);
|
||||
result.push(graph[idx].clone());
|
||||
|
||||
for neighbor in graph.neighbors_directed(idx, Direction::Outgoing) {
|
||||
let d = in_degree.get_mut(&neighbor).unwrap();
|
||||
|
||||
+97
-26
@@ -1,15 +1,22 @@
|
||||
use anyhow::Context;
|
||||
use starlark::{
|
||||
environment::{GlobalsBuilder, Module},
|
||||
values::UnpackValue,
|
||||
};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
use crate::eval::{Config, Metadata, TarballSource, eval_files, recipe_globals, types_globals};
|
||||
|
||||
pub struct SourceRecipe {
|
||||
pub name: String,
|
||||
pub source: Box<dyn Source>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
pub trait Source {}
|
||||
|
||||
pub struct ToolRecipe {
|
||||
pub name: String,
|
||||
pub sources: Vec<String>,
|
||||
@@ -17,40 +24,25 @@ pub struct ToolRecipe {
|
||||
pub pkgs_wanted: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug)]
|
||||
pub struct PackageRecipe {
|
||||
pub name: String,
|
||||
pub meta: Option<Metadata>,
|
||||
pub version: String,
|
||||
pub revision: u32,
|
||||
pub sources: Vec<String>,
|
||||
pub tools_wanted: Vec<String>,
|
||||
pub pkgs_wanted: Vec<String>,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for SourceRecipe {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "source:{}", self.name)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for ToolRecipe {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "tool:{}", self.name)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for PackageRecipe {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "package:{}", self.name)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct RecipeSet {
|
||||
pub struct RecipeSet<'a> {
|
||||
sources: HashMap<String, SourceRecipe>,
|
||||
tools: HashMap<String, ToolRecipe>,
|
||||
packages: HashMap<String, PackageRecipe>,
|
||||
pub packages: HashMap<String, PackageRecipe>,
|
||||
config: &'a Config,
|
||||
}
|
||||
|
||||
impl RecipeSet {
|
||||
impl<'a> RecipeSet<'a> {
|
||||
fn add_source(&mut self, name: &str, recipe: SourceRecipe) -> anyhow::Result<()> {
|
||||
if self.sources.insert(name.to_string(), recipe).is_some() {
|
||||
anyhow::bail!("source '{name}' already exists");
|
||||
@@ -77,7 +69,54 @@ impl RecipeSet {
|
||||
}
|
||||
|
||||
fn load_package_recipe(&mut self, name: &str, path: &Path) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
let module = eval_files(
|
||||
&[path],
|
||||
&GlobalsBuilder::standard()
|
||||
.with(types_globals)
|
||||
.with(recipe_globals)
|
||||
.build(),
|
||||
None,
|
||||
Some(self.config),
|
||||
None,
|
||||
)?;
|
||||
|
||||
let version: String = get_value_required(&module, "version")?;
|
||||
|
||||
let revision = get_value_option(&module, "revision")?.unwrap_or(1);
|
||||
|
||||
let metadata: Option<&Metadata> = get_value_option(&module, "metadata")?;
|
||||
|
||||
let source: &TarballSource = get_value_required(&module, "source")?;
|
||||
|
||||
self.add_source(
|
||||
name,
|
||||
SourceRecipe {
|
||||
name: name.to_string(),
|
||||
source: Box::new(source.clone()),
|
||||
},
|
||||
)?;
|
||||
|
||||
self.add_package(
|
||||
name,
|
||||
PackageRecipe {
|
||||
name: name.to_string(),
|
||||
meta: metadata.cloned(),
|
||||
version: version.to_string(),
|
||||
revision: revision as u32,
|
||||
sources: vec![name.to_string()],
|
||||
tools_wanted: vec![],
|
||||
pkgs_wanted: vec![],
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn new(config: &'a Config) -> Self {
|
||||
Self {
|
||||
sources: HashMap::new(),
|
||||
tools: HashMap::new(),
|
||||
packages: HashMap::new(),
|
||||
config,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_recipes(
|
||||
@@ -143,3 +182,35 @@ fn get_recipe_name_and_patch(
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn get_value_option<'v, T: UnpackValue<'v>>(
|
||||
module: &'v Module,
|
||||
name: &str,
|
||||
) -> anyhow::Result<Option<T>> {
|
||||
module
|
||||
.get(name)
|
||||
.map(|value| {
|
||||
T::unpack_value(value).unwrap().ok_or_else(|| {
|
||||
anyhow::anyhow!(
|
||||
"`{name}` should be of type `{}` but got `{}`",
|
||||
T::starlark_type_repr(),
|
||||
value.get_type()
|
||||
)
|
||||
})
|
||||
})
|
||||
.transpose()
|
||||
}
|
||||
|
||||
fn get_value_required<'v, T: UnpackValue<'v>>(module: &'v Module, name: &str) -> anyhow::Result<T> {
|
||||
let value = module
|
||||
.get(name)
|
||||
.ok_or_else(|| anyhow::anyhow!("`{name}` is required"))?;
|
||||
|
||||
T::unpack_value(value).unwrap().ok_or_else(|| {
|
||||
anyhow::anyhow!(
|
||||
"`{name}` should be of type `{}` but got `{}`",
|
||||
T::starlark_type_repr(),
|
||||
value.get_type()
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user