use crate::child;
use crate::command::build::BuildProfile;
use crate::emoji;
use crate::manifest::Crate;
use crate::PBAR;
use anyhow::{anyhow, bail, Context, Result};
use cargo_metadata::Message;
use std::io::BufReader;
use std::path::Path;
use std::process::{Command, Stdio};
use std::str;
pub mod wasm_target;
pub struct WasmPackVersion {
pub local: String,
pub latest: String,
}
pub fn check_rustc_version() -> Result<String> {
let local_minor_version = rustc_minor_version();
match local_minor_version {
Some(mv) => {
if mv < 30 {
bail!(
"Your version of Rust, '1.{}', is not supported. Please install Rust version 1.30.0 or higher.",
mv.to_string()
)
} else {
Ok(mv.to_string())
}
}
None => bail!("We can't figure out what your Rust version is- which means you might not have Rust installed. Please install Rust version 1.30.0 or higher."),
}
}
fn rustc_minor_version() -> Option<u32> {
macro_rules! otry {
($e:expr) => {
match $e {
Some(e) => e,
None => return None,
}
};
}
let output = otry!(Command::new("rustc").arg("--version").output().ok());
let version = otry!(str::from_utf8(&output.stdout).ok());
let mut pieces = version.split('.');
if pieces.next() != Some("rustc 1") {
return None;
}
otry!(pieces.next()).parse().ok()
}
pub fn check_wasm_pack_versions() -> Result<WasmPackVersion> {
match wasm_pack_local_version() {
Some(local) => Ok(WasmPackVersion {local, latest: Crate::return_wasm_pack_latest_version()?.unwrap_or_else(|| "".to_string())}),
None => bail!("We can't figure out what your wasm-pack version is, make sure the installation path is correct.")
}
}
fn wasm_pack_local_version() -> Option<String> {
let output = env!("CARGO_PKG_VERSION");
Some(output.to_string())
}
pub fn cargo_build_wasm(
path: &Path,
profile: BuildProfile,
extra_options: &[String],
) -> Result<String> {
let msg = format!("{}Compiling to Wasm...", emoji::CYCLONE);
PBAR.info(&msg);
let mut cmd = Command::new("cargo");
cmd.current_dir(path).arg("build").arg("--lib");
if PBAR.quiet() {
cmd.arg("--quiet");
}
match profile {
BuildProfile::Profiling => {
cmd.arg("--release");
}
BuildProfile::Release => {
cmd.arg("--release");
}
BuildProfile::Dev => {
}
BuildProfile::Custom(arg) => {
cmd.arg("--profile").arg(arg);
}
}
cmd.env("CARGO_BUILD_TARGET", "wasm32-unknown-unknown");
let mut handle_path = false;
let extra_options_with_absolute_paths = extra_options
.iter()
.map(|option| -> Result<String> {
let value = if handle_path && Path::new(option).is_relative() {
std::env::current_dir()?
.join(option)
.to_str()
.ok_or_else(|| anyhow!("path contains non-UTF-8 characters"))?
.to_string()
} else {
option.to_string()
};
handle_path = matches!(&**option, "--target-dir" | "--out-dir" | "--manifest-path");
Ok(value)
})
.collect::<Result<Vec<_>>>()?;
cmd.args(extra_options_with_absolute_paths);
cmd.arg("--message-format=json");
let mut cargo_process = cmd.stdout(Stdio::piped()).spawn()?;
let final_artifact =
Message::parse_stream(BufReader::new(cargo_process.stdout.as_mut().unwrap()))
.filter_map(|msg| {
match msg {
Ok(Message::CompilerArtifact(artifact)) => return Some(artifact),
Ok(Message::CompilerMessage(msg)) => eprintln!("{msg}"),
Ok(Message::TextLine(text)) => eprintln!("{text}"),
Err(err) => log::error!("Couldn't parse cargo message: {err}"),
_ => {} }
None
})
.last();
if !cargo_process
.wait()
.context("Failed to wait for cargo build process")?
.success()
{
bail!("`cargo build` failed, see the output above for details");
}
let wasm_files: Vec<_> = final_artifact
.context("Expected at least one compiler artifact in the output of `cargo build`")?
.filenames
.into_iter()
.filter(|path| path.extension() == Some("wasm"))
.collect();
match <[_; 1]>::try_from(wasm_files) {
Ok([filename]) => Ok(filename.into_string()),
Err(filenames) => {
bail!(
"Expected exactly one .wasm file in the compiler artifact, but found {filenames:?}"
)
}
}
}
pub fn cargo_build_wasm_tests(path: &Path, debug: bool, extra_options: &[String]) -> Result<()> {
let mut cmd = Command::new("cargo");
cmd.current_dir(path).arg("build").arg("--tests");
if PBAR.quiet() {
cmd.arg("--quiet");
}
if !debug {
cmd.arg("--release");
}
cmd.env("CARGO_BUILD_TARGET", "wasm32-unknown-unknown");
cmd.args(extra_options);
child::run(cmd, "cargo build").context("Compilation of your program failed")?;
Ok(())
}