Repository: casey/just (Rust)

Issue:
Function to get just' executable path (for when just is not in $PATH)
Hello, I have a simple justfile like:
```make
default:
  @just --list

test:
  echo "it works!"
```

I'm using the [Nix package manager](https://nixos.org/) which allows me to run software without really installing them, and thus they are not in PATH.
I'm trying to run `just` like this as a bootstrapping step: `nix run nixpkgs/nixpkgs-unstable#just` to run the first (default) recipe, but it fails rightfully with `sh: just: command not found` when trying to run `@just --list` in the `default` recipe.

I would like a function to get the full path to the `just` binary that is currently running, to be able to re-run it from a recipe.
The usage would be something like this:
```make
default:
  @{{just_executable()}} --list
```
And this would expand at runtime to something like (here using Nix):
```make
default:
  @/nix/store/ajq3r70f4pz5sqh5p83bbhzrkdj1cdrz-just-0.8.4/bin/just --list
```


Discussion:

Patch:
diff --git a/README.adoc b/README.adoc
index 2aeb392a1d..d7e53ba74e 100644
--- a/README.adoc
+++ b/README.adoc
@@ -622,6 +622,22 @@ script:
   ./{{justfile_directory()}}/scripts/some_script
 ```
 
+==== Just Executable
+
+- `just_executable()` - Absolute path to the just executable.
+
+For example:
+
+```make
+executable:
+    @echo The executable is at: {{just_executable()}}
+```
+
+```
+$ just
+The executable is at: /bin/just
+```
+
 ==== Dotenv Integration
 
 `just` will load environment variables from a file named `.env`. This file can be located in the same directory as your justfile or in a parent directory. These variables are environment variables, not `just` variables, and so must be accessed using `$VARIABLE_NAME` in recipes and backticks.
diff --git a/src/function.rs b/src/function.rs
index dffb3a51e6..3faed59c7c 100644
--- a/src/function.rs
+++ b/src/function.rs
@@ -18,6 +18,7 @@ lazy_static! {
     ("invocation_directory", Nullary(invocation_directory)),
     ("env_var", Unary(env_var)),
     ("env_var_or_default", Binary(env_var_or_default)),
+    ("just_executable", Nullary(just_executable)),
   ]
   .into_iter()
   .collect();
@@ -123,3 +124,15 @@ fn env_var_or_default(
     Ok(value) => Ok(value),
   }
 }
+
+fn just_executable(_context: &FunctionContext) -> Result<String, String> {
+  let exe_path =
+    std::env::current_exe().map_err(|e| format!("Error getting current executable: {}", e))?;
+
+  exe_path.to_str().map(str::to_owned).ok_or_else(|| {
+    format!(
+      "Executable path is not valid unicode: {}",
+      exe_path.to_string_lossy()
+    )
+  })
+}


Test patch:
diff --git a/tests/misc.rs b/tests/misc.rs
index 012fdc48df..2e0db25fb3 100644
--- a/tests/misc.rs
+++ b/tests/misc.rs
@@ -1203,6 +1203,18 @@ test! {
   status:   EXIT_FAILURE,
 }
 
+test! {
+  name:     test_just_executable_function,
+  justfile: "
+    a:
+      @printf 'Executable path is: %s\\n' '{{ just_executable() }}'
+  ",
+  args:     ("a"),
+  stdout:   format!("Executable path is: {}\n", executable_path("just").to_str().unwrap()).as_str(),
+  stderr:   "",
+  status:   EXIT_SUCCESS,
+}
+
 test! {
   name: infallable_command,
   justfile: r#"