Skip to content

Commit

Permalink
feat(runtime): Remove dependency on clap
Browse files Browse the repository at this point in the history
  • Loading branch information
kierendavies committed Apr 26, 2023
1 parent c596e46 commit 2e92064
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 28 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ doctest = false
anyhow = { workspace = true }
async-trait = { workspace = true }
chrono = { workspace = true }
clap = { workspace = true }
prost-types = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
Expand Down
120 changes: 96 additions & 24 deletions runtime/src/alpha/args.rs
Original file line number Diff line number Diff line change
@@ -1,37 +1,109 @@
use std::path::PathBuf;
use std::{
env,
fmt::{self, Debug, Display},
path::PathBuf,
str::FromStr,
};

use clap::{Parser, ValueEnum};
use tonic::transport::{Endpoint, Uri};

#[derive(Parser, Debug)]
#[command(version)]
pub struct Args {
/// Port to start runtime on
#[arg(long)]
pub port: u16,
macro_rules! arg_or_default {
($arg:literal, $field:ident $(,)?) => {
$field.ok_or_else(|| Error::MissingRequiredArgument { arg: $arg })
};
($arg:literal, $field:ident, $default:literal) => {
Ok($field.unwrap_or_else(|| $default.parse().unwrap()))
};
}

macro_rules! args {
($($arg:literal => $(#[arg(default_value = $default:literal)])? $field:ident: $ty:ty),+ $(,)?) => {
#[derive(Debug)]
pub struct Args {
$(pub $field: $ty,)+
}

/// Address to reach provisioner at
#[arg(long, default_value = "http://localhost:5000")]
pub provisioner_address: Endpoint,
impl Args {
pub fn parse() -> Result<Self, Error> {
$(let mut $field: Option<$ty> = None;)+

/// Type of storage manager to start
#[arg(long, value_enum)]
pub storage_manager_type: StorageManagerType,
let mut args_iter = env::args();
while let Some(arg) = args_iter.next() {
match arg.as_str() {
$($arg => {
if $field.is_some() {
return Err(Error::DuplicatedArgument { arg: $arg });
}
let raw_value = args_iter
.next()
.ok_or_else(|| Error::MissingValue { arg: $arg })?;
let value = raw_value.parse().map_err(|_| Error::InvalidValue {
arg: $arg,
value: raw_value,
})?;
$field = Some(value);
})+
_ => return Err(Error::UnexpectedArgument { arg }),
}
}

/// Path to use for storage manager
#[arg(long)]
pub storage_manager_path: PathBuf,
Ok(Args {
$($field: arg_or_default!($arg, $field, $($default)?)?,)+
})
}
}
}
}

/// Address to reach the authentication service at
#[arg(long, default_value = "http://127.0.0.1:8008")]
pub auth_uri: Uri,
args! {
"--port" => port: u16,
"--provisioner-address" => #[arg(default_value = "http://localhost:5000")] provisioner_address: Endpoint,
"--storage-manager-type" => storage_manager_type: StorageManagerType,
"--storage-manager-path" => storage_manager_path: PathBuf,
"--auth-uri" => #[arg(default_value = "http://127.0.0.1:8008")] auth_uri: Uri,
}

#[derive(Clone, Debug, ValueEnum)]
#[derive(Clone, Debug)]
pub enum StorageManagerType {
/// Use a deloyer artifacts directory
Artifacts,

/// Use a local working directory
WorkingDir,
}

impl FromStr for StorageManagerType {
type Err = ();

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"artifacts" => Ok(StorageManagerType::Artifacts),
"working-dir" => Ok(StorageManagerType::WorkingDir),
_ => Err(()),
}
}
}

#[derive(Debug)]
pub enum Error {
DuplicatedArgument { arg: &'static str },
MissingRequiredArgument { arg: &'static str },
UnexpectedArgument { arg: String },

InvalidValue { arg: &'static str, value: String },
MissingValue { arg: &'static str },
}

impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::DuplicatedArgument { arg } => write!(f, "duplicated argument {arg}"),
Self::MissingRequiredArgument { arg } => write!(f, "missing required argument {arg}"),
Self::UnexpectedArgument { arg } => write!(f, "unexpected argument: {arg}"),

Self::InvalidValue { arg, value } => {
write!(f, "invalid value for argument {arg}: {value}")
}
Self::MissingValue { arg } => write!(f, "missing value for argument {arg}"),
}
}
}

impl std::error::Error for Error {}
3 changes: 1 addition & 2 deletions runtime/src/alpha/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ use std::{

use anyhow::Context;
use async_trait::async_trait;
use clap::Parser;
use core::future::Future;
use shuttle_common::{
backends::{
Expand Down Expand Up @@ -51,7 +50,7 @@ use self::args::Args;
mod args;

pub async fn start(loader: impl Loader<ProvisionerFactory> + Send + 'static) {
let args = Args::parse();
let args = Args::parse().expect("could not parse arguments");
let addr = SocketAddr::new(Ipv4Addr::LOCALHOST.into(), args.port);

let provisioner_address = args.provisioner_address;
Expand Down

0 comments on commit 2e92064

Please sign in to comment.