installtest/src/lane_dir.rs
//! One derivation of "a cargo target directory that belongs to *this* worktree".
//!
//! Two callers need it and they are in different crates:
//!
//! * [`crate::subject`] — where the **subject binary** is built. Sharing that
//! directory means one worktree installs and asserts another worktree's `gunnar`.
//! MEASURED 2026-08-05: one worktree's `gunnar-install/release/gunnar` was
//! rewritten at 08:59 stamped `v1.1-8-g6c02185` while another worktree's run was
//! still reading `v1.1-6-g95354c2` out of the same path, and two arms were
//! green *because* of the sharing. Fixed in `81c5ae5`.
//! * `xtask`'s `install-test` / `bare` tasks — where the **harness itself** is
//! built. A constant there is a different failure with the same cause: five
//! lanes running `cargo xtask install-test` block on each other's package
//! lock instead of testing the wrong binary.
//!
//! Both must never be the same function written twice, so it is written
//! here, once, taking its root explicitly. `xtask` has **zero dependencies** on
//! purpose and cannot depend on this crate, so it reaches this file with
//! `#[path = "../../installtest/src/lane_dir.rs"]`: a source include adds no
//! edge to the dependency graph, and a second copy of nine lines of FNV is
//! exactly what that rule is not meant to buy.
use std::path::{Path, PathBuf};
/// `<target_root>/<worktree basename>-<8 hex of FNV-1a over the canonical path>`.
///
/// Taking `root` explicitly, and not off some ambient `workspace_root()`, so the
/// property that matters can actually be asserted: **two different worktrees
/// must get two different directories.** With a constant those two calls are
/// equal, which is the bug, and no test that only ever passes one root can see
/// it.
///
/// The hash is what carries the guarantee — worktree basenames collide
/// constantly here (`~/scratch/wt/redci/gunnar` and
/// `~/git/gunnar` are both `gunnar`) — and the basename rides along
/// only so a human reading `ls` can tell whose directory is whose.
pub fn lane_dir(target_root: &str, root: &Path) -> PathBuf {
let root = root.canonicalize().unwrap_or_else(|_| root.to_path_buf());
let name = root
.file_name()
.and_then(|s| s.to_str())
.unwrap_or("worktree");
let name: String = name
.chars()
.map(|c| {
if c.is_ascii_alphanumeric() || c == '-' || c == '_' {
c
} else {
'-'
}
})
.collect();
home_expanded(target_root).join(format!("{name}-{:08x}", path_hash(&root)))
}
/// **`~/…` expanded against `$HOME`.**
///
/// The scratch roots are written as `~/scratch/…` rather than as one
/// developer's absolute home: a path with a username baked into it is wrong for
/// everybody else and does not belong in a public tree. `~` is a shell
/// convention and nothing expands it inside a Rust string, so it is expanded
/// HERE — the one function every root passes through — rather than at each of
/// the callers, where the day somebody forgets is the day a literal `~` directory
/// appears in the working directory.
///
/// Restated rather than reused (the twin is `installtest::expand_home`, and the
/// canonical keep since 2026-09-10 is `nornir_xtask_support::expand_home` in
/// edda) because this file is also `#[path]`-included by `xtask`, which
/// deliberately has no dependencies and cannot reach either crate. The
/// zero-dependency rule is `xtask/Cargo.toml`'s and it is argued there: a
/// workspace member's dependency takes part in resolver-2 feature unification,
/// and the guard must not be the thing it guards against.
///
/// So this is the ONE copy the sweep could not remove even in principle —
/// `nornir mimir analyze duplicates` ranked the cluster first, `bench/` and
/// `deploy/upcloud/` became `pub use`s of the leaf, and this file and its
/// `#[path]` includer are the two that stay. Behaviour is pinned in the leaf by
/// `expand_home_expands_only_a_leading_tilde_slash`.
pub fn home_expanded(p: &str) -> PathBuf {
match p.strip_prefix("~/") {
Some(rest) => {
PathBuf::from(std::env::var("HOME").unwrap_or_else(|_| "/root".to_string())).join(rest)
}
None => PathBuf::from(p),
}
}
/// FNV-1a over the canonical path, folded to 32 bits. Hand-rolled because
/// `installtest` reaches this from a crate with one path dependency and `xtask`
/// from a crate with none; nothing cryptographic is being asked of it, only that
/// two distinct worktrees on one box do not land on one directory.
fn path_hash(path: &Path) -> u32 {
let mut h: u64 = 0xcbf2_9ce4_8422_2325;
for b in path.as_os_str().as_encoded_bytes() {
h ^= u64::from(*b);
h = h.wrapping_mul(0x0000_0100_0000_01b3);
}
(h ^ (h >> 32)) as u32
}
#[cfg(test)]
mod tests {
use super::*;
/// Two worktrees on this box, deliberately not existing, so this says
/// something about the derivation rather than about the desktop's filesystem.
const LANE_A: &str = "~/scratch/wt/__lane_a__/gunnar";
const LANE_B: &str = "~/scratch/wt/__lane_b__/gunnar";
const ROOT: &str = "~/scratch/cargo/__probe__";
/// The defect, in the derivation itself: both lanes are called `gunnar`, so
/// a basename-only slug — or a constant — makes these equal.
#[test]
fn two_worktrees_get_two_directories() {
assert_ne!(
lane_dir(ROOT, Path::new(LANE_A)),
lane_dir(ROOT, Path::new(LANE_B)),
"two worktrees resolved to one directory"
);
}
/// The identity-value trap in the other direction: a pid, a timestamp or a
/// random would satisfy the test above perfectly and throw away every
/// incremental build every lane has.
#[test]
fn one_worktree_gets_one_directory_every_time() {
assert_eq!(
lane_dir(ROOT, Path::new(LANE_A)),
lane_dir(ROOT, Path::new(LANE_A)),
"one worktree got two different directories, so nothing is ever incremental"
);
}
/// It stays under the root it was given, and it never collapses back onto
/// the root itself — which is the shared directory this exists to end.
#[test]
fn the_directory_is_under_the_root_and_is_not_the_root() {
let d = lane_dir(ROOT, Path::new(LANE_A));
assert!(
d.starts_with(home_expanded(ROOT)),
"{} left its root",
d.display()
);
assert_ne!(
d,
home_expanded(ROOT),
"the derivation collapsed back onto the shared root itself"
);
}
/// Two different roots must not be conflated either: `installtest`'s subject
/// directory and `xtask`'s harness directory are two different things for
/// the same worktree, and putting them in one place is the contention this
/// was split apart to end.
#[test]
fn two_roots_give_two_directories_for_one_worktree() {
assert_ne!(
lane_dir("~/scratch/cargo/gunnar-install", Path::new(LANE_A)),
lane_dir("~/scratch/cargo/gunnar-install-test", Path::new(LANE_A)),
"the subject directory and the harness directory are the same path"
);
}
}