forked from extern/nushell
Unwrap cleanup mitigation.
This commit is contained in:
parent
8b79b28971
commit
8d5fd6f379
@ -238,6 +238,7 @@ pub struct RunnableContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RunnableContext {
|
impl RunnableContext {
|
||||||
|
#[allow(unused)]
|
||||||
pub fn cwd(&self) -> PathBuf {
|
pub fn cwd(&self) -> PathBuf {
|
||||||
PathBuf::from(self.shell_manager.path())
|
PathBuf::from(self.shell_manager.path())
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,8 @@ pub struct Cpy;
|
|||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct CopyArgs {
|
pub struct CopyArgs {
|
||||||
source: Tagged<PathBuf>,
|
src: Tagged<PathBuf>,
|
||||||
destination: Tagged<PathBuf>,
|
dst: Tagged<PathBuf>,
|
||||||
recursive: Tagged<bool>,
|
recursive: Tagged<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,44 +32,43 @@ impl PerItemCommand for Cpy {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("cp")
|
Signature::build("cp")
|
||||||
.required("source", SyntaxType::Path)
|
.required("src", SyntaxType::Path)
|
||||||
.required("destination", SyntaxType::Path)
|
.required("dst", SyntaxType::Path)
|
||||||
.named("file", SyntaxType::Any)
|
.named("file", SyntaxType::Any)
|
||||||
.switch("recursive")
|
.switch("recursive")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cp(
|
fn cp(
|
||||||
args: CopyArgs,
|
CopyArgs {
|
||||||
context: &RunnablePerItemContext,
|
src,
|
||||||
|
dst,
|
||||||
|
recursive,
|
||||||
|
}: CopyArgs,
|
||||||
|
RunnablePerItemContext { name, .. }: &RunnablePerItemContext,
|
||||||
) -> Result<VecDeque<ReturnValue>, ShellError> {
|
) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||||
let mut source = PathBuf::from(context.shell_manager.path());
|
let source = src.item.clone();
|
||||||
let mut destination = PathBuf::from(context.shell_manager.path());
|
let mut destination = dst.item.clone();
|
||||||
let name_span = context.name;
|
let name_span = name;
|
||||||
|
|
||||||
source.push(&args.source.item);
|
let sources: Vec<_> = match glob::glob(&source.to_string_lossy()) {
|
||||||
|
Ok(files) => files.collect(),
|
||||||
destination.push(&args.destination.item);
|
Err(_) => {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
let sources = glob::glob(&source.to_string_lossy());
|
"Invalid pattern.",
|
||||||
|
"Invalid pattern.",
|
||||||
if sources.is_err() {
|
src.tag,
|
||||||
return Err(ShellError::labeled_error(
|
))
|
||||||
"Invalid pattern.",
|
}
|
||||||
"Invalid pattern.",
|
};
|
||||||
args.source.tag,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let sources: Vec<_> = sources.unwrap().collect();
|
|
||||||
|
|
||||||
if sources.len() == 1 {
|
if sources.len() == 1 {
|
||||||
if let Ok(entry) = &sources[0] {
|
if let Ok(entry) = &sources[0] {
|
||||||
if entry.is_dir() && !args.recursive.item {
|
if entry.is_dir() && !recursive.item {
|
||||||
return Err(ShellError::labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
"is a directory (not copied). Try using \"--recursive\".",
|
"is a directory (not copied). Try using \"--recursive\".",
|
||||||
"is a directory (not copied). Try using \"--recursive\".",
|
"is a directory (not copied). Try using \"--recursive\".",
|
||||||
args.source.tag,
|
src.tag,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,7 +166,16 @@ pub fn cp(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
destination.push(entry.file_name().unwrap());
|
match entry.file_name() {
|
||||||
|
Some(name) => destination.push(name),
|
||||||
|
None => {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
"Copy aborted. Not a valid path",
|
||||||
|
"Copy aborted. Not a valid path",
|
||||||
|
name_span,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match std::fs::create_dir_all(&destination) {
|
match std::fs::create_dir_all(&destination) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@ -234,18 +242,31 @@ pub fn cp(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if destination.exists() {
|
if destination.exists() {
|
||||||
if !sources.iter().all(|x| (x.as_ref().unwrap()).is_file()) {
|
if !sources.iter().all(|x| match x {
|
||||||
|
Ok(f) => f.is_file(),
|
||||||
|
Err(_) => false,
|
||||||
|
}) {
|
||||||
return Err(ShellError::labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
"Copy aborted (directories found). Recursive copying in patterns not supported yet (try copying the directory directly)",
|
"Copy aborted (directories found). Recursive copying in patterns not supported yet (try copying the directory directly)",
|
||||||
"Copy aborted (directories found). Recursive copying in patterns not supported yet (try copying the directory directly)",
|
"Copy aborted (directories found). Recursive copying in patterns not supported yet (try copying the directory directly)",
|
||||||
args.source.tag,
|
src.tag,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
for entry in sources {
|
for entry in sources {
|
||||||
if let Ok(entry) = entry {
|
if let Ok(entry) = entry {
|
||||||
let mut to = PathBuf::from(&destination);
|
let mut to = PathBuf::from(&destination);
|
||||||
to.push(&entry.file_name().unwrap());
|
|
||||||
|
match entry.file_name() {
|
||||||
|
Some(name) => to.push(name),
|
||||||
|
None => {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
"Copy aborted. Not a valid path",
|
||||||
|
"Copy aborted. Not a valid path",
|
||||||
|
name_span,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if entry.is_file() {
|
if entry.is_file() {
|
||||||
match std::fs::copy(&entry, &to) {
|
match std::fs::copy(&entry, &to) {
|
||||||
@ -253,7 +274,7 @@ pub fn cp(
|
|||||||
return Err(ShellError::labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
e.to_string(),
|
e.to_string(),
|
||||||
e.to_string(),
|
e.to_string(),
|
||||||
args.source.tag,
|
src.tag,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
Ok(o) => o,
|
Ok(o) => o,
|
||||||
@ -262,16 +283,23 @@ pub fn cp(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
let destination_file_name = {
|
||||||
|
match destination.file_name() {
|
||||||
|
Some(name) => PathBuf::from(name),
|
||||||
|
None => {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
"Copy aborted. Not a valid destination",
|
||||||
|
"Copy aborted. Not a valid destination",
|
||||||
|
name_span,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return Err(ShellError::labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
format!(
|
format!("Copy aborted. (Does {:?} exist?)", destination_file_name),
|
||||||
"Copy aborted. (Does {:?} exist?)",
|
format!("Copy aborted. (Does {:?} exist?)", destination_file_name),
|
||||||
&destination.file_name().unwrap()
|
&dst.span(),
|
||||||
),
|
|
||||||
format!(
|
|
||||||
"Copy aborted. (Does {:?} exist?)",
|
|
||||||
&destination.file_name().unwrap()
|
|
||||||
),
|
|
||||||
args.destination.span(),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,15 +5,12 @@ use crate::parser::registry::{CommandRegistry, Signature};
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
use crate::utils::FileStructure;
|
|
||||||
|
|
||||||
pub struct Move;
|
pub struct Move;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct MoveArgs {
|
pub struct MoveArgs {
|
||||||
source: Tagged<PathBuf>,
|
src: Tagged<PathBuf>,
|
||||||
destination: Tagged<PathBuf>,
|
dst: Tagged<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PerItemCommand for Move {
|
impl PerItemCommand for Move {
|
||||||
@ -39,17 +36,16 @@ impl PerItemCommand for Move {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mv(
|
fn mv(
|
||||||
args: MoveArgs,
|
MoveArgs { src, dst }: MoveArgs,
|
||||||
context: &RunnablePerItemContext,
|
RunnablePerItemContext {
|
||||||
|
name,
|
||||||
|
shell_manager,
|
||||||
|
}: &RunnablePerItemContext,
|
||||||
) -> Result<VecDeque<ReturnValue>, ShellError> {
|
) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||||
let mut source = PathBuf::from(context.shell_manager.path());
|
let source = src.item.clone();
|
||||||
let mut destination = PathBuf::from(context.shell_manager.path());
|
let mut destination = dst.item.clone();
|
||||||
let name_span = context.name;
|
let name_span = name;
|
||||||
|
|
||||||
source.push(&args.source.item);
|
|
||||||
|
|
||||||
destination.push(&args.destination.item);
|
|
||||||
|
|
||||||
let sources: Vec<_> = match glob::glob(&source.to_string_lossy()) {
|
let sources: Vec<_> = match glob::glob(&source.to_string_lossy()) {
|
||||||
Ok(files) => files.collect(),
|
Ok(files) => files.collect(),
|
||||||
@ -57,21 +53,23 @@ pub fn mv(
|
|||||||
return Err(ShellError::labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
"Invalid pattern.",
|
"Invalid pattern.",
|
||||||
"Invalid pattern.",
|
"Invalid pattern.",
|
||||||
args.source.tag,
|
src.tag,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let destination_file_name = {
|
if "." == destination.to_string_lossy() {
|
||||||
let path = &destination;
|
destination = PathBuf::from(shell_manager.path());
|
||||||
|
}
|
||||||
|
|
||||||
match path.file_name() {
|
let destination_file_name = {
|
||||||
|
match destination.file_name() {
|
||||||
Some(name) => PathBuf::from(name),
|
Some(name) => PathBuf::from(name),
|
||||||
None => {
|
None => {
|
||||||
return Err(ShellError::labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
"Rename aborted. Not a valid destination",
|
"Rename aborted. Not a valid destination",
|
||||||
"Rename aborted. Not a valid destination",
|
"Rename aborted. Not a valid destination",
|
||||||
name_span,
|
dst.span(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,6 +172,8 @@ pub fn mv(
|
|||||||
}
|
}
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
{
|
{
|
||||||
|
use crate::utils::FileStructure;
|
||||||
|
|
||||||
let mut sources: FileStructure = FileStructure::new();
|
let mut sources: FileStructure = FileStructure::new();
|
||||||
|
|
||||||
sources.walk_decorate(&entry)?;
|
sources.walk_decorate(&entry)?;
|
||||||
@ -284,7 +284,7 @@ pub fn mv(
|
|||||||
return Err(ShellError::labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
"Rename aborted (directories found). Renaming in patterns not supported yet (try moving the directory directly)",
|
"Rename aborted (directories found). Renaming in patterns not supported yet (try moving the directory directly)",
|
||||||
"Rename aborted (directories found). Renaming in patterns not supported yet (try moving the directory directly)",
|
"Rename aborted (directories found). Renaming in patterns not supported yet (try moving the directory directly)",
|
||||||
args.source.tag,
|
src.tag,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,7 +332,7 @@ pub fn mv(
|
|||||||
return Err(ShellError::labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
format!("Rename aborted. (Does {:?} exist?)", destination_file_name),
|
format!("Rename aborted. (Does {:?} exist?)", destination_file_name),
|
||||||
format!("Rename aborted. (Does {:?} exist?)", destination_file_name),
|
format!("Rename aborted. (Does {:?} exist?)", destination_file_name),
|
||||||
args.destination.span(),
|
dst.span(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,14 +12,6 @@ struct PickArgs {
|
|||||||
pub struct Pick;
|
pub struct Pick;
|
||||||
|
|
||||||
impl WholeStreamCommand for Pick {
|
impl WholeStreamCommand for Pick {
|
||||||
fn run(
|
|
||||||
&self,
|
|
||||||
args: CommandArgs,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<OutputStream, ShellError> {
|
|
||||||
args.process(registry, pick)?.run()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"pick"
|
"pick"
|
||||||
}
|
}
|
||||||
@ -27,6 +19,14 @@ impl WholeStreamCommand for Pick {
|
|||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("pick").rest()
|
Signature::build("pick").rest()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
args: CommandArgs,
|
||||||
|
registry: &CommandRegistry,
|
||||||
|
) -> Result<OutputStream, ShellError> {
|
||||||
|
args.process(registry, pick)?.run()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pick(
|
fn pick(
|
||||||
|
@ -10,7 +10,7 @@ pub struct Remove;
|
|||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct RemoveArgs {
|
pub struct RemoveArgs {
|
||||||
path: Tagged<PathBuf>,
|
target: Tagged<PathBuf>,
|
||||||
recursive: Tagged<bool>,
|
recursive: Tagged<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,32 +36,30 @@ impl PerItemCommand for Remove {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rm(
|
fn rm(
|
||||||
args: RemoveArgs,
|
RemoveArgs { target, recursive }: RemoveArgs,
|
||||||
context: &RunnablePerItemContext,
|
RunnablePerItemContext { name, .. }: &RunnablePerItemContext,
|
||||||
) -> Result<VecDeque<ReturnValue>, ShellError> {
|
) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||||
let mut path = PathBuf::from(context.shell_manager.path());
|
let path = target.item.clone();
|
||||||
let name_span = context.name;
|
let name_span = name;
|
||||||
|
|
||||||
let file = &args.path.item.to_string_lossy();
|
let file = path.to_string_lossy();
|
||||||
|
|
||||||
if file == "." || file == ".." {
|
if file == "." || file == ".." {
|
||||||
return Err(ShellError::labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
"Remove aborted. \".\" or \"..\" may not be removed.",
|
"Remove aborted. \".\" or \"..\" may not be removed.",
|
||||||
"Remove aborted. \".\" or \"..\" may not be removed.",
|
"Remove aborted. \".\" or \"..\" may not be removed.",
|
||||||
args.path.span(),
|
target.span(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
path.push(&args.path.item);
|
|
||||||
|
|
||||||
let entries: Vec<_> = match glob::glob(&path.to_string_lossy()) {
|
let entries: Vec<_> = match glob::glob(&path.to_string_lossy()) {
|
||||||
Ok(files) => files.collect(),
|
Ok(files) => files.collect(),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
return Err(ShellError::labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
"Invalid pattern.",
|
"Invalid pattern.",
|
||||||
"Invalid pattern.",
|
"Invalid pattern.",
|
||||||
args.path.tag,
|
target.tag,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -73,17 +71,11 @@ pub fn rm(
|
|||||||
|
|
||||||
source_dir.walk_decorate(&entry)?;
|
source_dir.walk_decorate(&entry)?;
|
||||||
|
|
||||||
if source_dir.contains_files() && !args.recursive.item {
|
if source_dir.contains_files() && !recursive.item {
|
||||||
return Err(ShellError::labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
format!(
|
format!("{:?} is a directory. Try using \"--recursive\".", file),
|
||||||
"{:?} is a directory. Try using \"--recursive\".",
|
format!("{:?} is a directory. Try using \"--recursive\".", file),
|
||||||
&args.path.item.to_string_lossy()
|
target.span(),
|
||||||
),
|
|
||||||
format!(
|
|
||||||
"{:?} is a directory. Try using \"--recursive\".",
|
|
||||||
&args.path.item.to_string_lossy()
|
|
||||||
),
|
|
||||||
args.path.span(),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,9 +86,7 @@ pub fn rm(
|
|||||||
match entry {
|
match entry {
|
||||||
Ok(path) => {
|
Ok(path) => {
|
||||||
let path_file_name = {
|
let path_file_name = {
|
||||||
let p = &path;
|
match path.file_name() {
|
||||||
|
|
||||||
match p.file_name() {
|
|
||||||
Some(name) => PathBuf::from(name),
|
Some(name) => PathBuf::from(name),
|
||||||
None => {
|
None => {
|
||||||
return Err(ShellError::labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
@ -112,7 +102,7 @@ pub fn rm(
|
|||||||
|
|
||||||
source_dir.walk_decorate(&path)?;
|
source_dir.walk_decorate(&path)?;
|
||||||
|
|
||||||
if source_dir.contains_more_than_one_file() && !args.recursive.item {
|
if source_dir.contains_more_than_one_file() && !recursive.item {
|
||||||
return Err(ShellError::labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
format!(
|
format!(
|
||||||
"Directory {:?} found somewhere inside. Try using \"--recursive\".",
|
"Directory {:?} found somewhere inside. Try using \"--recursive\".",
|
||||||
@ -122,7 +112,7 @@ pub fn rm(
|
|||||||
"Directory {:?} found somewhere inside. Try using \"--recursive\".",
|
"Directory {:?} found somewhere inside. Try using \"--recursive\".",
|
||||||
path_file_name
|
path_file_name
|
||||||
),
|
),
|
||||||
args.path.span(),
|
target.span(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,19 +36,26 @@ impl WholeStreamCommand for Save {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save(
|
fn save(
|
||||||
SaveArgs {
|
SaveArgs {
|
||||||
path,
|
path,
|
||||||
raw: save_raw,
|
raw: save_raw,
|
||||||
}: SaveArgs,
|
}: SaveArgs,
|
||||||
context: RunnableContext,
|
RunnableContext {
|
||||||
|
input,
|
||||||
|
name,
|
||||||
|
shell_manager,
|
||||||
|
source_map,
|
||||||
|
..
|
||||||
|
}: RunnableContext,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let mut full_path = context.cwd();
|
let mut full_path = PathBuf::from(shell_manager.path());
|
||||||
|
let name_span = name;
|
||||||
|
|
||||||
if path.is_none() {
|
if path.is_none() {
|
||||||
let source_map = context.source_map.clone();
|
let source_map = source_map.clone();
|
||||||
let stream = async_stream_block! {
|
let stream = async_stream_block! {
|
||||||
let input: Vec<Tagged<Value>> = context.input.values.collect().await;
|
let input: Vec<Tagged<Value>> = input.values.collect().await;
|
||||||
// If there is no filename, check the metadata for the origin filename
|
// If there is no filename, check the metadata for the origin filename
|
||||||
if input.len() > 0 {
|
if input.len() > 0 {
|
||||||
let origin = input[0].origin();
|
let origin = input[0].origin();
|
||||||
@ -61,7 +68,7 @@ pub fn save(
|
|||||||
yield Err(ShellError::labeled_error(
|
yield Err(ShellError::labeled_error(
|
||||||
"Save requires a filepath",
|
"Save requires a filepath",
|
||||||
"needs path",
|
"needs path",
|
||||||
context.name,
|
name_span,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -69,7 +76,7 @@ pub fn save(
|
|||||||
yield Err(ShellError::labeled_error(
|
yield Err(ShellError::labeled_error(
|
||||||
"Save requires a filepath",
|
"Save requires a filepath",
|
||||||
"needs path",
|
"needs path",
|
||||||
context.name,
|
name_span,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -77,139 +84,126 @@ pub fn save(
|
|||||||
yield Err(ShellError::labeled_error(
|
yield Err(ShellError::labeled_error(
|
||||||
"Save requires a filepath",
|
"Save requires a filepath",
|
||||||
"needs path",
|
"needs path",
|
||||||
context.name,
|
name_span,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let contents = match full_path.extension() {
|
let content = if !save_raw {
|
||||||
Some(x) if x == "csv" && !save_raw => {
|
to_string_for(full_path.extension(), &input)
|
||||||
if input.len() != 1 {
|
} else {
|
||||||
yield Err(ShellError::string(
|
string_from(&input)
|
||||||
"saving to csv requires a single object (or use --raw)",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
to_csv_to_string(&value_to_csv_value(&input[0])).unwrap()
|
|
||||||
}
|
|
||||||
Some(x) if x == "toml" && !save_raw => {
|
|
||||||
if input.len() != 1 {
|
|
||||||
yield Err(ShellError::string(
|
|
||||||
"saving to toml requires a single object (or use --raw)",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
toml::to_string(&value_to_toml_value(&input[0])).unwrap()
|
|
||||||
}
|
|
||||||
Some(x) if x == "json" && !save_raw => {
|
|
||||||
if input.len() != 1 {
|
|
||||||
yield Err(ShellError::string(
|
|
||||||
"saving to json requires a single object (or use --raw)",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
serde_json::to_string(&value_to_json_value(&input[0])).unwrap()
|
|
||||||
}
|
|
||||||
Some(x) if x == "yml" && !save_raw => {
|
|
||||||
if input.len() != 1 {
|
|
||||||
yield Err(ShellError::string(
|
|
||||||
"saving to yml requires a single object (or use --raw)",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
serde_yaml::to_string(&value_to_yaml_value(&input[0])).unwrap()
|
|
||||||
}
|
|
||||||
Some(x) if x == "yaml" && !save_raw => {
|
|
||||||
if input.len() != 1 {
|
|
||||||
yield Err(ShellError::string(
|
|
||||||
"saving to yaml requires a single object (or use --raw)",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
serde_yaml::to_string(&value_to_yaml_value(&input[0])).unwrap()
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
let mut save_data = String::new();
|
|
||||||
if input.len() > 0 {
|
|
||||||
let mut first = true;
|
|
||||||
for i in input.iter() {
|
|
||||||
if !first {
|
|
||||||
save_data.push_str("\n");
|
|
||||||
} else {
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
save_data.push_str(&i.as_string().unwrap());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
save_data
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let _ = std::fs::write(full_path, contents);
|
match content {
|
||||||
|
Ok(save_data) => match std::fs::write(full_path, save_data) {
|
||||||
|
Ok(o) => o,
|
||||||
|
Err(e) => yield Err(ShellError::string(e.to_string())),
|
||||||
|
},
|
||||||
|
Err(e) => yield Err(ShellError::string(e.to_string())),
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(OutputStream::new(stream))
|
Ok(OutputStream::new(stream))
|
||||||
} else {
|
} else {
|
||||||
full_path.push(path.unwrap().item());
|
if let Some(file) = path {
|
||||||
|
full_path.push(file.item());
|
||||||
|
}
|
||||||
|
|
||||||
let stream = async_stream_block! {
|
let stream = async_stream_block! {
|
||||||
let input: Vec<Tagged<Value>> = context.input.values.collect().await;
|
let input: Vec<Tagged<Value>> = input.values.collect().await;
|
||||||
|
|
||||||
let contents = match full_path.extension() {
|
let content = if !save_raw {
|
||||||
Some(x) if x == "csv" && !save_raw => {
|
to_string_for(full_path.extension(), &input)
|
||||||
if input.len() != 1 {
|
} else {
|
||||||
yield Err(ShellError::string(
|
string_from(&input)
|
||||||
"saving to csv requires a single object (or use --raw)",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
to_csv_to_string(&value_to_csv_value(&input[0])).unwrap()
|
|
||||||
}
|
|
||||||
Some(x) if x == "toml" && !save_raw => {
|
|
||||||
if input.len() != 1 {
|
|
||||||
yield Err(ShellError::string(
|
|
||||||
"saving to toml requires a single object (or use --raw)",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
toml::to_string(&value_to_toml_value(&input[0])).unwrap()
|
|
||||||
}
|
|
||||||
Some(x) if x == "json" && !save_raw => {
|
|
||||||
if input.len() != 1 {
|
|
||||||
yield Err(ShellError::string(
|
|
||||||
"saving to json requires a single object (or use --raw)",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
serde_json::to_string(&value_to_json_value(&input[0])).unwrap()
|
|
||||||
}
|
|
||||||
Some(x) if x == "yml" && !save_raw => {
|
|
||||||
if input.len() != 1 {
|
|
||||||
yield Err(ShellError::string(
|
|
||||||
"saving to yml requires a single object (or use --raw)",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
serde_yaml::to_string(&value_to_yaml_value(&input[0])).unwrap()
|
|
||||||
}
|
|
||||||
Some(x) if x == "yaml" && !save_raw => {
|
|
||||||
if input.len() != 1 {
|
|
||||||
yield Err(ShellError::string(
|
|
||||||
"saving to yaml requires a single object (or use --raw)",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
serde_yaml::to_string(&value_to_yaml_value(&input[0])).unwrap()
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
let mut save_data = String::new();
|
|
||||||
if input.len() > 0 {
|
|
||||||
let mut first = true;
|
|
||||||
for i in input.iter() {
|
|
||||||
if !first {
|
|
||||||
save_data.push_str("\n");
|
|
||||||
} else {
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
save_data.push_str(&i.as_string().unwrap());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
save_data
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let _ = std::fs::write(full_path, contents);
|
match content {
|
||||||
|
Ok(save_data) => match std::fs::write(full_path, save_data) {
|
||||||
|
Ok(o) => o,
|
||||||
|
Err(e) => yield Err(ShellError::string(e.to_string())),
|
||||||
|
},
|
||||||
|
Err(e) => yield Err(ShellError::string(e.to_string())),
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(OutputStream::new(stream))
|
Ok(OutputStream::new(stream))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn string_from(input: &Vec<Tagged<Value>>) -> Result<String, ShellError> {
|
||||||
|
let mut save_data = String::new();
|
||||||
|
|
||||||
|
if input.len() > 0 {
|
||||||
|
let mut first = true;
|
||||||
|
for i in input.iter() {
|
||||||
|
if !first {
|
||||||
|
save_data.push_str("\n");
|
||||||
|
} else {
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
if let Ok(data) = &i.as_string() {
|
||||||
|
save_data.push_str(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(save_data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_string_for(
|
||||||
|
ext: Option<&std::ffi::OsStr>,
|
||||||
|
input: &Vec<Tagged<Value>>,
|
||||||
|
) -> Result<String, ShellError> {
|
||||||
|
let contents = match ext {
|
||||||
|
Some(x) if x == "csv" => {
|
||||||
|
if input.len() != 1 {
|
||||||
|
return Err(ShellError::string(
|
||||||
|
"saving to csv requires a single object (or use --raw)",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
to_csv_to_string(&value_to_csv_value(&input[0]))?
|
||||||
|
}
|
||||||
|
Some(x) if x == "toml" => {
|
||||||
|
if input.len() != 1 {
|
||||||
|
return Err(ShellError::string(
|
||||||
|
"saving to toml requires a single object (or use --raw)",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
toml::to_string(&value_to_toml_value(&input[0]))?
|
||||||
|
}
|
||||||
|
Some(x) if x == "json" => {
|
||||||
|
if input.len() != 1 {
|
||||||
|
return Err(ShellError::string(
|
||||||
|
"saving to json requires a single object (or use --raw)",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
serde_json::to_string(&value_to_json_value(&input[0]))?
|
||||||
|
}
|
||||||
|
Some(x) if x == "yml" => {
|
||||||
|
if input.len() != 1 {
|
||||||
|
return Err(ShellError::string(
|
||||||
|
"saving to yml requires a single object (or use --raw)",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
serde_yaml::to_string(&value_to_yaml_value(&input[0]))?
|
||||||
|
}
|
||||||
|
Some(x) if x == "yaml" => {
|
||||||
|
if input.len() != 1 {
|
||||||
|
return Err(ShellError::string(
|
||||||
|
"saving to yaml requires a single object (or use --raw)",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
serde_yaml::to_string(&value_to_yaml_value(&input[0]))?
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(ShellError::string(
|
||||||
|
"tried saving a single object with an unrecognized format.",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(contents)
|
||||||
|
}
|
||||||
|
@ -411,6 +411,16 @@ impl std::fmt::Display for ShellError {
|
|||||||
|
|
||||||
impl std::error::Error for ShellError {}
|
impl std::error::Error for ShellError {}
|
||||||
|
|
||||||
|
impl std::convert::From<Box<dyn std::error::Error>> for ShellError {
|
||||||
|
fn from(input: Box<dyn std::error::Error>) -> ShellError {
|
||||||
|
ProximateShellError::String(StringError {
|
||||||
|
title: format!("{}", input),
|
||||||
|
error: Value::nothing(),
|
||||||
|
})
|
||||||
|
.start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl std::convert::From<std::io::Error> for ShellError {
|
impl std::convert::From<std::io::Error> for ShellError {
|
||||||
fn from(input: std::io::Error) -> ShellError {
|
fn from(input: std::io::Error) -> ShellError {
|
||||||
ProximateShellError::String(StringError {
|
ProximateShellError::String(StringError {
|
||||||
@ -431,6 +441,17 @@ impl std::convert::From<subprocess::PopenError> for ShellError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::convert::From<serde_yaml::Error> for ShellError {
|
||||||
|
fn from(input: serde_yaml::Error) -> ShellError {
|
||||||
|
ProximateShellError::String(StringError {
|
||||||
|
title: format!("{:?}", input),
|
||||||
|
error: Value::nothing(),
|
||||||
|
})
|
||||||
|
.start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
impl std::convert::From<toml::ser::Error> for ShellError {
|
impl std::convert::From<toml::ser::Error> for ShellError {
|
||||||
fn from(input: toml::ser::Error) -> ShellError {
|
fn from(input: toml::ser::Error) -> ShellError {
|
||||||
ProximateShellError::String(StringError {
|
ProximateShellError::String(StringError {
|
||||||
|
Loading…
Reference in New Issue
Block a user