Skip to content

Commit

Permalink
Add join function for joining paths (#882)
Browse files Browse the repository at this point in the history
  • Loading branch information
casey authored Jun 24, 2021
1 parent 9dc2385 commit 87e3952
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 80 deletions.
12 changes: 10 additions & 2 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -794,14 +794,22 @@ Starting server with database localhost:6379 on port 1337...

==== Path Manipulation

===== Fallible

- `extension(path)` - Extension of `path`. `extension("/foo/bar.txt")` is `txt`.
- `file_name(path)` - File name of `path` with any leading directory components removed. `file_name("/foo/bar.txt")` is `bar.txt`.
- `parent_directory(path)` - Parent directory of `path`. `parent_directory("/foo/bar.txt")` is `/foo`.
- `file_stem(path)` - File name of `path` without extension. `file_stem("/foo/bar.txt")` is `bar`.
- `parent_directory(path)` - Parent directory of `path`. `parent_directory("/foo/bar.txt")` is `/foo`.
- `without_extension(path)` - `path` without extension. `without_extension("/foo/bar.txt")` is `/foo/bar`.
- `extension(path)` - Extension of `path`. `extension("/foo/bar.txt")` is `txt`.

These functions can fail, for example if a path does not have an extension, which will halt execution.

===== Infallible

- `join(a, b)` - Join path `a` with path `b`. `join("foo/bar", "baz")` is `foo/bar/baz`.

These functions always succeed.

=== Command Evaluation Using Backticks

Backticks can be used to store the result of commands:
Expand Down
155 changes: 80 additions & 75 deletions src/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,20 @@ pub(crate) enum Function {
lazy_static! {
pub(crate) static ref TABLE: BTreeMap<&'static str, Function> = vec![
("arch", Nullary(arch)),
("os", Nullary(os)),
("os_family", Nullary(os_family)),
("justfile_directory", Nullary(justfile_directory)),
("justfile", Nullary(justfile)),
("invocation_directory", Nullary(invocation_directory)),
("env_var", Unary(env_var)),
("env_var_or_default", Binary(env_var_or_default)),
("just_executable", Nullary(just_executable)),
("extension", Unary(extension)),
("file_name", Unary(file_name)),
("parent_directory", Unary(parent_directory)),
("file_stem", Unary(file_stem)),
("invocation_directory", Nullary(invocation_directory)),
("join", Binary(join)),
("just_executable", Nullary(just_executable)),
("justfile", Nullary(justfile)),
("justfile_directory", Nullary(justfile_directory)),
("os", Nullary(os)),
("os_family", Nullary(os_family)),
("parent_directory", Unary(parent_directory)),
("without_extension", Unary(without_extension)),
("extension", Unary(extension))
]
.into_iter()
.collect();
Expand All @@ -42,55 +43,6 @@ fn arch(_context: &FunctionContext) -> Result<String, String> {
Ok(target::arch().to_owned())
}

fn os(_context: &FunctionContext) -> Result<String, String> {
Ok(target::os().to_owned())
}

fn os_family(_context: &FunctionContext) -> Result<String, String> {
Ok(target::os_family().to_owned())
}

fn invocation_directory(context: &FunctionContext) -> Result<String, String> {
Platform::convert_native_path(
&context.search.working_directory,
context.invocation_directory,
)
.map_err(|e| format!("Error getting shell path: {}", e))
}

fn justfile(context: &FunctionContext) -> Result<String, String> {
context
.search
.justfile
.to_str()
.map(str::to_owned)
.ok_or_else(|| {
format!(
"Justfile path is not valid unicode: {}",
context.search.justfile.to_string_lossy()
)
})
}

fn justfile_directory(context: &FunctionContext) -> Result<String, String> {
let justfile_directory = context.search.justfile.parent().ok_or_else(|| {
format!(
"Could not resolve justfile directory. Justfile `{}` had no parent.",
context.search.justfile.display()
)
})?;

justfile_directory
.to_str()
.map(str::to_owned)
.ok_or_else(|| {
format!(
"Justfile directory is not valid unicode: {}",
justfile_directory.to_string_lossy()
)
})
}

fn env_var(context: &FunctionContext, key: &str) -> Result<String, String> {
use std::env::VarError::*;

Expand Down Expand Up @@ -129,6 +81,39 @@ fn env_var_or_default(
}
}

fn extension(_context: &FunctionContext, path: &str) -> Result<String, String> {
Utf8Path::new(path)
.extension()
.map(str::to_owned)
.ok_or_else(|| format!("Could not extract extension from `{}`", path))
}

fn file_name(_context: &FunctionContext, path: &str) -> Result<String, String> {
Utf8Path::new(path)
.file_name()
.map(str::to_owned)
.ok_or_else(|| format!("Could not extract file name from `{}`", path))
}

fn file_stem(_context: &FunctionContext, path: &str) -> Result<String, String> {
Utf8Path::new(path)
.file_stem()
.map(str::to_owned)
.ok_or_else(|| format!("Could not extract file stem from `{}`", path))
}

fn invocation_directory(context: &FunctionContext) -> Result<String, String> {
Platform::convert_native_path(
&context.search.working_directory,
context.invocation_directory,
)
.map_err(|e| format!("Error getting shell path: {}", e))
}

fn join(_context: &FunctionContext, base: &str, with: &str) -> Result<String, String> {
Ok(Utf8Path::new(base).join(with).to_string())
}

fn just_executable(_context: &FunctionContext) -> Result<String, String> {
let exe_path =
std::env::current_exe().map_err(|e| format!("Error getting current executable: {}", e))?;
Expand All @@ -141,11 +126,45 @@ fn just_executable(_context: &FunctionContext) -> Result<String, String> {
})
}

fn file_name(_context: &FunctionContext, path: &str) -> Result<String, String> {
Utf8Path::new(path)
.file_name()
fn justfile(context: &FunctionContext) -> Result<String, String> {
context
.search
.justfile
.to_str()
.map(str::to_owned)
.ok_or_else(|| format!("Could not extract file name from `{}`", path))
.ok_or_else(|| {
format!(
"Justfile path is not valid unicode: {}",
context.search.justfile.to_string_lossy()
)
})
}

fn justfile_directory(context: &FunctionContext) -> Result<String, String> {
let justfile_directory = context.search.justfile.parent().ok_or_else(|| {
format!(
"Could not resolve justfile directory. Justfile `{}` had no parent.",
context.search.justfile.display()
)
})?;

justfile_directory
.to_str()
.map(str::to_owned)
.ok_or_else(|| {
format!(
"Justfile directory is not valid unicode: {}",
justfile_directory.to_string_lossy()
)
})
}

fn os(_context: &FunctionContext) -> Result<String, String> {
Ok(target::os().to_owned())
}

fn os_family(_context: &FunctionContext) -> Result<String, String> {
Ok(target::os_family().to_owned())
}

fn parent_directory(_context: &FunctionContext, path: &str) -> Result<String, String> {
Expand All @@ -155,13 +174,6 @@ fn parent_directory(_context: &FunctionContext, path: &str) -> Result<String, St
.ok_or_else(|| format!("Could not extract parent directory from `{}`", path))
}

fn file_stem(_context: &FunctionContext, path: &str) -> Result<String, String> {
Utf8Path::new(path)
.file_stem()
.map(str::to_owned)
.ok_or_else(|| format!("Could not extract file stem from `{}`", path))
}

fn without_extension(_context: &FunctionContext, path: &str) -> Result<String, String> {
let parent = Utf8Path::new(path)
.parent()
Expand All @@ -173,10 +185,3 @@ fn without_extension(_context: &FunctionContext, path: &str) -> Result<String, S

Ok(parent.join(file_stem).to_string())
}

fn extension(_context: &FunctionContext, path: &str) -> Result<String, String> {
Utf8Path::new(path)
.extension()
.map(str::to_owned)
.ok_or_else(|| format!("Could not extract extension from `{}`", path))
}
7 changes: 4 additions & 3 deletions tests/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1179,12 +1179,13 @@ fs := file_stem('/foo/bar/baz.hello')
fn := file_name('/foo/bar/baz.hello')
dir := parent_directory('/foo/bar/baz.hello')
ext := extension('/foo/bar/baz.hello')
jn := join('a', 'b')
foo:
/bin/echo '{{we}}' '{{fs}}' '{{fn}}' '{{dir}}' '{{ext}}'
/bin/echo '{{we}}' '{{fs}}' '{{fn}}' '{{dir}}' '{{ext}}' '{{jn}}'
"#,
stdout: "/foo/bar/baz baz baz.hello /foo/bar hello\n",
stderr: "/bin/echo '/foo/bar/baz' 'baz' 'baz.hello' '/foo/bar' 'hello'\n",
stdout: "/foo/bar/baz baz baz.hello /foo/bar hello a/b\n",
stderr: "/bin/echo '/foo/bar/baz' 'baz' 'baz.hello' '/foo/bar' 'hello' 'a/b'\n",
}

#[cfg(not(windows))]
Expand Down

0 comments on commit 87e3952

Please sign in to comment.