如何使用 structopt 创建嵌套子命令?

How to create nested subcommands with structopt?

简介

我目前有使用 structopt 的子命令,类似于另一个 answer。但是,我希望嵌套子命令与 docker 的工作方式类似:

docker image ls
docker image pull

当前代码

main.rs

mod cli;

use structopt::StructOpt;
use crate::cli::{Opt, Command};

fn main() {

    let opt = Opt::from_args();
    match opt.cmd {
        Command::Subcommand { .. } => {
            // Do something
        }
    }

}

cli/mod.rs

use structopt::StructOpt;

#[derive(StructOpt, Debug)]
pub enum Command {
    Subcommand {
       // args
    }
}

#[derive(StructOpt, Debug)]
pub struct Opt {
    #[structopt(subcommand)]
    pub cmd: Command,
}

我试过的

添加了另一个结构: main.rs

mod cli;

use structopt::StructOpt;
use crate::cli::{Opt, Resource};

fn main() {

    let opt = Opt::from_args();
    match opt.resource {
        Resource::Command { .. } => {
            // do something
        }
    }

}

cli/mod.rs

use structopt::StructOpt;

#[derive(StructOpt, Debug)]
pub enum Command {
    Subcommand {
        // args
    }
}

#[derive(StructOpt, Debug)]
pub struct Resource {
    #[structopt(subcommand)]
    image: Image
}

#[derive(StructOpt, Debug)]
pub struct Opt {
    #[structopt(subcommand)]
    pub resource: Resource,
}

但是我收到以下错误:

help: use fully-qualified syntax: `<Resource as Trait>::ImageCommand

由于命令被描述为枚举,因此子命令将是“子枚举”(枚举变体中的枚举)。在下面的示例中,ImageCommand 是 Command 枚举变体中的一个枚举:

use structopt::StructOpt;

#[derive(StructOpt, Debug)]
pub struct ImagePullOptions {
    pub name: String,
}

#[derive(StructOpt, Debug)]
pub enum ImageCommand {
    #[structopt(name = "ls")]
    List,
    Pull(ImagePullOptions),
}

#[derive(StructOpt, Debug)]
pub enum Command {
    Image(ImageCommand),
}

#[derive(StructOpt, Debug)]
pub struct Options {
    #[structopt(subcommand)]
    pub command: Command,
}

fn main() {
    let options: Options = Options::from_args();
    match options.command {
        Command::Image(image_command) => {
            match image_command {
                ImageCommand::List => println!("listing..."),
                ImageCommand::Pull(pull_options) => println!("pulling {}...", pull_options.name),
            }
        }
    }
}

测试:

$ cargo run -- image 

USAGE:
    testsubopt image <SUBCOMMAND>

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

SUBCOMMANDS:
    help    Prints this message or the help of the given subcommand(s)
    ls      
    pull    
$ cargo run -- image pull asd
pulling asd...