Repository: casey/just
Pull request #1106 (2022-02-17 12:56:07)

Path_exists() function
Hey! 
So here is promised PR for `path_exists()`. 
I also added tests for dirs and files, should I also add tests for hard/soft links? And sorry for their general clumsiness, I'm writing rust basically for the first time and I still have to wrap my head around it.

Closes: #1102 

heavelock: Thanks for your comments! I applied your suggestions and removed the tests for directories since we don't necessarily need to test for them.

Should I somehow refer in docs that this function is using internally rust's std behaviour?

casey: I think it probably isn't necessary to reference the stdlib function. I looked at the documentation for Path::exists, and we could probably include some of the details. I also think it's probably a good idea to put the function under a more descriptive heading, maybe, so something like:


```
#### Filesystem Access

- `path_exists(path)` - Returns `true` if the path points at an existing entity and `false` otherwise. Traverses symbolic links, and returns `false` if the path is inaccessible or points to a broken symlink.
```
heavelock: I changed the readme entry according to your suggestion.

Patch:
diff --git a/README.md b/README.md
index b1fa1586..8370fffa 100644
--- a/README.md
+++ b/README.md
@@ -981,6 +981,10 @@ These functions can fail, for example if a path does not have an extension, whic
 
 - `clean(path)` - Simplify `path` by removing extra path separators, intermediate `.` components, and `..` where possible. `clean("foo//bar")` is `foo/bar`, `clean("foo/..")` is `.`, `clean("foo/./bar")` is `foo/bar`.
 
+#### Filesystem Access
+
+- `path_exists(path)` - Returns `true` if the path points at an existing entity and `false` otherwise. Traverses symbolic links, and returns `false` if the path is inaccessible or points to a broken symlink.
+
 ### Command Evaluation Using Backticks
 
 Backticks can be used to store the result of commands:
diff --git a/src/function.rs b/src/function.rs
index 0c044cff..eba04e75 100644
--- a/src/function.rs
+++ b/src/function.rs
@@ -30,6 +30,7 @@ lazy_static! {
     ("os", Nullary(os)),
     ("os_family", Nullary(os_family)),
     ("parent_directory", Unary(parent_directory)),
+    ("path_exists", Unary(path_exists)),
     ("quote", Unary(quote)),
     ("replace", Ternary(replace)),
     ("trim", Unary(trim)),
@@ -210,6 +211,10 @@ fn parent_directory(_context: &FunctionContext, path: &str) -> Result<String, St
     .ok_or_else(|| format!("Could not extract parent directory from `{}`", path))
 }
 
+fn path_exists(_context: &FunctionContext, path: &str) -> Result<String, String> {
+  Ok(Utf8Path::new(path).exists().to_string())
+}
+
 fn quote(_context: &FunctionContext, s: &str) -> Result<String, String> {
   Ok(format!("'{}'", s.replace('\'', "'\\''")))
 }


Test patch:
diff --git a/tests/functions.rs b/tests/functions.rs
index abdcdf36..e499ea21 100644
--- a/tests/functions.rs
+++ b/tests/functions.rs
@@ -382,3 +382,24 @@ fn join_argument_count_error() {
     .status(EXIT_FAILURE)
     .run();
 }
+
+#[test]
+fn test_path_exists_filepath_exist() {
+  Test::new()
+    .tree(tree! {
+      testfile: ""
+    })
+    .justfile("x := path_exists('testfile')")
+    .args(&["--evaluate", "x"])
+    .stdout("true")
+    .run();
+}
+
+#[test]
+fn test_path_exists_filepath_doesnt_exist() {
+  Test::new()
+    .justfile("x := path_exists('testfile')")
+    .args(&["--evaluate", "x"])
+    .stdout("false")
+    .run();
+}