use clap::builder::{
Styles,
styling::{AnsiColor, Effects},
};
use clap::{Args, Parser, ValueEnum, ValueHint};
use clap_complete::Shell;
use openstack_sdk::AsyncOpenStack;
use crate::error::OpenStackCliError;
use crate::api;
use crate::auth;
use crate::block_storage::v3 as block_storage;
use crate::catalog;
use crate::compute::v2 as compute;
use crate::config::{Config, ConfigError};
use crate::container_infrastructure_management::v1 as container_infra;
use crate::dns::v2 as dns;
use crate::identity::v3 as identity;
#[cfg(feature = "keystone_ng")]
use crate::identity::v4 as identity_v4;
use crate::image::v2 as image;
use crate::load_balancer::v2 as load_balancer;
use crate::network::v2 as network;
use crate::object_store::v1 as object_store;
use crate::placement::v1 as placement;
fn styles() -> Styles {
Styles::styled()
.header(AnsiColor::Green.on_default() | Effects::BOLD)
.usage(AnsiColor::Green.on_default() | Effects::BOLD)
.literal(AnsiColor::White.on_default() | Effects::BOLD)
.placeholder(AnsiColor::Cyan.on_default())
}
#[derive(Parser)]
#[command(name="osc", author, version, about, long_about, styles = styles())]
#[command(propagate_version = true)]
pub struct Cli {
#[command(flatten)]
pub global_opts: GlobalOpts,
#[command(subcommand)]
pub command: TopLevelCommands,
#[arg(hide = true, long("cli-config"), value_parser = parse_config, default_value_t = Config::new().expect("invalid config"))]
pub config: Config,
}
pub fn parse_config(s: &str) -> Result<Config, OpenStackCliError> {
let mut builder = Config::builder()?;
if !s.is_empty() {
builder = builder.add_source(s).map_err(ConfigError::builder)?;
}
Ok(builder.build()?)
}
#[derive(Args)]
#[command(next_display_order = 800, next_help_heading = "Connection options")]
pub struct ConnectionOpts {
#[arg(long, env = "OS_CLOUD", global = true, display_order = 801, conflicts_with_all(["cloud_config_from_env", "os_cloud_name"]))]
pub os_cloud: Option<String>,
#[arg(long, global = true, action = clap::ArgAction::SetTrue, display_order = 802)]
pub cloud_config_from_env: bool,
#[arg(long, env = "OS_CLOUD_NAME", global = true, display_order = 802)]
pub os_cloud_name: Option<String>,
#[arg(long, env = "OS_PROJECT_ID", global = true, display_order = 803)]
pub os_project_id: Option<String>,
#[arg(long, env = "OS_PROJECT_NAME", global = true, display_order = 803)]
pub os_project_name: Option<String>,
#[arg(long, env = "OS_REGION_NAME", global = true, display_order = 804)]
pub os_region_name: Option<String>,
#[arg(
long,
env = "OS_CLIENT_CONFIG_FILE",
global = true,
value_hint = ValueHint::FilePath,
display_order = 805
)]
pub os_client_config_file: Option<String>,
#[arg(
long,
env = "OS_CLIENT_SECURE_FILE",
global = true,
value_hint = ValueHint::FilePath,
display_order = 805
)]
pub os_client_secure_file: Option<String>,
#[arg(long, global = true, value_hint = ValueHint::ExecutablePath, display_order = 810)]
pub auth_helper_cmd: Option<String>,
}
#[derive(Args)]
#[command(next_display_order = 900, next_help_heading = "Output options")]
pub struct OutputOpts {
#[arg(short, long, global = true, value_enum, display_order = 910)]
pub output: Option<OutputFormat>,
#[arg(short, long, global=true, action=clap::ArgAction::Append, display_order = 910)]
pub fields: Vec<String>,
#[arg(short, long, global=true, action = clap::ArgAction::SetTrue, display_order = 910)]
pub pretty: bool,
#[arg(short, long, global=true, action = clap::ArgAction::Count, display_order = 920)]
pub verbose: u8,
#[arg(long, global=true, default_value_t = TableArrangement::Dynamic, value_enum, display_order = 930)]
pub table_arrangement: TableArrangement,
#[arg(long, global=true, action = clap::ArgAction::SetTrue, display_order = 950)]
pub timing: bool,
}
#[derive(Args)]
#[command(next_display_order = 900)]
pub struct GlobalOpts {
#[command(flatten)]
pub connection: ConnectionOpts,
#[command(flatten)]
pub output: OutputOpts,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
pub enum OutputFormat {
Json,
Wide,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
pub enum TableArrangement {
#[default]
Dynamic,
DynamicFullWidth,
Disabled,
}
#[allow(missing_docs)]
#[derive(Parser)]
pub enum TopLevelCommands {
Api(api::ApiCommand),
Auth(auth::AuthCommand),
BlockStorage(block_storage::BlockStorageCommand),
Catalog(catalog::CatalogCommand),
Compute(compute::ComputeCommand),
#[command(aliases = ["container-infrastructure-management", "container"])]
ContainerInfrastructure(container_infra::ContainerInfrastructureCommand),
Dns(dns::DnsCommand),
Identity(identity::IdentityCommand),
#[cfg(feature = "keystone_ng")]
Identity4(identity_v4::IdentityCommand),
Image(image::ImageCommand),
LoadBalancer(load_balancer::LoadBalancerCommand),
Network(network::NetworkCommand),
ObjectStore(object_store::ObjectStoreCommand),
Placement(placement::PlacementCommand),
Completion(CompletionCommand),
}
#[derive(Parser, Debug)]
pub struct CompletionCommand {
#[arg(default_value_t = Shell::Bash)]
pub shell: Shell,
}
impl Cli {
pub async fn take_action(&self, client: &mut AsyncOpenStack) -> Result<(), OpenStackCliError> {
match &self.command {
TopLevelCommands::Api(args) => args.take_action(self, client).await,
TopLevelCommands::Auth(args) => args.take_action(self, client).await,
TopLevelCommands::BlockStorage(args) => args.take_action(self, client).await,
TopLevelCommands::Catalog(args) => args.take_action(self, client).await,
TopLevelCommands::Compute(args) => args.take_action(self, client).await,
TopLevelCommands::ContainerInfrastructure(args) => args.take_action(self, client).await,
TopLevelCommands::Dns(args) => args.take_action(self, client).await,
TopLevelCommands::Identity(args) => args.take_action(self, client).await,
#[cfg(feature = "keystone_ng")]
TopLevelCommands::Identity4(args) => args.take_action(self, client).await,
TopLevelCommands::Image(args) => args.take_action(self, client).await,
TopLevelCommands::LoadBalancer(args) => args.take_action(self, client).await,
TopLevelCommands::Network(args) => args.take_action(self, client).await,
TopLevelCommands::ObjectStore(args) => args.take_action(self, client).await,
TopLevelCommands::Placement(args) => args.take_action(self, client).await,
TopLevelCommands::Completion(_) => unimplemented!(),
}
}
}