use std::fmt;
use std::path::{Path, PathBuf};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, clap::ValueEnum, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum LogFormat {
#[default]
Pretty,
Json,
}
impl fmt::Display for LogFormat {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Pretty => f.write_str("pretty"),
Self::Json => f.write_str("json"),
}
}
}
#[derive(clap::Args, Debug)]
pub struct CommonChainArgs {
#[arg(long, value_name = "PATH")]
pub config: Option<PathBuf>,
#[arg(long, value_name = "URL")]
pub rpc_url: Option<String>,
#[arg(long, value_name = "ID")]
pub chain_id: Option<u64>,
#[arg(long, value_name = "PATH")]
pub keystore: Option<PathBuf>,
#[arg(long, value_name = "PATH")]
pub data_dir: Option<PathBuf>,
#[arg(long, value_name = "PATH", env = "DECDN_KEYSTORE_PASSWORD_FILE")]
pub keystore_password_file: Option<PathBuf>,
#[arg(long)]
pub dry_run: bool,
#[arg(long)]
pub json: bool,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, clap::ValueEnum, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum LogLevel {
Trace,
Debug,
#[default]
Info,
Warn,
Error,
}
impl fmt::Display for LogLevel {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match self {
Self::Trace => "trace",
Self::Debug => "debug",
Self::Info => "info",
Self::Warn => "warn",
Self::Error => "error",
};
f.write_str(s)
}
}
pub fn default_data_dir() -> Option<PathBuf> {
resolve_home().map(|h| h.join(".decdn"))
}
pub fn default_config_path() -> Option<PathBuf> {
default_data_dir().map(|d| d.join("node.toml"))
}
pub fn default_client_data_dir() -> Option<PathBuf> {
default_data_dir().map(|d| d.join("client"))
}
#[derive(Debug, Clone, Copy)]
pub enum ConfigPathSource {
Explicit,
Default,
}
pub fn expand_tilde(path: &Path) -> PathBuf {
let s = path.to_string_lossy();
if let Some(rest) = s.strip_prefix("~/") {
if let Some(home) = resolve_home() {
return home.join(rest);
}
tracing::warn!(path = %s, "cannot expand '~': home directory not available");
} else if s == "~" {
if let Some(home) = resolve_home() {
return home;
}
tracing::warn!("cannot expand '~': home directory not available");
}
path.to_path_buf()
}
fn resolve_home() -> Option<PathBuf> {
#[cfg(test)]
if let Some(o) = test_support::current_home_override() {
return o.into_inner();
}
dirs::home_dir()
}
#[cfg(test)]
pub(crate) mod test_support;
#[cfg(test)]
#[allow(
clippy::unwrap_used,
clippy::expect_used,
clippy::indexing_slicing,
clippy::panic
)]
mod tests;