From a04fda3a4cbcd4cad23a10ee6b890cbdcfd23328 Mon Sep 17 00:00:00 2001 From: claude Date: Mon, 13 Jul 2026 15:34:30 +0200 Subject: [PATCH] fix(cli): resolve a relative paths.data against the project root MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Env::data_path() handed paths.data to the data layer verbatim, so a relative value resolved against the invoking process's cwd — aura run from a project subdirectory silently read a different archive location than from the root, while runs/ stayed anchored. Relative values now join onto the project root, matching runs_root() and the [nodes] pointer resolution; absolute values and the no-project default pass through unchanged. RED-first unit test pins the root-anchored resolution. closes #254 --- crates/aura-cli/src/project.rs | 32 ++++++++++++++++++++++++++--- crates/aura-cli/tests/common/mod.rs | 5 +++-- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/crates/aura-cli/src/project.rs b/crates/aura-cli/src/project.rs index 625b4f3..d4c026d 100644 --- a/crates/aura-cli/src/project.rs +++ b/crates/aura-cli/src/project.rs @@ -182,12 +182,23 @@ impl Env { TraceStore::open(self.runs_root()) } - /// The data archive root: `paths.data` inside a project when set, - /// the data-server default otherwise. + /// The data archive root: `paths.data` inside a project when set + /// (relative values resolved against the project root, same as + /// `runs_root()` and the `[nodes]` pointers), the data-server default + /// otherwise. pub fn data_path(&self) -> String { self.project .as_ref() - .and_then(|p| p.toml.paths.data.clone()) + .and_then(|p| { + p.toml.paths.data.as_ref().map(|data| { + let path = Path::new(data); + if path.is_absolute() { + data.clone() + } else { + p.root.join(path).to_string_lossy().to_string() + } + }) + }) .unwrap_or_else(|| data_server::DEFAULT_DATA_PATH.to_string()) } @@ -615,6 +626,21 @@ mod tests { std::fs::remove_dir_all(&tmp).ok(); } + /// #254: a relative `paths.data` must resolve against the project root + /// (`p.root`), matching `runs_root()`'s and the `[nodes]` pointers' + /// resolution — not against the invoking process's cwd, which silently + /// changes the data location depending on the caller's working directory. + #[test] + fn data_path_resolves_a_relative_paths_data_against_the_project_root() { + let tmp = std::env::temp_dir().join(format!("aura-datarel-{}", std::process::id())); + std::fs::create_dir_all(&tmp).unwrap(); + std::fs::write(tmp.join("Aura.toml"), "[paths]\ndata = \"data\"\n").unwrap(); + let p = load(&tmp, false).expect("data-only load"); + let env = Env::with_project(p); + assert_eq!(env.data_path(), tmp.join("data").to_string_lossy().to_string()); + std::fs::remove_dir_all(&tmp).ok(); + } + #[test] fn two_nodes_pointers_refuse_with_multi_crate() { let tmp = std::env::temp_dir().join(format!("aura-multi-{}", std::process::id())); diff --git a/crates/aura-cli/tests/common/mod.rs b/crates/aura-cli/tests/common/mod.rs index 7a7211b..7ac6fff 100644 --- a/crates/aura-cli/tests/common/mod.rs +++ b/crates/aura-cli/tests/common/mod.rs @@ -69,8 +69,9 @@ fn mint_tempdir() -> PathBuf { /// Writes the `Aura.toml` + `demo_signal.json` common to every fresh project: /// an absolute `[nodes]` pointer at the shared, once-built fixture crate, and /// — when `data_dir` is `Some` — a `[paths] data` override pointing at it -/// (relative, resolved against the invocation cwd, which every test that uses -/// this always sets to `root` itself via `.current_dir`). +/// (relative, resolved against the project root — `root` itself — since +/// `Env::data_path` joins a relative `paths.data` onto the project root, +/// same as `runs_root()` and the `[nodes]` pointers, #254). fn write_project_files(root: &Path, data_dir: Option<&str>) { let fixture = built_project(); let data_line = data_dir.map(|d| format!("data = \"{d}\"\n")).unwrap_or_default();