use core::fmt;
pub const USAGE: &str = "\
shep-discord: a Discord dog for shep.
Usage:
shep-discord Run the dog: streams log lines and answers slash
commands. This is what the shepherd runs after
`shep adopt`.
shep-discord --print-config Print a commented [discord] block for dogs.toml
naming every option and its default, then exit.
shep-discord --version Print the build and the protocol version it
speaks, then exit.
shep-discord --schema Print a JSON Schema for the [discord] section,
then exit.
The last two are what `shep adopt` asks this binary, and they are answered
only as the first argument, which is the only one shep passes.
Settings are read from `dogs.toml` over the shepherd's own socket, never
from this process's arguments. The environment supplies two things and no
more: $SHEP_HOME names the socket, and $SHEP_DOG_NAME names the dog. The
shepherd sets both when it spawns this dog.";
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Action {
Run,
PrintConfig,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Usage(String);
impl fmt::Display for Usage {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}\n\n{USAGE}", self.0)
}
}
impl core::error::Error for Usage {}
impl Action {
pub fn parse<'a, I: IntoIterator<Item = &'a str>>(args: I) -> Result<Self, Usage> {
let mut action = Self::Run;
for arg in args {
match arg {
"--print-config" => action = Self::PrintConfig,
"--help" | "-h" => {
return Err(Usage("shep-discord takes no options.".to_owned()));
}
probe @ ("--version" | "--schema") => {
return Err(Usage(format!(
"shep-discord answers {probe} as its first argument only, which is \
where the shepherd asks it."
)));
}
other => {
return Err(Usage(format!("shep-discord does not understand {other}.")));
}
}
}
Ok(action)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_support::assert_no_dashes;
#[test]
fn nothing_printed_for_a_person_carries_a_dash() {
assert_no_dashes(USAGE);
let usage = Action::parse(["--bogus"]).expect_err("refused").to_string();
assert_no_dashes(&usage);
}
#[test]
fn print_config_is_the_only_argument() {
assert_eq!(Action::parse(["--print-config"]), Ok(Action::PrintConfig));
assert_eq!(Action::parse([]), Ok(Action::Run));
assert!(Action::parse(["--token"]).is_err());
}
#[test]
fn a_probe_flag_out_of_first_position_is_told_where_it_belongs() {
for flag in ["--version", "--schema"] {
let usage = Action::parse(["--print-config", flag])
.expect_err("refused")
.to_string();
assert!(usage.contains(flag), "{usage}");
assert!(usage.contains("first argument"), "{usage}");
assert!(!usage.contains("does not understand"), "{usage}");
}
}
}