#![allow(dead_code)]
use std::path::PathBuf;
use anyhow::{Result, anyhow};
#[derive(Clone, Debug)]
pub enum StateDirectory {
Absolute(PathBuf),
Default,
None,
}
impl StateDirectory {
#[allow(dead_code)]
pub fn is_none(&self) -> bool {
matches!(self, StateDirectory::None)
}
pub fn path(&self) -> Result<Option<PathBuf>> {
match self {
StateDirectory::Absolute(p) => Ok(Some(p.clone())),
StateDirectory::Default => Ok(None),
StateDirectory::None => Err(anyhow!("state is disabled")),
}
}
}
#[derive(Clone, Default)]
pub struct StateDirectoryValueParser {}
impl clap::builder::TypedValueParser for StateDirectoryValueParser {
type Value = StateDirectory;
fn parse_ref(
&self,
cmd: &clap::Command,
arg: Option<&clap::Arg>,
value: &std::ffi::OsStr,
) -> Result<Self::Value, clap::error::Error> {
use clap::error::*;
if value == "default" {
return Ok(StateDirectory::Default);
}
if value == "none" {
return Ok(StateDirectory::None);
}
if value.is_empty() {
let mut err = Error::new(ErrorKind::InvalidValue)
.with_cmd(cmd);
if let Some(arg) = arg {
err.insert(ContextKind::InvalidArg,
ContextValue::String(arg.to_string()));
}
err.insert(ContextKind::InvalidValue,
ContextValue::String("".into()));
err.insert(ContextKind::SuggestedValue,
ContextValue::String("default".into()));
err.insert(ContextKind::Suggested,
ContextValue::StyledStrs(vec![
"to use the default directory, use 'default'".into(),
]));
return Err(err);
}
let p = PathBuf::from(value);
let p = expand_tilde(p)?;
if ! p.is_absolute() {
let mut err = Error::new(ErrorKind::InvalidValue)
.with_cmd(cmd);
if let Some(arg) = arg {
err.insert(ContextKind::InvalidArg,
ContextValue::String(arg.to_string()));
}
err.insert(ContextKind::InvalidValue,
ContextValue::String(p.display().to_string()));
err.insert(ContextKind::Suggested,
ContextValue::StyledStrs(vec![
"must be an absolute path".into(),
]));
return Err(err);
}
Ok(StateDirectory::Absolute(p))
}
}
fn expand_tilde(p: PathBuf) -> clap::error::Result<PathBuf> {
if p.components().next().map(|c| c.as_os_str() == "~").unwrap_or(false) {
Ok(dirs::home_dir().ok_or_else(
|| {
use clap::error;
eprintln!("Error: no home directory known for this platform");
error::Error::new(error::ErrorKind::Io)
})?
.join(p.components().skip(1).collect::<PathBuf>()))
} else {
Ok(p)
}
}