fix(cli): resolve a relative paths.data against the project root

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
This commit is contained in:
2026-07-13 15:34:30 +02:00
parent 7abe89cb4f
commit 1f5c5ad80f
2 changed files with 32 additions and 5 deletions
+29 -3
View File
@@ -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()));
+3 -2
View File
@@ -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();