librojo/cli/
mod.rs

1//! Defines Rojo's CLI through clap types.
2
3mod build;
4mod doc;
5mod fmt_project;
6mod init;
7mod plugin;
8mod serve;
9mod sourcemap;
10mod upload;
11
12use std::{borrow::Cow, env, path::Path, str::FromStr};
13
14use clap::Parser;
15use thiserror::Error;
16
17pub use self::build::BuildCommand;
18pub use self::doc::DocCommand;
19pub use self::fmt_project::FmtProjectCommand;
20pub use self::init::{InitCommand, InitKind};
21pub use self::plugin::{PluginCommand, PluginSubcommand};
22pub use self::serve::ServeCommand;
23pub use self::sourcemap::SourcemapCommand;
24pub use self::upload::UploadCommand;
25
26/// Command line options that Rojo accepts, defined using the clap crate.
27#[derive(Debug, Parser)]
28#[clap(name = "Rojo", version, about)]
29pub struct Options {
30    #[clap(flatten)]
31    pub global: GlobalOptions,
32
33    /// Subcommand to run in this invocation.
34    #[clap(subcommand)]
35    pub subcommand: Subcommand,
36}
37
38impl Options {
39    pub fn run(self) -> anyhow::Result<()> {
40        match self.subcommand {
41            Subcommand::Init(subcommand) => subcommand.run(),
42            Subcommand::Serve(subcommand) => subcommand.run(self.global),
43            Subcommand::Build(subcommand) => subcommand.run(),
44            Subcommand::Upload(subcommand) => subcommand.run(),
45            Subcommand::Sourcemap(subcommand) => subcommand.run(),
46            Subcommand::FmtProject(subcommand) => subcommand.run(),
47            Subcommand::Doc(subcommand) => subcommand.run(),
48            Subcommand::Plugin(subcommand) => subcommand.run(),
49        }
50    }
51}
52
53#[derive(Debug, Parser)]
54pub struct GlobalOptions {
55    /// Sets verbosity level. Can be specified multiple times.
56    #[clap(long("verbose"), short, global(true), parse(from_occurrences))]
57    pub verbosity: u8,
58
59    /// Set color behavior. Valid values are auto, always, and never.
60    #[clap(long("color"), global(true), default_value("auto"))]
61    pub color: ColorChoice,
62}
63
64#[derive(Debug, Clone, Copy)]
65pub enum ColorChoice {
66    Auto,
67    Always,
68    Never,
69}
70
71impl FromStr for ColorChoice {
72    type Err = ColorChoiceParseError;
73
74    fn from_str(source: &str) -> Result<Self, Self::Err> {
75        match source {
76            "auto" => Ok(ColorChoice::Auto),
77            "always" => Ok(ColorChoice::Always),
78            "never" => Ok(ColorChoice::Never),
79            _ => Err(ColorChoiceParseError {
80                attempted: source.to_owned(),
81            }),
82        }
83    }
84}
85
86impl From<ColorChoice> for termcolor::ColorChoice {
87    fn from(value: ColorChoice) -> Self {
88        match value {
89            ColorChoice::Auto => termcolor::ColorChoice::Auto,
90            ColorChoice::Always => termcolor::ColorChoice::Always,
91            ColorChoice::Never => termcolor::ColorChoice::Never,
92        }
93    }
94}
95
96impl From<ColorChoice> for env_logger::WriteStyle {
97    fn from(value: ColorChoice) -> Self {
98        match value {
99            ColorChoice::Auto => env_logger::WriteStyle::Auto,
100            ColorChoice::Always => env_logger::WriteStyle::Always,
101            ColorChoice::Never => env_logger::WriteStyle::Never,
102        }
103    }
104}
105
106#[derive(Debug, Error)]
107#[error("Invalid color choice '{attempted}'. Valid values are: auto, always, never")]
108pub struct ColorChoiceParseError {
109    attempted: String,
110}
111
112#[derive(Debug, Parser)]
113pub enum Subcommand {
114    Init(InitCommand),
115    Serve(ServeCommand),
116    Build(BuildCommand),
117    Upload(UploadCommand),
118    Sourcemap(SourcemapCommand),
119    FmtProject(FmtProjectCommand),
120    Doc(DocCommand),
121    Plugin(PluginCommand),
122}
123
124pub(super) fn resolve_path(path: &Path) -> Cow<'_, Path> {
125    if path.is_absolute() {
126        Cow::Borrowed(path)
127    } else {
128        Cow::Owned(env::current_dir().unwrap().join(path))
129    }
130}