Crate eb_stack

crate eb_stack

EasyBuild stack lock: parse .eb files, resolvo SAT co-select, planned SBOM.

Modules

Re-exports

Functions

fn detect_foreign_format(path: &Path) -> Option<ForeignFormat>

Detect format from path basename / extension.

fn filter_baseline_candidates(base_cands: &[Candidate], policy_toolchain: &Toolchain, explicit_baseline_version: Option<&str>) -> Result<Vec<Candidate>>

Filter baseline candidates to one generation of the policy toolchain family.

When the tree only contains the policy target version (single generation), candidates are left unchanged. When other versions of the same toolchain name exist, applies select_baseline_generation (optional explicit override, else nearest lower).

fn load_json_file<T: serde::de::DeserializeOwned>(path: &Path) -> Result<T>

Read and deserialize a JSON file, naming the path in either failure.

fn package_plan_from_foreign(recipe: &ForeignRecipe, toolchain: &Toolchain) -> PackagePlan

Lower a parsed foreign recipe into the canonical package plan for a toolchain.

fn parse_foreign_path(path: &Path, format: Option<ForeignFormat>) -> Result<ForeignRecipe, ForeignError>

Parse from path; format auto-detected unless format is Some.

fn parse_foreign_str(format: ForeignFormat, text: &str) -> Result<ForeignRecipe, ForeignError>

Parse foreign recipe text for the given format.

fn select_baseline_generation(versions: impl IntoIterator<Item = impl AsRef<str>>, target_version: &str, explicit: Option<&str>) -> std::result::Result<String, BaselineGenError>

Choose the baseline toolchain version for a same-family multi-generation tree.

If explicit is set, that version must appear in versions and is used as-is. Otherwise select the nearest lower generation than target_version under cmp_version ordering (greatest version strictly less than the target).

This replaces an earlier first-non-target in BTreeSet sort order pick, which is wrong when more than one non-target generation is present (for example 2024b before 2025a when the target is 2025b).

fn solve_from_easyconfigs(easyconfigs_roots: &[&Path], policy_path: &Path, baseline_easyconfigs: Option<&Path>, lock_out: &Path, sbom_out: Option<&Path>) -> Result<StackLock>

Parse easyconfigs dir(s), filter to policy toolchain, solve with resolvo, write lock (and optional CycloneDX SBOM when sbom_out is Some).

easyconfigs_roots may list multiple trees; later paths override earlier ones for the same name+version+toolchain (site overlay on upstream).

When baseline_easyconfigs is set and that tree holds multiple generations of the policy toolchain family, the baseline generation is chosen by select_baseline_generation: optional baseline_toolchain_version override, else the nearest lower generation than the policy target.

fn solve_from_easyconfigs_with_baseline_version(easyconfigs_roots: &[&Path], policy_path: &Path, baseline_easyconfigs: Option<&Path>, baseline_toolchain_version: Option<&str>, lock_out: &Path, sbom_out: Option<&Path>) -> Result<StackLock>

Like solve_from_easyconfigs, with an optional explicit baseline toolchain version.

