use std::ffi::OsStr;
use std::io;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
use std::process::ExitStatus;
use radix_engine::utils::*;
use radix_engine_interface::types::Level;
use scrypto_compiler::*;
#[derive(Debug)]
pub enum BuildError {
ScryptoCompilerError(ScryptoCompilerError),
IOErrorAtPath(io::Error, PathBuf),
SchemaExtractionError(ExtractSchemaError),
SchemaEncodeError(sbor::EncodeError),
BuildArtifactsEmpty,
WorkspaceNotSupported,
EnvParsingError,
}
#[derive(Debug)]
pub enum TestError {
NotCargoPackage,
BuildError(BuildError),
IOError(io::Error),
CargoFailure(ExitStatus),
}
#[derive(Debug)]
pub enum FormatError {
BuildError(BuildError),
IOError(io::Error),
CargoFailure(ExitStatus),
}
pub fn build_package<P: AsRef<Path>>(
base_path: P,
disable_wasm_opt: bool,
log_level: Level,
coverage: bool,
env: impl IntoIterator<Item = (String, String)>,
) -> Result<Vec<(PathBuf, PathBuf)>, BuildError> {
let mut compiler_builder = ScryptoCompiler::builder();
compiler_builder
.manifest_path(base_path.as_ref())
.log_level(log_level);
if disable_wasm_opt {
compiler_builder.optimize_with_wasm_opt(None);
}
if coverage {
compiler_builder.coverage();
let mut target_path = PathBuf::from(base_path.as_ref());
target_path.push("coverage");
compiler_builder.target_directory(target_path);
}
env.into_iter().for_each(|(name, value)| {
compiler_builder.env(name.as_ref(), EnvironmentVariableAction::Set(value));
});
let build_results = compiler_builder
.compile()
.map_err(BuildError::ScryptoCompilerError)?;
Ok(build_results
.iter()
.map(|item| {
(
item.wasm.path.to_owned(),
item.package_definition.path.to_owned(),
)
})
.collect())
}
pub fn test_package<P: AsRef<Path>, I, S, E, K, V>(
path: P,
args: I,
coverage: bool,
locked: bool,
env_vars: E,
) -> Result<(), TestError>
where
I: IntoIterator<Item = S>,
S: AsRef<OsStr>,
E: IntoIterator<Item = (K, V)>,
K: AsRef<OsStr>,
V: AsRef<OsStr>,
{
if !coverage {
build_package(&path, false, Level::Trace, false, []).map_err(TestError::BuildError)?;
}
let mut cargo = path.as_ref().to_owned();
cargo.push("Cargo.toml");
if cargo.exists() {
let status = Command::new("cargo")
.arg("test")
.arg("--release")
.arg("--manifest-path")
.arg(cargo.to_str().unwrap())
.args({
if coverage {
vec!["--features", "scrypto-test/coverage"]
} else {
vec![]
}
})
.args({
if locked {
vec!["--locked"]
} else {
vec![]
}
})
.arg("--")
.args(args)
.envs(env_vars)
.status()
.map_err(TestError::IOError)?;
if !status.success() {
return Err(TestError::CargoFailure(status));
}
Ok(())
} else {
Err(TestError::NotCargoPackage)
}
}
pub fn fmt_package<P: AsRef<Path>>(path: P, check: bool, quiet: bool) -> Result<(), FormatError> {
let mut cargo = path.as_ref().to_owned();
cargo.push("Cargo.toml");
if cargo.exists() {
let status = Command::new("cargo")
.arg("fmt")
.arg("--manifest-path")
.arg(cargo.to_str().unwrap())
.args({
let mut args = Vec::new();
if check {
args.push("--check")
}
if quiet {
args.push("--quiet")
}
args
})
.status()
.map_err(FormatError::IOError)?;
if status.success() {
Ok(())
} else {
Err(FormatError::CargoFailure(status))
}
} else {
Ok(())
}
}