Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

custom error message when wasm-bindgen fails because --web isn't available #633

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 38 additions & 16 deletions src/bindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ pub fn wasm_bindgen_build(
Target::Bundler => "--browser",
};
let bindgen_path = bindgen.binary("wasm-bindgen")?;
let mut cmd = Command::new(bindgen_path);
let mut cmd = Command::new(&bindgen_path);
cmd.arg(&wasm_path)
.arg("--out-dir")
.arg(out_dir)
Expand All @@ -226,28 +226,50 @@ pub fn wasm_bindgen_build(
cmd.arg("--keep-debug");
}

child::run(cmd, "wasm-bindgen").context("Running the wasm-bindgen CLI")?;
let result = child::run(cmd, "wasm-bindgen");
let result: Result<(), failure::Error> = match result {
Ok(r) => Ok(r),
Err(e) => process_error(&bindgen_path, e),
};
result.context("Running the wasm-bindgen CLI")?;
Ok(())
}

fn process_error(bindgen_path: &PathBuf, e: child::CommandError) -> Result<(), failure::Error> {
match &e.stderr {
Some(err) if err.trim().starts_with("Unknown flag: '--web'") => {
let v = wasm_bindgen_get_version(bindgen_path).unwrap_or(String::from("unknown"));
bail!("Failed to execute `wasm-bindgen`: --web is not supported in version '{}'. Upgrade the wasm-bindgen dependency in Cargo.toml to version 0.2.39 or later.", v)
}
Some(err) => {
eprintln!("{}", err);
bail!("{}", e.to_string())
}
_ => bail!("{}", e.to_string()),
}
}

/// Check if the `wasm-bindgen` dependency is locally satisfied.
fn wasm_bindgen_version_check(bindgen_path: &PathBuf, dep_version: &str) -> bool {
wasm_bindgen_get_version(bindgen_path)
.map(|v| {
info!(
"Checking installed `wasm-bindgen` version == expected version: {} == {}",
v, dep_version
);
v == dep_version
})
.unwrap_or(false)
}

/// Get the `wasm-bindgen` version
fn wasm_bindgen_get_version(bindgen_path: &PathBuf) -> Option<String> {
let mut cmd = Command::new(bindgen_path);
cmd.arg("--version");
child::run_capture_stdout(cmd, "wasm-bindgen")
.map(|stdout| {
stdout
.trim()
.split_whitespace()
.nth(1)
.map(|v| {
info!(
"Checking installed `wasm-bindgen` version == expected version: {} == {}",
v, dep_version
);
v == dep_version
})
.unwrap_or(false)
.map(|stdout| match stdout.trim().split_whitespace().nth(1) {
Some(v) => return Some(v.to_owned()),
None => return None,
})
.unwrap_or(false)
.unwrap_or(None)
}
94 changes: 67 additions & 27 deletions src/child.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
//! This module helps us ensure that all child processes that we spawn get
//! properly logged and their output is logged as well.

use failure::Error;
use log::info;
use std::process::{Command, Stdio};
use std::io::Error as StdError;
use std::process::{Command, ExitStatus, Stdio};

/// Return a new Command object
pub fn new_command(program: &str) -> Command {
Expand All @@ -23,39 +23,79 @@ pub fn new_command(program: &str) -> Command {
}
}

/// Run the given command and return its stdout.
pub fn run(mut command: Command, command_name: &str) -> Result<(), Error> {
info!("Running {:?}", command);
/// Error from running Command processes
/// This captures the standard error output
#[derive(Fail, Debug)]
#[fail(display = "failed to execute `{}`: {}", command_name, fail_reason)]
pub struct CommandError {
command_name: String,
fail_reason: String,
/// the output printed to stderr, if any
pub stderr: Option<String>,
}

let status = command.status()?;
impl CommandError {
fn from_status(command_name: &str, status: ExitStatus, stderr: Option<String>) -> CommandError {
CommandError {
command_name: command_name.to_string(),
fail_reason: format!("exited with {}", status),
stderr: stderr,
}
}

if status.success() {
Ok(())
} else {
bail!(
"failed to execute `{}`: exited with {}",
command_name,
status
)
fn from_error(command_name: &str, err: StdError) -> CommandError {
CommandError {
command_name: command_name.to_string(),
fail_reason: err.to_string(),
stderr: None,
}
}
}

/// Run the given command and return its stdout.
pub fn run_capture_stdout(mut command: Command, command_name: &str) -> Result<String, Error> {
/// Run the given command and return on success.
pub fn run(mut command: Command, command_name: &str) -> Result<(), CommandError> {
info!("Running {:?}", command);

let output = command
.stderr(Stdio::inherit())
let cmd_output = command
.stdin(Stdio::inherit())
.output()?;
.stdout(Stdio::inherit())
.output();
match cmd_output {
Ok(output) => {
if output.status.success() {
Ok(())
} else {
Err(CommandError::from_status(
command_name,
output.status,
Some(String::from_utf8_lossy(&output.stderr).into_owned()),
))
}
}
Err(e) => Err(CommandError::from_error(command_name, e)),
}
}

if output.status.success() {
Ok(String::from_utf8_lossy(&output.stdout).into_owned())
} else {
bail!(
"failed to execute `{}`: exited with {}",
command_name,
output.status
)
/// Run the given command and return its stdout.
pub fn run_capture_stdout(
mut command: Command,
command_name: &str,
) -> Result<String, CommandError> {
info!("Running {:?}", command);

let cmd_output = command.stdin(Stdio::inherit()).output();
match cmd_output {
Ok(output) => {
if output.status.success() {
Ok(String::from_utf8_lossy(&output.stdout).into_owned())
} else {
Err(CommandError::from_status(
command_name,
output.status,
Some(String::from_utf8_lossy(&output.stderr).into_owned()),
))
}
}
Err(e) => Err(CommandError::from_error(command_name, e)),
}
}