version_manager/cli/
command.rs

1use super::VersionCommand;
2use crate::{VersionError, VersionResult, version::Scope};
3use clap::{
4    Command, CommandFactory, Parser,
5    builder::{Styles, styling::AnsiColor},
6    value_parser,
7};
8use clap_complete::{Generator, Shell, generate};
9use std::io;
10
11const STYLE: Styles = Styles::styled()
12    .header(AnsiColor::Yellow.on_default())
13    .error(AnsiColor::Red.on_default())
14    .usage(AnsiColor::Green.on_default())
15    .literal(AnsiColor::BrightBlue.on_default())
16    .placeholder(AnsiColor::Blue.on_default())
17    .valid(AnsiColor::Cyan.on_default())
18    .invalid(AnsiColor::Magenta.on_default());
19
20#[derive(Parser, Debug, Clone)]
21#[command(arg_required_else_help(true), styles = STYLE, name = "version")]
22/// A tool for managing the version of a project
23pub struct Cli {
24    #[command(subcommand)]
25    pub command: Option<VersionCommand>,
26    #[arg(long, value_parser = value_parser!(Shell), exclusive = true)]
27    /// Generate shell completions
28    pub generator: Option<Shell>,
29}
30
31impl Cli {
32    fn print_completions<G: Generator>(generator: G, cmd: &mut Command) -> VersionResult<()> {
33        generate(
34            generator,
35            cmd,
36            cmd.get_name().to_string(),
37            &mut io::stdout(),
38        );
39        Ok(())
40    }
41
42    pub fn run(&mut self) -> VersionResult<Option<Scope>> {
43        if let Some(generator) = self.generator.take() {
44            let mut cmd = Cli::command();
45            cmd.set_bin_name("version");
46            Self::print_completions(generator, &mut cmd)?;
47            return Ok(None);
48        } else if let Some(command) = self.command.take() {
49            return Ok(Some(command.try_into()?));
50        } else {
51            return Err(VersionError::InvalidOperation);
52        }
53    }
54}
55
56impl TryFrom<Cli> for Scope {
57    type Error = VersionError;
58
59    fn try_from(cli: Cli) -> Result<Self, Self::Error> {
60        match cli.command {
61            Some(command) => command.try_into(),
62            None => Err(VersionError::InvalidOperation),
63        }
64    }
65}