radix_clis/scrypto/
cmd_build.rs

1use crate::scrypto::*;
2use crate::utils::*;
3use clap::Parser;
4use radix_engine_interface::prelude::Level;
5use scrypto_compiler::*;
6use std::path::PathBuf;
7
8/// Build a Scrypto package
9#[derive(Parser, Debug, Default)]
10pub struct Build {
11    /// The package directory. If not specified current directory will be used.
12    #[clap(long)]
13    path: Option<PathBuf>,
14
15    /// The terget directory. If not specified default target directory for project will be used.
16    #[clap(long)]
17    target_dir: Option<PathBuf>,
18
19    /// Turn on tracing.
20    #[clap(short, long)]
21    trace: bool,
22
23    /// Disables wasm-opt from running on the built wasm.
24    #[clap(long)]
25    disable_wasm_opt: bool,
26
27    /// The max log level, such as ERROR, WARN, INFO, DEBUG and TRACE.
28    /// The default is INFO.
29    #[clap(long)]
30    log_level: Option<Level>,
31
32    /// Comma separated list of features to activate.
33    #[clap(short = 'F', long)]
34    features: Option<String>,
35
36    /// Environment variables to define. Specify as NAME=VALUE or NAME.
37    /// Scrypto compiler internally sets some compilation flags `TARGET_CFLAGS` for C libraries
38    /// to configure WASM with the same features as Radix Engine.
39    /// If you want to override it, then you can use this option.
40    /// If you want to remove TARGET_CFLAGS, then use `--unset-env` option
41    #[clap(short, long)]
42    env: Option<Vec<String>>,
43
44    /// Environment variables to unset by name.
45    #[clap(long)]
46    unset_env: Option<Vec<String>>,
47
48    /// If provided for workspace compilation only these packages will be compiled.
49    /// For workspace compilation all Scrypto packages must define in their manifest files
50    /// Scrypto metadata section: [package.metadata.scrypto].
51    #[clap(short, long)]
52    package: Option<Vec<String>>,
53
54    /// Project profile to use. The default is Release.
55    #[clap(long)]
56    profile: Option<Profile>,
57
58    /// Do not activate the `default` feature.
59    #[clap(long)]
60    no_default_features: bool,
61
62    /// Activate all available features.
63    #[clap(long)]
64    all_features: bool,
65
66    /// Ensures the Cargo.lock file is used as-is. Equivalent to `cargo build --locked`.
67    /// Alternatively, the `SCRYPTO_CARGO_LOCKED` environment variable can be used,
68    /// which makes it easy to set universally in CI.
69    #[clap(long)]
70    locked: bool,
71
72    /// Pass any additional option to `cargo build` call.
73    #[clap(long)]
74    custom_option: Option<Vec<String>>,
75
76    /// Prints compilation steps.
77    #[clap(short, long)]
78    verbose: bool,
79}
80
81impl Build {
82    pub fn run(&self) -> Result<(), String> {
83        let mut compiler_builder = ScryptoCompiler::builder();
84
85        if let Some(manifest_path) = &self.path {
86            compiler_builder.manifest_path(manifest_path);
87        }
88        if let Some(target_dir) = &self.target_dir {
89            compiler_builder.target_directory(target_dir);
90        }
91        if let Some(log_level) = self.log_level {
92            compiler_builder.log_level(log_level);
93        }
94        if let Some(profile) = &self.profile {
95            compiler_builder.profile(profile.clone());
96        }
97        if self.trace {
98            compiler_builder.scrypto_macro_trace();
99        }
100        if self.disable_wasm_opt {
101            compiler_builder.optimize_with_wasm_opt(None);
102        }
103        if self.no_default_features {
104            compiler_builder.no_default_features();
105        }
106        if self.all_features {
107            compiler_builder.all_features();
108        }
109        if self.locked {
110            compiler_builder.locked();
111        }
112        if let Some(features) = &self.features {
113            features.split(',').for_each(|f| {
114                compiler_builder.feature(f);
115            });
116        }
117        if let Some(packages) = &self.package {
118            packages.iter().for_each(|p| {
119                compiler_builder.package(p);
120            });
121        }
122        compiler_builder.debug(self.verbose);
123
124        if let Some(env) = &self.env {
125            let env_variables_decoded: Vec<Vec<&str>> = env
126                .iter()
127                .map(|e|
128                    // Split string on the first '=' occurence.
129                    // This is to cover cases like this:
130                    //   ENV_NAME=foo=bar
131                    match e.split_once('=') {
132                        Some((key, val)) => vec![key, val],
133                        None => vec![e.as_str()],
134                })
135                .collect();
136            for v in env_variables_decoded {
137                if v.len() == 1 {
138                    compiler_builder.env(v[0], EnvironmentVariableAction::Set("".into()));
139                } else if v.len() == 2 {
140                    compiler_builder.env(v[0], EnvironmentVariableAction::Set(v[1].into()));
141                } else {
142                    return Err(Error::BuildError(BuildError::EnvParsingError).into());
143                }
144            }
145        }
146        if let Some(unset_env) = &self.unset_env {
147            unset_env.iter().for_each(|v| {
148                compiler_builder.env(v, EnvironmentVariableAction::Unset);
149            });
150        }
151
152        if let Some(options) = &self.custom_option {
153            compiler_builder.custom_options(
154                options
155                    .iter()
156                    .map(|s| s.as_str())
157                    .collect::<Vec<&str>>()
158                    .as_slice(),
159            );
160        }
161
162        compiler_builder
163            .compile()
164            .map(|_| ())
165            .map_err(|e| Error::BuildError(BuildError::ScryptoCompilerError(e)).into())
166    }
167}