fix(cli): canonicalize build --output path

This fixes a potential issue with the new lock file hashing mechanism,
in which two different path literals pointing to the same location would
hash to separate lock files, allowing a race condition.
This commit is contained in:
WillLillis 2025-12-28 01:51:35 -05:00 committed by Christian Clason
parent 82486d4b0a
commit 93d793d249
2 changed files with 17 additions and 7 deletions

View file

@ -955,11 +955,21 @@ impl Build {
} else {
let output_path = if let Some(ref path) = self.output {
let path = Path::new(path);
if path.is_absolute() {
let full_path = if path.is_absolute() {
path.to_path_buf()
} else {
current_dir.join(path)
}
};
let parent_path = full_path
.parent()
.context("Output path must have a parent")?;
let name = full_path
.file_name()
.context("Ouput path must have a filename")?;
fs::create_dir_all(parent_path).context("Failed to create output path")?;
let mut canon_path = parent_path.canonicalize().context("Invalid output path")?;
canon_path.push(name);
canon_path
} else {
let file_name = grammar_path
.file_stem()

View file

@ -1098,11 +1098,11 @@ impl Loader {
// Ensure the dynamic library exists before trying to load it. This can
// happen in race conditions where we couldn't acquire the lock because
// another process was compiling but it still haven't finished by the
// another process was compiling but it still hasn't finished by the
// time we reach this point, so the output file still doesn't exist.
//
// Instead of complaining about library load failure in `load_language`,
// inform the user about the precise issue.
// Instead of allowing the `load_language` call below to fail, return a
// clearer error to the user here.
if !output_path.exists() {
let msg = format!(
"Dynamic library `{}` not found after build attempt. \
@ -1110,10 +1110,10 @@ impl Loader {
output_path.display()
);
return Err(LoaderError::IO(IoError::new(
Err(LoaderError::IO(IoError::new(
std::io::Error::new(std::io::ErrorKind::NotFound, msg),
Some(output_path.as_path()),
)));
)))?;
}
Self::load_language(&output_path, &language_fn_name)