node: Remove dependency on `anyhow`
`anyhow` is only used to capture a handful of errors. It also turns out that usage of `lexopt` was wrong, since it features `parse_with`, which neatly integrates with `FromStr`. The types, luckily, implement this trait already – making for cleaner parsing. For now, the execution errors are all "transparent", which shouldn't be much of a regression, if at all.
This commit is contained in:
parent
4bf3ab6fb8
commit
79d928551b
|
|
@ -2851,7 +2851,6 @@ name = "radicle-node"
|
||||||
version = "0.15.0"
|
version = "0.15.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"amplify",
|
"amplify",
|
||||||
"anyhow",
|
|
||||||
"bloomy",
|
"bloomy",
|
||||||
"bytes",
|
"bytes",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ test = ["radicle/test", "radicle-crypto/test", "radicle-crypto/cyphernet", "radi
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
amplify = { workspace = true }
|
amplify = { workspace = true }
|
||||||
anyhow = { workspace = true }
|
|
||||||
bloomy = "1.2"
|
bloomy = "1.2"
|
||||||
bytes = { workspace = true }
|
bytes = { workspace = true }
|
||||||
chrono = { workspace = true, features = ["clock"] }
|
chrono = { workspace = true, features = ["clock"] }
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::{env, fs, net, path::PathBuf, process};
|
use std::net::SocketAddr;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::process::exit;
|
||||||
|
|
||||||
use anyhow::Context;
|
|
||||||
use crossbeam_channel as chan;
|
use crossbeam_channel as chan;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
use radicle::node::device::Device;
|
use radicle::node::device::Device;
|
||||||
use radicle::profile;
|
use radicle::profile;
|
||||||
|
|
||||||
use radicle_node::crypto::ssh::keystore::{Keystore, MemorySigner};
|
use radicle_node::crypto::ssh::keystore::{Keystore, MemorySigner};
|
||||||
use radicle_node::{Runtime, VERSION};
|
use radicle_node::{Runtime, VERSION};
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
|
|
@ -39,65 +42,74 @@ Options
|
||||||
--help Print help
|
--help Print help
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Options {
|
struct Options {
|
||||||
config: Option<PathBuf>,
|
config: Option<PathBuf>,
|
||||||
listen: Vec<net::SocketAddr>,
|
listen: Vec<SocketAddr>,
|
||||||
log: Option<log::Level>,
|
log: Option<log::Level>,
|
||||||
force: bool,
|
force: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Options {
|
fn parse_options() -> Result<Options, lexopt::Error> {
|
||||||
fn from_env() -> Result<Self, anyhow::Error> {
|
use lexopt::prelude::*;
|
||||||
use lexopt::prelude::*;
|
use std::str::FromStr as _;
|
||||||
|
|
||||||
let mut parser = lexopt::Parser::from_env();
|
let mut parser = lexopt::Parser::from_env();
|
||||||
let mut listen = Vec::new();
|
let mut listen = Vec::new();
|
||||||
let mut config = None;
|
let mut config = None;
|
||||||
let mut force = false;
|
let mut force = false;
|
||||||
let mut log = None;
|
let mut log = None;
|
||||||
|
|
||||||
while let Some(arg) = parser.next()? {
|
while let Some(arg) = parser.next()? {
|
||||||
match arg {
|
match arg {
|
||||||
Long("force") => {
|
Long("force") => {
|
||||||
force = true;
|
force = true;
|
||||||
}
|
}
|
||||||
Long("config") => {
|
Long("config") => {
|
||||||
let value = parser.value()?;
|
config = Some(parser.value()?.parse_with(PathBuf::from_str)?);
|
||||||
let path = PathBuf::from(value);
|
}
|
||||||
config = Some(path);
|
Long("listen") => {
|
||||||
}
|
let addr = parser.value()?.parse_with(SocketAddr::from_str)?;
|
||||||
Long("listen") => {
|
listen.push(addr);
|
||||||
let addr = parser.value()?.parse()?;
|
}
|
||||||
listen.push(addr);
|
Long("log") => {
|
||||||
}
|
log = Some(parser.value()?.parse_with(log::Level::from_str)?);
|
||||||
Long("log") => {
|
}
|
||||||
log = Some(parser.value()?.parse()?);
|
Long("help") | Short('h') => {
|
||||||
}
|
println!("{HELP_MSG}");
|
||||||
Long("help") | Short('h') => {
|
exit(0);
|
||||||
println!("{HELP_MSG}");
|
}
|
||||||
process::exit(0);
|
Long("version") => {
|
||||||
}
|
let _ = VERSION.write(&mut io::stdout());
|
||||||
Long("version") => {
|
exit(0);
|
||||||
VERSION.write(&mut io::stdout())?;
|
}
|
||||||
process::exit(0);
|
_ => {
|
||||||
}
|
return Err(arg.unexpected());
|
||||||
_ => anyhow::bail!(arg.unexpected()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
force,
|
|
||||||
listen,
|
|
||||||
log,
|
|
||||||
config,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(Options {
|
||||||
|
force,
|
||||||
|
listen,
|
||||||
|
log,
|
||||||
|
config,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute() -> anyhow::Result<()> {
|
#[derive(Error, Debug)]
|
||||||
|
enum ExecutionError {
|
||||||
|
#[error(transparent)]
|
||||||
|
Io(#[from] io::Error),
|
||||||
|
#[error(transparent)]
|
||||||
|
ConfigurationLoading(#[from] profile::config::LoadError),
|
||||||
|
#[error(transparent)]
|
||||||
|
MemorySigner(#[from] radicle::crypto::ssh::keystore::MemorySignerError),
|
||||||
|
#[error(transparent)]
|
||||||
|
Runtime(#[from] radicle_node::runtime::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute(options: Options) -> Result<(), ExecutionError> {
|
||||||
let home = profile::home()?;
|
let home = profile::home()?;
|
||||||
let options = Options::from_env()?;
|
|
||||||
|
|
||||||
// Up to now, the active log level was `LOG_LEVEL_DEFAULT`.
|
// Up to now, the active log level was `LOG_LEVEL_DEFAULT`.
|
||||||
// The first thing we do after reading command line options is
|
// The first thing we do after reading command line options is
|
||||||
|
|
@ -126,16 +138,14 @@ fn execute() -> anyhow::Result<()> {
|
||||||
|
|
||||||
let passphrase = profile::env::passphrase();
|
let passphrase = profile::env::passphrase();
|
||||||
let keystore = Keystore::new(&home.keys());
|
let keystore = Keystore::new(&home.keys());
|
||||||
let signer = Device::from(
|
let signer = Device::from(MemorySigner::load(&keystore, passphrase)?);
|
||||||
MemorySigner::load(&keystore, passphrase).context("couldn't load secret key")?,
|
|
||||||
);
|
|
||||||
|
|
||||||
log::info!(target: "node", "Node ID is {}", signer.public_key());
|
log::info!(target: "node", "Node ID is {}", signer.public_key());
|
||||||
|
|
||||||
// Add the preferred seeds as persistent peers so that we reconnect to them automatically.
|
// Add the preferred seeds as persistent peers so that we reconnect to them automatically.
|
||||||
config.node.connect.extend(config.preferred_seeds);
|
config.node.connect.extend(config.preferred_seeds);
|
||||||
|
|
||||||
let listen: Vec<std::net::SocketAddr> = if !options.listen.is_empty() {
|
let listen = if !options.listen.is_empty() {
|
||||||
options.listen.clone()
|
options.listen.clone()
|
||||||
} else {
|
} else {
|
||||||
config.node.listen.clone()
|
config.node.listen.clone()
|
||||||
|
|
@ -161,7 +171,7 @@ fn execute() -> anyhow::Result<()> {
|
||||||
|
|
||||||
if options.force {
|
if options.force {
|
||||||
log::debug!(target: "node", "Removing existing control socket..");
|
log::debug!(target: "node", "Removing existing control socket..");
|
||||||
fs::remove_file(home.socket()).ok();
|
std::fs::remove_file(home.socket()).ok();
|
||||||
}
|
}
|
||||||
Runtime::init(home, config.node, listen, signals, signer)?.run()?;
|
Runtime::init(home, config.node, listen, signals, signer)?.run()?;
|
||||||
|
|
||||||
|
|
@ -186,7 +196,7 @@ fn initialize_logging() {
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
#[error("Error connecting to systemd journal: {0}")]
|
#[error("Error connecting to systemd journal: {0}")]
|
||||||
struct JournalError(std::io::Error);
|
struct JournalError(io::Error);
|
||||||
|
|
||||||
radicle_systemd::journal::logger::<&str, &str, _>("radicle-node".to_string(), [])
|
radicle_systemd::journal::logger::<&str, &str, _>("radicle-node".to_string(), [])
|
||||||
.map_err(|err| Box::new(JournalError(err)) as Error)
|
.map_err(|err| Box::new(JournalError(err)) as Error)
|
||||||
|
|
@ -226,8 +236,17 @@ fn main() {
|
||||||
|
|
||||||
initialize_logging();
|
initialize_logging();
|
||||||
|
|
||||||
if let Err(err) = execute() {
|
let options = match parse_options() {
|
||||||
|
Ok(options) => options,
|
||||||
|
Err(err) => {
|
||||||
|
// The lexopt errors read nicely with a comma.
|
||||||
|
log::error!(target: "node", "Failed to parse options, {err:#}");
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(err) = execute(options) {
|
||||||
log::error!(target: "node", "{err:#}");
|
log::error!(target: "node", "{err:#}");
|
||||||
process::exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue