Skip to main content

multiversx_sc_meta/cli/
cli_args_standalone.rs

1use clap::{ArgAction, Args, Parser, Subcommand, ValueEnum};
2use std::path::PathBuf;
3
4use multiversx_sc_meta_lib::cli::{CliArgsToRaw, ContractCliAction};
5
6/// Parsed arguments of the meta crate CLI.
7#[derive(Default, PartialEq, Eq, Debug, Parser)]
8#[command(
9    version,
10    about,
11    after_help = "
12The MultiversX smart contract Meta crate can be used in two ways:
13    A. Import it into a contract's specific meta-crate. 
14        There it will receive access to the contract ABI generator. 
15        Based on that it is able to build the contract and apply various tools.
16        This part also contains the multi-contract config infrastructure.
17
18    B. Use it as a standalone tool.
19        It can be used to automatically upgrade contracts from one version to the next.
20
21You are currently using the standalone tool (B).
22"
23)]
24#[command(propagate_version = true)]
25pub struct StandaloneCliArgs {
26    #[command(subcommand)]
27    pub command: Option<StandaloneCliAction>,
28}
29
30#[derive(Clone, PartialEq, Eq, Debug, Subcommand)]
31pub enum StandaloneCliAction {
32    #[command(name = "install", about = "Installs framework dependencies")]
33    Install(InstallArgs),
34
35    #[command(
36        about = "General info about the contract an libraries residing in the targeted directory.."
37    )]
38    Info(InfoArgs),
39
40    #[command(
41        about = "Calls the meta crates for all contracts under given path with the given arguments."
42    )]
43    All(AllArgs),
44
45    #[command(
46        about = "Upgrades a contract to the latest version. Multiple contract crates are allowed."
47    )]
48    Upgrade(UpgradeArgs),
49
50    #[command(name = "new", about = "Creates a contract by a pre-existing template")]
51    Template(TemplateArgs),
52
53    #[command(name = "templates", about = "Lists all pre-existing templates")]
54    TemplateList(TemplateListArgs),
55
56    #[command(
57        name = "test-gen",
58        about = "Generates Rust integration tests based on scenarios provided in the scenarios folder of each contract."
59    )]
60    TestGen(TestGenArgs),
61
62    #[command(
63        name = "scen-blackbox",
64        about = "Generates blackbox tests from scenario files (.scen.json)."
65    )]
66    ScenBlackbox(ScenBlackboxArgs),
67
68    #[command(name = "test", about = "Runs cargo test")]
69    Test(TestArgs),
70
71    #[command(name = "test-coverage", about = "Run test coverage and output report")]
72    TestCoverage(TestCoverageArgs),
73
74    #[command(name = "report", about = "Generate code report")]
75    CodeReportGen(CodeReportArgs),
76
77    #[command(
78        about = "Generates a scenario test initialized with real data fetched from the blockchain."
79    )]
80    Account(AccountArgs),
81
82    #[command(
83        name = "local-deps",
84        about = "Generates a report on the local dependencies of contract crates. Will explore indirect dependencies too."
85    )]
86    LocalDeps(LocalDepsArgs),
87
88    #[command(
89        name = "wallet",
90        about = "Generates a new wallet or performs actions on an existing wallet."
91    )]
92    Wallet(WalletArgs),
93
94    #[command(
95        name = "cs",
96        about = "Can install, start and stop a chain simulator configuration."
97    )]
98    ChainSimulator(ChainSimulatorArgs),
99}
100
101#[derive(Clone, PartialEq, Eq, Debug, Args)]
102pub struct ChainSimulatorArgs {
103    #[command(subcommand)]
104    pub command: ChainSimulatorCommand,
105}
106
107#[derive(Clone, PartialEq, Eq, Debug, Subcommand)]
108pub enum ChainSimulatorCommand {
109    #[command(
110        about = "Pulls the latest chain simulator docker image available. Needs Docker installed."
111    )]
112    Install,
113
114    #[command(about = "Starts the chain simulator.")]
115    Start,
116
117    #[command(about = "Stops the chain simulator.")]
118    Stop,
119}
120
121#[derive(Default, Clone, PartialEq, Eq, Debug, Args)]
122pub struct InfoArgs {
123    /// Target directory to retrieve info from.
124    /// Will be current directory if not specified.
125    #[arg(long, verbatim_doc_comment)]
126    pub path: Option<String>,
127
128    /// Ignore all directories with these names.
129    #[arg(long, verbatim_doc_comment)]
130    #[clap(global = true, default_value = "target")]
131    pub ignore: Vec<String>,
132}
133
134#[derive(Default, Clone, PartialEq, Eq, Debug, Args)]
135pub struct TestArgs {
136    /// Target directory where to generate contract integration tests (default: current directory)
137    #[arg(short, long)]
138    pub path: Option<String>,
139
140    /// Run Debugger (Rust-only) and Go tests; deprecated in favor of -w or --wasm (default: "false")
141    #[arg(short, long, default_value = "false")]
142    pub go: bool,
143
144    /// Run tests that are based on compiled contracts (default: "false")
145    #[arg(short, long, default_value = "false")]
146    pub wasm: bool,
147
148    /// Run interactor tests using chain simulator (default: "false")
149    #[arg(
150        short = 'c',
151        long = "chain-simulator",
152        default_value = "false",
153        verbatim_doc_comment
154    )]
155    pub chain_simulator: bool,
156
157    /// Run mx-scenario-go (default: "false")
158    /// Overrides other arguments
159    #[arg(short, long, default_value = "false", verbatim_doc_comment)]
160    pub scen: bool,
161
162    /// Print the entire output from the Rust tests (default: "false")
163    #[arg(short, long, default_value = "false", verbatim_doc_comment)]
164    pub nocapture: bool,
165}
166
167#[derive(Default, Clone, PartialEq, Eq, Debug, ValueEnum)]
168pub enum OutputFormat {
169    /// Markdown pretty-print summary
170    #[default]
171    Markdown,
172
173    /// JSON summary
174    Json,
175}
176
177#[derive(Default, Clone, PartialEq, Eq, Debug, Args)]
178pub struct TestCoverageArgs {
179    /// Output file path
180    #[arg(short, long, verbatim_doc_comment)]
181    pub output: String,
182
183    /// Output format
184    #[arg(short, long, verbatim_doc_comment)]
185    pub format: Option<OutputFormat>,
186
187    /// Ignore files by path patterns
188    #[arg(short = 'i', long = "ignore-filename-regex", verbatim_doc_comment)]
189    pub ignore_filename_regex: Vec<String>,
190}
191
192#[derive(Clone, PartialEq, Eq, Debug, Args)]
193pub struct CodeReportArgs {
194    #[command(subcommand)]
195    pub command: CodeReportAction,
196}
197
198#[derive(Clone, PartialEq, Eq, Debug, Subcommand)]
199pub enum CodeReportAction {
200    #[command(name = "compile", about = "Generates the contract report.")]
201    Compile(CompileArgs),
202
203    #[command(name = "compare", about = "Compare two contract reports.")]
204    Compare(CompareArgs),
205
206    #[command(
207        name = "convert",
208        about = "Converts a contract report to a Markdown file."
209    )]
210    Convert(ConvertArgs),
211}
212
213#[derive(Clone, PartialEq, Eq, Debug, Args)]
214pub struct CompileArgs {
215    /// Target directory where to generate code report.
216    #[arg(short, long, verbatim_doc_comment)]
217    pub path: PathBuf,
218
219    /// Path to the Markdown or JSON file where the report results will be written.
220    #[arg(short, long, verbatim_doc_comment)]
221    pub output: PathBuf,
222}
223
224#[derive(Clone, PartialEq, Eq, Debug, Args)]
225pub struct CompareArgs {
226    /// Path to the previous version of code report JSON file
227    /// that will be used for comparison.
228    #[arg(short, long, verbatim_doc_comment)]
229    pub baseline: PathBuf,
230
231    /// Path to the current version of the code report JSON file
232    /// that will be compared.
233    #[arg(short, long, verbatim_doc_comment)]
234    pub new: PathBuf,
235
236    /// Path to the Markdown file where the comparison results will be written.
237    #[arg(short, long, verbatim_doc_comment)]
238    pub output: PathBuf,
239}
240
241#[derive(Clone, PartialEq, Eq, Debug, Args)]
242pub struct ConvertArgs {
243    /// Path to the JSON report file that needs to be converted to Markdown format.
244    #[arg(short, long, verbatim_doc_comment)]
245    pub input: PathBuf,
246
247    /// Path to the Markdown file where the report results will be written.
248    #[arg(short, long, verbatim_doc_comment)]
249    pub output: PathBuf,
250}
251
252#[derive(Default, Clone, PartialEq, Eq, Debug, Args)]
253pub struct AllArgs {
254    #[command(subcommand)]
255    pub command: ContractCliAction,
256
257    /// Target directory where to call all contract meta crates.
258    /// Will be current directory if not specified.
259    #[arg(long, verbatim_doc_comment)]
260    #[clap(global = true)]
261    pub path: Option<String>,
262
263    /// Ignore all directories with these names.
264    #[arg(long, verbatim_doc_comment)]
265    #[clap(global = true, default_value = "target")]
266    pub ignore: Vec<String>,
267
268    #[arg(
269        long = "no-abi-git-version",
270        help = "Skips loading the Git version into the ABI",
271        action = ArgAction::SetFalse
272    )]
273    #[clap(global = true)]
274    pub load_abi_git_version: bool,
275
276    /// For the meta crates, allows specifying the target directory where the Rust compiler will build the intermediary files.
277    /// Sharing the same target directory can speed up building multiple contract crates at once.
278    #[arg(long = "target-dir-meta", verbatim_doc_comment)]
279    #[clap(global = true)]
280    pub target_dir_meta: Option<String>,
281
282    /// Overrides both the --target-dir-meta and the --target-dir-wasm args.
283    #[arg(long = "target-dir-all", verbatim_doc_comment)]
284    #[clap(global = true)]
285    pub target_dir_all: Option<String>,
286}
287
288impl AllArgs {
289    pub fn target_dir_all_override(&self) -> Self {
290        let mut result = self.clone();
291        if let Some(target_dir_all) = &self.target_dir_all {
292            result.target_dir_meta = Some(target_dir_all.clone());
293            match &mut result.command {
294                ContractCliAction::Build(build_args) => {
295                    build_args.target_dir_wasm = Some(target_dir_all.clone());
296                }
297                ContractCliAction::BuildDbg(build_args) => {
298                    build_args.target_dir_wasm = Some(target_dir_all.clone());
299                }
300                ContractCliAction::Twiggy(build_args) => {
301                    build_args.target_dir_wasm = Some(target_dir_all.clone());
302                }
303                _ => {}
304            }
305        }
306        result
307    }
308
309    pub fn to_cargo_run_args(&self) -> Vec<String> {
310        let processed = self.target_dir_all_override();
311        let mut raw = vec!["run".to_string()];
312        if let Some(target_dir_meta) = &processed.target_dir_meta {
313            raw.push("--target-dir".to_string());
314            raw.push(target_dir_meta.clone());
315        }
316        raw.append(&mut processed.command.to_raw());
317        if !processed.load_abi_git_version {
318            raw.push("--no-abi-git-version".to_string());
319        }
320        raw
321    }
322
323    /// Produces the arguments for an abi call corresponding to a build.
324    ///
325    /// Used to get the rustc and framework versions configured for a build.
326    pub fn to_cargo_abi_for_build(&self) -> Vec<String> {
327        let processed = self.target_dir_all_override();
328        let mut raw = vec!["run".to_string()];
329        if let Some(target_dir_meta) = &processed.target_dir_meta {
330            raw.push("--target-dir".to_string());
331            raw.push(target_dir_meta.clone());
332        }
333        raw.push("abi".to_string());
334        if !processed.load_abi_git_version {
335            raw.push("--no-abi-git-version".to_string());
336        }
337        raw
338    }
339}
340
341#[derive(Default, Clone, PartialEq, Eq, Debug, Args)]
342pub struct UpgradeArgs {
343    /// Target directory where to upgrade contracts.
344    /// Will be current directory if not specified.
345    #[arg(long, verbatim_doc_comment)]
346    pub path: Option<String>,
347
348    /// Ignore all directories with these names.
349    #[arg(long, verbatim_doc_comment)]
350    #[clap(global = true, default_value = "target")]
351    pub ignore: Vec<String>,
352
353    /// Overrides the version to upgrade to.
354    /// By default it will be the last version out.
355    #[arg(long = "to", verbatim_doc_comment)]
356    pub override_target_version: Option<String>,
357
358    /// Skips 'cargo check' after upgrade
359    #[arg(short, long, default_value = "false", verbatim_doc_comment)]
360    pub no_check: bool,
361}
362
363#[derive(Default, Clone, PartialEq, Eq, Debug, Args)]
364pub struct LocalDepsArgs {
365    /// Target directory where to generate local deps reports.
366    /// Will be current directory if not specified.
367    #[arg(long, verbatim_doc_comment)]
368    pub path: Option<String>,
369
370    /// Ignore all directories with these names.
371    #[arg(long, verbatim_doc_comment)]
372    #[clap(global = true, default_value = "target")]
373    pub ignore: Vec<String>,
374}
375
376#[derive(Default, Clone, PartialEq, Eq, Debug, Args)]
377pub struct TemplateArgs {
378    /// The new name the contract is to receive.
379    /// If missing, the template name will be considered.
380    #[arg(long, verbatim_doc_comment)]
381    pub name: Option<String>,
382
383    /// The contract template to clone.
384    #[arg(long, verbatim_doc_comment)]
385    pub template: String,
386
387    /// The framework version on which the contracts should be created.
388    #[arg(long, verbatim_doc_comment)]
389    pub tag: Option<String>,
390
391    /// Target directory where to create the new contract directory.
392    /// Will be current directory if not specified.
393    #[arg(long, verbatim_doc_comment)]
394    pub path: Option<PathBuf>,
395
396    /// The author of the contract.
397    /// If missing, the default author will be considered.
398    #[arg(long, verbatim_doc_comment)]
399    pub author: Option<String>,
400}
401
402impl CliArgsToRaw for TemplateArgs {
403    fn to_raw(&self) -> Vec<String> {
404        Vec::new()
405    }
406}
407
408#[derive(Default, Clone, PartialEq, Eq, Debug, Args)]
409pub struct TemplateListArgs {
410    /// The framework version referred to.
411    #[arg(long = "tag", verbatim_doc_comment)]
412    pub tag: Option<String>,
413}
414
415#[derive(Default, Clone, PartialEq, Eq, Debug, Args)]
416pub struct TestGenArgs {
417    /// Target directory where to generate contract integration tests.
418    /// Will be current directory if not specified.
419    #[arg(long, verbatim_doc_comment)]
420    pub path: Option<String>,
421
422    /// Ignore all directories with these names.
423    #[arg(long, verbatim_doc_comment)]
424    #[clap(global = true, default_value = "target")]
425    pub ignore: Vec<String>,
426
427    /// Creates test files if they don't exist.
428    #[arg(long, verbatim_doc_comment)]
429    pub create: bool,
430}
431
432#[derive(Default, Clone, PartialEq, Eq, Debug, Args)]
433pub struct ScenBlackboxArgs {
434    /// Target directory where to generate contract blackbox tests.
435    /// Will be current directory if not specified.
436    #[arg(long, verbatim_doc_comment)]
437    pub path: Option<String>,
438
439    /// Override test files if they already exist.
440    #[arg(long, verbatim_doc_comment)]
441    pub overwrite: bool,
442
443    /// Ignore all directories with these names.
444    #[arg(long, verbatim_doc_comment)]
445    #[clap(global = true, default_value = "target")]
446    pub ignore: Vec<String>,
447
448    /// Output file path for the generated blackbox test.
449    /// If not specified, the default path inside the contract's tests/ folder is used.
450    #[arg(long, verbatim_doc_comment)]
451    pub output: Option<String>,
452}
453
454#[derive(Default, PartialEq, Eq, Debug, Clone, Parser)]
455#[command(propagate_version = true)]
456pub struct InstallArgs {
457    #[command(subcommand)]
458    pub command: Option<InstallCommand>,
459}
460
461#[derive(Clone, PartialEq, Eq, Debug, Subcommand)]
462pub enum InstallCommand {
463    #[command(about = "Installs all the known tools")]
464    All,
465
466    #[command(about = "Installs the `mx-scenario-go` tool")]
467    MxScenarioGo(InstallMxScenarioGoArgs),
468
469    #[command(name = "wasm32", about = "Installs the `wasm32` target")]
470    Wasm32(InstallWasm32Args),
471
472    #[command(name = "wasm-opt", about = "Installs the `wasm-opt` tool")]
473    WasmOpt(InstallWasmOptArgs),
474
475    #[command(name = "debugger", about = "Installs the lldb debugger script tool")]
476    Debugger(InstallDebuggerArgs),
477}
478
479#[derive(Default, Clone, PartialEq, Eq, Debug, Args)]
480pub struct InstallMxScenarioGoArgs {
481    /// The framework version on which the contracts should be created.
482    #[arg(long, verbatim_doc_comment)]
483    pub tag: Option<String>,
484}
485
486#[derive(Default, Clone, PartialEq, Eq, Debug, Args)]
487pub struct InstallWasm32Args {}
488
489#[derive(Default, Clone, PartialEq, Eq, Debug, Args)]
490pub struct InstallWasmOptArgs {}
491
492#[derive(Default, Clone, PartialEq, Eq, Debug, Args)]
493pub struct InstallDebuggerArgs {}
494
495#[derive(Default, Clone, PartialEq, Eq, Debug, Args)]
496pub struct AccountArgs {
497    /// Provide the target API you want the data to come from
498    #[arg(long = "api")]
499    #[clap(global = true)]
500    pub api: Option<String>,
501
502    /// Provide the address you want to retrieve data from
503    #[arg(long = "address", verbatim_doc_comment)]
504    pub address: String,
505}
506
507#[derive(Clone, PartialEq, Eq, Debug, Subcommand)]
508pub enum WalletAction {
509    #[command(name = "new", about = "Creates a new wallet")]
510    New(WalletNewArgs),
511
512    #[command(
513        name = "bech32",
514        about = "Encodes/decodes a bech32 address to/from hex"
515    )]
516    Bech32(WalletBech32Args),
517    #[command(name = "convert", about = "Converts a wallet")]
518    Convert(WalletConvertArgs),
519}
520
521#[derive(Clone, PartialEq, Eq, Debug, Parser)]
522#[command(propagate_version = true)]
523pub struct WalletArgs {
524    #[command(subcommand)]
525    pub command: WalletAction,
526}
527
528#[derive(Default, Clone, PartialEq, Eq, Debug, Args)]
529pub struct WalletNewArgs {
530    /// The type of wallet to create.
531    #[arg(long = "format", verbatim_doc_comment)]
532    pub wallet_format: Option<String>,
533
534    /// The name of the wallet to create.
535    #[arg(long = "outfile", verbatim_doc_comment)]
536    pub outfile: Option<String>,
537
538    #[arg(long = "hrp", verbatim_doc_comment)]
539    pub hrp: Option<String>,
540}
541
542#[derive(Default, Clone, PartialEq, Eq, Debug, Args)]
543pub struct WalletConvertArgs {
544    #[arg(long = "in-format", verbatim_doc_comment)]
545    pub from: String,
546
547    #[arg(long = "out-format", verbatim_doc_comment)]
548    pub to: String,
549
550    #[arg(long = "infile", verbatim_doc_comment)]
551    pub infile: Option<String>,
552
553    #[arg(long = "outfile", verbatim_doc_comment)]
554    pub outfile: Option<String>,
555
556    #[arg(long = "hrp", verbatim_doc_comment)]
557    pub hrp: Option<String>,
558}
559
560#[derive(Default, Clone, PartialEq, Eq, Debug, Args)]
561pub struct WalletBech32Args {
562    #[arg(long = "encode", verbatim_doc_comment)]
563    pub hex_address: Option<String>,
564    #[arg(long = "decode", verbatim_doc_comment)]
565    pub bech32_address: Option<String>,
566}