Extend 'Shell' with open and save capabilities (#2165)

* Extend 'Shell' with open and save capabilities

* clippy fix
This commit is contained in:
Jonathan Turner 2020-07-13 21:07:44 +12:00 committed by GitHub
parent 7a207a673b
commit 07594222c0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 138 additions and 29 deletions

View file

@ -1,17 +1,14 @@
use crate::commands::classified::maybe_text_codec::{MaybeTextCodec, StringOrBinary};
use crate::commands::classified::maybe_text_codec::StringOrBinary;
use crate::commands::constants::BAT_LANGUAGES;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use futures_codec::FramedRead;
use encoding_rs::{Encoding, UTF_8};
use futures_util::StreamExt;
use log::debug;
use nu_errors::ShellError;
use nu_protocol::{CommandAction, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
use nu_source::{AnchorLocation, Span, Tagged};
use std::path::PathBuf;
extern crate encoding_rs;
use crate::commands::constants::BAT_LANGUAGES;
use encoding_rs::*;
use futures::prelude::*;
use log::debug;
use std::fs::File;
pub struct Open;
@ -103,6 +100,7 @@ pub fn get_encoding(opt: Option<Tagged<String>>) -> Result<&'static Encoding, Sh
async fn open(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let cwd = PathBuf::from(args.shell_manager.path());
let registry = registry.clone();
let shell_manager = args.shell_manager.clone();
let (
OpenArgs {
@ -159,17 +157,8 @@ async fn open(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStr
} else {
Some(get_encoding(encoding)?)
};
let f = File::open(&path).map_err(|e| {
ShellError::labeled_error(
format!("Error opening file: {:?}", e),
"Error opening file",
path.span(),
)
})?;
let async_reader = futures::io::AllowStdIo::new(f);
let sob_stream = FramedRead::new(async_reader, MaybeTextCodec::new(with_encoding))
.map_err(|e| ShellError::unexpected(format!("AsyncRead failed in open function: {:?}", e)))
.into_stream();
let sob_stream = shell_manager.open(&path.item, path.tag.span, with_encoding)?;
let final_stream = sob_stream.map(move |x| {
// The tag that will used when returning a Value

View file

@ -170,7 +170,7 @@ async fn save(
let host = raw_args.host.clone();
let ctrl_c = raw_args.ctrl_c.clone();
let current_errors = raw_args.current_errors.clone();
let shell_manager = raw_args.shell_manager.clone();
let mut shell_manager = raw_args.shell_manager.clone();
let head = raw_args.call_info.args.head.clone();
let (
@ -219,7 +219,7 @@ async fn save(
host,
ctrl_c,
current_errors,
shell_manager,
shell_manager: shell_manager.clone(),
call_info: UnevaluatedCallInfo {
args: nu_protocol::hir::Call {
head,
@ -252,14 +252,7 @@ async fn save(
};
match content {
Ok(save_data) => match std::fs::write(full_path, save_data) {
Ok(_) => Ok(OutputStream::empty()),
Err(e) => Err(ShellError::labeled_error(
e.to_string(),
"IO error while saving",
name,
)),
},
Ok(save_data) => shell_manager.save(&full_path, &save_data, name.span),
Err(e) => Err(e),
}
}

View file

@ -18,6 +18,11 @@ use std::collections::HashMap;
use std::io::{Error, ErrorKind};
use std::path::{Path, PathBuf};
use crate::commands::classified::maybe_text_codec::{MaybeTextCodec, StringOrBinary};
use encoding_rs::Encoding;
use futures_codec::FramedRead;
use futures_util::TryStreamExt;
#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;
@ -679,6 +684,45 @@ impl Shell for FilesystemShell {
self.path = path.to_string_lossy().to_string();
}
fn open(
&self,
path: &PathBuf,
name: Span,
with_encoding: Option<&'static Encoding>,
) -> Result<BoxStream<'static, Result<StringOrBinary, ShellError>>, ShellError> {
let f = std::fs::File::open(&path).map_err(|e| {
ShellError::labeled_error(
format!("Error opening file: {:?}", e),
"Error opening file",
name,
)
})?;
let async_reader = futures::io::AllowStdIo::new(f);
let sob_stream = FramedRead::new(async_reader, MaybeTextCodec::new(with_encoding))
.map_err(|e| {
ShellError::unexpected(format!("AsyncRead failed in open function: {:?}", e))
})
.into_stream();
Ok(sob_stream.boxed())
}
fn save(
&mut self,
full_path: &PathBuf,
save_data: &[u8],
name: Span,
) -> Result<OutputStream, ShellError> {
match std::fs::write(full_path, save_data) {
Ok(_) => Ok(OutputStream::empty()),
Err(e) => Err(ShellError::labeled_error(
e.to_string(),
"IO error while saving",
name,
)),
}
}
fn complete(
&self,
line: &str,

View file

@ -12,6 +12,8 @@ use crate::shell::shell::Shell;
use std::ffi::OsStr;
use std::path::PathBuf;
use crate::commands::classified::maybe_text_codec::StringOrBinary;
use encoding_rs::Encoding;
use nu_errors::ShellError;
use nu_protocol::{
Primitive, ReturnSuccess, ShellTypeName, TaggedDictBuilder, UntaggedValue, Value,
@ -197,6 +199,28 @@ impl Shell for HelpShell {
Ok(OutputStream::empty())
}
fn open(
&self,
_path: &PathBuf,
_name: Span,
_with_encoding: Option<&'static Encoding>,
) -> Result<BoxStream<'static, Result<StringOrBinary, ShellError>>, ShellError> {
Err(ShellError::unimplemented(
"open on help shell is not supported",
))
}
fn save(
&mut self,
_path: &PathBuf,
_contents: &[u8],
_name: Span,
) -> Result<OutputStream, ShellError> {
Err(ShellError::unimplemented(
"save on help shell is not supported",
))
}
fn complete(
&self,
line: &str,

View file

@ -1,4 +1,5 @@
use crate::commands::cd::CdArgs;
use crate::commands::classified::maybe_text_codec::StringOrBinary;
use crate::commands::command::EvaluatedWholeStreamCommandArgs;
use crate::commands::cp::CopyArgs;
use crate::commands::ls::LsArgs;
@ -7,6 +8,7 @@ use crate::commands::move_::mv::Arguments as MvArgs;
use crate::commands::rm::RemoveArgs;
use crate::prelude::*;
use crate::stream::OutputStream;
use encoding_rs::Encoding;
use nu_errors::ShellError;
use std::path::PathBuf;
@ -28,6 +30,18 @@ pub trait Shell: std::fmt::Debug {
fn path(&self) -> String;
fn pwd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError>;
fn set_path(&mut self, path: String);
fn open(
&self,
path: &PathBuf,
name: Span,
with_encoding: Option<&'static Encoding>,
) -> Result<BoxStream<'static, Result<StringOrBinary, ShellError>>, ShellError>;
fn save(
&mut self,
path: &PathBuf,
contents: &[u8],
name: Span,
) -> Result<OutputStream, ShellError>;
fn complete(
&self,

View file

@ -1,4 +1,5 @@
use crate::commands::cd::CdArgs;
use crate::commands::classified::maybe_text_codec::StringOrBinary;
use crate::commands::command::EvaluatedWholeStreamCommandArgs;
use crate::commands::cp::CopyArgs;
use crate::commands::ls::LsArgs;
@ -9,6 +10,7 @@ use crate::prelude::*;
use crate::shell::filesystem_shell::FilesystemShell;
use crate::shell::shell::Shell;
use crate::stream::OutputStream;
use encoding_rs::Encoding;
use nu_errors::ShellError;
use parking_lot::Mutex;
use std::error::Error;
@ -81,6 +83,25 @@ impl ShellManager {
self.shells.lock()[self.current_shell()].set_path(path)
}
pub fn open(
&self,
full_path: &PathBuf,
name: Span,
with_encoding: Option<&'static Encoding>,
) -> Result<impl Stream<Item = Result<StringOrBinary, ShellError>> + Send + 'static, ShellError>
{
self.shells.lock()[self.current_shell()].open(full_path, name, with_encoding)
}
pub fn save(
&mut self,
full_path: &PathBuf,
save_data: &[u8],
name: Span,
) -> Result<OutputStream, ShellError> {
self.shells.lock()[self.current_shell()].save(full_path, save_data, name)
}
pub fn complete(
&self,
line: &str,

View file

@ -9,6 +9,8 @@ use crate::prelude::*;
use crate::shell::shell::Shell;
use crate::utils::ValueStructure;
use crate::commands::classified::maybe_text_codec::StringOrBinary;
use encoding_rs::Encoding;
use std::ffi::OsStr;
use std::path::{Path, PathBuf};
@ -230,6 +232,28 @@ impl Shell for ValueShell {
self.path = path;
}
fn open(
&self,
_path: &PathBuf,
_name: Span,
_with_encoding: Option<&'static Encoding>,
) -> Result<BoxStream<'static, Result<StringOrBinary, ShellError>>, ShellError> {
Err(ShellError::unimplemented(
"open on help shell is not supported",
))
}
fn save(
&mut self,
_path: &PathBuf,
_contents: &[u8],
_name: Span,
) -> Result<OutputStream, ShellError> {
Err(ShellError::unimplemented(
"save on help shell is not supported",
))
}
fn complete(
&self,
line: &str,