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