implement -n, -v and -e commandline options

This commit is contained in:
Ward Wouts 2024-11-27 11:40:37 +01:00
parent 11ce644fca
commit 83ed7ee559
4 changed files with 179 additions and 20 deletions

120
Cargo.lock generated
View file

@ -2,6 +2,55 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "anstream"
version = "0.6.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
[[package]]
name = "anstyle-parse"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
dependencies = [
"anstyle",
"windows-sys 0.59.0",
]
[[package]]
name = "bitflags"
version = "2.6.0"
@ -20,6 +69,52 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "4.5.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.5.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7"
[[package]]
name = "colorchoice"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
[[package]]
name = "console"
version = "0.15.8"
@ -79,6 +174,18 @@ dependencies = [
"wasi",
]
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "lazy_static"
version = "1.5.0"
@ -101,6 +208,7 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
name = "mvw"
version = "0.1.3"
dependencies = [
"clap",
"dialoguer",
"rand",
"tempfile",
@ -188,6 +296,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.87"
@ -244,6 +358,12 @@ version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"

View file

@ -10,3 +10,4 @@ lto = "thin"
tempfile = "3.14.0"
dialoguer = "0.11.0"
rand = "0.8.5"
clap = { version = "4.5.21", features = [ "derive" ]}

View file

@ -5,13 +5,13 @@ use std::io::{ErrorKind, Write, BufRead, BufReader};
use std::collections::HashMap;
use rand::distributions::{Alphanumeric, DistString};
const POSTFIX_TMP_FILE: &str = ".mvwrap";
const LOCK_FILE: &str = ".mvwrap";
pub struct DirList {
safe_source: bool,
pub entries: Vec<String>,
noop: bool,
verbose: bool,
entries: Vec<String>,
}
impl DirList {
@ -27,7 +27,7 @@ impl DirList {
let mut path_list : Vec<String> = vec![];
for path in paths {
let path_string = path.display().to_string();
if path_string != format!("./{}", POSTFIX_TMP_FILE) {
if path_string != format!("./{}", LOCK_FILE) {
path_list.push(path_string[2..].to_string());
}
}
@ -35,6 +35,8 @@ impl DirList {
Self {
safe_source: true,
noop: false,
verbose: false,
entries: path_list,
}
}
@ -48,6 +50,8 @@ impl DirList {
Self {
safe_source: true,
noop: false,
verbose: false,
entries: lines,
}
}
@ -55,10 +59,20 @@ impl DirList {
pub fn from_list(list: &Vec<String>) -> Self {
Self {
safe_source: false,
noop: false,
verbose: false,
entries: list.to_vec(),
}
}
pub fn set_noop(&mut self) {
self.noop = true;
}
pub fn set_verbose(&mut self) {
self.verbose = true;
}
pub fn to_file(&self, target_file: &String) {
let mut file = File::create(target_file).expect("no such file");
@ -83,17 +97,17 @@ impl DirList {
if self.entries.iter().any(|j| j==&target_list.entries[i]) {
let unique = Self::get_unique_entry(&target_list);
intermediate_files.insert(unique.clone(), target_list.entries[i].clone());
fs::rename(&self.entries[i], &unique).expect("failed to rename file");
println!("Moving {} -> {}", self.entries[i], unique);
if ! self.noop { fs::rename(&self.entries[i], &unique).expect("failed to rename file"); }
if self.verbose { println!("Moving {} -> {}", self.entries[i], unique); }
} else {
fs::rename(&self.entries[i], &target_list.entries[i]).expect("failed to rename file");
println!("Moving {} -> {}", self.entries[i], target_list.entries[i]);
if ! self.noop { fs::rename(&self.entries[i], &target_list.entries[i]).expect("failed to rename file"); }
if self.verbose { println!("Moving {} -> {}", self.entries[i], target_list.entries[i]); }
}
}
}
for (src, dst) in intermediate_files.iter() {
fs::rename(src, dst).expect("failed to rename file");
println!("Moving {} -> {}", src, dst);
if ! self.noop { fs::rename(src, dst).expect("failed to rename file"); }
if self.verbose { println!("Moving {} -> {}", src, dst); }
}
Ok(())
}

View file

@ -1,5 +1,4 @@
mod dirlist;
pub use crate::dirlist::*;
use std::env;
@ -10,8 +9,11 @@ use std::process;
use std::process::Command;
use tempfile::NamedTempFile;
use dialoguer::Confirm;
use clap::Parser;
const LOCK_FILE: &str = ".mvwrap";
const SUFFIX_TMPFILE: &str = ".mvwrap";
const DEFAULT_EDITOR: &str = "vi";
struct Cleanup;
@ -21,6 +23,24 @@ impl Drop for Cleanup {
}
}
/// Wrapper to use an editor for renaming files
#[derive(Parser)]
#[command(version, about, long_about = None)]
struct Cli {
/// Only show actions, but don't move files
#[arg(short, long)]
noop: bool,
/// Show moves
#[arg(short, long)]
verbose: bool,
/// Override editor to use
#[arg(short, long)]
editor: Option<String>,
}
fn lock_dir() {
if Path::new(LOCK_FILE).is_file() {
panic!("Lock file \"{}\" already exists!", LOCK_FILE);
@ -35,7 +55,7 @@ fn unlock_dir() {
}
fn create_temp_file() -> String {
let tmpfile = NamedTempFile::with_suffix(".mvwrap").expect("Could not create tempfile");
let tmpfile = NamedTempFile::with_suffix(SUFFIX_TMPFILE).expect("Could not create tempfile");
let filepath = tmpfile.path().display().to_string();
@ -50,11 +70,10 @@ fn remove_temp_file(tmpfile: &String) {
}
}
fn edit_temp_file(tmpfile: &String) {
let editor = match env::var("EDITOR") {
Ok(e) => e,
Err(_) => "vi".to_string(),
};
fn edit_temp_file(tmpfile: &String, editor_cli: &Option<String>) {
let editor = env::var("EDITOR").unwrap_or(DEFAULT_EDITOR.to_string());
let editor = editor_cli.clone().unwrap_or(editor);
let _output = Command::new(editor)
.arg(tmpfile)
.status()
@ -62,6 +81,8 @@ fn edit_temp_file(tmpfile: &String) {
}
fn main() {
let args = Cli::parse();
// Place lockfile to not have multiple mvw processes running in the same dir at the same time
lock_dir();
let _cleanup = Cleanup; // Cleanup LOCK_FILE on panic
@ -73,7 +94,10 @@ fn main() {
let temp_file = create_temp_file();
source_list.to_file(&temp_file);
edit_temp_file(&temp_file);
if args.noop { source_list.set_noop(); source_list.set_verbose(); }
if args.verbose { source_list.set_verbose(); }
edit_temp_file(&temp_file, &args.editor);
let mut target_list = DirList::from_file(&temp_file);
@ -92,7 +116,7 @@ fn main() {
process::exit(1);
}
edit_temp_file(&temp_file);
edit_temp_file(&temp_file, &args.editor);
target_list = DirList::from_file(&temp_file);
}
}