Path dirname and filestem (#2428)

* add dirname and filestem to path commands

* hacked around with gedge's help to get it to compile with cargo b

* fmt
This commit is contained in:
Darren Schroeder 2020-08-26 14:47:23 -05:00 committed by GitHub
parent 781e423a97
commit 766533aafb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 140 additions and 5 deletions

View File

@ -455,11 +455,13 @@ pub fn create_default_context(
#[cfg(feature = "uuid_crate")] #[cfg(feature = "uuid_crate")]
whole_stream_command(RandomUUID), whole_stream_command(RandomUUID),
// Path // Path
whole_stream_command(PathCommand),
whole_stream_command(PathExtension),
whole_stream_command(PathBasename), whole_stream_command(PathBasename),
whole_stream_command(PathExpand), whole_stream_command(PathCommand),
whole_stream_command(PathDirname),
whole_stream_command(PathExists), whole_stream_command(PathExists),
whole_stream_command(PathExpand),
whole_stream_command(PathExtension),
whole_stream_command(PathFilestem),
whole_stream_command(PathType), whole_stream_command(PathType),
// Url // Url
whole_stream_command(UrlCommand), whole_stream_command(UrlCommand),

View File

@ -207,7 +207,10 @@ pub(crate) use next::Next;
pub(crate) use nth::Nth; pub(crate) use nth::Nth;
pub(crate) use open::Open; pub(crate) use open::Open;
pub(crate) use parse::Parse; pub(crate) use parse::Parse;
pub(crate) use path::{PathBasename, PathCommand, PathExists, PathExpand, PathExtension, PathType}; pub(crate) use path::{
PathBasename, PathCommand, PathDirname, PathExists, PathExpand, PathExtension, PathFilestem,
PathType,
};
pub(crate) use pivot::Pivot; pub(crate) use pivot::Pivot;
pub(crate) use prepend::Prepend; pub(crate) use prepend::Prepend;
pub(crate) use prev::Previous; pub(crate) use prev::Previous;

View File

@ -0,0 +1,60 @@
use super::{operate, DefaultArguments};
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_errors::ShellError;
use nu_protocol::{Signature, SyntaxShape, UntaggedValue, Value};
use std::path::Path;
pub struct PathDirname;
#[async_trait]
impl WholeStreamCommand for PathDirname {
fn name(&self) -> &str {
"path dirname"
}
fn signature(&self) -> Signature {
Signature::build("path dirname").rest(SyntaxShape::ColumnPath, "optionally operate by path")
}
fn usage(&self) -> &str {
"gets the dirname of a path"
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let tag = args.call_info.name_tag.clone();
let (DefaultArguments { rest }, input) = args.process(&registry).await?;
operate(input, rest, &action, tag.span).await
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Get dirname of a path",
example: "echo '/home/joe/test.txt' | path dirname",
result: Some(vec![Value::from("/home/joe")]),
}]
}
}
fn action(path: &Path) -> UntaggedValue {
UntaggedValue::string(match path.parent() {
Some(dirname) => dirname.to_string_lossy().to_string(),
_ => "".to_string(),
})
}
#[cfg(test)]
mod tests {
use super::PathDirname;
#[test]
fn examples_work_as_expected() {
use crate::examples::test as test_examples;
test_examples(PathDirname {})
}
}

View File

@ -0,0 +1,61 @@
use super::{operate, DefaultArguments};
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_errors::ShellError;
use nu_protocol::{Signature, SyntaxShape, UntaggedValue, Value};
use std::path::Path;
pub struct PathFilestem;
#[async_trait]
impl WholeStreamCommand for PathFilestem {
fn name(&self) -> &str {
"path filestem"
}
fn signature(&self) -> Signature {
Signature::build("path filestem")
.rest(SyntaxShape::ColumnPath, "optionally operate by path")
}
fn usage(&self) -> &str {
"gets the filestem of a path"
}
async fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let tag = args.call_info.name_tag.clone();
let (DefaultArguments { rest }, input) = args.process(&registry).await?;
operate(input, rest, &action, tag.span).await
}
fn examples(&self) -> Vec<Example> {
vec![Example {
description: "Get filestem of a path",
example: "echo '/home/joe/test.txt' | path filestem",
result: Some(vec![Value::from("test")]),
}]
}
}
fn action(path: &Path) -> UntaggedValue {
UntaggedValue::string(match path.file_stem() {
Some(stem) => stem.to_string_lossy().to_string(),
_ => "".to_string(),
})
}
#[cfg(test)]
mod tests {
use super::PathFilestem;
#[test]
fn examples_work_as_expected() {
use crate::examples::test as test_examples;
test_examples(PathFilestem {})
}
}

View File

@ -1,8 +1,10 @@
mod basename; mod basename;
mod command; mod command;
mod dirname;
mod exists; mod exists;
mod expand; mod expand;
mod extension; mod extension;
mod filestem;
mod r#type; mod r#type;
use crate::prelude::*; use crate::prelude::*;
@ -13,9 +15,11 @@ use std::path::Path;
pub use basename::PathBasename; pub use basename::PathBasename;
pub use command::Path as PathCommand; pub use command::Path as PathCommand;
pub use dirname::PathDirname;
pub use exists::PathExists; pub use exists::PathExists;
pub use expand::PathExpand; pub use expand::PathExpand;
pub use extension::PathExtension; pub use extension::PathExtension;
pub use filestem::PathFilestem;
pub use r#type::PathType; pub use r#type::PathType;
#[derive(Deserialize)] #[derive(Deserialize)]

View File

@ -34,7 +34,7 @@ impl Completer {
// These is_executable/pathext implementations are copied from ichwh and modified // These is_executable/pathext implementations are copied from ichwh and modified
// to not be async // to not be async
#[cfg(windows)] #[cfg(all(windows, feature = "ichwh"))]
fn pathext() -> IchwhResult<Vec<String>> { fn pathext() -> IchwhResult<Vec<String>> {
Ok(std::env::var_os("PATHEXT") Ok(std::env::var_os("PATHEXT")
.ok_or(IchwhError::PathextNotDefined)? .ok_or(IchwhError::PathextNotDefined)?
@ -45,6 +45,11 @@ fn pathext() -> IchwhResult<Vec<String>> {
.collect::<Vec<_>>()) .collect::<Vec<_>>())
} }
#[cfg(all(windows, not(feature = "ichwh")))]
fn pathext() -> Result<Vec<String>, ()> {
Err(())
}
#[cfg(windows)] #[cfg(windows)]
fn is_executable(file: &DirEntry) -> bool { fn is_executable(file: &DirEntry) -> bool {
if let Ok(metadata) = file.metadata() { if let Ok(metadata) = file.metadata() {