Add function to canonicalize paths (#1859)

This commit is contained in:
Casey Rodarmor 2024-01-19 12:04:28 -08:00 committed by GitHub
parent 22d462bd55
commit 43d88f50e0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 39 additions and 1 deletions

View File

@ -1381,7 +1381,10 @@ The process ID is: 420
##### Fallible
- `absolute_path(path)` - Absolute path to relative `path` in the working
directory. `absolute_path("./bar.txt")` in directory `/foo` is `/foo/bar.txt`.
directory. `absolute_path("./bar.txt")` in directory `/foo` is
`/foo/bar.txt`.
- `canonicalize(path)` - Canonicalize `path` by resolving symlinks and removing
`.`, `..`, and extra `/`s where possible.
- `extension(path)` - Extension of `path`. `extension("/foo/bar.txt")` is
`txt`.
- `file_name(path)` - File name of `path` with any leading directory components

View File

@ -21,6 +21,7 @@ pub(crate) fn get(name: &str) -> Option<Function> {
let function = match name {
"absolute_path" => Unary(absolute_path),
"arch" => Nullary(arch),
"canonicalize" => Unary(canonicalize),
"cache_directory" => Nullary(|_| dir("cache", dirs::cache_dir)),
"capitalize" => Unary(capitalize),
"clean" => Unary(clean),
@ -106,6 +107,18 @@ fn arch(_context: &FunctionContext) -> Result<String, String> {
Ok(target::arch().to_owned())
}
fn canonicalize(_context: &FunctionContext, path: &str) -> Result<String, String> {
let canonical =
std::fs::canonicalize(path).map_err(|err| format!("I/O error canonicalizing path: {err}"))?;
canonical.to_str().map(str::to_string).ok_or_else(|| {
format!(
"Canonical path is not valid unicode: {}",
canonical.display(),
)
})
}
fn capitalize(_context: &FunctionContext, s: &str) -> Result<String, String> {
let mut capitalized = String::new();
for (i, c) in s.chars().enumerate() {

View File

@ -662,3 +662,14 @@ fn just_pid() {
assert_eq!(stdout.parse::<u32>().unwrap(), pid);
}
#[cfg(unix)]
#[test]
fn canonicalize() {
Test::new()
.args(["--evaluate", "x"])
.justfile("x := canonicalize('foo')")
.symlink("justfile", "foo")
.stdout_regex(".*/justfile")
.run();
}

View File

@ -113,6 +113,17 @@ impl Test {
self.tempdir.path().join("justfile")
}
#[cfg(unix)]
#[track_caller]
pub(crate) fn symlink(self, original: &str, link: &str) -> Self {
std::os::unix::fs::symlink(
self.tempdir.path().join(original),
self.tempdir.path().join(link),
)
.unwrap();
self
}
pub(crate) fn no_justfile(mut self) -> Self {
self.justfile = None;
self