From 512c77012cbe3743c87678054999fd4214cf8109 Mon Sep 17 00:00:00 2001 From: konstin Date: Tue, 25 Sep 2018 02:07:42 +0200 Subject: [PATCH] Use `--message-format=json` to fix #333 --- Cargo.lock | 6 +- Cargo.toml | 4 +- src/bindgen.rs | 11 +-- src/build.rs | 140 +++++++++++++++++++++++++++---------- src/command/build.rs | 21 +++--- src/lib.rs | 1 + tests/all/build.rs | 18 +++++ tests/all/utils/fixture.rs | 55 +++++++++++++-- 8 files changed, 191 insertions(+), 65 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9cf4cf60..7546ab5e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -86,7 +86,7 @@ dependencies = [ [[package]] name = "cargo_metadata" version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://github.com/roblabla/cargo_metadata?rev=54a24e30864feb7414ca400f65a486d1e01ec474#54a24e30864feb7414ca400f65a486d1e01ec474" dependencies = [ "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -962,7 +962,7 @@ name = "wasm-pack" version = "0.5.0" dependencies = [ "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "cargo_metadata 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo_metadata 0.6.0 (git+https://github.com/roblabla/cargo_metadata?rev=54a24e30864feb7414ca400f65a486d1e01ec474)", "console 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "curl 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1064,7 +1064,7 @@ dependencies = [ "checksum byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "90492c5858dd7d2e78691cfb89f90d273a2800fc11d98f60786e5d87e2f83781" "checksum bzip2 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b" "checksum bzip2-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2c5162604199bbb17690ede847eaa6120a3f33d5ab4dcc8e7c25b16d849ae79b" -"checksum cargo_metadata 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d6809b327f87369e6f3651efd2c5a96c49847a3ed2559477ecba79014751ee1" +"checksum cargo_metadata 0.6.0 (git+https://github.com/roblabla/cargo_metadata?rev=54a24e30864feb7414ca400f65a486d1e01ec474)" = "" "checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16" "checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3" "checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" diff --git a/Cargo.toml b/Cargo.toml index 3e2e1377..f3a10f7d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,6 @@ documentation = "https://rustwasm.github.io/wasm-pack/" [dependencies] atty = "0.2.11" -cargo_metadata = "0.6.0" console = "0.6.1" curl = "0.4.13" failure = "0.1.2" @@ -32,8 +31,7 @@ tar = "0.4.16" toml = "0.4" which = "2.0.0" zip = "0.4.2" - -[dev-dependencies] +cargo_metadata = { git = "https://github.com/roblabla/cargo_metadata", rev = "54a24e30864feb7414ca400f65a486d1e01ec474" } tempfile = "3" [features] diff --git a/src/bindgen.rs b/src/bindgen.rs index a1a1e5ff..fa24d1a8 100644 --- a/src/bindgen.rs +++ b/src/bindgen.rs @@ -109,7 +109,7 @@ pub fn cargo_install_wasm_bindgen(crate_path: &Path, version: &str) -> Result<() pub fn wasm_bindgen_build( path: &Path, out_dir: &Path, - name: &str, + artifact: &Path, disable_dts: bool, target: &str, debug: bool, @@ -119,16 +119,9 @@ pub fn wasm_bindgen_build( let msg = format!("{}Running WASM-bindgen...", emoji::RUNNER); PBAR.step(step, &msg); - let binary_name = name.replace("-", "_"); - let release_or_debug = if debug { "debug" } else { "release" }; - let out_dir = out_dir.to_str().unwrap(); if let Some(wasm_bindgen_path) = wasm_bindgen_path(log, path) { - let wasm_path = format!( - "target/wasm32-unknown-unknown/{}/{}.wasm", - release_or_debug, binary_name - ); let dts_arg = if disable_dts { "--no-typescript" } else { @@ -142,7 +135,7 @@ pub fn wasm_bindgen_build( let bindgen_path = Path::new(&wasm_bindgen_path); let mut cmd = Command::new(bindgen_path); cmd.current_dir(path) - .arg(&wasm_path) + .arg(artifact) .arg("--out-dir") .arg(out_dir) .arg(dts_arg) diff --git a/src/build.rs b/src/build.rs index aeee4109..bec354e7 100644 --- a/src/build.rs +++ b/src/build.rs @@ -1,11 +1,17 @@ //! Building a Rust crate into a `.wasm` binary. +use cargo_metadata; +use cargo_metadata::Message; use emoji; use error::Error; use progressbar::Step; +use std::io::Read; use std::path::Path; +use std::path::PathBuf; use std::process::Command; +use std::process::Stdio; use std::str; +use tempfile::NamedTempFile; use PBAR; /// Ensure that `rustc` is present and that it is >= 1.30.0 @@ -16,20 +22,20 @@ pub fn check_rustc_version(step: &Step) -> Result { match local_minor_version { Some(mv) => { if mv < 30 { - return Err(Error::RustcVersion { - message: format!( - "Your version of Rust, '1.{}', is not supported. Please install Rust version 1.30.0 or higher.", - mv.to_string() - ), - local_minor_version: mv.to_string(), - }) + return Err(Error::RustcVersion { + message: format!( + "Your version of Rust, '1.{}', is not supported. Please install Rust version 1.30.0 or higher.", + mv.to_string() + ), + local_minor_version: mv.to_string(), + }); } else { - Ok(mv.to_string()) + Ok(mv.to_string()) } - }, - None => Err(Error::RustcMissing { - message: "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.".to_string(), - }), + } + None => Err(Error::RustcMissing { + message: "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.".to_string(), + }), } } @@ -71,38 +77,102 @@ pub fn rustup_add_wasm_target(step: &Step) -> Result<(), Error> { } /// Run `cargo build` targetting `wasm32-unknown-unknown`. -pub fn cargo_build_wasm(path: &Path, debug: bool, step: &Step) -> Result<(), Error> { +/// +/// Returns the location of the built wasm file. +pub fn cargo_build_wasm( + path: &Path, + debug: bool, + step: &Step, + crate_name: &str, +) -> Result { let msg = format!("{}Compiling to WASM...", emoji::CYCLONE); PBAR.step(step, &msg); - let output = { - let mut cmd = Command::new("cargo"); - cmd.current_dir(path).arg("build").arg("--lib"); - if !debug { - cmd.arg("--release"); - } - cmd.arg("--target").arg("wasm32-unknown-unknown"); - cmd.output()? - }; - if !output.status.success() { - let s = String::from_utf8_lossy(&output.stderr); - Error::cli("Compilation of your program failed", s) + // Since pipes like `Stdio::piped()` have a fixed capacity, we could deadlock with us + // waiting on stdout and cargo blocking on the full stderr pipe. This is why we use a file + // here + let mut stderr = NamedTempFile::new()?; + + let mut cmd = Command::new("cargo"); + cmd.current_dir(path) + .arg("+nightly") + .arg("build") + .arg("--lib") + .arg("--target=wasm32-unknown-unknown") + .arg("--message-format=json") + .stderr(Stdio::from(stderr.reopen()?)) + .stdout(Stdio::piped()); + if !debug { + cmd.arg("--release"); + } + let mut output = cmd.spawn()?; + + let message_stream = output + .stdout + .take() + .expect("cargo child process should always have an stdout"); + + let mut wasm_file = None; + + for message in cargo_metadata::parse_message_stream(message_stream) { + match message.unwrap() { + Message::CompilerArtifact(artifact) => { + if artifact.package_id.name() == crate_name { + let pos = artifact + .target + .crate_types + .iter() + .position(|x| x == "cdylib"); + + if let Some(pos) = pos { + wasm_file = Some(PathBuf::from(&artifact.filenames[pos])); + }; + }; + } + Message::CompilerMessage(message) => { + eprintln!( + "{}", + message + .message + .rendered + .unwrap_or_else(|| "Unrendered Message".to_string()) + ); + } + _ => (), + }; + } + + let status = output.wait()?; + if !status.success() { + let mut errors = String::new(); + stderr.read_to_string(&mut errors)?; + Err(Error::Cli { + message: "Compilation of your program failed".to_string(), + stderr: errors, + }) } else { - Ok(()) + if let Some(wasm_file) = wasm_file { + Ok(wasm_file) + } else { + Err(Error::CrateConfig { + message: "Your crate didn't produce a cdylib".to_string(), + }) + } } } /// Run `cargo build --tests` targetting `wasm32-unknown-unknown`. pub fn cargo_build_wasm_tests(path: &Path, debug: bool) -> Result<(), Error> { - let output = { - let mut cmd = Command::new("cargo"); - cmd.current_dir(path).arg("build").arg("--tests"); - if !debug { - cmd.arg("--release"); - } - cmd.arg("--target").arg("wasm32-unknown-unknown"); - cmd.output()? - }; + let mut cmd = Command::new("cargo"); + cmd.current_dir(path) + .arg("build") + .arg("--tests") + .arg("--target=wasm32-unknown-unknown"); + if !debug { + cmd.arg("--release"); + } + + let output = cmd.output()?; if !output.status.success() { let s = String::from_utf8_lossy(&output.stderr); diff --git a/src/command/build.rs b/src/command/build.rs index 9e81c653..fd039c82 100644 --- a/src/command/build.rs +++ b/src/command/build.rs @@ -27,6 +27,8 @@ pub(crate) struct Build { // build_config: Option, pub crate_name: String, pub out_dir: PathBuf, + /// This is a workaround to pass the artifact's location from build_wasm to run_wasm_bindgen + pub wasm_file: Option, } /// The `BuildMode` determines which mode of initialization we are running, and @@ -113,6 +115,7 @@ impl Build { // build_config, crate_name, out_dir, + wasm_file: None, }) } @@ -212,17 +215,13 @@ impl Build { fn step_build_wasm(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { info!(&log, "Building wasm..."); - build::cargo_build_wasm(&self.crate_path, self.debug, step)?; + let artifact = + build::cargo_build_wasm(&self.crate_path, self.debug, step, &self.crate_name)?; + + info!(&log, "wasm built at {:#?}.", &artifact); + + self.wasm_file = Some(artifact); - info!( - &log, - "wasm built at {:#?}.", - &self - .crate_path - .join("target") - .join("wasm32-unknown-unknown") - .join("release") - ); Ok(()) } @@ -293,7 +292,7 @@ impl Build { bindgen::wasm_bindgen_build( &self.crate_path, &self.out_dir, - &self.crate_name, + &self.wasm_file.clone().unwrap(), self.disable_dts, &self.target, self.debug, diff --git a/src/lib.rs b/src/lib.rs index bb3f2b1c..71060436 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,6 +22,7 @@ extern crate slog; extern crate slog_async; extern crate slog_term; extern crate tar; +extern crate tempfile; extern crate toml; extern crate which; extern crate zip; diff --git a/tests/all/build.rs b/tests/all/build.rs index 69a9bab9..b31e3db4 100644 --- a/tests/all/build.rs +++ b/tests/all/build.rs @@ -20,3 +20,21 @@ fn build_in_non_crate_directory_doesnt_panic() { let err_msg = result.unwrap_err().to_string(); assert!(err_msg.contains("missing a `Cargo.toml`")); } + +#[test] +fn build_in_nested_workspace() { + let fixture = utils::fixture::nested_workspace(); + let cli = Cli::from_iter_safe(vec![ + "wasm-pack", + "build", + "--debug", + "--mode=no-install", + &fixture.path.join("sub-crate").display().to_string(), + ]).unwrap(); + let logger = logger::new(&cli.cmd, cli.verbosity).unwrap(); + let result = command::run_wasm_pack(cli.cmd, &logger); + assert!( + result.is_ok(), + "Building with wasm-pack in nested workspace should succeed" + ); +} diff --git a/tests/all/utils/fixture.rs b/tests/all/utils/fixture.rs index 720953d0..2a9402bb 100644 --- a/tests/all/utils/fixture.rs +++ b/tests/all/utils/fixture.rs @@ -6,9 +6,8 @@ use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; use std::sync::{Once, ONCE_INIT}; use std::thread; -use wasm_pack; - use tempfile::TempDir; +use wasm_pack; fn hard_link_or_copy, P2: AsRef>(from: P1, to: P2) -> io::Result<()> { let from = from.as_ref(); @@ -107,9 +106,9 @@ impl Fixture { } /// Add a `src/lib.rs` file that contains a "hello world" program. - pub fn hello_world_src_lib(&self) -> &Self { + pub fn hello_world_with_path(&self, path: impl AsRef) -> &Self { self.file( - "src/lib.rs", + path, r#" extern crate wasm_bindgen; use wasm_bindgen::prelude::*; @@ -130,6 +129,10 @@ impl Fixture { ) } + pub fn hello_world_src_lib(&self) -> &Self { + self.hello_world_with_path("src/lib.rs") + } + /// Install a local wasm-bindgen for this fixture. /// /// Takes care not to re-install for every fixture, but only the one time @@ -470,3 +473,47 @@ pub fn wbg_test_node() -> Fixture { ); fixture } + +pub fn nested_workspace() -> Fixture { + let fixture = Fixture::new(); + + // The upper crate + fixture + .readme() + .file( + "src/lib.rs", + r#" + compile_error!("Wrong crate"); + "#, + ).file( + "Cargo.toml", + r#" + [package] + name = "main-crate" + version = "0.1.0" + authors = ["The wasm-pack developers"] + + [workspace] + members = [ + "sub-crate" + ] + "#, + ); + + fixture.hello_world_with_path("sub-crate/src/lib.rs").file( + "sub-crate/Cargo.toml", + r#" + [package] + name = "sub-crate" + version = "0.1.0" + authors = ["The wasm-pack developers"] + + [lib] + crate-type = ["cdylib"] + + [dependencies] + wasm-bindgen = "0.2" + "#, + ); + fixture +}