forc/cli/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
use self::commands::{
    addr2line, build, check, clean, completions, contract_id, init, new, parse_bytecode, plugins,
    predicate_root, template, test, update,
};
use addr2line::Command as Addr2LineCommand;
use anyhow::anyhow;
pub use build::Command as BuildCommand;
pub use check::Command as CheckCommand;
use clap::{Parser, Subcommand};
pub use clean::Command as CleanCommand;
pub use completions::Command as CompletionsCommand;
pub(crate) use contract_id::Command as ContractIdCommand;
use forc_tracing::{init_tracing_subscriber, TracingSubscriberOptions};
use forc_util::ForcResult;
pub use init::Command as InitCommand;
pub use new::Command as NewCommand;
use parse_bytecode::Command as ParseBytecodeCommand;
pub use plugins::Command as PluginsCommand;
pub(crate) use predicate_root::Command as PredicateRootCommand;
use std::str::FromStr;
pub use template::Command as TemplateCommand;
pub use test::Command as TestCommand;
use tracing::metadata::LevelFilter;
pub use update::Command as UpdateCommand;

mod commands;
mod plugin;
pub mod shared;

fn help() -> &'static str {
    Box::leak(
        format!(
            "Examples:\n{}{}{}{}",
            plugins::examples(),
            test::examples(),
            build::examples(),
            check::examples(),
        )
        .trim_end()
        .to_string()
        .into_boxed_str(),
    )
}

#[derive(Debug, Parser)]
#[clap(name = "forc", about = "Fuel Orchestrator", version, after_long_help = help())]
struct Opt {
    /// The command to run
    #[clap(subcommand)]
    command: Forc,

    /// Use verbose output
    #[clap(short, long, action = clap::ArgAction::Count, global = true)]
    verbose: u8,

    /// Silence all output
    #[clap(short, long, global = true)]
    silent: bool,

    /// Set the log level
    #[clap(short='L', long, global = true, value_parser = LevelFilter::from_str)]
    log_level: Option<LevelFilter>,
}

#[derive(Subcommand, Debug)]
enum Forc {
    #[clap(name = "addr2line")]
    Addr2Line(Addr2LineCommand),
    #[clap(visible_alias = "b")]
    Build(BuildCommand),
    Check(CheckCommand),
    Clean(CleanCommand),
    Completions(CompletionsCommand),
    New(NewCommand),
    Init(InitCommand),
    ParseBytecode(ParseBytecodeCommand),
    #[clap(visible_alias = "t")]
    Test(TestCommand),
    Update(UpdateCommand),
    Plugins(PluginsCommand),
    Template(TemplateCommand),
    ContractId(ContractIdCommand),
    PredicateRoot(PredicateRootCommand),
    /// This is a catch-all for unknown subcommands and their arguments.
    ///
    /// When we receive an unknown subcommand, we check for a plugin exe named
    /// `forc-<unknown-subcommand>` and try to execute it:
    ///
    /// ```ignore
    /// forc-<unknown-subcommand> <args>
    /// ```
    #[clap(external_subcommand)]
    Plugin(Vec<String>),
}

impl Forc {
    #[allow(dead_code)]
    pub fn possible_values() -> Vec<&'static str> {
        vec![
            "addr2line",
            "build",
            "check",
            "clean",
            "completions",
            "init",
            "new",
            "parse-bytecode",
            "plugins",
            "test",
            "update",
            "template",
            "contract-id",
            "predicate-root",
        ]
    }
}

pub async fn run_cli() -> ForcResult<()> {
    let opt = Opt::parse();
    let tracing_options = TracingSubscriberOptions {
        verbosity: Some(opt.verbose),
        silent: Some(opt.silent),
        log_level: opt.log_level,
        ..Default::default()
    };

    init_tracing_subscriber(tracing_options);

    match opt.command {
        Forc::Addr2Line(command) => addr2line::exec(command),
        Forc::Build(command) => build::exec(command),
        Forc::Check(command) => check::exec(command),
        Forc::Clean(command) => clean::exec(command),
        Forc::Completions(command) => completions::exec(command),
        Forc::Init(command) => init::exec(command),
        Forc::New(command) => new::exec(command),
        Forc::ParseBytecode(command) => parse_bytecode::exec(command),
        Forc::Plugins(command) => plugins::exec(command),
        Forc::Test(command) => test::exec(command),
        Forc::Update(command) => update::exec(command),
        Forc::Template(command) => template::exec(command),
        Forc::ContractId(command) => contract_id::exec(command),
        Forc::PredicateRoot(command) => predicate_root::exec(command),
        Forc::Plugin(args) => {
            let output = plugin::execute_external_subcommand(&args)?;
            let code = output
                .status
                .code()
                .ok_or_else(|| anyhow!("plugin exit status unknown"))?;
            std::process::exit(code);
        }
    }
}