forc/cli/
mod.rs

1use self::commands::{
2    addr2line, build, check, clean, completions, contract_id, init, new, parse_bytecode, plugins,
3    predicate_root, template, test, update,
4};
5use addr2line::Command as Addr2LineCommand;
6use anyhow::anyhow;
7pub use build::Command as BuildCommand;
8pub use check::Command as CheckCommand;
9use clap::{Parser, Subcommand};
10pub use clean::Command as CleanCommand;
11pub use completions::Command as CompletionsCommand;
12pub(crate) use contract_id::Command as ContractIdCommand;
13use forc_tracing::{init_tracing_subscriber, TracingSubscriberOptions};
14use forc_util::ForcResult;
15pub use init::Command as InitCommand;
16pub use new::Command as NewCommand;
17use parse_bytecode::Command as ParseBytecodeCommand;
18pub use plugins::Command as PluginsCommand;
19pub(crate) use predicate_root::Command as PredicateRootCommand;
20use std::str::FromStr;
21pub use template::Command as TemplateCommand;
22pub use test::Command as TestCommand;
23use tracing::metadata::LevelFilter;
24pub use update::Command as UpdateCommand;
25
26mod commands;
27mod plugin;
28pub mod shared;
29
30fn help() -> &'static str {
31    Box::leak(
32        format!(
33            "Examples:\n{}{}{}{}",
34            plugins::examples(),
35            test::examples(),
36            build::examples(),
37            check::examples(),
38        )
39        .trim_end()
40        .to_string()
41        .into_boxed_str(),
42    )
43}
44
45#[derive(Debug, Parser)]
46#[clap(name = "forc", about = "Fuel Orchestrator", version, after_long_help = help())]
47struct Opt {
48    /// The command to run
49    #[clap(subcommand)]
50    command: Forc,
51
52    /// Use verbose output
53    #[clap(short, long, action = clap::ArgAction::Count, global = true)]
54    verbose: u8,
55
56    /// Silence all output
57    #[clap(short, long, global = true)]
58    silent: bool,
59
60    /// Set the log level
61    #[clap(short='L', long, global = true, value_parser = LevelFilter::from_str)]
62    log_level: Option<LevelFilter>,
63}
64
65#[derive(Subcommand, Debug)]
66enum Forc {
67    #[clap(name = "addr2line")]
68    Addr2Line(Addr2LineCommand),
69    #[clap(visible_alias = "b")]
70    Build(BuildCommand),
71    Check(CheckCommand),
72    Clean(CleanCommand),
73    Completions(CompletionsCommand),
74    New(NewCommand),
75    Init(InitCommand),
76    ParseBytecode(ParseBytecodeCommand),
77    #[clap(visible_alias = "t")]
78    Test(TestCommand),
79    Update(UpdateCommand),
80    Plugins(PluginsCommand),
81    Template(TemplateCommand),
82    ContractId(ContractIdCommand),
83    PredicateRoot(PredicateRootCommand),
84    /// This is a catch-all for unknown subcommands and their arguments.
85    ///
86    /// When we receive an unknown subcommand, we check for a plugin exe named
87    /// `forc-<unknown-subcommand>` and try to execute it:
88    ///
89    /// ```ignore
90    /// forc-<unknown-subcommand> <args>
91    /// ```
92    #[clap(external_subcommand)]
93    Plugin(Vec<String>),
94}
95
96impl Forc {
97    #[allow(dead_code)]
98    pub fn possible_values() -> Vec<&'static str> {
99        vec![
100            "addr2line",
101            "build",
102            "check",
103            "clean",
104            "completions",
105            "init",
106            "new",
107            "parse-bytecode",
108            "plugins",
109            "test",
110            "update",
111            "template",
112            "contract-id",
113            "predicate-root",
114        ]
115    }
116}
117
118pub async fn run_cli() -> ForcResult<()> {
119    let opt = Opt::parse();
120    let tracing_options = TracingSubscriberOptions {
121        verbosity: Some(opt.verbose),
122        silent: Some(opt.silent),
123        log_level: opt.log_level,
124        ..Default::default()
125    };
126
127    init_tracing_subscriber(tracing_options);
128
129    match opt.command {
130        Forc::Addr2Line(command) => addr2line::exec(command),
131        Forc::Build(command) => build::exec(command),
132        Forc::Check(command) => check::exec(command),
133        Forc::Clean(command) => clean::exec(command),
134        Forc::Completions(command) => completions::exec(command),
135        Forc::Init(command) => init::exec(command),
136        Forc::New(command) => new::exec(command),
137        Forc::ParseBytecode(command) => parse_bytecode::exec(command),
138        Forc::Plugins(command) => plugins::exec(command),
139        Forc::Test(command) => test::exec(command),
140        Forc::Update(command) => update::exec(command),
141        Forc::Template(command) => template::exec(command),
142        Forc::ContractId(command) => contract_id::exec(command),
143        Forc::PredicateRoot(command) => predicate_root::exec(command),
144        Forc::Plugin(args) => {
145            let output = plugin::execute_external_subcommand(&args)?;
146            let code = output
147                .status
148                .code()
149                .ok_or_else(|| anyhow!("plugin exit status unknown"))?;
150            std::process::exit(code);
151        }
152    }
153}