Initial commit
This commit is contained in:
commit
228e1c779f
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
/target
|
||||||
|
tags
|
||||||
|
tags.*
|
287
Cargo.lock
generated
Normal file
287
Cargo.lock
generated
Normal file
@ -0,0 +1,287 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.0.78"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "4.0.29"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4d63b9e9c07271b9957ad22c173bae2a4d9a81127680962039296abcd2f8251d"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"clap_lex",
|
||||||
|
"is-terminal",
|
||||||
|
"strsim",
|
||||||
|
"termcolor",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_complete"
|
||||||
|
version = "4.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b7b3c9eae0de7bf8e3f904a5e40612b21fb2e2e566456d177809a48b892d24da"
|
||||||
|
dependencies = [
|
||||||
|
"clap",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_complete_nushell"
|
||||||
|
version = "0.1.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "956ceeff3734be0ba9e15998f1f1a487cd2928b31444209e8fcd92b30efac13a"
|
||||||
|
dependencies = [
|
||||||
|
"clap",
|
||||||
|
"clap_complete",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8"
|
||||||
|
dependencies = [
|
||||||
|
"os_str_bytes",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_mangen"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e503c3058af0a0854668ea01db55c622482a080092fede9dd2e00a00a9436504"
|
||||||
|
dependencies = [
|
||||||
|
"clap",
|
||||||
|
"roff",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno"
|
||||||
|
version = "0.2.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
|
||||||
|
dependencies = [
|
||||||
|
"errno-dragonfly",
|
||||||
|
"libc",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno-dragonfly"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.2.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hostname"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"match_cfg",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "io-lifetimes"
|
||||||
|
version = "1.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "is-terminal"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "927609f78c2913a6f6ac3c27a4fe87f43e2a35367c0c4b0f8265e8f49a104330"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi",
|
||||||
|
"io-lifetimes",
|
||||||
|
"rustix",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.138"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linux-raw-sys"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "match_cfg"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "os_str_bytes"
|
||||||
|
version = "6.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "roff"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustix"
|
||||||
|
version = "0.36.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"errno",
|
||||||
|
"io-lifetimes",
|
||||||
|
"libc",
|
||||||
|
"linux-raw-sys",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shitbox"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"clap",
|
||||||
|
"clap_complete",
|
||||||
|
"clap_complete_nushell",
|
||||||
|
"clap_mangen",
|
||||||
|
"hostname",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "termcolor"
|
||||||
|
version = "1.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-i686-pc-windows-gnu",
|
||||||
|
"winapi-x86_64-pc-windows-gnu",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-util"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.42.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm",
|
||||||
|
"windows_aarch64_msvc",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_gnullvm",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.42.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.42.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.42.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.42.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.42.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.42.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.42.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
|
13
Cargo.toml
Normal file
13
Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[package]
|
||||||
|
name = "shitbox"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
clap = "4.0.29"
|
||||||
|
clap_complete = "4.0.6"
|
||||||
|
clap_complete_nushell = "0.1.8"
|
||||||
|
clap_mangen = "0.2.5"
|
||||||
|
hostname = { version = "0.3", features = ["set"] }
|
26
src/cli.rs
Normal file
26
src/cli.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
use crate::cmd::{bootstrap, echo, head, hostname, r#false, r#true};
|
||||||
|
use clap::{value_parser, Arg, ArgAction, Command};
|
||||||
|
|
||||||
|
pub fn run() {
|
||||||
|
let matches = Command::new("shitbox")
|
||||||
|
.about("The Harbor Freight multitool of embedded Linux")
|
||||||
|
.version(env!("CARGO_PKG_VERSION"))
|
||||||
|
.arg_required_else_help(true)
|
||||||
|
.subcommands([
|
||||||
|
bootstrap::cli(),
|
||||||
|
echo::cli(),
|
||||||
|
r#false::cli(),
|
||||||
|
head::cli(),
|
||||||
|
hostname::cli(),
|
||||||
|
r#true::cli(),
|
||||||
|
])
|
||||||
|
.get_matches();
|
||||||
|
match matches.subcommand() {
|
||||||
|
Some(("echo", _matches)) => echo::run(),
|
||||||
|
Some(("false", _matches)) => r#false::run(),
|
||||||
|
Some(("head", matches)) => head::run(&matches),
|
||||||
|
Some(("hostname", matches)) => hostname::run(&matches),
|
||||||
|
Some(("true", _matches)) => r#true::run(),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
69
src/cmd/bootstrap/mod.rs
Normal file
69
src/cmd/bootstrap/mod.rs
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
use clap::{value_parser, Arg, ArgAction, ArgMatches, Command};
|
||||||
|
|
||||||
|
pub fn cli() -> Command {
|
||||||
|
Command::new("bootstrap")
|
||||||
|
.version(env!("CARGO_PKG_VERSION"))
|
||||||
|
.author("Nathan Fisher")
|
||||||
|
.about("Install shitbox into the filesystem")
|
||||||
|
.long_about("Install symlinks, manpages and shell completions")
|
||||||
|
.args([
|
||||||
|
Arg::new("prefix")
|
||||||
|
.help("The directory path under which to install")
|
||||||
|
.short('p')
|
||||||
|
.long("prefix")
|
||||||
|
.num_args(1)
|
||||||
|
.default_value("/")
|
||||||
|
.required(false),
|
||||||
|
Arg::new("usr")
|
||||||
|
.help("Use /usr")
|
||||||
|
.long_help(
|
||||||
|
"Split the installation so that some applets go into /bin | /sbin\n\
|
||||||
|
while others are placed into /usr/bin | /usr/sbin",
|
||||||
|
)
|
||||||
|
.short('u')
|
||||||
|
.long("usr")
|
||||||
|
.default_value("true")
|
||||||
|
.value_parser(value_parser!(bool)),
|
||||||
|
])
|
||||||
|
.subcommands([
|
||||||
|
Command::new("all").about("Install everything"),
|
||||||
|
Command::new("links")
|
||||||
|
.about("Install links for each applet")
|
||||||
|
.arg(
|
||||||
|
Arg::new("soft")
|
||||||
|
.help("Install soft links instead of hardlinks")
|
||||||
|
.short('s')
|
||||||
|
.long("soft"),
|
||||||
|
),
|
||||||
|
Command::new("manpages")
|
||||||
|
.about("Install Unix man pages")
|
||||||
|
.alias("man"),
|
||||||
|
Command::new("completions")
|
||||||
|
.about("Install shell completions")
|
||||||
|
.alias("comp")
|
||||||
|
.args([
|
||||||
|
Arg::new("all")
|
||||||
|
.help("Install completions for all supported shells")
|
||||||
|
.short('a')
|
||||||
|
.long("all"),
|
||||||
|
Arg::new("bash")
|
||||||
|
.help("Bash shell completions")
|
||||||
|
.short('b')
|
||||||
|
.long("bash"),
|
||||||
|
Arg::new("fish")
|
||||||
|
.help("Fish shell completions")
|
||||||
|
.short('f')
|
||||||
|
.long("fish"),
|
||||||
|
Arg::new("nu")
|
||||||
|
.help("Nushell completions")
|
||||||
|
.short('n')
|
||||||
|
.long("nu"),
|
||||||
|
Arg::new("pwsh")
|
||||||
|
.help("PowerShell completions")
|
||||||
|
.short('p')
|
||||||
|
.long("pwsh"),
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(matches: &ArgMatches) {}
|
1
src/cmd/cat/mod.rs
Normal file
1
src/cmd/cat/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
src/cmd/chmod/mod.rs
Normal file
1
src/cmd/chmod/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
src/cmd/cp/mod.rs
Normal file
1
src/cmd/cp/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
src/cmd/date/mod.rs
Normal file
1
src/cmd/date/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
src/cmd/dd/mod.rs
Normal file
1
src/cmd/dd/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
41
src/cmd/echo/mod.rs
Normal file
41
src/cmd/echo/mod.rs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
use crate::Path;
|
||||||
|
use clap::{Arg, Command};
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
pub const PATH: Path = Path::Bin;
|
||||||
|
|
||||||
|
pub fn cli() -> Command {
|
||||||
|
Command::new("echo")
|
||||||
|
.about("Display a line of text")
|
||||||
|
.long_about("Echo the STRING(s) to standard output")
|
||||||
|
.version(env!("CARGO_PKG_VERSION"))
|
||||||
|
.author("Nathan Fisher")
|
||||||
|
.args([
|
||||||
|
Arg::new("inline")
|
||||||
|
.short('n')
|
||||||
|
.help("Do not output a trailing newline"),
|
||||||
|
Arg::new("STRING").num_args(1..),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run() {
|
||||||
|
let args: Vec<String> = env::args().collect();
|
||||||
|
let idx = match crate::progname() {
|
||||||
|
Some(s) if s.as_str() == "echo" => 1,
|
||||||
|
Some(_) => 2,
|
||||||
|
None => unreachable!(),
|
||||||
|
};
|
||||||
|
let len = args.len();
|
||||||
|
let n = len > idx && args[idx] == "-n";
|
||||||
|
let i = if n { idx + 1 } else { idx };
|
||||||
|
for (index, arg) in args.iter().enumerate().skip(i) {
|
||||||
|
if index < len - 1 {
|
||||||
|
print!("{} ", arg);
|
||||||
|
} else {
|
||||||
|
print!("{}", arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !n {
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
}
|
17
src/cmd/false/mod.rs
Normal file
17
src/cmd/false/mod.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
use clap::Command;
|
||||||
|
use crate::Path;
|
||||||
|
use std::process;
|
||||||
|
|
||||||
|
pub const PATH: Path = Path::Bin;
|
||||||
|
|
||||||
|
pub fn cli() -> Command {
|
||||||
|
Command::new("false")
|
||||||
|
.about("Does nothing unsuccessfully")
|
||||||
|
.long_about("Exit with a status code indicating failure")
|
||||||
|
.author("Nathan Fisher")
|
||||||
|
.version(env!("CARGO_PKG_VERSION"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run() {
|
||||||
|
process::exit(1);
|
||||||
|
}
|
1
src/cmd/getty/mod.rs
Normal file
1
src/cmd/getty/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
112
src/cmd/head/mod.rs
Normal file
112
src/cmd/head/mod.rs
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
use clap::{value_parser, Arg, ArgAction, ArgMatches, Command};
|
||||||
|
use crate::Path;
|
||||||
|
use std::fs;
|
||||||
|
use std::io::{stdin, Read};
|
||||||
|
use std::process;
|
||||||
|
|
||||||
|
pub const PATH: Path = Path::Bin;
|
||||||
|
|
||||||
|
pub fn cli() -> Command {
|
||||||
|
Command::new("head")
|
||||||
|
.version(env!("CARGO_PKG_VERSION"))
|
||||||
|
.author("Nathan Fisher")
|
||||||
|
.about("Display first lines of a file")
|
||||||
|
.long_about(
|
||||||
|
"Print the first 10 lines of each FILE to standard output.\n\
|
||||||
|
With more than one FILE, precede each with a header giving the file name.\n\
|
||||||
|
With no FILE, or when FILE is -, read standard input.\n\
|
||||||
|
Mandatory arguments to long options are mandatory for short options too."
|
||||||
|
)
|
||||||
|
.args([
|
||||||
|
Arg::new("FILES")
|
||||||
|
.help("The input file to use")
|
||||||
|
.num_args(1..),
|
||||||
|
Arg::new("BYTES")
|
||||||
|
.help("Count bytes instead of lines")
|
||||||
|
.short('c')
|
||||||
|
.long("bytes")
|
||||||
|
.action(ArgAction::SetTrue),
|
||||||
|
Arg::new("QUIET")
|
||||||
|
.help("Disable printing a header. Overrides -c")
|
||||||
|
.short('q')
|
||||||
|
.long("quiet")
|
||||||
|
.action(ArgAction::SetTrue),
|
||||||
|
Arg::new("HEADER")
|
||||||
|
.help("Each file is preceded by a header consisting of the string \"==> XXX <==\" where \"XXX\" is the name of the file.")
|
||||||
|
.short('v')
|
||||||
|
.long("verbose")
|
||||||
|
.action(ArgAction::SetTrue),
|
||||||
|
Arg::new("LINES")
|
||||||
|
.help("Count n number of lines (or bytes if -c is specified).")
|
||||||
|
.short('n')
|
||||||
|
.long("lines")
|
||||||
|
.default_value("10")
|
||||||
|
.value_parser(value_parser!(usize))
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn head(file: &str, count: usize, header: bool, bytes: bool) {
|
||||||
|
let mut contents = String::new();
|
||||||
|
if file == "-" {
|
||||||
|
match stdin().read_to_string(&mut contents) {
|
||||||
|
Ok(_) => true,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("head: {}", e);
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
let buf = fs::read_to_string(file);
|
||||||
|
contents = match buf {
|
||||||
|
Ok(c) => c,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("head: {}", e);
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if header {
|
||||||
|
println!("==> {} <==", file);
|
||||||
|
}
|
||||||
|
if bytes {
|
||||||
|
for (index, char) in contents.chars().into_iter().enumerate() {
|
||||||
|
if index < count {
|
||||||
|
print!("{}", char);
|
||||||
|
} else {
|
||||||
|
println!();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
} else {
|
||||||
|
for (index, line) in contents.lines().into_iter().enumerate() {
|
||||||
|
if index < count {
|
||||||
|
println!("{}", line);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(matches: &ArgMatches) {
|
||||||
|
let files = match matches.get_many::<String>("FILES") {
|
||||||
|
Some(c) => c.map(std::string::ToString::to_string).collect(),
|
||||||
|
None => vec!["-".to_string()],
|
||||||
|
};
|
||||||
|
let header = !matches.get_flag("QUIET") && { files.len() > 1 || matches.get_flag("HEADER") };
|
||||||
|
for (index, file) in files.into_iter().enumerate() {
|
||||||
|
if index == 1 && header {
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
head(
|
||||||
|
&file,
|
||||||
|
match matches.get_one("LINES") {
|
||||||
|
Some(c) => *c,
|
||||||
|
None => 10,
|
||||||
|
},
|
||||||
|
header,
|
||||||
|
matches.get_flag("BYTES"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
55
src/cmd/hostname/mod.rs
Normal file
55
src/cmd/hostname/mod.rs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
use clap::{Arg, Command, ArgMatches, ArgAction};
|
||||||
|
use crate::Path;
|
||||||
|
use std::{io, process};
|
||||||
|
|
||||||
|
pub const PATH: Path = Path::Bin;
|
||||||
|
|
||||||
|
pub fn cli() -> Command {
|
||||||
|
Command::new("hostname")
|
||||||
|
.version(env!("CARGO_PKG_VERSION"))
|
||||||
|
.author("The JeanG3nie <jeang3nie@hitchhiker-linux.org>")
|
||||||
|
.about("Prints the name of the current host. The super-user can set the host name by supplying an argument.")
|
||||||
|
.arg(
|
||||||
|
Arg::new("NAME")
|
||||||
|
.help("name to set")
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("STRIP")
|
||||||
|
.help("Removes any domain information from the printed name.")
|
||||||
|
.short('s')
|
||||||
|
.long("strip")
|
||||||
|
.action(ArgAction::SetTrue)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(matches: &ArgMatches) {
|
||||||
|
if let Some(name) = matches.get_one::<String>("NAME") {
|
||||||
|
if let Err(e) = hostname::set(name) {
|
||||||
|
eprintln!("{e}");
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match hostname::get() {
|
||||||
|
Ok(hostname) => {
|
||||||
|
if matches.get_flag("STRIP") {
|
||||||
|
println!(
|
||||||
|
"{}",
|
||||||
|
match hostname.to_string_lossy().split('.').next() {
|
||||||
|
Some(c) => c,
|
||||||
|
None => {
|
||||||
|
eprintln!("hostname: missing operand");
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
println!("{}", hostname.to_string_lossy());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("{e}");
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
src/cmd/ln/mod.rs
Normal file
1
src/cmd/ln/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
src/cmd/ls/mod.rs
Normal file
1
src/cmd/ls/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
21
src/cmd/mod.rs
Normal file
21
src/cmd/mod.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
pub mod bootstrap;
|
||||||
|
mod cat;
|
||||||
|
mod chmod;
|
||||||
|
mod cp;
|
||||||
|
mod date;
|
||||||
|
mod dd;
|
||||||
|
pub mod echo;
|
||||||
|
pub mod r#false;
|
||||||
|
mod getty;
|
||||||
|
pub mod head;
|
||||||
|
pub mod hostname;
|
||||||
|
mod ln;
|
||||||
|
mod ls;
|
||||||
|
mod mountpoint;
|
||||||
|
mod mv;
|
||||||
|
mod pwd;
|
||||||
|
mod rm;
|
||||||
|
mod rmdir;
|
||||||
|
mod sleep;
|
||||||
|
mod sync;
|
||||||
|
pub mod r#true;
|
1
src/cmd/mountpoint/mod.rs
Normal file
1
src/cmd/mountpoint/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
src/cmd/mv/mod.rs
Normal file
1
src/cmd/mv/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
src/cmd/pwd/mod.rs
Normal file
1
src/cmd/pwd/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
src/cmd/rm/mod.rs
Normal file
1
src/cmd/rm/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
src/cmd/rmdir/mod.rs
Normal file
1
src/cmd/rmdir/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
src/cmd/sleep/mod.rs
Normal file
1
src/cmd/sleep/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
src/cmd/sync/mod.rs
Normal file
1
src/cmd/sync/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
17
src/cmd/true/mod.rs
Normal file
17
src/cmd/true/mod.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
use clap::Command;
|
||||||
|
use crate::Path;
|
||||||
|
use std::process;
|
||||||
|
|
||||||
|
pub const PATH: Path = Path::Bin;
|
||||||
|
|
||||||
|
pub fn cli() -> Command {
|
||||||
|
Command::new("true")
|
||||||
|
.about("Does nothing successfully")
|
||||||
|
.long_about("Exit with a status code indicating success")
|
||||||
|
.version(env!("CARGO_PKG_VERSION"))
|
||||||
|
.author("Nathan Fisher")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run() {
|
||||||
|
process::exit(0);
|
||||||
|
}
|
38
src/lib.rs
Normal file
38
src/lib.rs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#![warn(clippy::all, clippy::pedantic)]
|
||||||
|
use std::{env, path::PathBuf, string::ToString};
|
||||||
|
|
||||||
|
mod cli;
|
||||||
|
pub mod cmd;
|
||||||
|
|
||||||
|
pub enum Path {
|
||||||
|
Bin,
|
||||||
|
Sbin,
|
||||||
|
UsrBin,
|
||||||
|
UsrSbin,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn progname() -> Option<String> {
|
||||||
|
env::args()
|
||||||
|
.next()
|
||||||
|
.and_then(|x| {
|
||||||
|
PathBuf::from(x)
|
||||||
|
.file_name()
|
||||||
|
.map(|x| x.to_str().map(ToString::to_string))
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run() {
|
||||||
|
if let Some(progname) = progname() {
|
||||||
|
match progname.as_str() {
|
||||||
|
"echo" => cmd::echo::run(),
|
||||||
|
"false" => cmd::r#false::run(),
|
||||||
|
"head" => cmd::head::run(&cmd::head::cli().get_matches()),
|
||||||
|
"hostname" => cmd::hostname::run(&cmd::hostname::cli().get_matches()),
|
||||||
|
"true" => cmd::r#true::run(),
|
||||||
|
"shitbox" => cli::run(),
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
src/main.rs
Normal file
3
src/main.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fn main() {
|
||||||
|
shitbox::run();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user