mirror of
https://github.com/nushell/nushell.git
synced 2024-11-26 18:33:50 +01:00
Port network/url
command (#452)
* feat: add url command * feat(network/url): add sub-command for url
This commit is contained in:
parent
5c27ffa42e
commit
c3b6e07de6
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -1610,6 +1610,7 @@ dependencies = [
|
|||||||
"toml",
|
"toml",
|
||||||
"trash",
|
"trash",
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
|
"url",
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ nu-parser = { path = "../nu-parser" }
|
|||||||
nu-ansi-term = { path = "../nu-ansi-term" }
|
nu-ansi-term = { path = "../nu-ansi-term" }
|
||||||
|
|
||||||
# Potential dependencies for extras
|
# Potential dependencies for extras
|
||||||
|
url = "2.2.1"
|
||||||
csv = "1.1.3"
|
csv = "1.1.3"
|
||||||
glob = "0.3.0"
|
glob = "0.3.0"
|
||||||
Inflector = "0.11"
|
Inflector = "0.11"
|
||||||
|
@ -7,7 +7,7 @@ use nu_protocol::{
|
|||||||
|
|
||||||
use crate::To;
|
use crate::To;
|
||||||
|
|
||||||
use super::{Date, From, Into, Math, Random, Split, Str};
|
use super::{Date, From, Into, Math, Random, Split, Str, Url};
|
||||||
|
|
||||||
pub fn test_examples(cmd: impl Command + 'static) {
|
pub fn test_examples(cmd: impl Command + 'static) {
|
||||||
let examples = cmd.examples();
|
let examples = cmd.examples();
|
||||||
@ -25,6 +25,7 @@ pub fn test_examples(cmd: impl Command + 'static) {
|
|||||||
working_set.add_decl(Box::new(Split));
|
working_set.add_decl(Box::new(Split));
|
||||||
working_set.add_decl(Box::new(Math));
|
working_set.add_decl(Box::new(Math));
|
||||||
working_set.add_decl(Box::new(Date));
|
working_set.add_decl(Box::new(Date));
|
||||||
|
working_set.add_decl(Box::new(Url));
|
||||||
|
|
||||||
use super::Echo;
|
use super::Echo;
|
||||||
working_set.add_decl(Box::new(Echo));
|
working_set.add_decl(Box::new(Echo));
|
||||||
|
@ -17,6 +17,7 @@ mod yaml;
|
|||||||
|
|
||||||
pub use self::csv::FromCsv;
|
pub use self::csv::FromCsv;
|
||||||
pub use self::toml::FromToml;
|
pub use self::toml::FromToml;
|
||||||
|
pub use self::url::FromUrl;
|
||||||
pub use command::From;
|
pub use command::From;
|
||||||
pub use eml::FromEml;
|
pub use eml::FromEml;
|
||||||
pub use ics::FromIcs;
|
pub use ics::FromIcs;
|
||||||
@ -25,7 +26,6 @@ pub use json::FromJson;
|
|||||||
pub use ods::FromOds;
|
pub use ods::FromOds;
|
||||||
pub use ssv::FromSsv;
|
pub use ssv::FromSsv;
|
||||||
pub use tsv::FromTsv;
|
pub use tsv::FromTsv;
|
||||||
pub use url::FromUrl;
|
|
||||||
pub use vcf::FromVcf;
|
pub use vcf::FromVcf;
|
||||||
pub use xlsx::FromXlsx;
|
pub use xlsx::FromXlsx;
|
||||||
pub use xml::FromXml;
|
pub use xml::FromXml;
|
||||||
|
@ -8,7 +8,7 @@ mod url;
|
|||||||
|
|
||||||
pub use self::csv::ToCsv;
|
pub use self::csv::ToCsv;
|
||||||
pub use self::toml::ToToml;
|
pub use self::toml::ToToml;
|
||||||
|
pub use self::url::ToUrl;
|
||||||
pub use command::To;
|
pub use command::To;
|
||||||
pub use json::ToJson;
|
pub use json::ToJson;
|
||||||
pub use tsv::ToTsv;
|
pub use tsv::ToTsv;
|
||||||
pub use url::ToUrl;
|
|
||||||
|
@ -10,6 +10,7 @@ mod filesystem;
|
|||||||
mod filters;
|
mod filters;
|
||||||
mod formats;
|
mod formats;
|
||||||
mod math;
|
mod math;
|
||||||
|
mod network;
|
||||||
mod platform;
|
mod platform;
|
||||||
mod random;
|
mod random;
|
||||||
mod shells;
|
mod shells;
|
||||||
@ -29,6 +30,7 @@ pub use filesystem::*;
|
|||||||
pub use filters::*;
|
pub use filters::*;
|
||||||
pub use formats::*;
|
pub use formats::*;
|
||||||
pub use math::*;
|
pub use math::*;
|
||||||
|
pub use network::*;
|
||||||
pub use platform::*;
|
pub use platform::*;
|
||||||
pub use random::*;
|
pub use random::*;
|
||||||
pub use shells::*;
|
pub use shells::*;
|
||||||
|
3
crates/nu-command/src/network/mod.rs
Normal file
3
crates/nu-command/src/network/mod.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
mod url;
|
||||||
|
|
||||||
|
pub use self::url::*;
|
37
crates/nu-command/src/network/url/command.rs
Normal file
37
crates/nu-command/src/network/url/command.rs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
use nu_engine::get_full_help;
|
||||||
|
use nu_protocol::{
|
||||||
|
ast::Call,
|
||||||
|
engine::{Command, EngineState, Stack},
|
||||||
|
Category, IntoPipelineData, PipelineData, Signature, Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Url;
|
||||||
|
|
||||||
|
impl Command for Url {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"url"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("url").category(Category::Network)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Apply url function."
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
_stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
_input: PipelineData,
|
||||||
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
|
Ok(Value::String {
|
||||||
|
val: get_full_help(&Url.signature(), &Url.examples(), engine_state),
|
||||||
|
span: call.head,
|
||||||
|
}
|
||||||
|
.into_pipeline_data())
|
||||||
|
}
|
||||||
|
}
|
65
crates/nu-command/src/network/url/host.rs
Normal file
65
crates/nu-command/src/network/url/host.rs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
use super::{operator, url};
|
||||||
|
use nu_protocol::ast::Call;
|
||||||
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
|
use nu_protocol::{Category, Example, PipelineData, Signature, Span, SyntaxShape, Value};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SubCommand;
|
||||||
|
|
||||||
|
impl Command for SubCommand {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"url host"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("url host")
|
||||||
|
.rest(
|
||||||
|
"rest",
|
||||||
|
SyntaxShape::CellPath,
|
||||||
|
"optionally operate by cell path",
|
||||||
|
)
|
||||||
|
.category(Category::Network)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"gets the host of a url"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
|
operator(engine_state, stack, call, input, &host)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
let span = Span::unknown();
|
||||||
|
vec![Example {
|
||||||
|
description: "Get host of a url",
|
||||||
|
example: "echo 'http://www.example.com/foo/bar' | url host",
|
||||||
|
result: Some(Value::String {
|
||||||
|
val: "www.example.com".to_string(),
|
||||||
|
span,
|
||||||
|
}),
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn host(url: &url::Url) -> &str {
|
||||||
|
url.host_str().unwrap_or("")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
use crate::test_examples;
|
||||||
|
|
||||||
|
test_examples(SubCommand {})
|
||||||
|
}
|
||||||
|
}
|
92
crates/nu-command/src/network/url/mod.rs
Normal file
92
crates/nu-command/src/network/url/mod.rs
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
mod command;
|
||||||
|
mod host;
|
||||||
|
mod path;
|
||||||
|
mod query;
|
||||||
|
mod scheme;
|
||||||
|
|
||||||
|
use nu_engine::CallExt;
|
||||||
|
use nu_protocol::{
|
||||||
|
ast::{Call, CellPath},
|
||||||
|
engine::{EngineState, Stack},
|
||||||
|
PipelineData, ShellError, Span, Value,
|
||||||
|
};
|
||||||
|
use url::{self};
|
||||||
|
|
||||||
|
pub use self::host::SubCommand as UrlHost;
|
||||||
|
pub use self::path::SubCommand as UrlPath;
|
||||||
|
pub use self::query::SubCommand as UrlQuery;
|
||||||
|
pub use self::scheme::SubCommand as UrlScheme;
|
||||||
|
pub use command::Url;
|
||||||
|
|
||||||
|
fn handle_value<F>(action: &F, v: &Value, span: Span) -> Value
|
||||||
|
where
|
||||||
|
F: Fn(&url::Url) -> &str + Send + 'static,
|
||||||
|
{
|
||||||
|
let a = |url| Value::String {
|
||||||
|
val: action(url).to_string(),
|
||||||
|
span,
|
||||||
|
};
|
||||||
|
|
||||||
|
match v {
|
||||||
|
Value::String { val: s, .. } => {
|
||||||
|
let s = s.trim();
|
||||||
|
|
||||||
|
match url::Url::parse(s) {
|
||||||
|
Ok(url) => a(&url),
|
||||||
|
Err(_) => Value::String {
|
||||||
|
val: "".to_string(),
|
||||||
|
span,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
other => {
|
||||||
|
let span = other.span();
|
||||||
|
match span {
|
||||||
|
Ok(s) => {
|
||||||
|
let got = format!("Expected a string, got {} instead", other.get_type());
|
||||||
|
Value::Error {
|
||||||
|
error: ShellError::UnsupportedInput(got, s),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => Value::Error { error: e },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn operator<F>(
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
action: &'static F,
|
||||||
|
) -> Result<PipelineData, ShellError>
|
||||||
|
where
|
||||||
|
F: Fn(&url::Url) -> &str + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
let span = call.head;
|
||||||
|
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
||||||
|
|
||||||
|
input.map(
|
||||||
|
move |v| {
|
||||||
|
if column_paths.is_empty() {
|
||||||
|
handle_value(&action, &v, span)
|
||||||
|
} else {
|
||||||
|
let mut ret = v;
|
||||||
|
|
||||||
|
for path in &column_paths {
|
||||||
|
let r = ret.update_cell_path(
|
||||||
|
&path.members,
|
||||||
|
Box::new(move |old| handle_value(&action, old, span)),
|
||||||
|
);
|
||||||
|
if let Err(error) = r {
|
||||||
|
return Value::Error { error };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
},
|
||||||
|
engine_state.ctrlc.clone(),
|
||||||
|
)
|
||||||
|
}
|
71
crates/nu-command/src/network/url/path.rs
Normal file
71
crates/nu-command/src/network/url/path.rs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
use super::{operator, url};
|
||||||
|
use nu_protocol::ast::Call;
|
||||||
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
|
use nu_protocol::{Category, Example, PipelineData, Signature, Span, SyntaxShape, Value};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SubCommand;
|
||||||
|
|
||||||
|
impl Command for SubCommand {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"url path"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("url path")
|
||||||
|
.rest(
|
||||||
|
"rest",
|
||||||
|
SyntaxShape::CellPath,
|
||||||
|
"optionally operate by cell path",
|
||||||
|
)
|
||||||
|
.category(Category::Network)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"gets the path of a url"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
|
operator(engine_state, stack, call, input, &url::Url::path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
let span = Span::unknown();
|
||||||
|
vec![
|
||||||
|
Example {
|
||||||
|
description: "Get path of a url",
|
||||||
|
example: "echo 'http://www.example.com/foo/bar' | url path",
|
||||||
|
result: Some(Value::String {
|
||||||
|
val: "/foo/bar".to_string(),
|
||||||
|
span,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "A trailing slash will be reflected in the path",
|
||||||
|
example: "echo 'http://www.example.com' | url path",
|
||||||
|
result: Some(Value::String {
|
||||||
|
val: "/".to_string(),
|
||||||
|
span,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
use crate::test_examples;
|
||||||
|
|
||||||
|
test_examples(SubCommand {})
|
||||||
|
}
|
||||||
|
}
|
75
crates/nu-command/src/network/url/query.rs
Normal file
75
crates/nu-command/src/network/url/query.rs
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
use super::{operator, url};
|
||||||
|
use nu_protocol::ast::Call;
|
||||||
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
|
use nu_protocol::{Category, Example, PipelineData, Signature, Span, SyntaxShape, Value};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SubCommand;
|
||||||
|
|
||||||
|
impl Command for SubCommand {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"url query"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("url query")
|
||||||
|
.rest(
|
||||||
|
"rest",
|
||||||
|
SyntaxShape::CellPath,
|
||||||
|
"optionally operate by cell path",
|
||||||
|
)
|
||||||
|
.category(Category::Network)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"gets the query of a url"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
|
operator(engine_state, stack, call, input, &query)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
let span = Span::unknown();
|
||||||
|
vec![
|
||||||
|
Example {
|
||||||
|
description: "Get query of a url",
|
||||||
|
example: "echo 'http://www.example.com/?foo=bar&baz=quux' | url query",
|
||||||
|
result: Some(Value::String {
|
||||||
|
val: "foo=bar&baz=quux".to_string(),
|
||||||
|
span,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "No query gives the empty string",
|
||||||
|
example: "echo 'http://www.example.com/' | url query",
|
||||||
|
result: Some(Value::String {
|
||||||
|
val: "".to_string(),
|
||||||
|
span,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn query(url: &url::Url) -> &str {
|
||||||
|
url.query().unwrap_or("")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
use crate::test_examples;
|
||||||
|
|
||||||
|
test_examples(SubCommand {})
|
||||||
|
}
|
||||||
|
}
|
71
crates/nu-command/src/network/url/scheme.rs
Normal file
71
crates/nu-command/src/network/url/scheme.rs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
use super::{operator, url};
|
||||||
|
use nu_protocol::ast::Call;
|
||||||
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
|
use nu_protocol::{Category, Example, PipelineData, Signature, Span, SyntaxShape, Value};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SubCommand;
|
||||||
|
|
||||||
|
impl Command for SubCommand {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"url scheme"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("url scheme")
|
||||||
|
.rest(
|
||||||
|
"rest",
|
||||||
|
SyntaxShape::CellPath,
|
||||||
|
"optionally operate by cell path",
|
||||||
|
)
|
||||||
|
.category(Category::Network)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"gets the scheme (eg http, file) of a url"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
|
operator(engine_state, stack, call, input, &url::Url::scheme)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
let span = Span::unknown();
|
||||||
|
vec![
|
||||||
|
Example {
|
||||||
|
description: "Get scheme of a url",
|
||||||
|
example: "echo 'http://www.example.com' | url scheme",
|
||||||
|
result: Some(Value::String {
|
||||||
|
val: "http".to_string(),
|
||||||
|
span,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "You get an empty string if there is no scheme",
|
||||||
|
example: "echo 'test' | url scheme",
|
||||||
|
result: Some(Value::String {
|
||||||
|
val: "".to_string(),
|
||||||
|
span,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
use crate::test_examples;
|
||||||
|
|
||||||
|
test_examples(SubCommand {})
|
||||||
|
}
|
||||||
|
}
|
@ -42,6 +42,7 @@ pub enum Category {
|
|||||||
Filters,
|
Filters,
|
||||||
Formats,
|
Formats,
|
||||||
Math,
|
Math,
|
||||||
|
Network,
|
||||||
Random,
|
Random,
|
||||||
Platform,
|
Platform,
|
||||||
Shells,
|
Shells,
|
||||||
@ -64,6 +65,7 @@ impl std::fmt::Display for Category {
|
|||||||
Category::Filters => "filters",
|
Category::Filters => "filters",
|
||||||
Category::Formats => "formats",
|
Category::Formats => "formats",
|
||||||
Category::Math => "math",
|
Category::Math => "math",
|
||||||
|
Category::Network => "network",
|
||||||
Category::Random => "random",
|
Category::Random => "random",
|
||||||
Category::Platform => "platform",
|
Category::Platform => "platform",
|
||||||
Category::Shells => "shells",
|
Category::Shells => "shells",
|
||||||
|
Loading…
Reference in New Issue
Block a user