recipe: basic recipe parsing

This commit is contained in:
2026-05-22 20:54:44 +02:00
parent a525868969
commit 1a7c817fb9
7 changed files with 238 additions and 82 deletions
+52 -47
View File
@@ -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();