feat(sprout): generator variants (#105)

Generators can now declare variant axes. Every generated entry is
multiplied by each combination of choices, one per axis. A choice sets
the axis name to the choice name and inserts its own values, and the
entry name is suffixed with the choice names.

Generators can also declare exclude rules, which remove generated
entries whose values match every glob pattern in a rule. This covers
unwanted variant combinations and entries like BLS rescue kernels.

Entry matching for default-entry and the bootloader interface now
accepts `*` anywhere in the pattern instead of only at the end, so
generated entry names can be matched regardless of the kernel version
in the middle of the name.

The BLS generator gains a pin-names option (default true, the existing
behavior). Two BLS generators reading the same directory previously
produced entries with identical names; disabling pin-names prefixes
them with the generator name instead. Sprout now warns when more than
one entry has the same name.

* docs(config): note that variants suffix pinned BLS entry names

Pinned BLS entry names match the BLS entry ids, but variants still
append their choice names, so those entries need a pattern like
<id>-* to be selected.
This commit is contained in:
alex authored and GitHub committed 2026-10-03 15:16:05 -07:00
1 parent 1cd9f67c48
commit 96b6c6f86a
9 files changed
+419 -26

No files matched your search

+18 -10
View File
@@ -9,7 +9,12 @@ use crate::{
options::SproutOptions,
phases::phase,
};
use alloc::{collections::BTreeMap, format, string::ToString, vec::Vec};
use alloc::{
collections::{BTreeMap, BTreeSet},
format,
string::ToString,
vec::Vec,
};
use anyhow::{Context, Result, bail};
use core::{ops::Deref, time::Duration};
use edera_sprout_bls::compare_versions;
@@ -245,18 +250,21 @@ fn run() -> Result<()> {
for (name, generator) in config.generators {
let context = context.fork().freeze();
// We will prefix all entries with [name]-, provided the name is not pinned.
let prefix = format!("{}-", name);
// Add all the entries generated by the generator to the entry list.
// The generator specifies the context associated with the entry.
for mut entry in generators::generate(context.clone(), &generator)? {
// If the entry name is not pinned, prepend the name prefix.
if !entry.is_pin_name() {
entry.prepend_name_prefix(&prefix);
}
entries.extend(generators::generate(&name, context, &generator)?);
}
entries.push(entry);
// Entry names are used to select entries, so duplicates make the selection ambiguous.
// This can happen when two generators pin names, like two BLS generators reading the
// same BLS directory.
let mut seen_names = BTreeSet::new();
for entry in &entries {
if !seen_names.insert(entry.name()) {
warn!(
"more than one entry is named {}, selecting it by name is ambiguous",
entry.name()
);
}
}