radix_clis/utils/
cargo.rs1use std::ffi::OsStr;
2use std::io;
3use std::path::Path;
4use std::path::PathBuf;
5use std::process::Command;
6use std::process::ExitStatus;
7
8use radix_engine::utils::*;
9use radix_engine_interface::types::Level;
10use scrypto_compiler::*;
11
12#[derive(Debug)]
13pub enum BuildError {
14 ScryptoCompilerError(ScryptoCompilerError),
15
16 IOErrorAtPath(io::Error, PathBuf),
17
18 SchemaExtractionError(ExtractSchemaError),
19
20 SchemaEncodeError(sbor::EncodeError),
21
22 BuildArtifactsEmpty,
23
24 WorkspaceNotSupported,
25
26 EnvParsingError,
27}
28
29#[derive(Debug)]
30pub enum TestError {
31 NotCargoPackage,
32
33 BuildError(BuildError),
34
35 IOError(io::Error),
36
37 CargoFailure(ExitStatus),
38}
39
40#[derive(Debug)]
41pub enum FormatError {
42 BuildError(BuildError),
43
44 IOError(io::Error),
45
46 CargoFailure(ExitStatus),
47}
48
49pub fn build_package<P: AsRef<Path>>(
51 base_path: P,
52 disable_wasm_opt: bool,
53 log_level: Level,
54 coverage: bool,
55 env: impl IntoIterator<Item = (String, String)>,
56) -> Result<Vec<(PathBuf, PathBuf)>, BuildError> {
57 let mut compiler_builder = ScryptoCompiler::builder();
58 compiler_builder
59 .manifest_path(base_path.as_ref())
60 .log_level(log_level);
61
62 if disable_wasm_opt {
63 compiler_builder.optimize_with_wasm_opt(None);
64 }
65 if coverage {
66 compiler_builder.coverage();
67
68 let mut target_path = PathBuf::from(base_path.as_ref());
69 target_path.push("coverage");
70 compiler_builder.target_directory(target_path);
71 }
72 env.into_iter().for_each(|(name, value)| {
73 compiler_builder.env(name.as_ref(), EnvironmentVariableAction::Set(value));
74 });
75
76 let build_results = compiler_builder
77 .compile()
78 .map_err(BuildError::ScryptoCompilerError)?;
79
80 Ok(build_results
81 .iter()
82 .map(|item| {
83 (
84 item.wasm.path.to_owned(),
85 item.package_definition.path.to_owned(),
86 )
87 })
88 .collect())
89}
90
91pub fn test_package<P: AsRef<Path>, I, S, E, K, V>(
93 path: P,
94 args: I,
95 coverage: bool,
96 locked: bool,
97 env_vars: E,
98) -> Result<(), TestError>
99where
100 I: IntoIterator<Item = S>,
101 S: AsRef<OsStr>,
102 E: IntoIterator<Item = (K, V)>,
103 K: AsRef<OsStr>,
104 V: AsRef<OsStr>,
105{
106 if !coverage {
107 build_package(&path, false, Level::Trace, false, []).map_err(TestError::BuildError)?;
108 }
109
110 let mut cargo = path.as_ref().to_owned();
111 cargo.push("Cargo.toml");
112 if cargo.exists() {
113 let status = Command::new("cargo")
114 .arg("test")
115 .arg("--release")
116 .arg("--manifest-path")
117 .arg(cargo.to_str().unwrap())
118 .args({
119 if coverage {
120 vec!["--features", "scrypto-test/coverage"]
121 } else {
122 vec![]
123 }
124 })
125 .args({
126 if locked {
127 vec!["--locked"]
128 } else {
129 vec![]
130 }
131 })
132 .arg("--")
133 .args(args)
134 .envs(env_vars)
135 .status()
136 .map_err(TestError::IOError)?;
137 if !status.success() {
138 return Err(TestError::CargoFailure(status));
139 }
140 Ok(())
141 } else {
142 Err(TestError::NotCargoPackage)
143 }
144}
145
146pub fn fmt_package<P: AsRef<Path>>(path: P, check: bool, quiet: bool) -> Result<(), FormatError> {
148 let mut cargo = path.as_ref().to_owned();
149 cargo.push("Cargo.toml");
150 if cargo.exists() {
151 let status = Command::new("cargo")
152 .arg("fmt")
153 .arg("--manifest-path")
154 .arg(cargo.to_str().unwrap())
155 .args({
156 let mut args = Vec::new();
157 if check {
158 args.push("--check")
159 }
160 if quiet {
161 args.push("--quiet")
162 }
163 args
164 })
165 .status()
166 .map_err(FormatError::IOError)?;
167
168 if status.success() {
169 Ok(())
170 } else {
171 Err(FormatError::CargoFailure(status))
172 }
173 } else {
174 Ok(())
175 }
176}