Add guard to replace_symlink on Windows (#4519)

`junction::create` apparently will happily succeed but not create a link
to files? Since our symlink function does not indicate that it cannot
handle files, this was quite surprising.


Tested over in #4509 which previously failed on an assertion that
`black.exe` existed.
```
error: Failed to install entrypoint
    Caused by: Cannot create a junction for [TEMP_DIR]/tools/black/Scripts/black.exe: is not a directory
```

We should file an issue upstream too, I think?
This commit is contained in:
Zanie Blue 2024-06-25 14:47:40 -04:00 committed by GitHub
parent a07e70d93a
commit 5641f3a5d9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -48,8 +48,20 @@ pub async fn read_to_string_transcode(path: impl AsRef<Path>) -> std::io::Result
/// Create a symlink at `dst` pointing to `src`, replacing any existing symlink.
///
/// On Windows, this uses the `junction` crate to create a junction point.
/// Note because junctions are used, the source must be a directory.
#[cfg(windows)]
pub fn replace_symlink(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> std::io::Result<()> {
// If the source is a file, we can't create a junction
if src.as_ref().is_file() {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
format!(
"Cannot create a junction for {}: is not a directory",
src.as_ref().display()
),
));
}
// Remove the existing symlink, if any.
match junction::delete(dunce::simplified(dst.as_ref())) {
Ok(()) => match fs_err::remove_dir_all(dst.as_ref()) {