我正在开发一个 CLI 工具,其中包含多个子命令,适用于不同的用例。这是我的项目结构:
project/
├── Cargo.toml
└── crates/
├── project-foo/
│ └── src/
│ └── lib.rs (subcommand for 'foo')
├── project-bar/
│ └── src/
│ └── lib.rs (subcommand for 'bar')
└── project-core/
└── src/
└── main.rs (main entry point for the CLI app)
在我的
Cargo.toml
中,我设置了如下工作区配置:
[workspace]
members = ["crates/*"]
resolver = "2"
例如,考虑
project-foo
箱,它公开一个名为 FileAction
的子命令。该子命令包含两个子命令。
#[derive(Debug, Subcommand)]
pub enum FileAction {
Copy(CopyCommand),
Paste(PasteCommand),
}
#[derive(Debug, clap::Args)]
pub struct CopyCommand {
// Include any relevant options here.
}
impl CopyCommand {
pub async fn handle(&self) -> Result<()> {
// handle the code
}
}
在
project-core
箱中,我们使用 Cli
结构来管理这些子命令。
#[derive(Parser)]
#[command(subcommand_required = true)]
pub struct Cli {
#[command(subcommand)]
pub command: Commands,
}
#[derive(Subcommand)]
pub enum Commands {
File {
#[clap(subcommand)]
action: FileAction,
},
}
fn main() {
let matches = Cli::command().get_matches();
let cli = Cli::from_arg_matches(&matches).unwrap();
match cli.command {
File { action } => match action {
FileAction::Copy(copy_args) => {
if let Err(err) = copy_args.handle().await {
eprintln!("{}", err);
}
},
FileAction::Paste(paste_args) => {
if let Err(err) = paste_args.handle().await {
eprintln!("{}", err);
}
},
},
}
}
理想情况下,我的
project-core/Cargo.toml
看起来像这样:
[package]
name = "project"
version = "0.1.0"
edition = "2021"
[dependencies]
project-foo = { path = "../project-foo" }
project-bar = { path = "../project-bar" }
由于两个子命令中使用的 crate 之间存在持续的依赖性问题,因此此方法不起作用。这个问题似乎不太可能在不久的将来得到解决。
注意:由于功能统一
,无法使用Cargo功能来解决问题我最初的想法是将一个箱子移到
crates
文件夹之外,这样当我运行 cargo build
时它就不会自动编译。然后,我想找到一种方法从 project-core
构建它,并将其作为 project-core/main.rs
中定义的 CLI 中的子进程执行。
这种方法是否可行,是否是一个好的解决方案?或者有没有更直接的方法来解决这个问题
我设法通过修补导致问题的板条箱解决了这个问题。
在两个依赖项(例如
project-foo
和 project-bar
)依赖于第三个 crate 的不同版本的情况下,会出现依赖项冲突。
每个 crate 都指定一个特定的版本,从而导致这种冲突。幸运的是,我在第三个箱子中发现了一个满足两个箱子版本要求的提交。我在我的
Cargo.toml
中添加了一个补丁来解决这个问题:
[patch.crates-io.third_crate]
git = "https://github.com/user/third_crate"
rev = "<commit>" # This commit meets both crates' version requirements
但是,如果不存在合适的提交,我会通过分叉箱子并进行修改来解决问题。