Skip to content

Commit

Permalink
Add CLI Skeleton (#3)
Browse files Browse the repository at this point in the history
This commit adds the skeleton for the CLI. It adds
a `version` subcommand and uses clap to print
help text.

feature: Add Version subcommand.
  • Loading branch information
RobbieMcKinstry authored Oct 17, 2024
1 parent c7390ae commit d04a532
Show file tree
Hide file tree
Showing 10 changed files with 942 additions and 0 deletions.
764 changes: 764 additions & 0 deletions Cargo.lock

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,30 @@
name = "canary"
version = "0.1.0"
edition = "2021"
default-run = "canary"
repository = "https://github.com/wack/canary"

[[bin]]
name = "canary"
path = "src/bin/main.rs"

[dependencies]
# aws-config = { version = "1.1.7", features = ["behavior-version-latest"] }
# aws-sdk-s3 = "1.49.0"
clap = { version = "4.3", features = ["derive"] }
# console = "0.15.8"
# dialoguer = "0.11.0"
# directories = "5.0"
# indexmap = { version = "2.1.0", features = ["serde"] }
miette = { version = "7", features = ["fancy"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
thiserror = "1.0.61"
tokio = { version = "1.37.0", features = ["full"] }
# toml = { version = "0.8.8", features = ["preserve_order"] }
# uuid = { version = "1.9", features = ["serde", "v4"] }

[dev-dependencies]
pretty_assertions = "1.4"
static_assertions = "1.1"

34 changes: 34 additions & 0 deletions src/bin/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use clap::{CommandFactory, Parser};
use miette::Result;

use canary::Flags;

#[tokio::main]
async fn main() -> Result<()> {
// Parse the args provided to this process, including
// commands and flags.
let flags = Flags::parse();
// Execute whichever command was requested.
dispatch_command(flags).await
}

/// This function inspects the command that was provided and
/// delegates to its entrypoint.
async fn dispatch_command(flags: Flags) -> Result<()> {
match flags.cmd() {
// No command was provided.
None => empty_command(),
// One or more flags were
// TODO: Re-enable
Some(cmd) => cmd.dispatch().await,
}
}

/// When the CLI is run without any commands, we print
/// the help text and exit successfully.
fn empty_command() -> Result<()> {
Flags::command()
.print_long_help()
.expect("unable to print help message");
Ok(())
}
4 changes: 4 additions & 0 deletions src/cmd/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/// A subcommand to print the version of this executable.
pub use version::Version;

mod version;
22 changes: 22 additions & 0 deletions src/cmd/version.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use miette::Result;

/// This is the version of the canary CLI, pulled from Cargo.toml.
pub const CLI_VERSION: &str = env!("CARGO_PKG_VERSION");

/// Print the CLI version to stdout.
#[derive(Default)]
pub struct Version;

impl Version {
pub fn new() -> Self {
Self::default()
}

/// Print the version and exit.
pub fn dispatch(self) -> Result<()> {
// TODO: Reincorporate the "Terminal" abstraction to
// mediate writing to stdout from one spot.
println!("{CLI_VERSION}");
Ok(())
}
}
29 changes: 29 additions & 0 deletions src/config/colors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use clap::ValueEnum;

/// This enum tracks the user's preference on whether we should
/// use ANSI color codes in terminal output. If no preference is
/// provided, we check whether the output file is a TTY (and thus
/// support color codes).
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Default)]
pub enum EnableColors {
/// Always color the output
Always,
/// Never color the output.
Never,
/// Detect whether the terminal is a tty before deciding to color
#[default]
Auto,
}

impl EnableColors {
/// A convenience helper function that returns the user's
/// preference for color. None indicates that this program
/// should decide (i.e. "auto").
pub fn color_preference(self) -> Option<bool> {
match self {
EnableColors::Always => Some(true),
EnableColors::Never => Some(false),
EnableColors::Auto => None,
}
}
}
21 changes: 21 additions & 0 deletions src/config/command.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use clap::Subcommand;
use miette::Result;

use crate::cmd::Version;

/// one of the top-level commands accepted by
/// the canary CLI.
#[derive(Subcommand, Clone)]
pub enum CanaryCommand {
/// Print the CLI version and exit
Version,
}

impl CanaryCommand {
/// dispatch the user-provided arguments to the command handler.
pub async fn dispatch(&self) -> Result<()> {
match self.clone() {
Self::Version => Version::new().dispatch(),
}
}
}
29 changes: 29 additions & 0 deletions src/config/flags.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use clap::{command, Parser};

use super::colors::EnableColors;
use super::command::CanaryCommand;

/// Canary is tool to manage self-promoting deployments.
#[derive(Parser)]
pub struct Flags {
/// The subcommand to execute
#[command(subcommand)]
cmd: Option<CanaryCommand>,

/// Whether to color the output
#[arg(long, value_enum, default_value_t=EnableColors::default())]
enable_colors: EnableColors,
}

impl Flags {
/// Return the top-level command provided, if it exists.
pub fn cmd(&self) -> Option<&CanaryCommand> {
self.cmd.as_ref()
}

/// Getter that returns the user-provided preference
/// for using color codes in the terminal output.
pub fn enable_colors(&self) -> EnableColors {
self.enable_colors
}
}
5 changes: 5 additions & 0 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pub use flags::Flags;

mod colors;
mod command;
mod flags;
9 changes: 9 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#![allow(dead_code)]

pub use config::Flags;

/// Contains the dispatch logic for running individual CLI subcommands.
/// The CLI's main function calls into these entrypoints for each subcommand.
mod cmd;
/// configuration of the CLI, either from the environment of flags.
mod config;

0 comments on commit d04a532

Please sign in to comment.