forked from nushell/nushell
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial implementation of umv from uutils (nushell#10822)
<!-- if this PR closes one or more issues, you can automatically link the PR with them by using one of the [*linking keywords*](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword), e.g. - this PR should close #xxxx - fixes #xxxx you can also mention related issues, PRs or discussions! --> # Description Hi, This closes nushell#10446 , wherein we start implementing `mv` from `uutils`. There are some stuff to iron out, particularly * Decide on behavior from ignored tests * Wait for release/PRs to be approved on `uutils` side, but still can be tested for now. See [PR approved](uutils/coreutils#5428), and [pending](uutils/coreutils#5429). * `--progress` does not seem to work on `uutils mv` either and have not checked whether certain `X` size has to be achieved in order for it to appear, thus something to investigate as well, but thought it wasnt important enough to not make the PR. See [issue comment](nushell#10446 (comment)), on the possible strategy to follow, mainly copy what we did with `ucp`. I still left some comments on purpose particularly on tests, which of course would be removed before something is decided here. :) @fdncred <!-- Thank you for improving Nushell. Please, check our [contributing guide](../CONTRIBUTING.md) and talk to the core team before making major changes. Description of your pull request goes here. **Provide examples and/or screenshots** if your changes affect the user experience. --> # User-Facing Changes <!-- List of all changes that impact the user experience here. This helps us keep track of breaking changes. --> # Tests + Formatting Don't forget to add tests that cover your changes. Make sure you've run and fixed any issues with these commands: - [X] `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes) - [X] `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used` to check that you're using the standard code style - [X] `cargo test --workspace` to check that all tests pass (on Windows make sure to [enable developer mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging)) - [X] `cargo run -- -c "use std testing; testing run-tests --path crates/nu-std"` to run the tests for the standard library <!-- > **Note** > from `nushell` you can also use the `toolkit` as follows > ```bash > use toolkit.nu # or use an `env_change` hook to activate it automatically > toolkit check pr > ``` --> # After Submitting <!-- If your PR had any user-facing changes, update [the documentation](https://github.com/nushell/nushell.github.io) after the PR is merged, if necessary. This will help us keep the docs up to date. -->
- Loading branch information
1 parent
81c71ef
commit 865914c
Showing
7 changed files
with
786 additions
and
0 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
use nu_cmd_base::arg_glob; | ||
use nu_engine::current_dir; | ||
use nu_engine::CallExt; | ||
use nu_glob::GlobResult; | ||
use nu_path::{expand_path_with, expand_to_real_path}; | ||
use nu_protocol::ast::Call; | ||
use nu_protocol::engine::{Command, EngineState, Stack}; | ||
use nu_protocol::{ | ||
Category, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape, Type, | ||
}; | ||
use std::ffi::OsString; | ||
use std::path::PathBuf; | ||
use uu_mv::{BackupMode, UpdateMode}; | ||
|
||
#[derive(Clone)] | ||
pub struct UMv; | ||
|
||
impl Command for UMv { | ||
fn name(&self) -> &str { | ||
"umv" | ||
} | ||
|
||
fn usage(&self) -> &str { | ||
"Move files or directories." | ||
} | ||
|
||
fn examples(&self) -> Vec<Example> { | ||
vec![ | ||
Example { | ||
description: "Rename a file", | ||
example: "umv before.txt after.txt", | ||
result: None, | ||
}, | ||
Example { | ||
description: "Move a file into a directory", | ||
example: "umv test.txt my/subdirectory", | ||
result: None, | ||
}, | ||
Example { | ||
description: "Move many files into a directory", | ||
example: "umv *.txt my/subdirectory", | ||
result: None, | ||
}, | ||
] | ||
} | ||
|
||
fn search_terms(&self) -> Vec<&str> { | ||
vec!["move"] | ||
} | ||
|
||
fn signature(&self) -> nu_protocol::Signature { | ||
Signature::build("umv") | ||
.input_output_types(vec![(Type::Nothing, Type::Nothing)]) | ||
.switch("force", "do not prompt before overwriting", Some('f')) | ||
.switch("verbose", "explain what is being done.", Some('v')) | ||
.switch("progress", "display a progress bar", Some('p')) | ||
.switch("interactive", "prompt before overwriting", Some('i')) | ||
.switch("no-clobber", "do not overwrite an existing file", Some('n')) | ||
.rest( | ||
"paths", | ||
SyntaxShape::Filepath, | ||
"Rename SRC to DST, or move SRC to DIR.", | ||
) | ||
.allow_variants_without_examples(true) | ||
.category(Category::FileSystem) | ||
} | ||
|
||
fn run( | ||
&self, | ||
engine_state: &EngineState, | ||
stack: &mut Stack, | ||
call: &Call, | ||
_input: PipelineData, | ||
) -> Result<PipelineData, ShellError> { | ||
let interactive = call.has_flag(engine_state, stack, "interactive")?; | ||
let no_clobber = call.has_flag(engine_state, stack, "no-clobber")?; | ||
let progress = call.has_flag(engine_state, stack, "progress")?; | ||
let verbose = call.has_flag(engine_state, stack, "verbose")?; | ||
let overwrite = if no_clobber { | ||
uu_mv::OverwriteMode::NoClobber | ||
} else if interactive { | ||
uu_mv::OverwriteMode::Interactive | ||
} else { | ||
uu_mv::OverwriteMode::Force | ||
}; | ||
|
||
let paths: Vec<Spanned<String>> = call.rest(engine_state, stack, 0)?; | ||
let paths: Vec<Spanned<String>> = paths | ||
.into_iter() | ||
.map(|p| Spanned { | ||
item: nu_utils::strip_ansi_string_unlikely(p.item), | ||
span: p.span, | ||
}) | ||
.collect(); | ||
if paths.is_empty() { | ||
return Err(ShellError::GenericError { | ||
error: "Missing file operand".into(), | ||
msg: "Missing file operand".into(), | ||
span: Some(call.head), | ||
help: Some("Please provide source and destination paths".into()), | ||
inner: Vec::new(), | ||
}); | ||
} | ||
if paths.len() == 1 { | ||
return Err(ShellError::GenericError { | ||
error: "Missing destination path".into(), | ||
msg: format!("Missing destination path operand after {}", paths[0].item), | ||
span: Some(paths[0].span), | ||
help: None, | ||
inner: Vec::new(), | ||
}); | ||
} | ||
|
||
// Do not glob target | ||
let sources = &paths[..paths.len() - 1]; | ||
let cwd = current_dir(engine_state, stack)?; | ||
let mut files: Vec<PathBuf> = Vec::new(); | ||
for p in sources { | ||
let exp_files = arg_glob(p, &cwd)?.collect::<Vec<GlobResult>>(); | ||
if exp_files.is_empty() { | ||
return Err(ShellError::FileNotFound { span: p.span }); | ||
}; | ||
let mut app_vals: Vec<PathBuf> = Vec::new(); | ||
for v in exp_files { | ||
match v { | ||
Ok(path) => { | ||
app_vals.push(path); | ||
} | ||
Err(e) => { | ||
return Err(ShellError::ErrorExpandingGlob { | ||
msg: format!("error {} in path {}", e.error(), e.path().display()), | ||
span: p.span, | ||
}); | ||
} | ||
} | ||
} | ||
files.append(&mut app_vals); | ||
} | ||
// Add back the target after globbing | ||
let spanned_target = paths.last().ok_or(ShellError::NushellFailedSpanned { | ||
msg: "Missing file operand".into(), | ||
label: "Missing file operand".into(), | ||
span: call.head, | ||
})?; | ||
let expanded_target = expand_to_real_path(spanned_target.item.clone()); | ||
let abs_target_path = expand_path_with(expanded_target, &cwd); | ||
files.push(abs_target_path.clone()); | ||
let files = files | ||
.into_iter() | ||
.map(|p| p.into_os_string()) | ||
.collect::<Vec<OsString>>(); | ||
let options = uu_mv::Options { | ||
overwrite, | ||
progress_bar: progress, | ||
verbose, | ||
suffix: String::from("~"), | ||
backup: BackupMode::NoBackup, | ||
update: UpdateMode::ReplaceAll, | ||
target_dir: None, | ||
no_target_dir: false, | ||
strip_slashes: false, | ||
}; | ||
if let Err(error) = uu_mv::mv(&files, &options) { | ||
return Err(ShellError::GenericError { | ||
error: format!("{}", error), | ||
msg: format!("{}", error), | ||
span: None, | ||
help: None, | ||
inner: Vec::new(), | ||
}); | ||
} | ||
Ok(PipelineData::empty()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
mod column; | ||
mod mv; | ||
mod umv; |
Oops, something went wrong.