diff --git a/Cargo.lock b/Cargo.lock
index 9423e02..c2f6328 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -62,15 +62,6 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
-[[package]]
-name = "c-main"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "797bbff8bd2bcddb7f0ee638b55398686adac15174689a86da5ffc0f51219f75"
-dependencies = [
- "libc",
-]
-
[[package]]
name = "cc"
version = "1.0.79"
@@ -300,7 +291,6 @@ name = "hopper"
version = "0.1.0"
dependencies = [
"arg",
- "c-main",
"console",
"curl",
"dialoguer",
@@ -380,6 +370,15 @@ version = "0.2.140"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
+[[package]]
+name = "libc-print"
+version = "0.1.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06cea5d58bd9ba4717bbf5c6c5bb11bb6e9e76685b7fff34039b80f50ce86c11"
+dependencies = [
+ "libc",
+]
+
[[package]]
name = "libloading"
version = "0.7.4"
@@ -551,9 +550,9 @@ checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
[[package]]
name = "proc-macro2"
-version = "1.0.53"
+version = "1.0.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba466839c78239c09faf015484e5cc04860f88242cff4d03eb038f04b4699b73"
+checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534"
dependencies = [
"unicode-ident",
]
@@ -1010,16 +1009,16 @@ dependencies = [
[[package]]
name = "yacexits"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53fe740dd05c1bbc919431e842e6c1bea30195e0518ae99cae35b7f0730ddc18"
+version = "0.2.0"
+source = "git+https://git.tebibyte.media/yac/yacexits.git?branch=c-entry#d2af983f4ad18dec2af0604d7f34b7863daa5c25"
dependencies = [
"bindgen",
"libc",
+ "libc-print",
]
[[package]]
name = "zeroize"
-version = "1.5.7"
+version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f"
+checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
diff --git a/Cargo.toml b/Cargo.toml
index 225a24b..baca1d2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,7 +12,6 @@ authors = [
[dependencies]
arg = "0.4.1"
-c-main = "1.0.1"
console = "0.15.0"
curl = "0.4.44"
dialoguer = "0.9.0"
@@ -23,4 +22,4 @@ serde_json = "1"
tokio = { version = "1", features = ["full"] }
toml = "0.7.3"
xdg = "2.4.1"
-yacexits = "0.1.3"
+yacexits = { git = "https://git.tebibyte.media/yac/yacexits.git", branch = "c-entry", version = "0.2.0" }
diff --git a/src/config.rs b/src/config.rs
index 2c77a21..265143b 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -19,9 +19,11 @@
* Hopper. If not, see .
*/
+use crate::HopError;
+
use std::{
fs::File,
- io::{Read, self},
+ io::{ Read, self },
path::PathBuf,
};
@@ -32,8 +34,6 @@ use yacexits::{
EX_UNAVAILABLE,
};
-use crate::error::CError;
-
#[derive(Deserialize)]
pub struct Config {
pub hopfiles: Vec,
@@ -46,52 +46,103 @@ pub struct Sources {
}
pub enum ConfigError {
- CreateFailed(io::Error),
+ CreateError(io::Error),
OpenError(io::Error),
ReadError(io::Error),
FormatError(std::string::FromUtf8Error),
ParseError(toml::de::Error),
}
-impl CError for ConfigError {
- fn message(&self) -> String {
- match self {
- Self::CreateFailed(err) => {
- format!("Unable to create configuration file: {}", err)
+impl From for HopError {
+ fn from(error: ConfigError) -> Self {
+ let (message, code) = match error {
+ ConfigError::CreateError(err) => {
+ (
+ format!("{}: Unable to create configuration file.", err),
+ EX_UNAVAILABLE,
+ )
},
- Self::OpenError(err) => {
- format!("Unable to open configuration file: {}", err)
+ ConfigError::OpenError(err) => {
+ (
+ format!("{}: Unable to open configuration file.", err),
+ EX_UNAVAILABLE,
+ )
},
- Self::ReadError(err) => {
- format!("Error while reading configuration file: {}", err)
+ ConfigError::ReadError(err) => {
+ (
+ format!("{}: Error while reading configuration file", err),
+ EX_DATAERR,
+ )
},
- Self::FormatError(err) => {
- format!("Configuration file is not valid utf-8: {}", err)
+ ConfigError::FormatError(err) => {
+ (
+ format!("{}: Configuration file is not valid UTF-8.", err),
+ EX_DATAERR
+ )
},
- Self::ParseError(err) => {
- format!("Unable to parse configuration file: {}", err)
+ ConfigError::ParseError(err) => {
+ (
+ format!("{}: Unable to parse configuration file.", err),
+ EX_DATAERR,
+ )
},
- }
- }
+ };
- fn code(&self) -> u32 {
- match self {
- Self::CreateFailed(_) => EX_UNAVAILABLE,
- Self::OpenError(_) => EX_UNAVAILABLE,
- Self::ReadError(_) => EX_DATAERR,
- Self::FormatError(_) => EX_DATAERR,
- Self::ParseError(_) => EX_DATAERR,
- }
-
+ Self { message, code }
}
}
-pub fn get_config(dirs: BaseDirectories) -> Result {
- dirs.place_config_file("config.toml").map_err(ConfigError::CreateFailed)
+impl From for (String, u32) {
+ fn from(error: ConfigError) -> Self {
+ let (message, code) = match error {
+ ConfigError::CreateError(err) => {
+ (
+ format!("{}: Unable to create configuration file.", err),
+ EX_UNAVAILABLE,
+ )
+ },
+ ConfigError::OpenError(err) => {
+ (
+ format!("{}: Unable to open configuration file.", err),
+ EX_UNAVAILABLE,
+ )
+ },
+ ConfigError::ReadError(err) => {
+ (
+ format!("{}: Error while reading configuration file", err),
+ EX_DATAERR,
+ )
+ },
+ ConfigError::FormatError(err) => {
+ (
+ format!("{}: Configuration file is not valid UTF-8.", err),
+ EX_DATAERR
+ )
+ },
+ ConfigError::ParseError(err) => {
+ (
+ format!("{}: Unable to parse configuration file", err),
+ EX_DATAERR,
+ )
+ },
+ };
+
+ (message, code)
+ }
+
+}
+
+impl From for ConfigError {
+ fn from(err: xdg::BaseDirectoriesError) -> Self {
+ ConfigError::CreateError(io::Error::from(err))
+ }
}
impl Config {
- pub fn read_config(config_path: PathBuf) -> Result {
+ pub fn read_config() -> Result {
+ let config_path = BaseDirectories::with_prefix("hopper")?
+ .place_config_file("config.toml")
+ .map_err(ConfigError::CreateError)?;
let mut buf: Vec = Vec::new();
let mut config_file = File::open(&config_path)
diff --git a/src/error.rs b/src/error.rs
index 751a146..9e59fef 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -18,48 +18,38 @@
use yacexits::*;
-pub trait CError {
- fn code(&self) -> u32;
+pub struct HopError {
+ pub code: u32,
- fn message(&self) -> String;
-
- fn exit(&self) -> ! {
- eprintln!("{}: {}", program_invokation(), self.message());
- exit(self.code());
- }
+ pub message: String,
}
-fn program_invokation() -> String {
- // TODO: ideally this would be argv[0] from main.
- // This could be done with a const OnceCell, but I'm not sure I like that solution.
- // Using std, we can do this though:
- std::env::args().next()
- // with a fallback to the program name
- .unwrap_or_else(|| env!("CARGO_PKG_NAME").to_owned())
-}
-
-impl<'l> CError for arg::ParseKind<'l> {
- fn message(&self) -> String {
- format!(
- "Usage: {}{}",
- program_invokation(), // argv[0],
- " [-v] add | get | init | list | remove | update\n\n".to_owned() +
+impl From> for HopError {
+ fn from(_: arg::ParseKind) -> Self {
+ let message = format!(
+ "Usage: {}",
+ "[-v] add | get | init | list | remove | update\n\n".to_owned() +
"add [-m version] [-f hopfiles...] packages...\n" +
"get [-n] [-d directory] [-m versions...] [-t types...] packages\n" +
"init [-f hopfiles...] version type\n" +
"list [[-f hopfiles...] | [-m versions...] [-t types...]]\n" +
"remove [[-f hopfiles...] | type version]] packages...\n" +
"update [[-f hopfiles... | [-m versions...] [-t types...]]",
- )
+ );
+ Self { message, code: EX_USAGE }
}
-
- fn code(&self) -> u32 { EX_USAGE }
}
-impl CError for xdg::BaseDirectoriesError {
- fn message(&self) -> String {
- format!("Unable to open configuration file: {}", self)
- }
+impl From for HopError {
+ fn from(err: xdg::BaseDirectoriesError) -> Self {
+ let message = format!("{}: Unable to open configuration file", err);
- fn code(&self) -> u32 { EX_UNAVAILABLE }
-}
\ No newline at end of file
+ Self { message, code: EX_UNAVAILABLE }
+ }
+}
+
+impl From for (String, u32) {
+ fn from(err: HopError) -> Self {
+ (err.message, err.code)
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index 7c45e19..79d3a1e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -36,7 +36,8 @@ use hopfile::*;
use error::*;
use yacexits::{
- exit,
+ exit,
+ EX_OSERR,
EX_SOFTWARE,
};
@@ -47,34 +48,30 @@ struct AppContext {
#[tokio::main]
#[no_mangle]
-async fn rust_main(arguments: c_main::Args) {
+async fn rust_main(arguments: yacexits::Args) -> Result {
let argv: Vec<&str> = arguments.into_iter().collect();
- let args = Arguments::from_args(
- argv
- .clone()
- .into_iter()
- ).unwrap_or_else(|e| e.exit());
+ let args = match Arguments::from_args(argv.clone().into_iter()) {
+ Ok(args) => args,
+ Err(_) => {
+ return Err((format!("Unable to ascertain arguments."), EX_OSERR));
+ }
+ };
- let xdg_basedirs = xdg::BaseDirectories::with_prefix("hopper")
- .unwrap_or_else(|e| e.exit());
-
- let config = get_config(xdg_basedirs)
- .and_then(Config::read_config)
- .unwrap_or_else(|e| e.exit());
-
+ let config = Config::read_config()?;
let ctx = AppContext { args, config };
match ctx.args.sub {
// Command::Get(search_args) => cmd_get(&ctx, search_args).await,
// Command::Init(hopfile_args) => cmd_init(hopfile_args).await,
_ => {
- eprintln!(
- "{}: {}: Unimplemented subcommand.",
- argv[0],
- ctx.args.sub
- );
- exit(EX_SOFTWARE);
+ return Err((
+ format!(
+ "{}: Unimplemented subcommand.",
+ ctx.args.sub
+ ),
+ EX_SOFTWARE,
+ ));
},
};
}