use failure::Error;
use error::CargoWasmError::*;
use std::path::{ Path, PathBuf };
use std::process::{ Command, ExitStatus };
use std::fs;
use std::fs::{ OpenOptions, File };
use std::io::Write;
use assets::*;
pub fn cargo_build(release: bool, output_dir: Option<&str>) -> Result<(), Error> {
if release {
let exit = Command::new("cargo")
.arg("build")
.arg("--release")
.arg("--target=wasm32-unknown-unknown")
.spawn()?
.wait()?;
if !exit.success() {
return Err(CargoFail {
exit: match exit_code(exit) {
Some(i) => format!("{}", i),
None => "No error code found".into(),
}
}.into())
}
} else {
let exit = Command::new("cargo")
.arg("build")
.arg("--target=wasm32-unknown-unknown")
.spawn()?
.wait()?;
if !exit.success() {
return Err(CargoFail {
exit: match exit_code(exit) {
Some(i) => format!("{}", i),
None => "No error code found".into(),
}
}.into())
}
}
let wasm = find_wasm(release)?;
let filename = wasm.file_name().unwrap().to_str().unwrap();
let target_dir = output_dir.unwrap_or("site");
let path = format!("{}/{}", &target_dir, &filename);
fs::copy(&wasm, &path)?;
if release {
let temp = format!("{}/{}.temp", &target_dir, &filename);
let exit = Command::new("wasm-gc")
.arg(&path)
.arg(&temp)
.spawn()?
.wait()?;
if !exit.success() {
return Err(WasmGcFail {
exit: match exit_code(exit) {
Some(i) => format!("{}", i),
None => "No error code found".into(),
}
}.into())
}
fs::rename(temp, path)?;
}
Ok(())
}
fn find_wasm(release: bool) -> Result<PathBuf, Error> {
let check_folder = if release {
"target/wasm32-unknown-unknown/release"
} else {
"target/wasm32-unknown-unknown/debug"
};
for entry in fs::read_dir(check_folder)? {
let entry = entry?;
let path = entry.path();
match path.extension() {
Some(ext) => if ext == "wasm" {
return Ok(entry.path());
},
None => {},
}
}
Err(NoWasmCompiled.into())
}
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
pub fn exit_code(val: ExitStatus) -> Option<i32> {
use std::os::unix::process::ExitStatusExt;
match val.code() {
Some(i) => Some(i),
None => val.signal(),
}
}
#[cfg(any(target_os = "windows", target_os = "macos"))]
pub fn exit_code(val: ExitStatus) -> Option<i32> {
val.code()
}
pub fn cargo_run(release: bool, path: Option<&str>) -> Result<(), Error> {
cargo_build(release, None)?;
match path {
Some(p) => open_project(&Path::new(p)),
None => open_project(&find_crate_root()?),
}
}
pub fn cargo_new(project_name: &str) -> Result<(), Error> {
let exit = Command::new("cargo")
.arg("new")
.arg("--lib")
.arg(project_name)
.spawn()?
.wait()?;
if !exit.success() {
return Err(CargoFail {
exit: match exit_code(exit) {
Some(i) => format!("{}", i),
None => "No error code found".into(),
}
}.into())
}
fs::create_dir(format!("{}/site", project_name))?;
let mut lib = File::create(format!("{}/src/lib.rs", project_name))?;
let mut index = File::create(format!("{}/site/index.html", project_name))?;
let index_string = String::from(INDEX_HTML);
let lib_name = project_name.replace('-', "_");
let index_html = index_string.replace("lib", &lib_name);
lib.write_all(LIB_RS.as_bytes())?;
index.write_all(index_html.as_bytes())?;
let mut toml = OpenOptions::new().append(true).open(format!("{}/Cargo.toml", &project_name))?;
const CRATE_TYPE: &str = "\n[lib]\ncrate-type = [\"cdylib\"]\n";
toml.write_all(CRATE_TYPE.as_bytes())?;
Ok(())
}
fn find_crate_root() -> Result<PathBuf, Error> {
let mut path = PathBuf::new();
path.push("site");
path.push("index.html");
Ok(path)
}
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
fn open_project(path: &Path) -> Result<(), Error> {
use std::env;
let mut methods = Vec::new();
if let Ok(name) = env::var("BROWSER") {
match Command::new(name).arg(path).status() {
Ok(_) => return Ok(()),
Err(_) => methods.push("$BROWSER"),
}
}
for m in ["xdg-open", "gnome-open", "kde-open"].iter() {
match Command::new(m).arg(path).status() {
Ok(_) => return Ok(()),
Err(_) => methods.push(m),
}
}
let mut method_folded = String::new();
let len = methods.len();
for (i, j) in methods.into_iter().enumerate() {
method_folded.push_str(j);
if i != len {
method_folded.push(',');
}
}
Err(BrowserOpenFail{ methods: method_folded }.into())
}
#[cfg(target_os = "windows")]
fn open_project(path: &Path) -> Result<(), Error> {
match Command::new("cmd").arg("/C").arg(path).status() {
Ok(_) => Ok(()),
Err(_) => Err(BrowserOpenFail{ methods: String::from("cmd /C") }.into())
}
}
#[cfg(target_os = "macos")]
fn open_project(path: &Path) -> Result<(), Error> {
match Command::new("open").arg(path).status() {
Ok(_) => Ok(()),
Err(_) => Err(BrowserOpenFail{ methods: String::from("open") }.into())
}
}
pub fn cargo_install_wasm_gc() -> Result<(), Error> {
let exit = Command::new("cargo")
.arg("install")
.arg("--git")
.arg("https://github.com/alexcrichton/wasm-gc")
.arg("--force")
.spawn()?
.wait()?;
if !exit.success() {
return Err(CargoFail {
exit: match exit_code(exit) {
Some(i) => format!("{}", i),
None => "No error code found".into(),
}
}.into())
}
Ok(())
}