feat: do error handling with anyhow, slight refactor (#6)
Co-authored-by: user0-07161 <user0thenyancat@proton.me>
This commit is contained in:
parent
5413c35fb4
commit
0cd7b3af12
37 changed files with 244 additions and 151 deletions
12
Cargo.lock
generated
12
Cargo.lock
generated
|
|
@ -2,9 +2,18 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100"
|
||||
|
||||
[[package]]
|
||||
name = "boxutils"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
|
|
@ -16,6 +25,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||
name = "coreutils"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"boxutils",
|
||||
"hostname",
|
||||
"num_cpus",
|
||||
|
|
@ -58,6 +68,7 @@ dependencies = [
|
|||
name = "rebox"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"boxutils",
|
||||
"coreutils",
|
||||
"shell",
|
||||
|
|
@ -67,6 +78,7 @@ dependencies = [
|
|||
name = "shell"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"boxutils",
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -11,11 +11,13 @@ resolver = "3"
|
|||
coreutils = { path = "./coreutils" }
|
||||
boxutils = { path = "./utils" }
|
||||
shell = { path = "./shell" }
|
||||
anyhow = "1.0.99"
|
||||
|
||||
[dependencies]
|
||||
coreutils.workspace = true
|
||||
boxutils.workspace = true
|
||||
shell.workspace = true
|
||||
anyhow.workspace = true
|
||||
|
||||
[[bin]]
|
||||
name = "box"
|
||||
|
|
|
|||
|
|
@ -5,5 +5,8 @@ edition = "2024"
|
|||
|
||||
[dependencies]
|
||||
boxutils.workspace = true
|
||||
anyhow.workspace = true
|
||||
|
||||
# TODO: get rid of these
|
||||
hostname = "0.4.0"
|
||||
num_cpus = "1.16.0"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use anyhow::{Result, bail};
|
||||
use boxutils::args::ArgParser;
|
||||
use boxutils::commands::Command;
|
||||
use boxutils::encoding::base32;
|
||||
|
|
@ -11,7 +12,7 @@ use std::io::Read;
|
|||
pub struct Base32;
|
||||
|
||||
impl Command for Base32 {
|
||||
fn execute(&self) {
|
||||
fn execute(&self) -> Result<()> {
|
||||
let args = ArgParser::builder()
|
||||
.add_flag("-d") // decode flag
|
||||
.parse_args("base32");
|
||||
|
|
@ -22,7 +23,7 @@ impl Command for Base32 {
|
|||
let mut file: Box<dyn Read> = match &args.get_normal_args()[..] {
|
||||
[] => Box::new(std::io::stdin()),
|
||||
[file] => Box::new(OpenOptions::new().read(true).open(file).unwrap()),
|
||||
_ => panic!("base32: multiple files provided"),
|
||||
_ => bail!("base32: multiple files provided"),
|
||||
};
|
||||
|
||||
let mut buffer = String::new();
|
||||
|
|
@ -35,5 +36,7 @@ impl Command for Base32 {
|
|||
|
||||
println!("{}", data);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use anyhow::{Result, bail};
|
||||
use boxutils::args::ArgParser;
|
||||
use boxutils::commands::Command;
|
||||
use boxutils::encoding::base64;
|
||||
|
|
@ -11,7 +12,7 @@ use std::io::Read;
|
|||
pub struct Base64;
|
||||
|
||||
impl Command for Base64 {
|
||||
fn execute(&self) {
|
||||
fn execute(&self) -> Result<()> {
|
||||
let args = ArgParser::builder()
|
||||
.add_flag("-d") // decode flag
|
||||
.parse_args("base64");
|
||||
|
|
@ -22,7 +23,7 @@ impl Command for Base64 {
|
|||
let mut file: Box<dyn Read> = match &args.get_normal_args()[..] {
|
||||
[] => Box::new(std::io::stdin()),
|
||||
[file] => Box::new(OpenOptions::new().read(true).open(file).unwrap()),
|
||||
_ => panic!("base64: multiple files provided"),
|
||||
_ => bail!("base64: multiple files provided"),
|
||||
};
|
||||
|
||||
let mut buffer = String::new();
|
||||
|
|
@ -35,5 +36,7 @@ impl Command for Base64 {
|
|||
|
||||
println!("{}", data);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use anyhow::Result;
|
||||
use boxutils::commands::Command;
|
||||
use boxutils::commands::get_args;
|
||||
use std::env;
|
||||
|
|
@ -7,9 +8,9 @@ use std::io::{self, BufReader, Read, Write};
|
|||
pub struct Cat;
|
||||
|
||||
impl Command for Cat {
|
||||
fn execute(&self) {
|
||||
fn execute(&self) -> Result<()> {
|
||||
let args: Vec<String> = env::args().collect::<Vec<_>>().clone();
|
||||
let arguments: Vec<String> = get_args(String::from("cat"), args);
|
||||
let arguments: Vec<String> = get_args("cat".to_owned(), args);
|
||||
let mut vecbuf = Vec::new();
|
||||
|
||||
if arguments.len() == 0 {
|
||||
|
|
@ -23,6 +24,8 @@ impl Command for Cat {
|
|||
let _ = vecbuf.append(&mut tmpbuf);
|
||||
}
|
||||
|
||||
let _ = io::stdout().write_all(&vecbuf);
|
||||
io::stdout().write_all(&vecbuf)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use anyhow::{Result, bail};
|
||||
use boxutils::commands::Command;
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
|
|
@ -8,7 +9,7 @@ use std::time::Instant;
|
|||
pub struct Dd;
|
||||
|
||||
impl Command for Dd {
|
||||
fn execute(&self) {
|
||||
fn execute(&self) -> Result<()> {
|
||||
// dd has its seperate argument parsing
|
||||
let mut arguments = HashMap::new();
|
||||
let mut blocksize = 512;
|
||||
|
|
@ -24,19 +25,18 @@ impl Command for Dd {
|
|||
let (k, v) = bs.split_at(bs.len() - 1);
|
||||
if v.parse::<u64>().is_ok() {
|
||||
// assume the bs is specified in bytes,
|
||||
// because the last char is a number
|
||||
blocksize = bs.parse::<u64>().unwrap()
|
||||
// because it can be parsed as u64
|
||||
blocksize = bs.parse::<u64>()?
|
||||
} else {
|
||||
match v {
|
||||
"K" | "k" => blocksize = k.parse::<u64>().unwrap() * 1024,
|
||||
"M" => blocksize = k.parse::<u64>().unwrap() * 1024 * 1024,
|
||||
"G" => blocksize = k.parse::<u64>().unwrap() * 1024 * 1024 * 1024,
|
||||
"kB" => blocksize = k.parse::<u64>().unwrap() * 1000,
|
||||
"MB" => blocksize = k.parse::<u64>().unwrap() * 1000 * 1000,
|
||||
"GB" => blocksize = k.parse::<u64>().unwrap() * 1000 * 1000 * 1000,
|
||||
"K" | "k" => blocksize = k.parse::<u64>()? * 1024,
|
||||
"M" => blocksize = k.parse::<u64>()? * 1024 * 1024,
|
||||
"G" => blocksize = k.parse::<u64>()? * 1024 * 1024 * 1024,
|
||||
"kB" => blocksize = k.parse::<u64>()? * 1000,
|
||||
"MB" => blocksize = k.parse::<u64>()? * 1000 * 1000,
|
||||
"GB" => blocksize = k.parse::<u64>()? * 1000 * 1000 * 1000,
|
||||
_ => {
|
||||
eprintln!("Invalid blocksize specified.");
|
||||
return;
|
||||
bail!("Invalid blocksize specified.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -46,17 +46,17 @@ impl Command for Dd {
|
|||
let start = Instant::now();
|
||||
|
||||
if let Some(input) = arguments.get("if") {
|
||||
let mut f = BufReader::new(File::open(input).unwrap());
|
||||
let _ = f.read_to_end(&mut vecbuf).unwrap();
|
||||
let mut f = BufReader::new(File::open(input)?);
|
||||
f.read_to_end(&mut vecbuf)?;
|
||||
} else {
|
||||
let _ = io::stdin().read_to_end(&mut vecbuf).unwrap();
|
||||
io::stdin().read_to_end(&mut vecbuf)?;
|
||||
}
|
||||
|
||||
if let Some(output) = arguments.get("of") {
|
||||
let buffer = File::create(output);
|
||||
let _ = buffer.unwrap().write(&vecbuf);
|
||||
buffer.unwrap().write(&vecbuf)?;
|
||||
} else {
|
||||
let _ = io::stdout().write_all(&vecbuf);
|
||||
io::stdout().write_all(&vecbuf)?;
|
||||
}
|
||||
|
||||
let duration = start.elapsed().as_secs_f64();
|
||||
|
|
@ -77,6 +77,8 @@ impl Command for Dd {
|
|||
vecbuf.len(),
|
||||
duration,
|
||||
kb_per_sec
|
||||
)
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,16 @@
|
|||
use std::path::Path;
|
||||
|
||||
use anyhow::{Result, bail};
|
||||
use boxutils::{args::ArgParser, commands::Command};
|
||||
|
||||
use std::path::Path;
|
||||
pub struct Dirname;
|
||||
|
||||
impl Command for Dirname {
|
||||
fn execute(&self) {
|
||||
fn execute(&self) -> Result<()> {
|
||||
let args = ArgParser::builder()
|
||||
.add_flag("--help")
|
||||
.parse_args("dirname");
|
||||
|
||||
if args.get_normal_args().len() != 1 || args.get_flag("--help") {
|
||||
println!("Usage: dirname FILENAME");
|
||||
return;
|
||||
bail!("Usage: dirname FILENAME");
|
||||
}
|
||||
|
||||
// note(teesh): we have already checked for argnums, so we're fine :D
|
||||
|
|
@ -30,7 +28,9 @@ impl Command for Dirname {
|
|||
|
||||
println!("{}", to_print);
|
||||
} else {
|
||||
println!("dirname: could not get parent")
|
||||
}
|
||||
bail!("dirname: could not get parent")
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
use anyhow::{Result, bail};
|
||||
use boxutils::args::ArgParser;
|
||||
use boxutils::commands::Command;
|
||||
use std::fs::File;
|
||||
use std::io::{self, BufReader, Read, Write};
|
||||
use std::process::exit;
|
||||
|
||||
pub fn convert(arguments: &ArgParser, d2u: bool) -> Vec<u8> {
|
||||
let mut vecbuf = Vec::new();
|
||||
|
|
@ -19,10 +19,7 @@ pub fn convert(arguments: &ArgParser, d2u: bool) -> Vec<u8> {
|
|||
}
|
||||
|
||||
if d2u {
|
||||
vecbuf.retain(
|
||||
|x|
|
||||
*x != b'\r'
|
||||
);
|
||||
vecbuf.retain(|x| *x != b'\r');
|
||||
} else {
|
||||
let mut tmpbuf = Vec::new();
|
||||
vecbuf.iter().enumerate().for_each(|(i, &b)| {
|
||||
|
|
@ -40,7 +37,7 @@ pub fn convert(arguments: &ArgParser, d2u: bool) -> Vec<u8> {
|
|||
pub struct Dos2Unix;
|
||||
|
||||
impl Command for Dos2Unix {
|
||||
fn execute(&self) {
|
||||
fn execute(&self) -> Result<()> {
|
||||
let args = ArgParser::builder()
|
||||
.add_flag("-u")
|
||||
.add_flag("-d")
|
||||
|
|
@ -58,19 +55,23 @@ impl Command for Dos2Unix {
|
|||
}
|
||||
|
||||
if args.get_flag("--help") {
|
||||
println!("Usage: dos2unix [-d] [-u] [FILE]");
|
||||
print!("\n");
|
||||
println!("-d: unix2dos");
|
||||
println!("-u: dos2unix (default)");
|
||||
exit(0);
|
||||
let help_text = "\
|
||||
Usage: dos2unix [-d] [-u] [FILE]
|
||||
|
||||
-d: unix2dos
|
||||
-u: dos2unix (default)\
|
||||
";
|
||||
bail!("{}", help_text)
|
||||
}
|
||||
|
||||
let result = convert(&args, dos2unix);
|
||||
|
||||
if args.get_normal_args().len() < 1 {
|
||||
let _ = io::stdout().write_all(&result);
|
||||
io::stdout().write_all(&result)?;
|
||||
} else {
|
||||
let _ = std::fs::write(args.get_normal_args()[0].clone(), &result);
|
||||
}
|
||||
std::fs::write(args.get_normal_args()[0].clone(), &result)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
use anyhow::Result;
|
||||
use boxutils::commands::Command;
|
||||
|
||||
pub struct Echo;
|
||||
|
||||
impl Command for Echo {
|
||||
fn execute(&self) {
|
||||
fn execute(&self) -> Result<()> {
|
||||
let args: Vec<String> = std::env::args().collect::<Vec<_>>();
|
||||
let arguments: Vec<String> = boxutils::commands::get_args(String::from("echo"), args);
|
||||
let message = &arguments.join(" ");
|
||||
println!("{}", message);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use anyhow::Result;
|
||||
use boxutils::args::ArgParser;
|
||||
use boxutils::commands::Command;
|
||||
|
||||
|
|
@ -35,7 +36,7 @@ impl Env {
|
|||
}
|
||||
|
||||
impl Command for Env {
|
||||
fn execute(&self) {
|
||||
fn execute(&self) -> Result<()> {
|
||||
let args = ArgParser::builder()
|
||||
.add_flag("-i")
|
||||
.add_flag("-0")
|
||||
|
|
@ -59,20 +60,20 @@ impl Command for Env {
|
|||
if to_run.is_empty() {
|
||||
Env::print_all_vars();
|
||||
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some((command, args)) = to_run.split_first() {
|
||||
std::process::Command::new(command)
|
||||
.args(args)
|
||||
.spawn()
|
||||
.expect("env: failed to start command")
|
||||
.wait()
|
||||
.expect("env: could not wait for command");
|
||||
.spawn()?
|
||||
.wait()?;
|
||||
}
|
||||
|
||||
if null_terminate {
|
||||
print!("\0");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
use anyhow::Result;
|
||||
use boxutils::commands::Command;
|
||||
use std::process::exit;
|
||||
|
||||
pub struct False;
|
||||
|
||||
impl Command for False {
|
||||
fn execute(&self) {
|
||||
fn execute(&self) -> Result<()> {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
use anyhow::Result;
|
||||
use boxutils::commands::Command;
|
||||
|
||||
pub struct Hello;
|
||||
|
||||
impl Command for Hello {
|
||||
fn execute(&self) {
|
||||
fn execute(&self) -> Result<()> {
|
||||
println!("Hello, world!");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
use anyhow::Result;
|
||||
use boxutils::args::ArgParser;
|
||||
use boxutils::commands::Command;
|
||||
|
||||
pub struct Hostname;
|
||||
|
||||
impl Command for Hostname {
|
||||
fn execute(&self) {
|
||||
fn execute(&self) -> Result<()> {
|
||||
let args = ArgParser::builder()
|
||||
.add_flag("--help")
|
||||
.parse_args("hostname");
|
||||
|
|
@ -19,5 +20,7 @@ impl Command for Hostname {
|
|||
};
|
||||
|
||||
println!("{}", hostname.to_string_lossy());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
use anyhow::{Result, bail};
|
||||
use boxutils::args::ArgParser;
|
||||
use boxutils::commands::Command;
|
||||
use std::fs;
|
||||
|
||||
pub struct Ln;
|
||||
|
||||
impl Command for Ln {
|
||||
fn execute(&self) {
|
||||
fn execute(&self) -> Result<()> {
|
||||
let args = ArgParser::builder()
|
||||
.add_flag("--help")
|
||||
.add_flag("-s")
|
||||
|
|
@ -20,7 +20,7 @@ impl Command for Ln {
|
|||
let help = args.get_normal_args().len() != 2 || args.get_flag("--help");
|
||||
if help {
|
||||
println!("Usage: ln [-sfnbtv] [-S SUF] TARGET LINK");
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let to_be_linked = args.get_normal_args()[0].clone();
|
||||
|
|
@ -31,11 +31,11 @@ impl Command for Ln {
|
|||
}
|
||||
|
||||
if args.get_flag("-f") {
|
||||
if fs::exists(&destination).unwrap() {
|
||||
if fs::metadata(&destination).unwrap().is_dir() {
|
||||
fs::remove_dir_all(&destination).unwrap();
|
||||
if fs::exists(&destination)? {
|
||||
if fs::metadata(&destination)?.is_dir() {
|
||||
fs::remove_dir_all(&destination)?;
|
||||
} else {
|
||||
fs::remove_file(&destination).unwrap();
|
||||
fs::remove_file(&destination)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -47,19 +47,22 @@ impl Command for Ln {
|
|||
if args.get_flag("-b") {
|
||||
let suffix = args.get_option("-S").unwrap_or("~");
|
||||
let new_filename = format!("{}{}", destination, suffix);
|
||||
let _ = fs::rename(&destination, &new_filename);
|
||||
fs::rename(&destination, &new_filename)?;
|
||||
}
|
||||
|
||||
if args.get_flag("-s") {
|
||||
let symlink_result = boxutils::cross::fs::symlink(to_be_linked, destination, dereference);
|
||||
let symlink_result =
|
||||
boxutils::cross::fs::symlink(to_be_linked, destination, dereference);
|
||||
|
||||
if let Err(e) = symlink_result {
|
||||
eprintln!("ln: failed to create symlink: {}", e);
|
||||
bail!("ln: failed to create symlink: {}", e);
|
||||
}
|
||||
} else {
|
||||
if let Err(e) = boxutils::cross::fs::hard_link(to_be_linked, destination, dereference) {
|
||||
eprintln!("ln: failed to create hard link: {}", e);
|
||||
bail!("ln: failed to create hard link: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use anyhow::{Result, bail};
|
||||
use boxutils::args::ArgParser;
|
||||
use boxutils::commands::Command;
|
||||
use std::fs;
|
||||
|
|
@ -5,7 +6,7 @@ use std::fs;
|
|||
pub struct Mkdir;
|
||||
|
||||
impl Command for Mkdir {
|
||||
fn execute(&self) {
|
||||
fn execute(&self) -> Result<()> {
|
||||
let args = ArgParser::builder()
|
||||
.add_flag("-p")
|
||||
.add_flag("--parents")
|
||||
|
|
@ -14,11 +15,11 @@ impl Command for Mkdir {
|
|||
|
||||
if args.get_flag("--help") {
|
||||
println!("Usage: mkdir [DIR1] [DIR2] etc. pp. [-p, --parents]");
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if args.get_normal_args().len() == 0 {
|
||||
panic!("Usage: mkdir [DIR1] [DIR1] etc. pp. [-p, --parents]");
|
||||
bail!("Usage: mkdir [DIR1] [DIR1] etc. pp. [-p, --parents]");
|
||||
}
|
||||
|
||||
let parented = args.get_flag("-p") || args.get_flag("--parents");
|
||||
|
|
@ -27,10 +28,12 @@ impl Command for Mkdir {
|
|||
|
||||
for dir in to_create {
|
||||
if parented {
|
||||
let _ = fs::create_dir_all(dir);
|
||||
fs::create_dir_all(dir)?;
|
||||
} else {
|
||||
let _ = fs::create_dir(dir);
|
||||
fs::create_dir(dir)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use anyhow::Result;
|
||||
use boxutils::args::ArgParser;
|
||||
use boxutils::commands::Command;
|
||||
use num_cpus::get;
|
||||
|
|
@ -5,7 +6,7 @@ use num_cpus::get;
|
|||
pub struct Nproc;
|
||||
|
||||
impl Command for Nproc {
|
||||
fn execute(&self) {
|
||||
fn execute(&self) -> Result<()> {
|
||||
let args = ArgParser::builder()
|
||||
.add_flag("--help")
|
||||
.add_flag("--ignore")
|
||||
|
|
@ -23,7 +24,7 @@ Prints the number of available CPUs to stdout.
|
|||
--ignore=N, --ignore N Ignore N CPUs
|
||||
"
|
||||
);
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if args.get_flag("--all") {
|
||||
|
|
@ -31,13 +32,13 @@ Prints the number of available CPUs to stdout.
|
|||
}
|
||||
|
||||
if args.get_flag("--ignore") {
|
||||
ignore = args.get_option("--ignore").unwrap().parse().unwrap();
|
||||
ignore = args.get_option("--ignore").unwrap().parse()?;
|
||||
}
|
||||
|
||||
for argument in args.get_normal_args() {
|
||||
if let Some((k, v)) = argument.split_once('=') {
|
||||
if k == "--ignore" {
|
||||
ignore = v.parse().unwrap();
|
||||
ignore = v.parse()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -47,5 +48,7 @@ Prints the number of available CPUs to stdout.
|
|||
} else {
|
||||
println!("{}", get() as u64 - ignore)
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,21 @@
|
|||
use anyhow::Result;
|
||||
use boxutils::args::ArgParser;
|
||||
use boxutils::commands::Command;
|
||||
|
||||
pub struct Pwd;
|
||||
|
||||
impl Command for Pwd {
|
||||
fn execute(&self) {
|
||||
fn execute(&self) -> Result<()> {
|
||||
let args = ArgParser::builder().add_flag("--help").parse_args("yes");
|
||||
|
||||
if args.get_flag("--help") {
|
||||
println!("Usage: pwd");
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let pwd = std::env::current_dir().unwrap();
|
||||
let pwd = std::env::current_dir()?;
|
||||
println!("{}", pwd.display());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
use anyhow::{Result, bail};
|
||||
use boxutils::{args::ArgParser, commands::Command};
|
||||
|
||||
pub struct Seq;
|
||||
|
||||
impl Command for Seq {
|
||||
fn execute(&self) {
|
||||
fn execute(&self) -> Result<()> {
|
||||
let args = ArgParser::builder()
|
||||
.add_option("-s")
|
||||
.add_flag("-w")
|
||||
|
|
@ -31,7 +32,7 @@ impl Command for Seq {
|
|||
incnum = inc.parse().expect("seq: invalid inc number");
|
||||
lastnum = last.parse().expect("seq: invalid last number");
|
||||
}
|
||||
_ => panic!("seq: malformed arguments"),
|
||||
_ => bail!("seq: malformed arguments"),
|
||||
}
|
||||
|
||||
let mut accumulator = firstnum;
|
||||
|
|
@ -62,5 +63,7 @@ impl Command for Seq {
|
|||
print!("{}", separator);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
use anyhow::{Result, bail};
|
||||
use boxutils::{args::ArgParser, commands::Command};
|
||||
|
||||
pub struct Sleep;
|
||||
|
||||
impl Command for Sleep {
|
||||
fn execute(&self) {
|
||||
fn execute(&self) -> Result<()> {
|
||||
let args = ArgParser::builder().parse_args("sleep");
|
||||
let mut sleep_for = 0;
|
||||
|
||||
for arg in args.get_normal_args() {
|
||||
if arg.chars().last().unwrap().is_numeric() {
|
||||
sleep_for += arg.parse::<i32>().unwrap();
|
||||
sleep_for += arg.parse::<i32>()?;
|
||||
} else {
|
||||
let multiplier = match arg.chars().last().unwrap() {
|
||||
's' => 1,
|
||||
|
|
@ -17,20 +18,21 @@ impl Command for Sleep {
|
|||
'h' => 3600,
|
||||
'd' => 86400,
|
||||
_ => {
|
||||
println!("Invalid time interval '{}'", arg);
|
||||
return;
|
||||
bail!("Invalid time interval '{}'", arg);
|
||||
}
|
||||
};
|
||||
|
||||
sleep_for += arg[..arg.len() - 1].parse::<i32>().unwrap() * multiplier;
|
||||
sleep_for += arg[..arg.len() - 1].parse::<i32>()? * multiplier;
|
||||
}
|
||||
}
|
||||
|
||||
if sleep_for == 0 {
|
||||
println!("Usage: sleep [N]...");
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
std::thread::sleep(std::time::Duration::from_secs(sleep_for as u64));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use anyhow::{Result, bail};
|
||||
use boxutils::args::ArgParser;
|
||||
use boxutils::commands::Command;
|
||||
use std::fs::OpenOptions;
|
||||
|
|
@ -10,7 +11,7 @@ use std::io::Write;
|
|||
pub struct Tee;
|
||||
|
||||
impl Command for Tee {
|
||||
fn execute(&self) {
|
||||
fn execute(&self) -> Result<()> {
|
||||
let args = ArgParser::builder()
|
||||
.add_flag("--help")
|
||||
.add_flag("-a")
|
||||
|
|
@ -34,17 +35,19 @@ impl Command for Tee {
|
|||
if let Ok(this_file) = this_file {
|
||||
writes.push(Box::new(this_file));
|
||||
} else {
|
||||
eprintln!("tee: unable to open file: {}", file);
|
||||
bail!("tee: unable to open file: {}", file);
|
||||
}
|
||||
}
|
||||
|
||||
let mut buffer = String::new();
|
||||
while boxutils::input::repl(&mut buffer) {
|
||||
for output in &mut writes {
|
||||
let _ = output.write_all(buffer.as_bytes());
|
||||
let _ = output.flush();
|
||||
output.write_all(buffer.as_bytes())?;
|
||||
output.flush()?;
|
||||
}
|
||||
buffer.clear();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use anyhow::{Result, bail};
|
||||
use boxutils::args::ArgParser;
|
||||
use boxutils::commands::Command;
|
||||
|
||||
|
|
@ -194,7 +195,7 @@ impl Test {
|
|||
}
|
||||
|
||||
impl Command for Test {
|
||||
fn execute(&self) {
|
||||
fn execute(&self) -> Result<()> {
|
||||
let args = ArgParser::builder()
|
||||
.add_flags(STRING_TESTS.into())
|
||||
.add_flags(NUMBER_TESTS.into())
|
||||
|
|
@ -202,7 +203,7 @@ impl Command for Test {
|
|||
.parse_args(if self.bracket { "[" } else { "test" });
|
||||
|
||||
if self.bracket && !args.get_flag("]") {
|
||||
panic!("[: missing ]");
|
||||
bail!("[: missing ]");
|
||||
}
|
||||
|
||||
if STRING_TESTS.iter().any(|&x| args.get_flag(x)) {
|
||||
|
|
@ -214,5 +215,6 @@ impl Command for Test {
|
|||
}
|
||||
|
||||
exit_false();
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
use anyhow::Result;
|
||||
use boxutils::commands::Command;
|
||||
use std::process::exit;
|
||||
|
||||
pub struct True;
|
||||
|
||||
impl Command for True {
|
||||
fn execute(&self) {
|
||||
fn execute(&self) -> Result<()> {
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use crate::commands::dos2unix::convert;
|
||||
use anyhow::Result;
|
||||
use boxutils::args::ArgParser;
|
||||
use boxutils::commands::Command;
|
||||
use std::io::{self, Write};
|
||||
|
|
@ -7,7 +8,7 @@ use std::process::exit;
|
|||
pub struct Unix2Dos;
|
||||
|
||||
impl Command for Unix2Dos {
|
||||
fn execute(&self) {
|
||||
fn execute(&self) -> Result<()> {
|
||||
let args = ArgParser::builder()
|
||||
.add_flag("-u")
|
||||
.add_flag("-d")
|
||||
|
|
@ -35,10 +36,11 @@ impl Command for Unix2Dos {
|
|||
let result = convert(&args, dos2unix);
|
||||
|
||||
if args.get_normal_args().len() < 1 {
|
||||
let _ = io::stdout().write_all(&result);
|
||||
io::stdout().write_all(&result)?;
|
||||
} else {
|
||||
let _ = std::fs::write(args.get_normal_args()[0].clone(), &result);
|
||||
std::fs::write(args.get_normal_args()[0].clone(), &result)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use anyhow::Result;
|
||||
use boxutils::args::ArgParser;
|
||||
use boxutils::commands::Command;
|
||||
use boxutils::cross::user;
|
||||
|
|
@ -5,16 +6,18 @@ use boxutils::cross::user;
|
|||
pub struct WhoAmI;
|
||||
|
||||
impl Command for WhoAmI {
|
||||
fn execute(&self) {
|
||||
fn execute(&self) -> Result<()> {
|
||||
let args = ArgParser::builder().add_flag("--help").parse_args("whoami");
|
||||
|
||||
if args.get_flag("--help") {
|
||||
println!("Usage: whoami");
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let username = user::get_username().unwrap_or_else(|| "unknown".to_string());
|
||||
let username = user::get_username().unwrap_or("unknown".to_string());
|
||||
|
||||
println!("{}", username);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
use anyhow::Result;
|
||||
use boxutils::args::ArgParser;
|
||||
use boxutils::commands::Command;
|
||||
|
||||
pub struct Yes;
|
||||
|
||||
impl Command for Yes {
|
||||
fn execute(&self) {
|
||||
fn execute(&self) -> Result<()> {
|
||||
let args = ArgParser::builder().add_flag("--help").parse_args("yes");
|
||||
|
||||
if args.get_flag("--help") {
|
||||
println!("Usage: yes [STRING]");
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let string = if args.get_normal_args().is_empty() {
|
||||
|
|
|
|||
|
|
@ -5,3 +5,4 @@ edition = "2024"
|
|||
|
||||
[dependencies]
|
||||
boxutils.workspace = true
|
||||
anyhow.workspace = true
|
||||
|
|
|
|||
|
|
@ -1,14 +1,17 @@
|
|||
use boxutils::commands::Command;
|
||||
|
||||
use std::env;
|
||||
use std::io::{self, Write};
|
||||
use std::process;
|
||||
|
||||
use anyhow::{Error, Result};
|
||||
|
||||
use crate::built_in::{Action, run_if_exists};
|
||||
|
||||
pub struct Ash;
|
||||
|
||||
impl Command for Ash {
|
||||
fn execute(&self) {
|
||||
fn execute(&self) -> Result<(), Error> {
|
||||
let mut path = env::current_dir().unwrap().display().to_string();
|
||||
|
||||
loop {
|
||||
|
|
@ -20,13 +23,13 @@ impl Command for Ash {
|
|||
print!("{} {} ", path.clone(), userchar);
|
||||
let _ = io::stdout().flush();
|
||||
let mut input = String::new();
|
||||
io::stdin().read_line(&mut input).unwrap();
|
||||
io::stdin().read_line(&mut input)?;
|
||||
let mut full_cmd = input.trim().split_whitespace();
|
||||
let command = full_cmd.next().unwrap_or("");
|
||||
let arguments: Vec<&str> = full_cmd.collect();
|
||||
|
||||
if let Some(action) = run_if_exists(command.to_string(), arguments.clone()) {
|
||||
match action {
|
||||
match action? {
|
||||
Action::Exit => {
|
||||
break;
|
||||
}
|
||||
|
|
@ -39,17 +42,13 @@ impl Command for Ash {
|
|||
Action::Nothing => {}
|
||||
}
|
||||
} else {
|
||||
let out = process::Command::new(command)
|
||||
process::Command::new(command)
|
||||
.args(arguments.clone())
|
||||
.spawn();
|
||||
.spawn()?
|
||||
.wait()?;
|
||||
}
|
||||
}
|
||||
|
||||
match out {
|
||||
Ok(mut out) => {
|
||||
let _ = out.wait();
|
||||
}
|
||||
Err(err) => println!("{:?}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
use crate::built_in::Action;
|
||||
use anyhow::{Result, bail};
|
||||
|
||||
pub fn cd(arguments: Vec<&str>) -> Action {
|
||||
pub fn cd(arguments: Vec<&str>) -> Result<Action> {
|
||||
if arguments.len() < 1 {
|
||||
panic!("cd expects **one** argument");
|
||||
bail!("cd expects **one** argument");
|
||||
}
|
||||
|
||||
Action::ChangeDirectory(arguments[0].to_owned().clone())
|
||||
Ok(Action::ChangeDirectory(arguments[0].to_owned().clone()))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,16 @@
|
|||
use crate::built_in::Action;
|
||||
use anyhow::{Result, bail};
|
||||
use std::process::Command;
|
||||
|
||||
pub fn eval(arguments: Vec<&str>) -> Action {
|
||||
pub fn eval(arguments: Vec<&str>) -> Result<Action> {
|
||||
if arguments.len() < 1 {
|
||||
panic!("eval expects **one or more** arguments");
|
||||
bail!("eval expects **one or more** arguments");
|
||||
}
|
||||
|
||||
let output = Command::new(arguments[0]).args(&arguments[1..]).spawn();
|
||||
match output {
|
||||
Ok(mut output) => {
|
||||
output.wait().expect("failed to wait for process exit");
|
||||
}
|
||||
Err(err) => println!("{:?}", err)
|
||||
}
|
||||
Action::Nothing
|
||||
Command::new(arguments[0])
|
||||
.args(&arguments[1..])
|
||||
.spawn()?
|
||||
.wait()?;
|
||||
Ok(Action::Nothing)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use crate::built_in::Action;
|
||||
use anyhow::Result;
|
||||
|
||||
pub fn exit(_: Vec<&str>) -> Action {
|
||||
Action::Exit
|
||||
pub fn exit(_: Vec<&str>) -> Result<Action> {
|
||||
Ok(Action::Exit)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,23 @@
|
|||
mod cd;
|
||||
mod exit;
|
||||
mod eval;
|
||||
mod exit;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Action {
|
||||
Exit,
|
||||
ChangeDirectory(String),
|
||||
Nothing
|
||||
Nothing,
|
||||
}
|
||||
|
||||
fn get_function(command: String) -> Option<fn(Vec<&str>) -> Action> {
|
||||
fn get_function(command: String) -> Option<fn(Vec<&str>) -> Result<Action>> {
|
||||
let registry = [
|
||||
("exit", exit::exit as fn(Vec<&str>) -> Action),
|
||||
("cd", cd::cd as fn(Vec<&str>) -> Action),
|
||||
("eval", eval::eval as fn(Vec<&str>) -> Action)
|
||||
("exit", exit::exit as fn(Vec<&str>) -> Result<Action>),
|
||||
("cd", cd::cd as fn(Vec<&str>) -> Result<Action>),
|
||||
("eval", eval::eval as fn(Vec<&str>) -> Result<Action>),
|
||||
];
|
||||
let mut function: Option<fn(Vec<&str>) -> Action> = None;
|
||||
let mut function: Option<fn(Vec<&str>) -> Result<Action>> = None;
|
||||
|
||||
for entry in registry {
|
||||
if entry.0 == &command {
|
||||
|
|
@ -26,7 +28,7 @@ fn get_function(command: String) -> Option<fn(Vec<&str>) -> Action> {
|
|||
function
|
||||
}
|
||||
|
||||
pub fn run_if_exists(command: String, arguments: Vec<&str>) -> Option<Action> {
|
||||
pub fn run_if_exists(command: String, arguments: Vec<&str>) -> Option<Result<Action>> {
|
||||
let function = get_function(command);
|
||||
if let Some(function) = function {
|
||||
let action = function(arguments);
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
use super::registry::get_registry;
|
||||
use anyhow::{Result, bail};
|
||||
use boxutils::args::ArgParser;
|
||||
use boxutils::commands::Command;
|
||||
|
||||
pub struct Boxcmd;
|
||||
|
||||
impl Command for Boxcmd {
|
||||
fn execute(&self) {
|
||||
fn execute(&self) -> Result<()> {
|
||||
let parser = ArgParser::builder().parse_args("box");
|
||||
|
||||
let registry = get_registry();
|
||||
|
|
@ -15,11 +16,10 @@ impl Command for Boxcmd {
|
|||
continue;
|
||||
}
|
||||
|
||||
registry.execute(&command);
|
||||
return;
|
||||
registry.execute(&command)?;
|
||||
}
|
||||
|
||||
println!(
|
||||
bail!(
|
||||
"No valid command provided. Included commands:\n{}",
|
||||
registry.list().join(", ")
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
mod boxcmd;
|
||||
mod registry;
|
||||
|
||||
use anyhow::{Error, Result};
|
||||
use boxutils::commands::being_called_as;
|
||||
|
||||
fn main() {
|
||||
fn main() -> Result<(), Error> {
|
||||
let utility_name = being_called_as();
|
||||
registry::get_registry().execute(&utility_name);
|
||||
registry::get_registry().execute(&utility_name)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,3 +4,4 @@ version = "0.1.0"
|
|||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ use std::env;
|
|||
use std::mem;
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::{Error, Result};
|
||||
|
||||
pub fn being_called_as() -> String {
|
||||
let args = env::args().collect::<Vec<String>>();
|
||||
let exe_path = args[0].clone();
|
||||
|
|
@ -34,5 +36,5 @@ pub fn get_args(commandname: String, args: Vec<String>) -> Vec<String> {
|
|||
}
|
||||
|
||||
pub trait Command {
|
||||
fn execute(&self);
|
||||
fn execute(&self) -> Result<(), Error>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
use super::commands::Command;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::{Error, Result, bail};
|
||||
|
||||
pub struct CommandRegistry {
|
||||
commands: HashMap<String, Box<dyn Command>>,
|
||||
}
|
||||
|
|
@ -28,23 +30,31 @@ impl CommandRegistry {
|
|||
self.commands.get(name)
|
||||
}
|
||||
|
||||
pub fn execute(&self, name: &str) {
|
||||
pub fn execute(&self, name: &str) -> Result<(), Error> {
|
||||
if let Some(command) = self.get(name) {
|
||||
command.execute();
|
||||
command.execute()?;
|
||||
} else {
|
||||
println!("Command not found: {}", name);
|
||||
bail!("Command not found: {}", name);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
mod tests {
|
||||
#[allow(unused_imports)] // why the heck is rust saying it's unused??
|
||||
use anyhow::{Error, Result};
|
||||
|
||||
#[test]
|
||||
fn test_register() {
|
||||
use super::Command;
|
||||
use super::CommandRegistry;
|
||||
|
||||
struct TestCommand;
|
||||
impl Command for TestCommand {
|
||||
fn execute(&self) {}
|
||||
fn execute(&self) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
let mut registry = CommandRegistry::new();
|
||||
|
|
@ -53,18 +63,23 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_execute() {
|
||||
fn test_execute() -> Result<(), Error> {
|
||||
use super::Command;
|
||||
use super::CommandRegistry;
|
||||
|
||||
struct TestCommand;
|
||||
impl Command for TestCommand {
|
||||
fn execute(&self) {
|
||||
fn execute(&self) -> Result<(), Error> {
|
||||
println!("TestCommand executed");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
let mut registry = CommandRegistry::new();
|
||||
registry.register("test", Box::new(TestCommand));
|
||||
registry.execute("test");
|
||||
registry.execute("test")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue