[issue #7] CLI parse subcommands

This commit is contained in:
anastasia
2021-03-26 19:08:45 +03:00
committed by Stas Kelvich
parent c018247c56
commit 853c130ff0
7 changed files with 192 additions and 101 deletions

View File

@@ -31,3 +31,4 @@ tokio-stream = { version = "0.1.4" }
tokio-postgres = { git = "https://github.com/kelvich/rust-postgres", branch = "replication_rebase" }
postgres-protocol = { git = "https://github.com/kelvich/rust-postgres", branch = "replication_rebase" }
postgres = { git = "https://github.com/kelvich/rust-postgres", branch = "replication_rebase" }
anyhow = "1.0"

46
src/bin/cli/main.rs Normal file
View File

@@ -0,0 +1,46 @@
use clap::{App, AppSettings};
use anyhow::{Result};
mod subcommand;
pub mod pg;
pub mod storage;
pub mod snapshot;
fn main() -> Result<()> {
let cli_commands = subcommand::ClapCommands {
commands: vec![
Box::new(pg::PgCmd {
clap_cmd: clap::SubCommand::with_name("pg"),
}),
Box::new(storage::StorageCmd {
clap_cmd: clap::SubCommand::with_name("storage"),
}),
Box::new(snapshot::SnapshotCmd {
clap_cmd: clap::SubCommand::with_name("snapshot"),
}),
],
};
let matches = App::new("zenith")
.about("Zenith CLI")
.version("1.0")
.setting(AppSettings::SubcommandRequiredElseHelp)
.subcommands(cli_commands.generate())
.get_matches();
if let Some(subcommand) = matches.subcommand_name() {
println!("'git {}' was used", subcommand);
}
match matches.subcommand() {
("pg", Some(sub_args)) => cli_commands.commands[0].run(sub_args.clone())?,
("storage", Some(sub_args)) => cli_commands.commands[1].run(sub_args.clone())?,
("snapshot", Some(sub_args)) => cli_commands.commands[2].run(sub_args.clone())?,
("", None) => println!("No subcommand"),
_ => unreachable!(),
}
Ok(())
}

41
src/bin/cli/pg.rs Normal file
View File

@@ -0,0 +1,41 @@
use clap::{App, AppSettings, Arg};
use anyhow::{Result};
use crate::subcommand;
pub struct PgCmd<'a> {
pub clap_cmd: clap::App<'a, 'a>,
}
impl subcommand::SubCommand for PgCmd<'_> {
fn gen_clap_command(&self) -> clap::App {
let c = self.clap_cmd.clone();
c.about("Operations with zenith compute nodes")
.setting(AppSettings::SubcommandRequiredElseHelp)
.subcommand(
App::new("list")
)
.subcommand(
App::new("create")
.arg(Arg::with_name("pgdata").required(true)),
)
.subcommand(
App::new("destroy")
)
.subcommand(
App::new("start")
)
.subcommand(
App::new("stop")
)
.subcommand(
App::new("show")
)
}
fn run(&self, args: clap::ArgMatches) -> Result<()> {
println!("Run PgCmd with args {:?}", args);
Ok(())
}
}

41
src/bin/cli/snapshot.rs Normal file
View File

@@ -0,0 +1,41 @@
use clap::{App, AppSettings, Arg};
use anyhow::{Result};
use crate::subcommand;
pub struct SnapshotCmd<'a> {
pub clap_cmd: clap::App<'a, 'a>,
}
impl subcommand::SubCommand for SnapshotCmd<'_> {
fn gen_clap_command(&self) -> clap::App {
let c = self.clap_cmd.clone();
c.about("Operations with zenith snapshots")
.setting(AppSettings::SubcommandRequiredElseHelp)
.subcommand(
App::new("list")
)
.subcommand(
App::new("create")
.arg(Arg::with_name("pgdata").required(true)),
)
.subcommand(
App::new("destroy")
)
.subcommand(
App::new("start")
)
.subcommand(
App::new("stop")
)
.subcommand(
App::new("show")
)
}
fn run(&self, args: clap::ArgMatches) -> Result<()> {
println!("Run SnapshotCmd with args {:?}", args);
Ok(())
}
}

34
src/bin/cli/storage.rs Normal file
View File

@@ -0,0 +1,34 @@
use clap::{App, AppSettings};
use anyhow::{Result};
use crate::subcommand;
pub struct StorageCmd<'a> {
pub clap_cmd: clap::App<'a, 'a>,
}
impl subcommand::SubCommand for StorageCmd<'_> {
fn gen_clap_command(&self) -> clap::App {
let c = self.clap_cmd.clone();
c.about("Operations with zenith storage nodes")
.setting(AppSettings::SubcommandRequiredElseHelp)
.subcommand(
App::new("list")
)
.subcommand(
App::new("attach")
)
.subcommand(
App::new("detach")
)
.subcommand(
App::new("show")
)
}
fn run(&self, args: clap::ArgMatches) -> Result<()> {
println!("Run StorageCmd with args {:?}", args);
Ok(())
}
}

29
src/bin/cli/subcommand.rs Normal file
View File

@@ -0,0 +1,29 @@
use anyhow::Result;
/// All subcommands need to implement this interface.
pub trait SubCommand {
/// Generates the cli-config that Clap requires for the subcommand.
fn gen_clap_command(&self) -> clap::App;
/// Runs the body of the subcommand.
fn run(&self, args: clap::ArgMatches) -> Result<()>;
}
/// A struct which holds a vector of heap-allocated `Box`es of trait objects all of which must
/// implement the `SubCommand` trait, but other than that, can be of any type.
pub struct ClapCommands {
pub commands: Vec<Box<dyn SubCommand>>,
}
impl ClapCommands {
/// Generates a vector of `clap::Apps` that can be passed into clap's `.subcommands()` method in
/// order to generate the full CLI.
pub fn generate(&self) -> Vec<clap::App> {
let mut v: Vec<clap::App> = Vec::new();
for command in self.commands.iter() {
v.push(command.gen_clap_command());
}
v
}
}

View File

@@ -1,101 +0,0 @@
use clap::{App, AppSettings, Arg};
fn main() {
let matches = App::new("zenith")
.about("Zenith CLI")
.version("1.0")
.setting(AppSettings::SubcommandRequiredElseHelp)
.subcommand(
App::new("pg")
.about("compute node postgres")
.setting(AppSettings::SubcommandRequiredElseHelp)
.subcommand(
App::new("list")
)
.subcommand(
App::new("create")
.arg(Arg::with_name("pgdata").required(true)),
)
.subcommand(
App::new("destroy")
)
.subcommand(
App::new("start")
)
.subcommand(
App::new("stop")
)
.subcommand(
App::new("show")
),
)
.subcommand(
App::new("storage")
.about("storage node postgres")
.setting(AppSettings::SubcommandRequiredElseHelp)
.subcommand(
App::new("list")
)
.subcommand(
App::new("attach")
)
.subcommand(
App::new("detach")
)
.subcommand(
App::new("show")
),
)
.get_matches();
if let Some(subcommand) = matches.subcommand_name() {
println!("'git {}' was used", subcommand);
}
match matches.subcommand() {
("pg", Some(pg_matches)) => {
println!("pg subcommand");
match pg_matches.subcommand()
{
("list", _) => {
println!("list subcommand");
}
("create", _) => {
}
("destroy", _) => {
}
("start", _) => {
}
("stop", _) => {
}
("show", _) => {
}
("", None) => println!("No subcommand"),
_ => unreachable!(),
}
}
("storage", Some(storage_matches)) => {
println!("storage subcommand");
match storage_matches.subcommand()
{
("list", _) => {
println!("list subcommand");
}
("attach", _) => {
}
("detach", _) => {
}
("show", _) => {
}
("", None) => println!("No subcommand"),
_ => unreachable!(),
}
}
("", None) => println!("No subcommand"),
_ => unreachable!(),
}
}