forked from extern/nushell
Merge pull request #326 from androbtech/wrip-wrap
Unwrap surveying, improvements, adds.
This commit is contained in:
commit
9b1034074a
@ -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,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,15 +79,19 @@ pub fn cp(
|
|||||||
if entry.is_file() {
|
if entry.is_file() {
|
||||||
let strategy = |(source_file, _depth_level)| {
|
let strategy = |(source_file, _depth_level)| {
|
||||||
if destination.exists() {
|
if destination.exists() {
|
||||||
let mut new_dst = dunce::canonicalize(destination.clone()).unwrap();
|
let mut new_dst = dunce::canonicalize(destination.clone())?;
|
||||||
new_dst.push(entry.file_name().unwrap());
|
if let Some(name) = entry.file_name() {
|
||||||
(source_file, new_dst)
|
new_dst.push(name);
|
||||||
|
}
|
||||||
|
Ok((source_file, new_dst))
|
||||||
} else {
|
} else {
|
||||||
(source_file, destination.clone())
|
Ok((source_file, destination.clone()))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for (ref src, ref dst) in sources.paths_applying_with(strategy) {
|
let sources = sources.paths_applying_with(strategy)?;
|
||||||
|
|
||||||
|
for (ref src, ref dst) in sources {
|
||||||
if src.is_file() {
|
if src.is_file() {
|
||||||
match std::fs::copy(src, dst) {
|
match std::fs::copy(src, dst) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@ -119,7 +122,7 @@ pub fn cp(
|
|||||||
|
|
||||||
let strategy = |(source_file, depth_level)| {
|
let strategy = |(source_file, depth_level)| {
|
||||||
let mut new_dst = destination.clone();
|
let mut new_dst = destination.clone();
|
||||||
let path = dunce::canonicalize(&source_file).unwrap();
|
let path = dunce::canonicalize(&source_file)?;
|
||||||
|
|
||||||
let mut comps: Vec<_> = path
|
let mut comps: Vec<_> = path
|
||||||
.components()
|
.components()
|
||||||
@ -134,10 +137,12 @@ pub fn cp(
|
|||||||
new_dst.push(fragment);
|
new_dst.push(fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
(PathBuf::from(&source_file), PathBuf::from(new_dst))
|
Ok((PathBuf::from(&source_file), PathBuf::from(new_dst)))
|
||||||
};
|
};
|
||||||
|
|
||||||
for (ref src, ref dst) in sources.paths_applying_with(strategy) {
|
let sources = sources.paths_applying_with(strategy)?;
|
||||||
|
|
||||||
|
for (ref src, ref dst) in sources {
|
||||||
if src.is_dir() {
|
if src.is_dir() {
|
||||||
if !dst.exists() {
|
if !dst.exists() {
|
||||||
match std::fs::create_dir_all(dst) {
|
match std::fs::create_dir_all(dst) {
|
||||||
@ -167,7 +172,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) => {
|
||||||
@ -181,8 +195,8 @@ pub fn cp(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let strategy = |(source_file, depth_level)| {
|
let strategy = |(source_file, depth_level)| {
|
||||||
let mut new_dst = dunce::canonicalize(&destination).unwrap();
|
let mut new_dst = dunce::canonicalize(&destination)?;
|
||||||
let path = dunce::canonicalize(&source_file).unwrap();
|
let path = dunce::canonicalize(&source_file)?;
|
||||||
|
|
||||||
let mut comps: Vec<_> = path
|
let mut comps: Vec<_> = path
|
||||||
.components()
|
.components()
|
||||||
@ -197,10 +211,12 @@ pub fn cp(
|
|||||||
new_dst.push(fragment);
|
new_dst.push(fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
(PathBuf::from(&source_file), PathBuf::from(new_dst))
|
Ok((PathBuf::from(&source_file), PathBuf::from(new_dst)))
|
||||||
};
|
};
|
||||||
|
|
||||||
for (ref src, ref dst) in sources.paths_applying_with(strategy) {
|
let sources = sources.paths_applying_with(strategy)?;
|
||||||
|
|
||||||
|
for (ref src, ref dst) in sources {
|
||||||
if src.is_dir() {
|
if src.is_dir() {
|
||||||
if !dst.exists() {
|
if !dst.exists() {
|
||||||
match std::fs::create_dir_all(dst) {
|
match std::fs::create_dir_all(dst) {
|
||||||
@ -234,18 +250,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 +282,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 +291,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(),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,25 @@
|
|||||||
|
use crate::commands::command::RunnablePerItemContext;
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::parser::hir::SyntaxType;
|
|
||||||
use crate::parser::registry::{CommandRegistry, Signature};
|
use crate::parser::registry::{CommandRegistry, Signature};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub struct Mkdir;
|
pub struct Mkdir;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct MkdirArgs {
|
||||||
|
rest: Vec<Tagged<PathBuf>>,
|
||||||
|
}
|
||||||
|
|
||||||
impl PerItemCommand for Mkdir {
|
impl PerItemCommand for Mkdir {
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
call_info: &CallInfo,
|
call_info: &CallInfo,
|
||||||
registry: &CommandRegistry,
|
_registry: &CommandRegistry,
|
||||||
shell_manager: &ShellManager,
|
shell_manager: &ShellManager,
|
||||||
input: Tagged<Value>,
|
_input: Tagged<Value>,
|
||||||
) -> Result<VecDeque<ReturnValue>, ShellError> {
|
) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||||
mkdir(call_info, registry, shell_manager, input)
|
call_info.process(shell_manager, mkdir)?.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
@ -22,29 +27,46 @@ impl PerItemCommand for Mkdir {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("mkdir").named("file", SyntaxType::Any)
|
Signature::build("mkdir").rest()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mkdir(
|
fn mkdir(
|
||||||
call_info: &CallInfo,
|
MkdirArgs { rest: directories }: MkdirArgs,
|
||||||
_registry: &CommandRegistry,
|
RunnablePerItemContext {
|
||||||
shell_manager: &ShellManager,
|
name,
|
||||||
_input: Tagged<Value>,
|
shell_manager,
|
||||||
|
..
|
||||||
|
}: &RunnablePerItemContext,
|
||||||
) -> Result<VecDeque<ReturnValue>, ShellError> {
|
) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||||
let mut full_path = PathBuf::from(shell_manager.path());
|
let full_path = PathBuf::from(shell_manager.path());
|
||||||
|
|
||||||
match &call_info.args.nth(0) {
|
if directories.len() == 0 {
|
||||||
Some(Tagged { item: value, .. }) => full_path.push(Path::new(&value.as_string()?)),
|
return Err(ShellError::labeled_error(
|
||||||
_ => {}
|
"mkdir requires directory paths",
|
||||||
|
"needs parameter",
|
||||||
|
name,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
match std::fs::create_dir_all(full_path) {
|
for dir in directories.iter() {
|
||||||
Err(reason) => Err(ShellError::labeled_error(
|
let create_at = {
|
||||||
reason.to_string(),
|
let mut loc = full_path.clone();
|
||||||
reason.to_string(),
|
loc.push(&dir.item);
|
||||||
call_info.args.nth(0).unwrap().span(),
|
loc
|
||||||
)),
|
};
|
||||||
Ok(_) => Ok(VecDeque::new()),
|
|
||||||
|
match std::fs::create_dir_all(create_at) {
|
||||||
|
Err(reason) => {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
reason.to_string(),
|
||||||
|
reason.to_string(),
|
||||||
|
dir.span(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
Ok(_) => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(VecDeque::new())
|
||||||
}
|
}
|
||||||
|
@ -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)?;
|
||||||
@ -181,7 +181,7 @@ pub fn mv(
|
|||||||
let strategy = |(source_file, depth_level)| {
|
let strategy = |(source_file, depth_level)| {
|
||||||
let mut new_dst = destination.clone();
|
let mut new_dst = destination.clone();
|
||||||
|
|
||||||
let path = dunce::canonicalize(&source_file).unwrap();
|
let path = dunce::canonicalize(&source_file)?;
|
||||||
|
|
||||||
let mut comps: Vec<_> = path
|
let mut comps: Vec<_> = path
|
||||||
.components()
|
.components()
|
||||||
@ -196,10 +196,12 @@ pub fn mv(
|
|||||||
new_dst.push(fragment);
|
new_dst.push(fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
(PathBuf::from(&source_file), PathBuf::from(new_dst))
|
Ok((PathBuf::from(&source_file), PathBuf::from(new_dst)))
|
||||||
};
|
};
|
||||||
|
|
||||||
for (ref src, ref dst) in sources.paths_applying_with(strategy) {
|
let sources = sources.paths_applying_with(strategy)?;
|
||||||
|
|
||||||
|
for (ref src, ref dst) in sources {
|
||||||
if src.is_dir() {
|
if src.is_dir() {
|
||||||
if !dst.exists() {
|
if !dst.exists() {
|
||||||
match std::fs::create_dir_all(dst) {
|
match std::fs::create_dir_all(dst) {
|
||||||
@ -284,7 +286,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 +334,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 {
|
||||||
|
@ -105,9 +105,9 @@ impl FileStructure {
|
|||||||
self.root = path.to_path_buf();
|
self.root = path.to_path_buf();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn paths_applying_with<F>(&mut self, to: F) -> Vec<(PathBuf, PathBuf)>
|
pub fn paths_applying_with<F>(&mut self, to: F) -> Result<Vec<(PathBuf, PathBuf)>, Box<dyn std::error::Error>>
|
||||||
where
|
where
|
||||||
F: Fn((PathBuf, usize)) -> (PathBuf, PathBuf),
|
F: Fn((PathBuf, usize)) -> Result<(PathBuf, PathBuf), Box<dyn std::error::Error>>,
|
||||||
{
|
{
|
||||||
self.resources
|
self.resources
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -2,7 +2,7 @@ mod helpers;
|
|||||||
|
|
||||||
use h::{in_directory as cwd, Playground};
|
use h::{in_directory as cwd, Playground};
|
||||||
use helpers as h;
|
use helpers as h;
|
||||||
use std::path::PathBuf;
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn creates_directory() {
|
fn creates_directory() {
|
||||||
@ -19,11 +19,25 @@ fn creates_directory() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn creates_intermediary_directories() {
|
fn accepts_and_creates_directories() {
|
||||||
let sandbox = Playground::setup_for("mkdir_test_2").test_dir_name();
|
let sandbox = Playground::setup_for("mkdir_test_2").test_dir_name();
|
||||||
|
|
||||||
let full_path = format!("{}/{}", Playground::root(), sandbox);
|
let full_path = format!("{}/{}", Playground::root(), sandbox);
|
||||||
|
|
||||||
|
nu!(_output, cwd(&full_path), "mkdir dir_1 dir_2 dir_3");
|
||||||
|
|
||||||
|
assert!(h::files_exist_at(
|
||||||
|
vec![Path::new("dir_1"), Path::new("dir_2"), Path::new("dir_3")],
|
||||||
|
PathBuf::from(&full_path)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn creates_intermediary_directories() {
|
||||||
|
let sandbox = Playground::setup_for("mkdir_test_3").test_dir_name();
|
||||||
|
|
||||||
|
let full_path = format!("{}/{}", Playground::root(), sandbox);
|
||||||
|
|
||||||
nu!(
|
nu!(
|
||||||
_output,
|
_output,
|
||||||
cwd(&full_path),
|
cwd(&full_path),
|
||||||
|
Loading…
Reference in New Issue
Block a user