flux_bin/
cargo_flux_opts.rs1use std::{path::Path, process::Command};
2
3use cargo_metadata::{MetadataCommand, camino::Utf8PathBuf};
4
5use crate::{cargo_style, utils::get_version};
6
7#[derive(clap::Parser)]
8#[command(name = "cargo")]
9#[command(bin_name = "cargo")]
10#[command(styles = cargo_style::CLAP_STYLING)]
11pub enum Cli {
12 Flux {
14 #[command(flatten)]
15 check_opts: CheckOpts,
16
17 #[command(subcommand)]
18 command: Option<CargoFluxCommand>,
19 },
20}
21
22#[derive(clap::Subcommand)]
23#[command(version = get_version())]
24pub enum CargoFluxCommand {
25 Check(CheckOpts),
28 Clean(CleanOpts),
30}
31
32impl CargoFluxCommand {
33 pub fn forward_args(&self, cmd: &mut Command, config_file: &Path) {
35 match self {
36 CargoFluxCommand::Check(check_opts) => {
37 cmd.arg("check");
38 check_opts.forward_args(cmd);
39 }
40 CargoFluxCommand::Clean(clean_opts) => {
41 cmd.arg("clean");
42 clean_opts.forward_args(cmd);
43 }
44 }
45 cmd.args(["--profile", "flux"]);
46 cmd.args(["--config".as_ref(), config_file.as_os_str()]);
47 }
48
49 pub fn metadata(&self) -> MetadataCommand {
50 let mut meta = cargo_metadata::MetadataCommand::new();
51 match self {
52 CargoFluxCommand::Check(check_options) => {
53 check_options.forward_to_metadata(&mut meta);
54 }
55 CargoFluxCommand::Clean(clean_options) => {
56 clean_options.forward_to_metadata(&mut meta);
57 }
58 }
59 meta
60 }
61}
62
63#[derive(clap::Args)]
64pub struct CheckOpts {
65 #[arg(long, value_name = "FMT")]
67 message_format: Option<String>,
68
69 #[command(flatten)]
70 workspace: Workspace,
71 #[command(flatten)]
72 features: Features,
73 #[command(flatten)]
74 manifest: ManifestOptions,
75}
76
77impl CheckOpts {
78 fn forward_args(&self, cmd: &mut Command) {
79 let CheckOpts { message_format, workspace, features, manifest } = self;
80 if let Some(message_format) = &message_format {
81 cmd.args(["--message-format", message_format]);
82 }
83 workspace.forward_args(cmd);
84 features.forward_args(cmd);
85 manifest.forward_args(cmd);
86 }
87
88 fn forward_to_metadata(&self, meta: &mut MetadataCommand) {
89 let CheckOpts { message_format: _, workspace: _, features, manifest } = self;
90 features.forward_to_metadata(meta);
91 manifest.forward_to_metadata(meta);
92 }
93}
94
95#[derive(clap::Args)]
96pub struct CleanOpts {
97 #[command(flatten, next_help_heading = "Package Selection")]
98 package: Package,
99 #[command(flatten)]
100 features: Features,
101 #[command(flatten)]
102 manifest: ManifestOptions,
103}
104
105impl CleanOpts {
106 fn forward_args(&self, cmd: &mut Command) {
107 let CleanOpts { package, features, manifest } = self;
108 package.forward_args(cmd);
109 features.forward_args(cmd);
110 manifest.forward_args(cmd);
111 }
112
113 fn forward_to_metadata(&self, meta: &mut MetadataCommand) {
114 let CleanOpts { package: _, features, manifest } = self;
115 features.forward_to_metadata(meta);
116 manifest.forward_to_metadata(meta);
117 }
118}
119
120#[derive(Debug, clap::Args)]
121#[command(about = None, long_about = None, next_help_heading = "Package Selection")]
122pub struct Workspace {
123 #[command(flatten)]
124 pub package: Package,
125
126 #[arg(long)]
127 pub workspace: bool,
129
130 #[arg(long, value_name = "SPEC")]
131 pub exclude: Vec<String>,
133}
134
135impl Workspace {
136 fn forward_args(&self, cmd: &mut Command) {
137 let Workspace { package, workspace, exclude } = self;
138 package.forward_args(cmd);
139 if *workspace {
140 cmd.arg("--workspace");
141 }
142 if !exclude.is_empty() {
143 cmd.args(exclude.iter().flat_map(|package| ["--exclude", package]));
144 }
145 }
146}
147
148#[derive(Debug, clap::Args)]
149#[command(about = None, long_about = None)]
150pub struct Package {
151 #[arg(short, long, value_name = "SPEC")]
152 pub package: Vec<String>,
154}
155
156impl Package {
157 fn forward_args(&self, cmd: &mut Command) {
158 let Package { package } = self;
159 if !package.is_empty() {
160 cmd.args(package.iter().flat_map(|package| ["--package", package]));
161 }
162 }
163}
164
165#[derive(Default, Clone, Debug, PartialEq, Eq, clap::Args)]
166#[command(about = None, long_about = None, next_help_heading = "Feature Selection")]
167pub struct Features {
168 #[arg(short = 'F', long, value_delimiter = ' ')]
169 pub features: Vec<String>,
171 #[arg(long)]
172 pub all_features: bool,
174 #[arg(long)]
175 pub no_default_features: bool,
177}
178
179impl Features {
180 fn forward_args(&self, cmd: &mut Command) {
181 let Features { features, all_features, no_default_features } = self;
182 if !features.is_empty() {
183 cmd.args(features.iter().flat_map(|feature| ["--features", feature]));
184 }
185 if *all_features {
186 cmd.arg("--all-features");
187 }
188 if *no_default_features {
189 cmd.arg("--no-default-features");
190 }
191 }
192
193 fn forward_to_metadata(&self, meta: &mut MetadataCommand) {
194 let Features { features, all_features, no_default_features } = self;
195 if *all_features {
196 meta.features(cargo_metadata::CargoOpt::AllFeatures);
197 }
198 if *no_default_features {
199 meta.features(cargo_metadata::CargoOpt::NoDefaultFeatures);
200 }
201 if !features.is_empty() {
202 meta.features(cargo_metadata::CargoOpt::SomeFeatures(features.clone()));
203 }
204 }
205}
206
207#[derive(Debug, clap::Args)]
208#[command(next_help_heading = "Manifest Options")]
209pub struct ManifestOptions {
210 #[arg(long, name = "PATH")]
211 manifest_path: Option<Utf8PathBuf>,
213 #[arg(long)]
215 offline: bool,
216}
217
218impl ManifestOptions {
219 fn forward_args(&self, cmd: &mut Command) {
220 let ManifestOptions { manifest_path, offline } = self;
221 if let Some(manifest_path) = &manifest_path {
222 cmd.args(["--manifest-path", manifest_path.as_str()]);
223 }
224 if *offline {
225 cmd.arg("--offline");
226 }
227 }
228
229 fn forward_to_metadata(&self, meta: &mut MetadataCommand) {
230 let ManifestOptions { manifest_path, offline: _ } = self;
232 if let Some(manifest_path) = &manifest_path {
233 meta.manifest_path(manifest_path);
234 }
235 }
236}