Add join function for joining paths (#882)

This commit is contained in:
Casey Rodarmor 2021-06-24 15:55:29 -07:00 committed by GitHub
parent 9dc2385c64
commit 87e395254b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 96 additions and 82 deletions

View File

@ -794,14 +794,22 @@ Starting server with database localhost:6379 on port 1337...
==== Path Manipulation ==== Path Manipulation
- `file_name(path)` - File name of `path` with any leading directory components removed. `file_name("/foo/bar.txt")` is `bar.txt`. ===== Fallible
- `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`.
- `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`. - `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`.
- `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`.
These functions can fail, for example if a path does not have an extension, which will halt execution. 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 === Command Evaluation Using Backticks
Backticks can be used to store the result of commands: Backticks can be used to store the result of commands:

View File

@ -10,19 +10,20 @@ pub(crate) enum Function {
lazy_static! { lazy_static! {
pub(crate) static ref TABLE: BTreeMap<&'static str, Function> = vec![ pub(crate) static ref TABLE: BTreeMap<&'static str, Function> = vec![
("arch", Nullary(arch)), ("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", Unary(env_var)),
("env_var_or_default", Binary(env_var_or_default)), ("env_var_or_default", Binary(env_var_or_default)),
("just_executable", Nullary(just_executable)), ("extension", Unary(extension)),
("file_name", Unary(file_name)), ("file_name", Unary(file_name)),
("parent_directory", Unary(parent_directory)),
("file_stem", Unary(file_stem)), ("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)), ("without_extension", Unary(without_extension)),
("extension", Unary(extension))
] ]
.into_iter() .into_iter()
.collect(); .collect();
@ -42,55 +43,6 @@ fn arch(_context: &FunctionContext) -> Result<String, String> {
Ok(target::arch().to_owned()) 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> { fn env_var(context: &FunctionContext, key: &str) -> Result<String, String> {
use std::env::VarError::*; use std::env::VarError::*;
@ -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> { fn just_executable(_context: &FunctionContext) -> Result<String, String> {
let exe_path = let exe_path =
std::env::current_exe().map_err(|e| format!("Error getting current executable: {}", e))?; std::env::current_exe().map_err(|e| format!("Error getting current executable: {}", e))?;
@ -141,11 +126,45 @@ fn just_executable(_context: &FunctionContext) -> Result<String, String> {
}) })
} }
fn file_name(_context: &FunctionContext, path: &str) -> Result<String, String> { fn justfile(context: &FunctionContext) -> Result<String, String> {
Utf8Path::new(path) context
.file_name() .search
.justfile
.to_str()
.map(str::to_owned) .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> { fn parent_directory(_context: &FunctionContext, path: &str) -> Result<String, String> {
@ -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)) .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> { fn without_extension(_context: &FunctionContext, path: &str) -> Result<String, String> {
let parent = Utf8Path::new(path) let parent = Utf8Path::new(path)
.parent() .parent()
@ -173,10 +185,3 @@ fn without_extension(_context: &FunctionContext, path: &str) -> Result<String, S
Ok(parent.join(file_stem).to_string()) 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))
}

View File

@ -1179,12 +1179,13 @@ fs := file_stem('/foo/bar/baz.hello')
fn := file_name('/foo/bar/baz.hello') fn := file_name('/foo/bar/baz.hello')
dir := parent_directory('/foo/bar/baz.hello') dir := parent_directory('/foo/bar/baz.hello')
ext := extension('/foo/bar/baz.hello') ext := extension('/foo/bar/baz.hello')
jn := join('a', 'b')
foo: 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", 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'\n", stderr: "/bin/echo '/foo/bar/baz' 'baz' 'baz.hello' '/foo/bar' 'hello' 'a/b'\n",
} }
#[cfg(not(windows))] #[cfg(not(windows))]