The Expand evaluator canonicalizes Path-typed values eagerly, since #22. Canonicalization is an I/O operation, and fails if the resulting path does not exist on-disk. As a result, if a Path-valued string is expanded to a value that containers another Expand placeholder (expandable variable), the expansion will fail.
This is exhibited by an important use case that currently fails:
#[test]
fn test_setup_dir_and_target_exe() -> Result<()> {
let expand = Expand::new()
.setup_dir("/my/setup")
.target_exe("{setup_dir}/my-fuzzer.exe");
let target_exe = expand.evaluate_value("{target_exe}")?;
assert_eq!(target_exe, "/my/setup/my-fuzzer.exe.);
Ok(())
}
In the above, the internal expansions should be:
{target_exe}
{setup_dir}/my-fuzzer.exe
/my/setup/my-fuzzer.exe
But, since the intermediate state of (2) is an ExpandedValue::Path and does not exist on disk due to the unexpanded path segment, the call to canonicalize() in Expand::replace_value() fails.
The fix to this must support the above test case, and maybe reasonably abandon canonicalization (or at least have a mode that permits canonicalization failures). It must also avoid expansion cycles that would lead to stack overflows or infinite loops.
AB#41312795