switch from reqwest to surf

This commit is contained in:
Jonathan Turner 2019-08-25 07:36:19 +12:00 committed by Jacob Chae
parent 9c4f94fed5
commit c2e1616f70
17 changed files with 429 additions and 760 deletions

867
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -28,8 +28,8 @@ chrono-humanize = "0.0.11"
byte-unit = "3.0.1"
ordered-float = {version = "1.0.2", features = ["serde"]}
prettyprint = "0.7.0"
futures-preview = { version = "=0.3.0-alpha.18", features = ["compat", "io-compat"] }
futures-sink-preview = "=0.3.0-alpha.18"
futures-preview = { version = "=0.3.0-alpha.17", features = ["compat", "io-compat"] }
futures-sink-preview = "=0.3.0-alpha.17"
futures-async-stream = "0.1.0-alpha.1"
futures_codec = "0.2.5"
term = "0.5.2"
@ -52,7 +52,8 @@ dirs = "2.0.2"
glob = "0.3.0"
ctrlc = "3.1.3"
ptree = "0.2"
reqwest = "0.9"
surf = "1.0"
url = "2.1.0"
roxmltree = "0.7.0"
nom5_locate = "0.1.1"
enum-utils = "0.1.1"

View File

@ -166,7 +166,8 @@ impl InternalCommand {
&full_path,
&location,
Span::unknown(),
)?;
)
.await?;
if let Some(uuid) = contents_tag.origin {
// If we have loaded something, track its source

View File

@ -81,7 +81,7 @@ impl CallInfo {
pub fn process<'de, T: Deserialize<'de>>(
&self,
shell_manager: &ShellManager,
callback: fn(T, &RunnablePerItemContext) -> Result<VecDeque<ReturnValue>, ShellError>,
callback: fn(T, &RunnablePerItemContext) -> Result<OutputStream, ShellError>,
) -> Result<RunnablePerItemArgs<T>, ShellError> {
let mut deserializer = ConfigDeserializer::from_call_info(self.clone());
@ -250,11 +250,11 @@ impl RunnableContext {
pub struct RunnablePerItemArgs<T> {
args: T,
context: RunnablePerItemContext,
callback: fn(T, &RunnablePerItemContext) -> Result<VecDeque<ReturnValue>, ShellError>,
callback: fn(T, &RunnablePerItemContext) -> Result<OutputStream, ShellError>,
}
impl<T> RunnablePerItemArgs<T> {
pub fn run(self) -> Result<VecDeque<ReturnValue>, ShellError> {
pub fn run(self) -> Result<OutputStream, ShellError> {
(self.callback)(self.args, &self.context)
}
}
@ -485,7 +485,7 @@ pub trait PerItemCommand: Send + Sync {
registry: &CommandRegistry,
shell_manager: &ShellManager,
input: Tagged<Value>,
) -> Result<VecDeque<ReturnValue>, ShellError>;
) -> Result<OutputStream, ShellError>;
fn signature(&self) -> Signature {
Signature {
@ -552,7 +552,7 @@ impl Command {
.unwrap();
match command.run(&call_info, &registry, &raw_args.shell_manager, x) {
Ok(o) => o,
Err(e) => VecDeque::from(vec![ReturnValue::Err(e)]),
Err(e) => VecDeque::from(vec![ReturnValue::Err(e)]).to_output_stream(),
}
})
.flatten();

View File

@ -21,7 +21,7 @@ impl PerItemCommand for Cpy {
_registry: &CommandRegistry,
shell_manager: &ShellManager,
_input: Tagged<Value>,
) -> Result<VecDeque<ReturnValue>, ShellError> {
) -> Result<OutputStream, ShellError> {
call_info.process(shell_manager, cp)?.run()
}
@ -38,10 +38,7 @@ impl PerItemCommand for Cpy {
}
}
fn cp(
args: CopyArgs,
context: &RunnablePerItemContext,
) -> Result<VecDeque<ReturnValue>, ShellError> {
fn cp(args: CopyArgs, context: &RunnablePerItemContext) -> Result<OutputStream, ShellError> {
let shell_manager = context.shell_manager.clone();
shell_manager.cp(args, context)
}

View File

@ -21,7 +21,7 @@ impl PerItemCommand for Enter {
_registry: &registry::CommandRegistry,
_shell_manager: &ShellManager,
_input: Tagged<Value>,
) -> Result<VecDeque<ReturnValue>, ShellError> {
) -> Result<OutputStream, ShellError> {
match call_info.args.expect_nth(0)? {
Tagged {
item: Value::Primitive(Primitive::String(location)),

View File

@ -18,7 +18,7 @@ impl PerItemCommand for Mkdir {
_registry: &CommandRegistry,
shell_manager: &ShellManager,
_input: Tagged<Value>,
) -> Result<VecDeque<ReturnValue>, ShellError> {
) -> Result<OutputStream, ShellError> {
call_info.process(shell_manager, mkdir)?.run()
}
@ -31,10 +31,7 @@ impl PerItemCommand for Mkdir {
}
}
fn mkdir(
args: MkdirArgs,
context: &RunnablePerItemContext,
) -> Result<VecDeque<ReturnValue>, ShellError> {
fn mkdir(args: MkdirArgs, context: &RunnablePerItemContext) -> Result<OutputStream, ShellError> {
let shell_manager = context.shell_manager.clone();
shell_manager.mkdir(args, context)
}

View File

@ -31,15 +31,12 @@ impl PerItemCommand for Move {
_registry: &CommandRegistry,
shell_manager: &ShellManager,
_input: Tagged<Value>,
) -> Result<VecDeque<ReturnValue>, ShellError> {
) -> Result<OutputStream, ShellError> {
call_info.process(shell_manager, mv)?.run()
}
}
fn mv(
args: MoveArgs,
context: &RunnablePerItemContext,
) -> Result<VecDeque<ReturnValue>, ShellError> {
fn mv(args: MoveArgs, context: &RunnablePerItemContext) -> Result<OutputStream, ShellError> {
let shell_manager = context.shell_manager.clone();
shell_manager.mv(args, context)
}

View File

@ -7,6 +7,7 @@ use crate::prelude::*;
use mime::Mime;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use surf::mime;
use uuid::Uuid;
pub struct Open;
@ -27,15 +28,12 @@ impl PerItemCommand for Open {
_registry: &CommandRegistry,
shell_manager: &ShellManager,
_input: Tagged<Value>,
) -> Result<VecDeque<ReturnValue>, ShellError> {
) -> Result<OutputStream, ShellError> {
run(call_info, shell_manager)
}
}
fn run(
call_info: &CallInfo,
shell_manager: &ShellManager,
) -> Result<VecDeque<ReturnValue>, ShellError> {
fn run(call_info: &CallInfo, shell_manager: &ShellManager) -> Result<OutputStream, ShellError> {
let cwd = PathBuf::from(shell_manager.path());
let full_path = PathBuf::from(cwd);
@ -46,85 +44,101 @@ fn run(
{
file => file,
};
let path_str = path.as_string()?;
let path_span = path.span();
let name_span = call_info.name_span;
let has_raw = call_info.args.has("raw");
let (file_extension, contents, contents_tag, span_source) =
fetch(&full_path, &path_str, path.span())?;
let stream = async_stream_block! {
let file_extension = if call_info.args.has("raw") {
None
} else {
file_extension
};
//FIXME: unwraps
let mut stream = VecDeque::new();
let (file_extension, contents, contents_tag, span_source) =
fetch(&full_path, &path_str, path_span).await.unwrap();
if let Some(uuid) = contents_tag.origin {
// If we have loaded something, track its source
stream.push_back(ReturnSuccess::action(CommandAction::AddSpanSource(
uuid,
span_source,
)))
}
let file_extension = if has_raw {
None
} else {
file_extension
};
match contents {
Value::Primitive(Primitive::String(string)) => {
let value = parse_as_value(file_extension, string, contents_tag, call_info.name_span)?;
match value {
Tagged {
item: Value::List(list),
..
} => {
for elem in list {
stream.push_back(ReturnSuccess::value(elem));
}
}
x => stream.push_back(ReturnSuccess::value(x)),
}
if let Some(uuid) = contents_tag.origin {
// If we have loaded something, track its source
yield ReturnSuccess::action(CommandAction::AddSpanSource(
uuid,
span_source,
));
}
other => stream.push_back(ReturnSuccess::value(other.tagged(contents_tag))),
match contents {
Value::Primitive(Primitive::String(string)) => {
let value = parse_as_value(file_extension, string, contents_tag, name_span).unwrap();
match value {
Tagged {
item: Value::List(list),
..
} => {
for elem in list {
yield ReturnSuccess::value(elem);
}
}
x => yield ReturnSuccess::value(x),
}
}
other => yield ReturnSuccess::value(other.tagged(contents_tag)),
};
};
Ok(stream)
Ok(stream.to_output_stream())
}
pub fn fetch(
pub async fn fetch(
cwd: &PathBuf,
location: &str,
span: Span,
) -> Result<(Option<String>, Value, Tag, SpanSource), ShellError> {
let mut cwd = cwd.clone();
if location.starts_with("http:") || location.starts_with("https:") {
let response = reqwest::get(location);
let response = surf::get(location).await;
match response {
Ok(mut r) => match r.headers().get("content-type") {
Some(content_type) => {
let content_type = Mime::from_str(content_type.to_str().unwrap()).unwrap();
let content_type = Mime::from_str(content_type).unwrap();
match (content_type.type_(), content_type.subtype()) {
(mime::APPLICATION, mime::XML) => Ok((
Some("xml".to_string()),
Value::string(r.text().unwrap()),
Value::string(r.body_string().await.map_err(|_| {
ShellError::labeled_error(
"Could not load text from remote url",
"could not load",
span,
)
})?),
Tag {
span,
origin: Some(Uuid::new_v4()),
},
SpanSource::Url(r.url().to_string()),
SpanSource::Url(location.to_string()),
)),
(mime::APPLICATION, mime::JSON) => Ok((
Some("json".to_string()),
Value::string(r.text().unwrap()),
Value::string(r.body_string().await.map_err(|_| {
ShellError::labeled_error(
"Could not load text from remote url",
"could not load",
span,
)
})?),
Tag {
span,
origin: Some(Uuid::new_v4()),
},
SpanSource::Url(r.url().to_string()),
SpanSource::Url(location.to_string()),
)),
(mime::APPLICATION, mime::OCTET_STREAM) => {
let mut buf: Vec<u8> = vec![];
r.copy_to(&mut buf).map_err(|_| {
let buf: Vec<u8> = r.body_bytes().await.map_err(|_| {
ShellError::labeled_error(
"Could not load binary file",
"could not load",
@ -138,12 +152,11 @@ pub fn fetch(
span,
origin: Some(Uuid::new_v4()),
},
SpanSource::Url(r.url().to_string()),
SpanSource::Url(location.to_string()),
))
}
(mime::IMAGE, image_ty) => {
let mut buf: Vec<u8> = vec![];
r.copy_to(&mut buf).map_err(|_| {
let buf: Vec<u8> = r.body_bytes().await.map_err(|_| {
ShellError::labeled_error(
"Could not load image file",
"could not load",
@ -157,21 +170,27 @@ pub fn fetch(
span,
origin: Some(Uuid::new_v4()),
},
SpanSource::Url(r.url().to_string()),
SpanSource::Url(location.to_string()),
))
}
(mime::TEXT, mime::HTML) => Ok((
Some("html".to_string()),
Value::string(r.text().unwrap()),
Value::string(r.body_string().await.map_err(|_| {
ShellError::labeled_error(
"Could not load text from remote url",
"could not load",
span,
)
})?),
Tag {
span,
origin: Some(Uuid::new_v4()),
},
SpanSource::Url(r.url().to_string()),
SpanSource::Url(location.to_string()),
)),
(mime::TEXT, mime::PLAIN) => {
let path_extension = r
.url()
let path_extension = url::Url::parse(location)
.unwrap()
.path_segments()
.and_then(|segments| segments.last())
.and_then(|name| if name.is_empty() { None } else { Some(name) })
@ -183,12 +202,18 @@ pub fn fetch(
Ok((
path_extension,
Value::string(r.text().unwrap()),
Value::string(r.body_string().await.map_err(|_| {
ShellError::labeled_error(
"Could not load text from remote url",
"could not load",
span,
)
})?),
Tag {
span,
origin: Some(Uuid::new_v4()),
},
SpanSource::Url(r.url().to_string()),
SpanSource::Url(location.to_string()),
))
}
(ty, sub_ty) => Ok((
@ -201,7 +226,7 @@ pub fn fetch(
span,
origin: Some(Uuid::new_v4()),
},
SpanSource::Url(r.url().to_string()),
SpanSource::Url(location.to_string()),
)),
}
}
@ -212,7 +237,7 @@ pub fn fetch(
span,
origin: Some(Uuid::new_v4()),
},
SpanSource::Url(r.url().to_string()),
SpanSource::Url(location.to_string()),
)),
},
Err(_) => {

View File

@ -30,15 +30,12 @@ impl PerItemCommand for Remove {
_registry: &CommandRegistry,
shell_manager: &ShellManager,
_input: Tagged<Value>,
) -> Result<VecDeque<ReturnValue>, ShellError> {
) -> Result<OutputStream, ShellError> {
call_info.process(shell_manager, rm)?.run()
}
}
fn rm(
args: RemoveArgs,
context: &RunnablePerItemContext,
) -> Result<VecDeque<ReturnValue>, ShellError> {
fn rm(args: RemoveArgs, context: &RunnablePerItemContext) -> Result<OutputStream, ShellError> {
let shell_manager = context.shell_manager.clone();
shell_manager.rm(args, context)
}

View File

@ -21,10 +21,10 @@ impl PerItemCommand for Where {
_registry: &registry::CommandRegistry,
_shell_manager: &ShellManager,
input: Tagged<Value>,
) -> Result<VecDeque<ReturnValue>, ShellError> {
) -> Result<OutputStream, ShellError> {
let input_clone = input.clone();
let condition = call_info.args.expect_nth(0)?;
match condition {
let stream = match condition {
Tagged {
item: Value::Block(block),
tag,
@ -33,23 +33,29 @@ impl PerItemCommand for Where {
match result {
Ok(v) => {
if v.is_true() {
Ok(VecDeque::from(vec![Ok(ReturnSuccess::Value(input_clone))]))
VecDeque::from(vec![Ok(ReturnSuccess::Value(input_clone))])
} else {
Ok(VecDeque::new())
VecDeque::new()
}
}
Err(e) => Err(ShellError::labeled_error(
format!("Could not evaluate ({})", e.to_string()),
"could not evaluate",
tag.span,
)),
Err(e) => {
return Err(ShellError::labeled_error(
format!("Could not evaluate ({})", e.to_string()),
"could not evaluate",
tag.span,
))
}
}
}
Tagged { tag, .. } => Err(ShellError::labeled_error(
"Expected a condition",
"where needs a condition",
tag.span,
)),
}
Tagged { tag, .. } => {
return Err(ShellError::labeled_error(
"Expected a condition",
"where needs a condition",
tag.span,
))
}
};
Ok(stream.to_output_stream())
}
}

View File

@ -451,7 +451,6 @@ impl std::convert::From<serde_yaml::Error> for ShellError {
}
}
impl std::convert::From<toml::ser::Error> for ShellError {
fn from(input: toml::ser::Error) -> ShellError {
ProximateShellError::String(StringError {
@ -482,6 +481,16 @@ impl std::convert::From<regex::Error> for ShellError {
}
}
impl std::convert::From<Box<dyn std::error::Error + Send + Sync>> for ShellError {
fn from(input: Box<dyn std::error::Error + Send + Sync>) -> ShellError {
ProximateShellError::String(StringError {
title: format!("{:?}", input),
error: Value::nothing(),
})
.start()
}
}
pub trait ShellErrorUtils<T> {
fn unwrap_error(self, desc: impl Into<String>) -> Result<T, ShellError>;
}

View File

@ -308,7 +308,7 @@ fn view_text_value(value: &Tagged<Value>, source_map: &SourceMap) {
path.extension().map(|x| x.to_string_lossy().to_string())
}
SpanSource::Url(url) => {
let url = reqwest::Url::parse(url);
let url = url::Url::parse(url);
if let Ok(url) = url {
let url = url.clone();
if let Some(mut segments) = url.path_segments() {

View File

@ -221,7 +221,7 @@ impl Shell for FilesystemShell {
}: CopyArgs,
name: Span,
path: &str,
) -> Result<VecDeque<ReturnValue>, ShellError> {
) -> Result<OutputStream, ShellError> {
let name_span = name;
let mut source = PathBuf::from(path);
@ -491,7 +491,7 @@ impl Shell for FilesystemShell {
}
}
Ok(VecDeque::new())
Ok(OutputStream::empty())
}
fn mkdir(
@ -504,7 +504,7 @@ impl Shell for FilesystemShell {
// }: &RunnablePerItemContext,
name: Span,
path: &str,
) -> Result<VecDeque<ReturnValue>, ShellError> {
) -> Result<OutputStream, ShellError> {
let full_path = PathBuf::from(path);
if directories.len() == 0 {
@ -534,7 +534,7 @@ impl Shell for FilesystemShell {
}
}
Ok(VecDeque::new())
Ok(OutputStream::empty())
}
fn mv(
@ -542,7 +542,7 @@ impl Shell for FilesystemShell {
MoveArgs { src, dst }: MoveArgs,
name: Span,
path: &str,
) -> Result<VecDeque<ReturnValue>, ShellError> {
) -> Result<OutputStream, ShellError> {
let name_span = name;
let mut source = PathBuf::from(path);
@ -837,7 +837,7 @@ impl Shell for FilesystemShell {
}
}
Ok(VecDeque::new())
Ok(OutputStream::empty())
}
fn rm(
@ -845,7 +845,7 @@ impl Shell for FilesystemShell {
RemoveArgs { target, recursive }: RemoveArgs,
name: Span,
path: &str,
) -> Result<VecDeque<ReturnValue>, ShellError> {
) -> Result<OutputStream, ShellError> {
let name_span = name;
if target.item.to_str() == Some(".") || target.item.to_str() == Some("..") {
@ -941,7 +941,7 @@ impl Shell for FilesystemShell {
}
}
Ok(VecDeque::new())
Ok(OutputStream::empty())
}
fn path(&self) -> String {

View File

@ -12,30 +12,10 @@ pub trait Shell: std::fmt::Debug {
fn name(&self, source_map: &SourceMap) -> String;
fn ls(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError>;
fn cd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError>;
fn cp(
&self,
args: CopyArgs,
name: Span,
path: &str,
) -> Result<VecDeque<ReturnValue>, ShellError>;
fn mkdir(
&self,
args: MkdirArgs,
name: Span,
path: &str,
) -> Result<VecDeque<ReturnValue>, ShellError>;
fn mv(
&self,
args: MoveArgs,
name: Span,
path: &str,
) -> Result<VecDeque<ReturnValue>, ShellError>;
fn rm(
&self,
args: RemoveArgs,
name: Span,
path: &str,
) -> Result<VecDeque<ReturnValue>, ShellError>;
fn cp(&self, args: CopyArgs, name: Span, path: &str) -> Result<OutputStream, ShellError>;
fn mkdir(&self, args: MkdirArgs, name: Span, path: &str) -> Result<OutputStream, ShellError>;
fn mv(&self, args: MoveArgs, name: Span, path: &str) -> Result<OutputStream, ShellError>;
fn rm(&self, args: RemoveArgs, name: Span, path: &str) -> Result<OutputStream, ShellError>;
fn path(&self) -> String;
fn set_path(&mut self, path: String);

View File

@ -116,7 +116,7 @@ impl ShellManager {
&self,
args: CopyArgs,
context: &RunnablePerItemContext,
) -> Result<VecDeque<ReturnValue>, ShellError> {
) -> Result<OutputStream, ShellError> {
let env = self.shells.lock();
match env {
@ -136,7 +136,7 @@ impl ShellManager {
&self,
args: RemoveArgs,
context: &RunnablePerItemContext,
) -> Result<VecDeque<ReturnValue>, ShellError> {
) -> Result<OutputStream, ShellError> {
let env = self.shells.lock();
match env {
@ -156,7 +156,7 @@ impl ShellManager {
&self,
args: MkdirArgs,
context: &RunnablePerItemContext,
) -> Result<VecDeque<ReturnValue>, ShellError> {
) -> Result<OutputStream, ShellError> {
let env = self.shells.lock();
match env {
@ -176,7 +176,7 @@ impl ShellManager {
&self,
args: MoveArgs,
context: &RunnablePerItemContext,
) -> Result<VecDeque<ReturnValue>, ShellError> {
) -> Result<OutputStream, ShellError> {
let env = self.shells.lock();
match env {

View File

@ -103,12 +103,7 @@ impl Shell for ValueShell {
Ok(stream.into())
}
fn cp(
&self,
_args: CopyArgs,
name: Span,
_path: &str,
) -> Result<VecDeque<ReturnValue>, ShellError> {
fn cp(&self, _args: CopyArgs, name: Span, _path: &str) -> Result<OutputStream, ShellError> {
Err(ShellError::labeled_error(
"cp not currently supported on values",
"not currently supported",
@ -116,12 +111,7 @@ impl Shell for ValueShell {
))
}
fn mv(
&self,
_args: MoveArgs,
name: Span,
_path: &str,
) -> Result<VecDeque<ReturnValue>, ShellError> {
fn mv(&self, _args: MoveArgs, name: Span, _path: &str) -> Result<OutputStream, ShellError> {
Err(ShellError::labeled_error(
"mv not currently supported on values",
"not currently supported",
@ -129,12 +119,7 @@ impl Shell for ValueShell {
))
}
fn mkdir(
&self,
_args: MkdirArgs,
name: Span,
_path: &str,
) -> Result<VecDeque<ReturnValue>, ShellError> {
fn mkdir(&self, _args: MkdirArgs, name: Span, _path: &str) -> Result<OutputStream, ShellError> {
Err(ShellError::labeled_error(
"mkdir not currently supported on values",
"not currently supported",
@ -142,12 +127,7 @@ impl Shell for ValueShell {
))
}
fn rm(
&self,
_args: RemoveArgs,
name: Span,
_path: &str,
) -> Result<VecDeque<ReturnValue>, ShellError> {
fn rm(&self, _args: RemoveArgs, name: Span, _path: &str) -> Result<OutputStream, ShellError> {
Err(ShellError::labeled_error(
"rm not currently supported on values",
"not currently supported",