feat(sessions): per-loadout follow symlinks setting - #713
Conversation
📝 WalkthroughWalkthroughLoadouts can specify symlink-following overrides that propagate through patch composition and enumeration. Patch enumeration now resolves this setting per patch. ChangesLoadout composition and patch metadata
Sequence Diagram(s)sequenceDiagram
participant Loadout
participant Contribution
participant expand_patch_sources
participant enumerate_patch_files
Loadout->>Contribution: apply optional symlink override
Contribution->>expand_patch_sources: provide contributed patches
expand_patch_sources->>enumerate_patch_files: provide resolved per-patch flags
enumerate_patch_files->>enumerate_patch_files: follow symlinks per patch
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
crates/sessions/src/core/loadout.rs (1)
382-423: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winAdd an end-to-end test for
contribute()stamping.The new tests cover TOML round-trip and the
with_follow_symlinksbuilder, but nothing exercises the actual propagation path: aLoadoutwithfollow_symlinks = Some(v)and at least one patch, callingcontribute(), then asserting the resultingContribution'sProvenancedPatch::follow_symlinks()reflects the override. This is the core new behavior (set_follow_symlinks_on_patchesstamping), and it's currently only verified indirectly viaenumerate.rs's walker test, which doesn't go throughLoadout::contribute.✅ Suggested additional test
#[test] fn contribute_stamps_follow_symlinks_override_onto_patches() { use crate::core::compose::Composable; use crate::core::primitives::PatchDest; let patch = Patch::new("a", PatchDest::try_new("a").unwrap()); let loadout = Loadout::new(LoadoutName::try_new("test").unwrap()) .with_patch(patch) .with_follow_symlinks(true); let env: &dyn Fn(&str) -> Result<String, std::env::VarError> = &|_| Err(std::env::VarError::NotPresent); let contribution = loadout.contribute(env).unwrap(); assert_eq!(contribution.patches().len(), 1); assert_eq!(contribution.patches()[0].follow_symlinks(), Some(true)); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/sessions/src/core/loadout.rs` around lines 382 - 423, Add an end-to-end test near with_follow_symlinks_builder_sets_the_field that constructs a Loadout with a Patch, applies with_follow_symlinks(true), calls Loadout::contribute with an environment lookup returning VarError::NotPresent, and asserts the resulting Contribution contains one patch whose ProvenancedPatch::follow_symlinks() is Some(true).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@crates/sessions/src/core/loadout.rs`:
- Around line 382-423: Add an end-to-end test near
with_follow_symlinks_builder_sets_the_field that constructs a Loadout with a
Patch, applies with_follow_symlinks(true), calls Loadout::contribute with an
environment lookup returning VarError::NotPresent, and asserts the resulting
Contribution contains one patch whose ProvenancedPatch::follow_symlinks() is
Some(true).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 96bcd936-5cbe-418c-8153-8b23f137fd38
📒 Files selected for processing (6)
crates/sessions/src/client/composer.rscrates/sessions/src/client/handler.rscrates/sessions/src/core/compose.rscrates/sessions/src/core/enumerate.rscrates/sessions/src/core/loadout.rscrates/sessions/src/core/source.rs
Adds a per-loadout
follow_symlinksfield to loadout TOML that overridesthe client config's
[loadouts].follow_symlinksdefault for one loadout'spatches.
None(the default) inherits the global setting;Some(bool)wins.
The override travels through the compose pipeline as a field on
ProvenancedPatch (Option), stamped by Loadout::contribute and
read once by expand_patch_sources (follow_override.unwrap_or(default)).
Non-loadout contributors (packages, projects) leave it None and inherit
the default. enumerate_patch_files reads the field per-item, so a single
call can walk two patches with different follow behavior. No wire-format
change — the setting resolves to a walk decision on the client before the
wire contribution is built.
Also in this PR: UserComposer::add rejects duplicate loadout names so
Source::UserLoadout { name } unambiguously identifies one loadout in
logs and conflict messages.
Summary by CodeRabbit