mod patch_evolution

module patch_evolution

Decide how a patch set evolves across a version bump, from tree evidence.

A version bump commonly changes the patch set: fixes land upstream and their patches drop, and new releases need new patches. The strongest evidence available without building is a same-version sibling: a recipe for the new version that already exists in the robot tree under another toolchain. Its patch list is what a maintainer already shipped for this version, so the bump adopts it verbatim (the raw patches = [...] block, preserving tuple entries and comments) and reports a per-patch decision trail. Without a sibling, patches whose file name embeds the old version are flagged undecided rather than silently carried.

Functions

fn adopt_sibling_patch_block(text: &str, sibling_path: &str) -> Result<String, EmitError>

Splice the sibling’s literal patches = [...] assignment into text, replacing the existing one (or inserting before moduleclass when the source has none). Textual adoption keeps tuple entries, patch levels, and comments exactly as the sibling ships them.

fn plan_patch_evolution(new_version: &str, old_patches: &[String], sibling: Option<&SiblingRecipe>) -> PatchPlan

Decide the patch set for a bump to new_version.

old_patches come from the source recipe; sibling is the best same-version recipe the caller resolved from the tree, if any.

fn sibling_paths(name: &str, new_version: &str, candidates: &[Candidate], target_toolchain: &Toolchain) -> Vec<String>

Tree locations of same-version siblings worth resolving as evidence, ranked: same toolchain family first, then the lexically newest toolchain version, then path for determinism. The first resolvable one wins.

Enums

enum PatchDecision

What happens to one patch across the bump.

Carry

Kept: present before the bump and in the evidence recipe (or no evidence spoke against it).

Drop

Removed: the same-version sibling ships without it.

Adopt

Added: the same-version sibling ships it and the source did not.

Undecided

No evidence either way and the name embeds the old version, so carrying it forward is a guess.

Implementations

impl PatchDecision

Functions

fn as_str(&self) -> &'static str

Lowercase verb for residual summaries and logs.

Structs and Unions

struct PatchCall

One patch, its decision, and the evidence the decision rests on.

patch: String

Patch file name as the recipe lists it.

decision: PatchDecision

What happens to it across the bump.

evidence: String

The observation the decision rests on, naming the recipe consulted.

struct PatchPlan

The full evolution plan for a bump’s patch set.

calls: Vec<PatchCall>

One decision per patch across old set and sibling set.

sibling: Option<String>

Path of the same-version sibling recipe the plan adopts, when one exists in the tree.

Implementations

impl PatchPlan

Functions

fn changed(&self) -> bool

Whether the plan changes the patch set at all.

fn final_patches(&self) -> Vec<&str>

Patches that survive the bump, in evidence order.

fn undecided(&self) -> Vec<&str>

Patches whose fate could not be decided from evidence.

struct SiblingRecipe

A same-version recipe already in the tree, resolved far enough to serve as patch evidence. The caller owns the parse so this module stays pure.

easyconfig_path: String

Tree path of the sibling recipe, cited in every decision.

toolchain: Toolchain

Toolchain the sibling builds against; family match raises its rank.

patch_names: Vec<String>

Patch files the sibling ships, in its own order.