fn solve_from_easyconfigs_with_baseline_version_and_extras(easyconfigs_roots: &[&Path], policy_path: &Path, baseline_easyconfigs: Option<&Path>, baseline_toolchain_version: Option<&str>, lock_out: &Path, sbom_out: Option<&Path>, extra: SolveExtraOut<'_>) -> Result<StackLock>

Full form: explicit baseline toolchain generation selection (see select_baseline_generation) plus optional operator artifacts (build list / stack diff, see SolveExtraOut). SBOM is written only when sbom_out is Some.

Multiple easyconfigs_roots are merged with later-path overlay precedence.

fn solve_from_easyconfigs_with_extras(easyconfigs_roots: &[&Path], policy_path: &Path, baseline_easyconfigs: Option<&Path>, lock_out: &Path, sbom_out: Option<&Path>, extra: SolveExtraOut<'_>) -> Result<StackLock>

Like solve_from_easyconfigs, optionally writing build-list and stack-diff files.

fn write_json_pretty(path: &Path, value: &impl serde::Serialize) -> Result<()>

Write pretty-printed JSON, creating the parent directory first.

fn write_text(path: &Path, text: &str) -> Result<()>

Write text to a path, creating the parent directory first.

Enums

enum BaselineGenError

Errors when choosing which toolchain generation is the baseline.

ExplicitNotFound(String)

--baseline-toolchain-version (or equivalent) is not present in the tree.

NoLowerGeneration

Default rule needs a generation strictly lower than the policy target.

target: String

Generation that was asked for.

found: Vec<String>

Generations present in the tree instead.

enum ForeignError

Why a foreign recipe could not be read.

Parse(String)

The recipe could not be parsed.

Unsupported(String)

The recipe uses a construct this extractor does not handle.

Io(String)

The recipe file could not be read.

enum ForeignFormat

Origin of a foreign recipe.

CondaForge

A conda-forge recipe: meta.yaml or recipe.yaml.

Spack

A Spack package.py.

Pypi

Offline PyPI metadata or a requirements.txt.

Cran

A CRAN DESCRIPTION file or package list.

Cargo

A Cargo.toml or crates.io JSON document.

Luarocks

A LuaRocks *.rockspec.

Raku

A Raku META6.json.

Implementations

impl ForeignFormat

Functions

fn as_str(self) -> &'static str

The stable kebab-case name used in output.

enum ForeignRuleKind

Whether a rule forbids a combination or demands one.

Conflict

The combination must not occur.

Requirement

The combination is required.

Structs and Unions

struct ForeignDep

One dependency name (and optional pin) drawn from a foreign recipe.

name: String

Dependency name as the foreign recipe spells it.

pin: Option<String>

Pin / constraint as written in the foreign recipe when present.

role: String

Role: build, host, run, or Spack type string when known.

original_spec: Option<String>

Complete upstream dependency spec before EasyBuild name mapping.

condition: ConditionExpr

Selector / when= expression represented structurally.

provenance: Vec<Provenance>

Where this dependency was read from.

struct ForeignPatch

A patch directive preserved from a foreign recipe.

location: String

Local path or exact remote URL as declared by the source recipe.

sha256: Option<String>

Hash of the patch bytes, when the recipe gives one.

condition: ConditionExpr

When the patch applies.

provenance: Vec<Provenance>

Where the patch was declared.

struct ForeignRecipe

Syntax-normalized fields shared by all foreign recipe formats.

format: ForeignFormat

Which ecosystem this came from.

name: String

Package name as the recipe declares it.

version: String

Version the recipe declares.

homepage: Option<String>

Project homepage.

source_url: Option<String>

Preferred / primary source (first expanded URL or preferred Spack version).

source_filename: Option<String>

Filename of the primary source.

sha256: Option<String>

Hash of the primary source.

sources: Vec<ForeignSource>

All sources when the foreign recipe lists multiple (conda multi-source, etc.).

summary: Option<String>

One-line summary.

description: Option<String>

Longer description when available (conda about.description, Spack docstring).

license: Option<String>

License string as the recipe declares it.

dependencies: Vec<ForeignDep>

Dependencies as declared, before any mapping to EasyBuild names.

build_system_hints: Vec<String>

Build-system / base-class hints (e.g. Spack MesonPackage, CMakePackage).

configopts: Option<String>

Mechanically extracted configure flags (e.g. Spack meson_args / cmake_args literals).

patches: Vec<ForeignPatch>

Patch artifacts recorded from the foreign recipe for canonical planning and bundle materialization.

variants: Vec<ForeignVariant>

Spack variants (and residual conda features when recorded).

rules: Vec<ForeignRule>

Spack conflicts() and requires() directives.

notes: Vec<String>

Human notes from the parser.

residuals: Vec<ForeignResidual>

Typed work that remains after syntax normalization.

classifiers: Vec<String>

What the upstream ecosystem says the package is for: PyPI Trove classifiers today. This is what a moduleclass is derived from.

struct ForeignResidual

Parser work that cannot be represented mechanically in the canonical plan.

category: String

Short machine-readable category.

severity: ResidualSeverity

How much attention it needs.

summary: String

One line a reviewer can triage from.

evidence: Option<String>

The source text that was not understood.

provenance: Option<Provenance>

Where in the recipe it arose.

struct ForeignRule

A constraint the foreign recipe states beyond its dependencies.

kind: ForeignRuleKind

Whether this forbids or requires.

spec: String

The combination, in the recipe’s own spelling.

when: Option<String>

Original when= text, kept beside the lowered condition.

condition: ConditionExpr

When the rule applies, lowered from the selector.

message: Option<String>

Message the recipe attaches to it.

provenance: Provenance

Where the rule was read from.

struct ForeignSource

One source artifact (URL/git + optional checksum).

url: Option<String>

Download URL, for a fetched artifact.

filename: Option<String>

Local filename, when the recipe names one.

sha256: Option<String>

Hash of the downloaded bytes. Valid only for the artifact this URL serves; a hash from a different artifact class describes other bytes.

git: Option<String>

Remote to clone, for a checkout rather than a download.

tag: Option<String>

Tag to check out.

commit: Option<String>

Commit to check out.

target_directory: Option<String>

Conda target_directory or Spack resource destination folder.

condition: ConditionExpr

Selector / when= expression controlling profile inclusion.

struct ForeignVariant

Variant / feature flag from Spack variant() or residual conda feature.

name: String

Variant name.

default: Option<String>

Default value, when the recipe states one.

description: Option<String>

What the variant does.

condition: ConditionExpr

When the variant is available.

provenance: Vec<Provenance>

Where it was declared.

struct SolveExtraOut<'a>

Optional operator artifacts written after a successful solve.

build_list_out: Option<&'a Path>

Where to write the ordered build list, when one is wanted.

stack_diff_out: Option<&'a Path>

Where to write the stack diff against the baseline, when one is wanted.