Use `child::run` for spawning child processes everywhere

master
Nick Fitzgerald 7 years ago
parent 4fd08dcbd2
commit 2fa961d97d
  1. 62
      src/bindgen.rs
  2. 70
      src/build.rs
  3. 38
      src/command/build.rs
  4. 5
      src/command/login.rs
  5. 9
      src/command/mod.rs
  6. 4
      src/command/pack.rs
  7. 4
      src/command/publish/mod.rs
  8. 61
      src/command/test.rs
  9. 12
      src/error.rs
  10. 9
      src/manifest/mod.rs
  11. 64
      src/npm.rs
  12. 21
      src/test/mod.rs
  13. 14
      src/test/webdriver.rs
  14. 10
      tests/all/utils/fixture.rs

@ -1,8 +1,10 @@
//! Functionality related to installing and running `wasm-bindgen`. //! Functionality related to installing and running `wasm-bindgen`.
use binaries::{self, bin_path, install_binaries_from_targz_at_url}; use binaries::{self, bin_path, install_binaries_from_targz_at_url};
use child;
use emoji; use emoji;
use error::Error; use error::Error;
use failure::{self, ResultExt};
use progressbar::Step; use progressbar::Step;
use slog::Logger; use slog::Logger;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -22,7 +24,7 @@ pub fn install_wasm_bindgen(
install_permitted: bool, install_permitted: bool,
step: &Step, step: &Step,
log: &Logger, log: &Logger,
) -> Result<(), Error> { ) -> Result<(), failure::Error> {
// If the `wasm-bindgen` dependency is already met, print a message and return. // If the `wasm-bindgen` dependency is already met, print a message and return.
if wasm_bindgen_path(log, root_path) if wasm_bindgen_path(log, root_path)
.map(|bindgen_path| wasm_bindgen_version_check(&bindgen_path, version, log)) .map(|bindgen_path| wasm_bindgen_version_check(&bindgen_path, version, log))
@ -37,7 +39,7 @@ pub fn install_wasm_bindgen(
// permitted, return a configuration error. // permitted, return a configuration error.
if !install_permitted { if !install_permitted {
let msg = format!("wasm-bindgen v{} is not installed!", version); let msg = format!("wasm-bindgen v{} is not installed!", version);
return Error::crate_config(&msg); return Err(Error::crate_config(&msg).into());
} }
let msg = format!("{}Installing wasm-bindgen...", emoji::DOWN_ARROW); let msg = format!("{}Installing wasm-bindgen...", emoji::DOWN_ARROW);
@ -48,7 +50,7 @@ pub fn install_wasm_bindgen(
log, log,
"could not download pre-built `wasm-bindgen`: {}. Falling back to `cargo install`.", e "could not download pre-built `wasm-bindgen`: {}. Falling back to `cargo install`.", e
); );
cargo_install_wasm_bindgen(root_path, version) cargo_install_wasm_bindgen(log, root_path, version)
}) })
} }
@ -81,28 +83,23 @@ pub fn download_prebuilt_wasm_bindgen(root_path: &Path, version: &str) -> Result
/// Use `cargo install` to install the `wasm-bindgen` CLI locally into the given /// Use `cargo install` to install the `wasm-bindgen` CLI locally into the given
/// crate. /// crate.
pub fn cargo_install_wasm_bindgen(crate_path: &Path, version: &str) -> Result<(), Error> { pub fn cargo_install_wasm_bindgen(
let output = Command::new("cargo") logger: &Logger,
.arg("install") crate_path: &Path,
version: &str,
) -> Result<(), failure::Error> {
let mut cmd = Command::new("cargo");
cmd.arg("install")
.arg("--force") .arg("--force")
.arg("wasm-bindgen-cli") .arg("wasm-bindgen-cli")
.arg("--version") .arg("--version")
.arg(version) .arg(version)
.arg("--root") .arg("--root")
.arg(crate_path) .arg(crate_path);
.output()?;
if !output.status.success() { child::run(logger, cmd, "cargo install").context("Installing wasm-bindgen with cargo")?;
let message = "Installing wasm-bindgen failed".to_string(); assert!(binaries::local_bin_path(crate_path, "wasm-bindgen").is_file());
let s = String::from_utf8_lossy(&output.stderr); Ok(())
Err(Error::Cli {
message,
stderr: s.to_string(),
exit_status: output.status,
})
} else {
assert!(binaries::local_bin_path(crate_path, "wasm-bindgen").is_file());
Ok(())
}
} }
/// Run the `wasm-bindgen` CLI to generate bindings for the current crate's /// Run the `wasm-bindgen` CLI to generate bindings for the current crate's
@ -116,7 +113,7 @@ pub fn wasm_bindgen_build(
debug: bool, debug: bool,
step: &Step, step: &Step,
log: &Logger, log: &Logger,
) -> Result<(), Error> { ) -> Result<(), failure::Error> {
let msg = format!("{}Running WASM-bindgen...", emoji::RUNNER); let msg = format!("{}Running WASM-bindgen...", emoji::RUNNER);
PBAR.step(step, &msg); PBAR.step(step, &msg);
@ -153,27 +150,20 @@ pub fn wasm_bindgen_build(
cmd.arg("--debug"); cmd.arg("--debug");
} }
let output = cmd.output()?; child::run(log, cmd, "wasm-bindgen").context("Running the wasm-bindgen CLI")?;
if !output.status.success() { Ok(())
let s = String::from_utf8_lossy(&output.stderr);
Error::cli("wasm-bindgen failed to execute properly", s, output.status)
} else {
Ok(())
}
} else { } else {
Error::crate_config("Could not find `wasm-bindgen`") Err(Error::crate_config("Could not find `wasm-bindgen`").into())
} }
} }
/// Check if the `wasm-bindgen` dependency is locally satisfied. /// Check if the `wasm-bindgen` dependency is locally satisfied.
fn wasm_bindgen_version_check(bindgen_path: &PathBuf, dep_version: &str, log: &Logger) -> bool { fn wasm_bindgen_version_check(bindgen_path: &PathBuf, dep_version: &str, log: &Logger) -> bool {
Command::new(bindgen_path) let mut cmd = Command::new(bindgen_path);
.arg("--version") cmd.arg("--version");
.output() child::run(log, cmd, "wasm-bindgen")
.ok() .map(|stdout| {
.filter(|output| output.status.success()) stdout
.map(|output| {
String::from_utf8_lossy(&output.stdout)
.trim() .trim()
.split_whitespace() .split_whitespace()
.nth(1) .nth(1)

@ -1,8 +1,11 @@
//! Building a Rust crate into a `.wasm` binary. //! Building a Rust crate into a `.wasm` binary.
use child;
use emoji; use emoji;
use error::Error; use error::Error;
use failure::ResultExt;
use progressbar::Step; use progressbar::Step;
use slog::Logger;
use std::path::Path; use std::path::Path;
use std::process::Command; use std::process::Command;
use std::str; use std::str;
@ -54,28 +57,23 @@ fn rustc_minor_version() -> Option<u32> {
/// Ensure that `rustup` has the `wasm32-unknown-unknown` target installed for /// Ensure that `rustup` has the `wasm32-unknown-unknown` target installed for
/// current toolchain /// current toolchain
pub fn rustup_add_wasm_target(step: &Step) -> Result<(), Error> { pub fn rustup_add_wasm_target(log: &Logger, step: &Step) -> Result<(), failure::Error> {
let msg = format!("{}Adding WASM target...", emoji::TARGET); let msg = format!("{}Adding WASM target...", emoji::TARGET);
PBAR.step(step, &msg); PBAR.step(step, &msg);
let output = Command::new("rustup") let mut cmd = Command::new("rustup");
.arg("target") cmd.arg("target").arg("add").arg("wasm32-unknown-unknown");
.arg("add") child::run(log, cmd, "rustup")
.arg("wasm32-unknown-unknown") .context("Adding the wasm32-unknown-unknown target with rustup")?;
.output()?; Ok(())
if !output.status.success() {
let s = String::from_utf8_lossy(&output.stderr);
Error::cli(
"Adding the wasm32-unknown-unknown target failed",
s,
output.status,
)
} else {
Ok(())
}
} }
/// Run `cargo build` targetting `wasm32-unknown-unknown`. /// Run `cargo build` targetting `wasm32-unknown-unknown`.
pub fn cargo_build_wasm(path: &Path, debug: bool, step: &Step) -> Result<(), Error> { pub fn cargo_build_wasm(
log: &Logger,
path: &Path,
debug: bool,
step: &Step,
) -> Result<(), failure::Error> {
let msg = format!("{}Compiling to WASM...", emoji::CYCLONE); let msg = format!("{}Compiling to WASM...", emoji::CYCLONE);
PBAR.step(step, &msg); PBAR.step(step, &msg);
let mut cmd = Command::new("cargo"); let mut cmd = Command::new("cargo");
@ -84,32 +82,22 @@ pub fn cargo_build_wasm(path: &Path, debug: bool, step: &Step) -> Result<(), Err
cmd.arg("--release"); cmd.arg("--release");
} }
cmd.arg("--target").arg("wasm32-unknown-unknown"); cmd.arg("--target").arg("wasm32-unknown-unknown");
let output = cmd.output()?; child::run(log, cmd, "cargo build").context("Compiling your crate to WebAssembly")?;
Ok(())
if !output.status.success() {
let s = String::from_utf8_lossy(&output.stderr);
Error::cli("Compilation of your program failed", s, output.status)
} else {
Ok(())
}
} }
/// Run `cargo build --tests` targetting `wasm32-unknown-unknown`. /// Run `cargo build --tests` targetting `wasm32-unknown-unknown`.
pub fn cargo_build_wasm_tests(path: &Path, debug: bool) -> Result<(), Error> { pub fn cargo_build_wasm_tests(
let output = { log: &Logger,
let mut cmd = Command::new("cargo"); path: &Path,
cmd.current_dir(path).arg("build").arg("--tests"); debug: bool,
if !debug { ) -> Result<(), failure::Error> {
cmd.arg("--release"); let mut cmd = Command::new("cargo");
} cmd.current_dir(path).arg("build").arg("--tests");
cmd.arg("--target").arg("wasm32-unknown-unknown"); if !debug {
cmd.output()? cmd.arg("--release");
};
if !output.status.success() {
let s = String::from_utf8_lossy(&output.stderr);
Error::cli("Compilation of your program failed", s, output.status)
} else {
Ok(())
} }
cmd.arg("--target").arg("wasm32-unknown-unknown");
child::run(log, cmd, "cargo build").context("Compilation of your program failed")?;
Ok(())
} }

@ -55,7 +55,7 @@ impl FromStr for BuildMode {
"no-install" => Ok(BuildMode::Noinstall), "no-install" => Ok(BuildMode::Noinstall),
"normal" => Ok(BuildMode::Normal), "normal" => Ok(BuildMode::Normal),
"force" => Ok(BuildMode::Force), "force" => Ok(BuildMode::Force),
_ => Error::crate_config(&format!("Unknown build mode: {}", s)).map(|_| unreachable!()), _ => Err(Error::crate_config(&format!("Unknown build mode: {}", s))),
} }
} }
} }
@ -94,11 +94,11 @@ pub struct BuildOptions {
pub out_dir: String, pub out_dir: String,
} }
type BuildStep = fn(&mut Build, &Step, &Logger) -> Result<(), Error>; type BuildStep = fn(&mut Build, &Step, &Logger) -> Result<(), failure::Error>;
impl Build { impl Build {
/// Construct a build command from the given options. /// Construct a build command from the given options.
pub fn try_from_opts(build_opts: BuildOptions) -> Result<Self, Error> { pub fn try_from_opts(build_opts: BuildOptions) -> Result<Self, failure::Error> {
let crate_path = set_crate_path(build_opts.path)?; let crate_path = set_crate_path(build_opts.path)?;
let crate_name = manifest::get_crate_name(&crate_path)?; let crate_name = manifest::get_crate_name(&crate_path)?;
let out_dir = crate_path.join(PathBuf::from(build_opts.out_dir)); let out_dir = crate_path.join(PathBuf::from(build_opts.out_dir));
@ -117,7 +117,7 @@ impl Build {
} }
/// Execute this `Build` command. /// Execute this `Build` command.
pub fn run(&mut self, log: &Logger) -> Result<(), Error> { pub fn run(&mut self, log: &Logger) -> Result<(), failure::Error> {
let process_steps = Build::get_process_steps(&self.mode); let process_steps = Build::get_process_steps(&self.mode);
let mut step_counter = Step::new(process_steps.len()); let mut step_counter = Step::new(process_steps.len());
@ -188,7 +188,11 @@ impl Build {
} }
} }
fn step_check_rustc_version(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { fn step_check_rustc_version(
&mut self,
step: &Step,
log: &Logger,
) -> Result<(), failure::Error> {
info!(&log, "Checking rustc version..."); info!(&log, "Checking rustc version...");
let version = build::check_rustc_version(step)?; let version = build::check_rustc_version(step)?;
let msg = format!("rustc version is {}.", version); let msg = format!("rustc version is {}.", version);
@ -196,23 +200,23 @@ impl Build {
Ok(()) Ok(())
} }
fn step_check_crate_config(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { fn step_check_crate_config(&mut self, step: &Step, log: &Logger) -> Result<(), failure::Error> {
info!(&log, "Checking crate configuration..."); info!(&log, "Checking crate configuration...");
manifest::check_crate_config(&self.crate_path, step)?; manifest::check_crate_config(&self.crate_path, step)?;
info!(&log, "Crate is correctly configured."); info!(&log, "Crate is correctly configured.");
Ok(()) Ok(())
} }
fn step_add_wasm_target(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { fn step_add_wasm_target(&mut self, step: &Step, log: &Logger) -> Result<(), failure::Error> {
info!(&log, "Adding wasm-target..."); info!(&log, "Adding wasm-target...");
build::rustup_add_wasm_target(step)?; build::rustup_add_wasm_target(log, step)?;
info!(&log, "Adding wasm-target was successful."); info!(&log, "Adding wasm-target was successful.");
Ok(()) Ok(())
} }
fn step_build_wasm(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { fn step_build_wasm(&mut self, step: &Step, log: &Logger) -> Result<(), failure::Error> {
info!(&log, "Building wasm..."); info!(&log, "Building wasm...");
build::cargo_build_wasm(&self.crate_path, self.debug, step)?; build::cargo_build_wasm(log, &self.crate_path, self.debug, step)?;
info!( info!(
&log, &log,
@ -226,14 +230,14 @@ impl Build {
Ok(()) Ok(())
} }
fn step_create_dir(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { fn step_create_dir(&mut self, step: &Step, log: &Logger) -> Result<(), failure::Error> {
info!(&log, "Creating a pkg directory..."); info!(&log, "Creating a pkg directory...");
create_pkg_dir(&self.out_dir, step)?; create_pkg_dir(&self.out_dir, step)?;
info!(&log, "Created a pkg directory at {:#?}.", &self.crate_path); info!(&log, "Created a pkg directory at {:#?}.", &self.crate_path);
Ok(()) Ok(())
} }
fn step_create_json(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { fn step_create_json(&mut self, step: &Step, log: &Logger) -> Result<(), failure::Error> {
info!(&log, "Writing a package.json..."); info!(&log, "Writing a package.json...");
manifest::write_package_json( manifest::write_package_json(
&self.crate_path, &self.crate_path,
@ -251,14 +255,18 @@ impl Build {
Ok(()) Ok(())
} }
fn step_copy_readme(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { fn step_copy_readme(&mut self, step: &Step, log: &Logger) -> Result<(), failure::Error> {
info!(&log, "Copying readme from crate..."); info!(&log, "Copying readme from crate...");
readme::copy_from_crate(&self.crate_path, &self.out_dir, step)?; readme::copy_from_crate(&self.crate_path, &self.out_dir, step)?;
info!(&log, "Copied readme from crate to {:#?}.", &self.out_dir); info!(&log, "Copied readme from crate to {:#?}.", &self.out_dir);
Ok(()) Ok(())
} }
fn step_install_wasm_bindgen(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { fn step_install_wasm_bindgen(
&mut self,
step: &Step,
log: &Logger,
) -> Result<(), failure::Error> {
info!(&log, "Identifying wasm-bindgen dependency..."); info!(&log, "Identifying wasm-bindgen dependency...");
let lockfile = Lockfile::new(&self.crate_path)?; let lockfile = Lockfile::new(&self.crate_path)?;
let bindgen_version = lockfile.require_wasm_bindgen()?; let bindgen_version = lockfile.require_wasm_bindgen()?;
@ -288,7 +296,7 @@ impl Build {
Ok(()) Ok(())
} }
fn step_run_wasm_bindgen(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { fn step_run_wasm_bindgen(&mut self, step: &Step, log: &Logger) -> Result<(), failure::Error> {
info!(&log, "Building the wasm bindings..."); info!(&log, "Building the wasm bindings...");
bindgen::wasm_bindgen_build( bindgen::wasm_bindgen_build(
&self.crate_path, &self.crate_path,

@ -1,4 +1,3 @@
use error::Error;
use npm; use npm;
use slog::Logger; use slog::Logger;
use std::result; use std::result;
@ -10,7 +9,7 @@ pub fn login(
always_auth: bool, always_auth: bool,
auth_type: Option<String>, auth_type: Option<String>,
log: &Logger, log: &Logger,
) -> result::Result<(), Error> { ) -> result::Result<(), failure::Error> {
let registry = registry.unwrap_or(npm::DEFAULT_NPM_REGISTRY.to_string()); let registry = registry.unwrap_or(npm::DEFAULT_NPM_REGISTRY.to_string());
info!(&log, "Logging in to npm..."); info!(&log, "Logging in to npm...");
@ -23,7 +22,7 @@ pub fn login(
&auth_type &auth_type
); );
info!(&log, "npm info located in the npm debug log"); info!(&log, "npm info located in the npm debug log");
npm::npm_login(&registry, &scope, always_auth, &auth_type)?; npm::npm_login(log, &registry, &scope, always_auth, &auth_type)?;
info!(&log, "Logged you in!"); info!(&log, "Logged you in!");
PBAR.message(&format!("👋 logged you in!")); PBAR.message(&format!("👋 logged you in!"));

@ -84,7 +84,7 @@ pub enum Command {
} }
/// Run a command with the given logger! /// Run a command with the given logger!
pub fn run_wasm_pack(command: Command, log: &Logger) -> result::Result<(), Error> { pub fn run_wasm_pack(command: Command, log: &Logger) -> result::Result<(), failure::Error> {
// Run the correct command based off input and store the result of it so that we can clear // Run the correct command based off input and store the result of it so that we can clear
// the progress bar then return it // the progress bar then return it
let status = match command { let status = match command {
@ -129,7 +129,12 @@ pub fn run_wasm_pack(command: Command, log: &Logger) -> result::Result<(), Error
Ok(_) => {} Ok(_) => {}
Err(ref e) => { Err(ref e) => {
error!(&log, "{}", e); error!(&log, "{}", e);
PBAR.error(e.error_type()); for c in e.iter_chain() {
if let Some(e) = c.downcast_ref::<Error>() {
PBAR.error(e.error_type());
break;
}
}
} }
} }

@ -8,7 +8,7 @@ use PBAR;
/// Executes the 'npm pack' command on the 'pkg' directory /// Executes the 'npm pack' command on the 'pkg' directory
/// which creates a tarball that can be published to the NPM registry /// which creates a tarball that can be published to the NPM registry
pub fn pack(path: Option<PathBuf>, log: &Logger) -> result::Result<(), Error> { pub fn pack(path: Option<PathBuf>, log: &Logger) -> result::Result<(), failure::Error> {
let crate_path = set_crate_path(path)?; let crate_path = set_crate_path(path)?;
info!(&log, "Packing up the npm package..."); info!(&log, "Packing up the npm package...");
@ -18,7 +18,7 @@ pub fn pack(path: Option<PathBuf>, log: &Logger) -> result::Result<(), Error> {
&crate_path, &crate_path &crate_path, &crate_path
), ),
})?; })?;
npm::npm_pack(&pkg_directory.to_string_lossy())?; npm::npm_pack(log, &pkg_directory.to_string_lossy())?;
info!( info!(
&log, &log,
"Your package is located at {:#?}", "Your package is located at {:#?}",

@ -16,7 +16,7 @@ pub fn publish(
path: Option<PathBuf>, path: Option<PathBuf>,
access: Option<Access>, access: Option<Access>,
log: &Logger, log: &Logger,
) -> result::Result<(), Error> { ) -> result::Result<(), failure::Error> {
let crate_path = set_crate_path(path)?; let crate_path = set_crate_path(path)?;
info!(&log, "Publishing the npm package..."); info!(&log, "Publishing the npm package...");
@ -28,7 +28,7 @@ pub fn publish(
), ),
})?; })?;
npm::npm_publish(&pkg_directory.to_string_lossy(), access)?; npm::npm_publish(log, &pkg_directory.to_string_lossy(), access)?;
info!(&log, "Published your package!"); info!(&log, "Published your package!");
PBAR.message("💥 published your package!"); PBAR.message("💥 published your package!");

@ -94,11 +94,11 @@ pub struct Test {
test_runner_path: Option<PathBuf>, test_runner_path: Option<PathBuf>,
} }
type TestStep = fn(&mut Test, &Step, &Logger) -> Result<(), Error>; type TestStep = fn(&mut Test, &Step, &Logger) -> Result<(), failure::Error>;
impl Test { impl Test {
/// Construct a test command from the given options. /// Construct a test command from the given options.
pub fn try_from_opts(test_opts: TestOptions) -> Result<Self, Error> { pub fn try_from_opts(test_opts: TestOptions) -> Result<Self, failure::Error> {
let TestOptions { let TestOptions {
path, path,
node, node,
@ -124,18 +124,18 @@ impl Test {
let any_browser = chrome || firefox || safari; let any_browser = chrome || firefox || safari;
if !node && !any_browser { if !node && !any_browser {
return Error::crate_config( return Err(Error::crate_config(
"Must specify at least one of `--node`, `--chrome`, `--firefox`, or `--safari`", "Must specify at least one of `--node`, `--chrome`, `--firefox`, or `--safari`",
) )
.map(|_| unreachable!()); .into());
} }
if headless && !any_browser { if headless && !any_browser {
return Error::crate_config( return Err(Error::crate_config(
"The `--headless` flag only applies to browser tests. Node does not provide a UI, \ "The `--headless` flag only applies to browser tests. Node does not provide a UI, \
so it doesn't make sense to talk about a headless version of Node tests.", so it doesn't make sense to talk about a headless version of Node tests.",
) )
.map(|_| unreachable!()); .into());
} }
Ok(Test { Ok(Test {
@ -155,7 +155,7 @@ impl Test {
} }
/// Execute this test command. /// Execute this test command.
pub fn run(mut self, log: &Logger) -> Result<(), Error> { pub fn run(mut self, log: &Logger) -> Result<(), failure::Error> {
let process_steps = self.get_process_steps(); let process_steps = self.get_process_steps();
let mut step_counter = Step::new(process_steps.len()); let mut step_counter = Step::new(process_steps.len());
@ -227,40 +227,48 @@ impl Test {
} }
} }
fn step_check_rustc_version(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { fn step_check_rustc_version(
&mut self,
step: &Step,
log: &Logger,
) -> Result<(), failure::Error> {
info!(log, "Checking rustc version..."); info!(log, "Checking rustc version...");
let _ = build::check_rustc_version(step)?; let _ = build::check_rustc_version(step)?;
info!(log, "Rustc version is correct."); info!(log, "Rustc version is correct.");
Ok(()) Ok(())
} }
fn step_check_crate_config(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { fn step_check_crate_config(&mut self, step: &Step, log: &Logger) -> Result<(), failure::Error> {
info!(log, "Checking crate configuration..."); info!(log, "Checking crate configuration...");
manifest::check_crate_config(&self.crate_path, step)?; manifest::check_crate_config(&self.crate_path, step)?;
info!(log, "Crate is correctly configured."); info!(log, "Crate is correctly configured.");
Ok(()) Ok(())
} }
fn step_add_wasm_target(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { fn step_add_wasm_target(&mut self, step: &Step, log: &Logger) -> Result<(), failure::Error> {
info!(&log, "Adding wasm-target..."); info!(&log, "Adding wasm-target...");
build::rustup_add_wasm_target(step)?; build::rustup_add_wasm_target(log, step)?;
info!(&log, "Adding wasm-target was successful."); info!(&log, "Adding wasm-target was successful.");
Ok(()) Ok(())
} }
fn step_build_tests(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { fn step_build_tests(&mut self, step: &Step, log: &Logger) -> Result<(), failure::Error> {
info!(log, "Compiling tests to wasm..."); info!(log, "Compiling tests to wasm...");
let msg = format!("{}Compiling tests to WASM...", emoji::CYCLONE); let msg = format!("{}Compiling tests to WASM...", emoji::CYCLONE);
PBAR.step(step, &msg); PBAR.step(step, &msg);
build::cargo_build_wasm_tests(&self.crate_path, !self.release)?; build::cargo_build_wasm_tests(log, &self.crate_path, !self.release)?;
info!(log, "Finished compiling tests to wasm."); info!(log, "Finished compiling tests to wasm.");
Ok(()) Ok(())
} }
fn step_install_wasm_bindgen(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { fn step_install_wasm_bindgen(
&mut self,
step: &Step,
log: &Logger,
) -> Result<(), failure::Error> {
info!(&log, "Identifying wasm-bindgen dependency..."); info!(&log, "Identifying wasm-bindgen dependency...");
let lockfile = Lockfile::new(&self.crate_path)?; let lockfile = Lockfile::new(&self.crate_path)?;
let bindgen_version = lockfile.require_wasm_bindgen()?; let bindgen_version = lockfile.require_wasm_bindgen()?;
@ -277,7 +285,7 @@ impl Test {
wasm-bindgen-test = \"0.2\"", wasm-bindgen-test = \"0.2\"",
style("wasm-bindgen-test").bold().dim(), style("wasm-bindgen-test").bold().dim(),
); );
return Err(Error::CrateConfig { message }); return Err(Error::CrateConfig { message }.into());
} }
let install_permitted = match self.mode { let install_permitted = match self.mode {
@ -310,7 +318,7 @@ impl Test {
Ok(()) Ok(())
} }
fn step_test_node(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { fn step_test_node(&mut self, step: &Step, log: &Logger) -> Result<(), failure::Error> {
assert!(self.node); assert!(self.node);
info!(log, "Running tests in node..."); info!(log, "Running tests in node...");
PBAR.step(step, "Running tests in node..."); PBAR.step(step, "Running tests in node...");
@ -327,7 +335,7 @@ impl Test {
Ok(()) Ok(())
} }
fn step_get_chromedriver(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { fn step_get_chromedriver(&mut self, step: &Step, log: &Logger) -> Result<(), failure::Error> {
PBAR.step(step, "Getting chromedriver..."); PBAR.step(step, "Getting chromedriver...");
assert!(self.chrome && self.chromedriver.is_none()); assert!(self.chrome && self.chromedriver.is_none());
@ -339,7 +347,7 @@ impl Test {
Ok(()) Ok(())
} }
fn step_test_chrome(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { fn step_test_chrome(&mut self, step: &Step, log: &Logger) -> Result<(), failure::Error> {
PBAR.step(step, "Running tests in Chrome..."); PBAR.step(step, "Running tests in Chrome...");
let chromedriver = self.chromedriver.as_ref().unwrap().display().to_string(); let chromedriver = self.chromedriver.as_ref().unwrap().display().to_string();
@ -366,10 +374,11 @@ impl Test {
envs.push(("NO_HEADLESS", "1")); envs.push(("NO_HEADLESS", "1"));
} }
test::cargo_test_wasm(&self.crate_path, self.release, log, envs) test::cargo_test_wasm(&self.crate_path, self.release, log, envs)?;
Ok(())
} }
fn step_get_geckodriver(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { fn step_get_geckodriver(&mut self, step: &Step, log: &Logger) -> Result<(), failure::Error> {
PBAR.step(step, "Getting geckodriver..."); PBAR.step(step, "Getting geckodriver...");
assert!(self.firefox && self.geckodriver.is_none()); assert!(self.firefox && self.geckodriver.is_none());
@ -381,7 +390,7 @@ impl Test {
Ok(()) Ok(())
} }
fn step_test_firefox(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { fn step_test_firefox(&mut self, step: &Step, log: &Logger) -> Result<(), failure::Error> {
PBAR.step(step, "Running tests in Firefox..."); PBAR.step(step, "Running tests in Firefox...");
let geckodriver = self.geckodriver.as_ref().unwrap().display().to_string(); let geckodriver = self.geckodriver.as_ref().unwrap().display().to_string();
@ -408,10 +417,11 @@ impl Test {
envs.push(("NO_HEADLESS", "1")); envs.push(("NO_HEADLESS", "1"));
} }
test::cargo_test_wasm(&self.crate_path, self.release, log, envs) test::cargo_test_wasm(&self.crate_path, self.release, log, envs)?;
Ok(())
} }
fn step_get_safaridriver(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { fn step_get_safaridriver(&mut self, step: &Step, log: &Logger) -> Result<(), failure::Error> {
PBAR.step(step, "Getting safaridriver..."); PBAR.step(step, "Getting safaridriver...");
assert!(self.safari && self.safaridriver.is_none()); assert!(self.safari && self.safaridriver.is_none());
@ -419,7 +429,7 @@ impl Test {
Ok(()) Ok(())
} }
fn step_test_safari(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { fn step_test_safari(&mut self, step: &Step, log: &Logger) -> Result<(), failure::Error> {
PBAR.step(step, "Running tests in Safari..."); PBAR.step(step, "Running tests in Safari...");
let safaridriver = self.safaridriver.as_ref().unwrap().display().to_string(); let safaridriver = self.safaridriver.as_ref().unwrap().display().to_string();
@ -446,6 +456,7 @@ impl Test {
envs.push(("NO_HEADLESS", "1")); envs.push(("NO_HEADLESS", "1"));
} }
test::cargo_test_wasm(&self.crate_path, self.release, log, envs) test::cargo_test_wasm(&self.crate_path, self.release, log, envs)?;
Ok(())
} }
} }

@ -101,19 +101,19 @@ pub enum Error {
impl Error { impl Error {
/// Construct a CLI error. /// Construct a CLI error.
pub fn cli(message: &str, stderr: Cow<str>, exit_status: ExitStatus) -> Result<(), Self> { pub fn cli(message: &str, stderr: Cow<str>, exit_status: ExitStatus) -> Self {
Err(Error::Cli { Error::Cli {
message: message.to_string(), message: message.to_string(),
stderr: stderr.to_string(), stderr: stderr.to_string(),
exit_status, exit_status,
}) }
} }
/// Construct a crate configuration error. /// Construct a crate configuration error.
pub fn crate_config(message: &str) -> Result<(), Self> { pub fn crate_config(message: &str) -> Self {
Err(Error::CrateConfig { Error::CrateConfig {
message: message.to_string(), message: message.to_string(),
}) }
} }
/// Construct an archive error. /// Construct an archive error.

@ -78,11 +78,10 @@ struct CargoLib {
fn read_cargo_toml(path: &Path) -> Result<CargoManifest, Error> { fn read_cargo_toml(path: &Path) -> Result<CargoManifest, Error> {
let manifest_path = path.join("Cargo.toml"); let manifest_path = path.join("Cargo.toml");
if !manifest_path.is_file() { if !manifest_path.is_file() {
return Error::crate_config(&format!( return Err(Error::crate_config(&format!(
"Crate directory is missing a `Cargo.toml` file; is `{}` the wrong directory?", "Crate directory is missing a `Cargo.toml` file; is `{}` the wrong directory?",
path.display() path.display()
)) )));
.map(|_| unreachable!());
} }
let mut cargo_file = File::open(manifest_path)?; let mut cargo_file = File::open(manifest_path)?;
let mut cargo_contents = String::new(); let mut cargo_contents = String::new();
@ -254,10 +253,10 @@ fn check_crate_type(path: &Path) -> Result<(), Error> {
}) { }) {
return Ok(()); return Ok(());
} }
Error::crate_config( Err(Error::crate_config(
"crate-type must be cdylib to compile to wasm32-unknown-unknown. Add the following to your \ "crate-type must be cdylib to compile to wasm32-unknown-unknown. Add the following to your \
Cargo.toml file:\n\n\ Cargo.toml file:\n\n\
[lib]\n\ [lib]\n\
crate-type = [\"cdylib\", \"rlib\"]" crate-type = [\"cdylib\", \"rlib\"]"
) ))
} }

@ -1,56 +1,51 @@
//! Functionality related to publishing to npm. //! Functionality related to publishing to npm.
use child;
use command::publish::access::Access; use command::publish::access::Access;
use error::Error; use failure::{self, ResultExt};
use slog::Logger;
use std::process::{Command, Stdio}; use std::process::{Command, Stdio};
/// The default npm registry used when we aren't working with a custom registry. /// The default npm registry used when we aren't working with a custom registry.
pub const DEFAULT_NPM_REGISTRY: &'static str = "https://registry.npmjs.org/"; pub const DEFAULT_NPM_REGISTRY: &'static str = "https://registry.npmjs.org/";
/// Run the `npm pack` command. /// Run the `npm pack` command.
pub fn npm_pack(path: &str) -> Result<(), Error> { pub fn npm_pack(log: &Logger, path: &str) -> Result<(), failure::Error> {
let output = Command::new("npm").current_dir(path).arg("pack").output()?; let mut cmd = Command::new("npm");
if !output.status.success() { cmd.current_dir(path).arg("pack");
let s = String::from_utf8_lossy(&output.stderr); child::run(log, cmd, "npm pack").context("Packaging up your code failed")?;
Error::cli("Packaging up your code failed", s, output.status) Ok(())
} else {
Ok(())
}
} }
/// Run the `npm publish` command. /// Run the `npm publish` command.
pub fn npm_publish(path: &str, access: Option<Access>) -> Result<(), Error> { pub fn npm_publish(log: &Logger, path: &str, access: Option<Access>) -> Result<(), failure::Error> {
let output = match access { let mut cmd = Command::new("npm");
Some(a) => Command::new("npm") match access {
Some(a) => cmd
.current_dir(path) .current_dir(path)
.arg("publish") .arg("publish")
.arg(&format!("{}", a.to_string())) .arg(&format!("{}", a.to_string()))
.stdin(Stdio::inherit()) .stdin(Stdio::inherit())
.stdout(Stdio::inherit()) .stdout(Stdio::inherit()),
.output()?, None => cmd
None => Command::new("npm")
.current_dir(path) .current_dir(path)
.arg("publish") .arg("publish")
.stdin(Stdio::inherit()) .stdin(Stdio::inherit())
.stdout(Stdio::inherit()) .stdout(Stdio::inherit()),
.output()?,
}; };
if !output.status.success() { child::run(log, cmd, "npm publish").context("Publishing to npm failed")?;
let s = String::from_utf8_lossy(&output.stderr); Ok(())
Error::cli("Publishing to npm failed", s, output.status)
} else {
Ok(())
}
} }
/// Run the `npm login` command. /// Run the `npm login` command.
pub fn npm_login( pub fn npm_login(
log: &Logger,
registry: &String, registry: &String,
scope: &Option<String>, scope: &Option<String>,
always_auth: bool, always_auth: bool,
auth_type: &Option<String>, auth_type: &Option<String>,
) -> Result<(), Error> { ) -> Result<(), failure::Error> {
let mut args = String::new(); let mut args = String::new();
args.push_str(&format!("--registry={}", registry)); args.push_str(&format!("--registry={}", registry));
@ -67,21 +62,12 @@ pub fn npm_login(
args.push_str(&format!(" --auth_type={}", auth_type)); args.push_str(&format!(" --auth_type={}", auth_type));
} }
let output = Command::new("npm") let mut cmd = Command::new("npm");
.arg("login") cmd.arg("login")
.arg(args) .arg(args)
.stdin(Stdio::inherit()) .stdin(Stdio::inherit())
.stdout(Stdio::inherit()) .stdout(Stdio::inherit());
.output()?; child::run(log, cmd, "npm login")
.with_context(|_| format!("Login to registry {} failed", registry))?;
if !output.status.success() { Ok(())
let s = String::from_utf8_lossy(&output.stderr);
Error::cli(
&format!("Login to registry {} failed", registry),
s,
output.status,
)
} else {
Ok(())
}
} }

@ -2,7 +2,8 @@
pub mod webdriver; pub mod webdriver;
use error::Error; use child;
use failure::{self, ResultExt};
use slog::Logger; use slog::Logger;
use std::ffi::OsStr; use std::ffi::OsStr;
use std::path::Path; use std::path::Path;
@ -15,7 +16,7 @@ pub fn cargo_test_wasm<I, K, V>(
release: bool, release: bool,
log: &Logger, log: &Logger,
envs: I, envs: I,
) -> Result<(), Error> ) -> Result<(), failure::Error>
where where
I: IntoIterator<Item = (K, V)>, I: IntoIterator<Item = (K, V)>,
K: AsRef<OsStr>, K: AsRef<OsStr>,
@ -35,17 +36,13 @@ where
cmd.arg("--release"); cmd.arg("--release");
} }
cmd.arg("--target").arg("wasm32-unknown-unknown"); cmd.arg("--target").arg("wasm32-unknown-unknown");
cmd.output()? child::run(log, cmd, "cargo test")
.context("Running Wasm tests with wasm-bindgen-test failed")?
}; };
if !output.status.success() { for line in output.lines() {
let s = String::from_utf8_lossy(&output.stderr); info!(log, "test output: {}", line);
Error::cli("Running wasm tests failed", s, output.status) println!("{}", line);
} else {
for line in String::from_utf8_lossy(&output.stdout).lines() {
info!(log, "test output: {}", line);
println!("{}", line);
}
Ok(())
} }
Ok(())
} }

@ -20,12 +20,11 @@ pub fn get_or_install_chromedriver(
(_, Some(path)) => Ok(path), (_, Some(path)) => Ok(path),
(BuildMode::Normal, None) => install_chromedriver(crate_path), (BuildMode::Normal, None) => install_chromedriver(crate_path),
(BuildMode::Force, None) => install_chromedriver(crate_path), (BuildMode::Force, None) => install_chromedriver(crate_path),
(BuildMode::Noinstall, None) => Error::crate_config( (BuildMode::Noinstall, None) => Err(Error::crate_config(
"No crate-local `chromedriver` binary found, and could not find a global \ "No crate-local `chromedriver` binary found, and could not find a global \
`chromedriver` on the `$PATH`. Not installing `chromedriver` because of noinstall \ `chromedriver` on the `$PATH`. Not installing `chromedriver` because of noinstall \
mode.", mode.",
) )),
.map(|_| unreachable!()),
} }
} }
@ -72,11 +71,10 @@ pub fn get_or_install_geckodriver(
(_, Some(path)) => Ok(path), (_, Some(path)) => Ok(path),
(BuildMode::Normal, None) => install_geckodriver(crate_path), (BuildMode::Normal, None) => install_geckodriver(crate_path),
(BuildMode::Force, None) => install_geckodriver(crate_path), (BuildMode::Force, None) => install_geckodriver(crate_path),
(BuildMode::Noinstall, None) => Error::crate_config( (BuildMode::Noinstall, None) => Err(Error::crate_config(
"No crate-local `geckodriver` binary found, and could not find a global `geckodriver` \ "No crate-local `geckodriver` binary found, and could not find a global `geckodriver` \
on the `$PATH`. Not installing `geckodriver` because of noinstall mode.", on the `$PATH`. Not installing `geckodriver` because of noinstall mode.",
) )),
.map(|_| unreachable!()),
} }
} }
@ -133,6 +131,8 @@ pub fn get_safaridriver(log: &Logger, crate_path: &Path) -> Result<PathBuf, Erro
if let Some(p) = bin_path(log, crate_path, "safaridriver") { if let Some(p) = bin_path(log, crate_path, "safaridriver") {
Ok(p) Ok(p)
} else { } else {
Error::crate_config("could not find `safaridriver` on the `$PATH`").map(|_| unreachable!()) Err(Error::crate_config(
"could not find `safaridriver` on the `$PATH`",
))
} }
} }

@ -1,3 +1,4 @@
use super::logger::null_logger;
use std::env; use std::env;
use std::fs; use std::fs;
use std::io; use std::io;
@ -6,9 +7,8 @@ use std::path::{Path, PathBuf};
use std::process::{Command, Stdio}; use std::process::{Command, Stdio};
use std::sync::{Once, ONCE_INIT}; use std::sync::{Once, ONCE_INIT};
use std::thread; use std::thread;
use wasm_pack;
use tempfile::TempDir; use tempfile::TempDir;
use wasm_pack;
fn hard_link_or_copy<P1: AsRef<Path>, P2: AsRef<Path>>(from: P1, to: P2) -> io::Result<()> { fn hard_link_or_copy<P1: AsRef<Path>, P2: AsRef<Path>>(from: P1, to: P2) -> io::Result<()> {
let from = from.as_ref(); let from = from.as_ref();
@ -151,7 +151,11 @@ impl Fixture {
const WASM_BINDGEN_VERSION: &str = "0.2.21"; const WASM_BINDGEN_VERSION: &str = "0.2.21";
wasm_pack::bindgen::download_prebuilt_wasm_bindgen(&tests, WASM_BINDGEN_VERSION) wasm_pack::bindgen::download_prebuilt_wasm_bindgen(&tests, WASM_BINDGEN_VERSION)
.or_else(|_| { .or_else(|_| {
wasm_pack::bindgen::cargo_install_wasm_bindgen(&tests, WASM_BINDGEN_VERSION) wasm_pack::bindgen::cargo_install_wasm_bindgen(
&null_logger(),
&tests,
WASM_BINDGEN_VERSION,
)
}) })
.unwrap(); .unwrap();
}); });

Loading…
Cancel
Save