Merge pull request #623 from rustwasm/generate

generate
master
ashley williams 6 years ago committed by GitHub
commit a267075be8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      .travis.yml
  2. 767
      Cargo.lock
  3. 3
      Cargo.toml
  4. 45
      README.md
  5. 2
      docs/src/SUMMARY.md
  6. 7
      docs/src/commands/index.md
  7. 50
      docs/src/commands/new.md
  8. 13
      docs/src/quickstart.md
  9. 189
      src/bindgen.rs
  10. 2
      src/build/mod.rs
  11. 3
      src/child.rs
  12. 59
      src/command/build.rs
  13. 28
      src/command/generate.rs
  14. 31
      src/command/mod.rs
  15. 37
      src/command/test.rs
  16. 1
      src/command/utils.rs
  17. 1
      src/emoji.rs
  18. 25
      src/generate.rs
  19. 24
      src/install/krate.rs
  20. 245
      src/install/mod.rs
  21. 43
      src/install/mode.rs
  22. 18
      src/install/tool.rs
  23. 2
      src/lib.rs
  24. 25
      src/main.rs
  25. 12
      src/manifest/mod.rs
  26. 16
      src/npm.rs
  27. 18
      src/test/webdriver.rs
  28. 19
      tests/all/download.rs
  29. 21
      tests/all/generate.rs
  30. 3
      tests/all/main.rs
  31. 22
      tests/all/manifest.rs
  32. 33
      tests/all/utils/fixture.rs

@ -52,8 +52,8 @@ matrix:
- cargo fmt --version
- cargo fmt --all -- --check
- rustup component add clippy-preview
- cargo clippy --version
- cargo clippy
# - cargo clippy --version
# - cargo clippy
- name: Book
rust: stable

767
Cargo.lock generated

File diff suppressed because it is too large Load Diff

@ -23,6 +23,7 @@ glob = "0.2"
log = "0.4.6"
openssl = { version = '0.10.11', optional = true }
parking_lot = "0.6"
reqwest = "0.9.14"
serde = "1.0.74"
serde_derive = "1.0.74"
serde_ignored = "0.0.4"
@ -37,7 +38,7 @@ walkdir = "2"
chrono = "0.4.6"
[dev-dependencies]
assert_cmd = "0.10.2"
assert_cmd = "0.11"
lazy_static = "1.1.0"
predicates = "1.0.0"
tempfile = "3"

@ -50,8 +50,15 @@ This project requires Rust 1.30.0 or later.
- [Development Environment](https://rustwasm.github.io/wasm-pack/book/prerequisites/index.html)
- [Installation](https://rustwasm.github.io/wasm-pack/installer)
## ⚡ Quickstart Guide
Visit the [quickstart quide] in our documentation.
[quickstart guide]: https://rustwasm.github.io/wasm-pack/book/quickstart.html
## 🎙 Commands
- [`generate`](https://rustwasm.github.io/wasm-pack/book/commands/generate.html): Generate a new RustWasm project using a template
- [`build`](https://rustwasm.github.io/wasm-pack/book/commands/build.html): Generate an npm wasm pkg from a rustwasm crate
- [`test`](https://rustwasm.github.io/wasm-pack/book/commands/test.html): Run browser tests
- [`pack` and `publish`](https://rustwasm.github.io/wasm-pack/book/commands/pack-and-publish.html): Create a tarball of your rustwasm pkg and/or publish to a registry
@ -85,41 +92,3 @@ This project was started by [ashleygwilliams] and is co-maintained by [ashleygwi
[ashleygwilliams]: https://github.com/ashleygwilliams
[drager]: https://github.com/drager
[rustwasm Working Group]: https://github.com/rustwasm/team
## ⚡ Quickstart Guide
1. Write a crate in Rust.
2. Add `wasm-bindgen` to your `Cargo.toml`:
```toml
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2"
```
3. Add this to the top of your `src/lib.rs`:
```rust
use wasm_bindgen::prelude::*;
```
4. Annotate your public functions with `#[wasm_bindgen]`, for example:
```rust
#[wasm_bindgen]
extern {
pub fn alert(s: &str);
}
#[wasm_bindgen]
pub fn greet(name: &str) {
alert(&format!("Hello, {}!", name));
}
```
5. Install this tool: `cargo install wasm-pack`
6. Run `wasm-pack build`, optionally, pass a path to a dir or a scope (see above for details)
7. This tool generates files in a `pkg` dir
8. To publish to npm, run `wasm-pack publish`. You may need to login to the
registry you want to publish to. You can login using `wasm-pack login`.

@ -1,10 +1,12 @@
# Summary
- [Introduction](./introduction.md)
- [Quickstart](./quickstart.md)
- [Prerequisites](./prerequisites/index.md)
- [npm (optional)](./prerequisites/npm.md)
- [Non-`rustup` setups](./prerequisites/non-rustup-setups.md)
- [Commands](./commands/index.md)
- [`new`](./commands/new.md)
- [`build`](./commands/build.md)
- [`test`](./commands/test.md)
- [`pack` and `publish`](./commands/pack-and-publish.md)

@ -3,9 +3,14 @@
`wasm-pack` has several commands to help you during the process of building
a Rust-generated WebAssembly project.
- `init`: This command has been deprecated in favor of `build`.
- `new`: This command generates a new project for you using a template. [Learn more][generate]
- `build`: This command builds a `pkg` directory for you with compiled wasm and generated JS. [Learn more][build]
- `pack` and `publish`: These command will create a tarball, and optionally publish it to a registry, such as npm. [Learn more][pack-pub]
### Deprecated Commands
- `init`: This command has been deprecated in favor of `build`.
[build]: ./build.html
[new]: ./new.html
[pack-pub]: ./pack-and-publish.html

@ -0,0 +1,50 @@
# wasm-pack new
The `wasm-pack new` command creates a new RustWasm project for you,
using [`cargo-generate`] under the hood.
It takes 3 parameters, name, template, and mode:
```
wasm-pack new <name> --template <template> --mode <normal|noinstall|force>
```
The template will default to the `rustwasm/wasm-pack-template`.
## Name
The `wasm-pack new` command must be given a name argument, e.g.:
```
wasm-pack new myproject
```
## Template
The `wasm-pack new` command can be given an optional template argument, e.g.:
```
wasm-pack new myproject --template https://github.com/rustwasm/wasm-pack-template
```
The template can be an address to a git repo that contains a [`cargo-generate`]
template.
[`cargo-generate`]: https://github.com/ashleygwilliams/cargo-generate
## Mode
The `wasm-pack new` command can be given an optional mode argument, e.g.:
```
wasm-pack new myproject --mode noinstall
```
The mode pass can be either "normal", "noinstall", or "force". "normal is passed by
degault.
`noinstall` means that wasm-pack should not attempt to install any underlying tools.
If a necessary tool cannot be found, the command will error.
`force` means that wasm-pack should not check the local Rust version. If a local Rust
is an unacceptable Rust version, the command will error.

@ -0,0 +1,13 @@
# Quickstart
1. Install `rust` using [`rustup`].
1. [Install this tool.]
1. Run `wasm-pack new hello-wasm`.
1. `cd hello-wasm`
1. Run `wasm-pack build`.
1. This tool generates files in a `pkg` dir
1. To publish to npm, run `wasm-pack publish`. You may need to login to the
registry you want to publish to. You can login using `wasm-pack login`.
[`rustup`]: https://rustup.rs/
[Install this tool.]: https://rustwasm.github.io/wasm-pack/installer/

@ -1,171 +1,12 @@
//! Functionality related to installing and running `wasm-bindgen`.
//! Functionality related to running `wasm-bindgen`.
use binary_install::{Cache, Download};
use binary_install::Download;
use child;
use command::build::{BuildProfile, Target};
use emoji;
use failure::{self, ResultExt};
use log::debug;
use log::{info, warn};
use manifest::CrateData;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::path::Path;
use std::process::Command;
use target;
use which::which;
use PBAR;
/// Install the `wasm-bindgen` CLI.
///
/// Prefers an existing local install, if any exists. Then checks if there is a
/// global install on `$PATH` that fits the bill. Then attempts to download a
/// tarball from the GitHub releases page, if this target has prebuilt
/// binaries. Finally, falls back to `cargo install`.
pub fn install_wasm_bindgen(
cache: &Cache,
version: &str,
install_permitted: bool,
) -> Result<Download, failure::Error> {
// If `wasm-bindgen` is installed globally and it has the right version, use
// that. Assume that other tools are installed next to it.
//
// This situation can arise if `wasm-bindgen` is already installed via
// `cargo install`, for example.
if let Ok(path) = which("wasm-bindgen") {
debug!("found global wasm-bindgen binary at: {}", path.display());
if wasm_bindgen_version_check(&path, version) {
return Ok(Download::at(path.parent().unwrap()));
}
}
let msg = format!("{}Installing wasm-bindgen...", emoji::DOWN_ARROW);
PBAR.info(&msg);
let dl = download_prebuilt_wasm_bindgen(&cache, version, install_permitted);
match dl {
Ok(dl) => return Ok(dl),
Err(e) => {
warn!(
"could not download pre-built `wasm-bindgen`: {}. Falling back to `cargo install`.",
e
);
}
}
cargo_install_wasm_bindgen(&cache, version, install_permitted)
}
/// Downloads a precompiled copy of wasm-bindgen, if available.
pub fn download_prebuilt_wasm_bindgen(
cache: &Cache,
version: &str,
install_permitted: bool,
) -> Result<Download, failure::Error> {
let url = match prebuilt_url(version) {
Some(url) => url,
None => bail!("no prebuilt wasm-bindgen binaries are available for this platform"),
};
let binaries = &["wasm-bindgen", "wasm-bindgen-test-runner"];
match cache.download(install_permitted, "wasm-bindgen", binaries, &url)? {
Some(download) => Ok(download),
None => bail!("wasm-bindgen v{} is not installed!", version),
}
}
/// Returns the URL of a precompiled version of wasm-bindgen, if we have one
/// available for our host platform.
fn prebuilt_url(version: &str) -> Option<String> {
let target = if target::LINUX && target::x86_64 {
"x86_64-unknown-linux-musl"
} else if target::MACOS && target::x86_64 {
"x86_64-apple-darwin"
} else if target::WINDOWS && target::x86_64 {
"x86_64-pc-windows-msvc"
} else {
return None;
};
Some(format!(
"https://github.com/rustwasm/wasm-bindgen/releases/download/{0}/wasm-bindgen-{0}-{1}.tar.gz",
version,
target
))
}
/// Use `cargo install` to install the `wasm-bindgen` CLI locally into the given
/// crate.
pub fn cargo_install_wasm_bindgen(
cache: &Cache,
version: &str,
install_permitted: bool,
) -> Result<Download, failure::Error> {
debug!(
"Attempting to use a `cargo install`ed version of `wasm-bindgen={}`",
version
);
let dirname = format!("wasm-bindgen-cargo-install-{}", version);
let destination = cache.join(dirname.as_ref());
if destination.exists() {
debug!(
"`cargo install`ed `wasm-bindgen={}` already exists at {}",
version,
destination.display()
);
return Ok(Download::at(&destination));
}
if !install_permitted {
bail!("wasm-bindgen v{} is not installed!", version)
}
// Run `cargo install` to a temporary location to handle ctrl-c gracefully
// and ensure we don't accidentally use stale files in the future
let tmp = cache.join(format!(".{}", dirname).as_ref());
drop(fs::remove_dir_all(&tmp));
debug!(
"cargo installing wasm-bindgen to tempdir: {}",
tmp.display()
);
fs::create_dir_all(&tmp)
.context("failed to create temp dir for `cargo install wasm-bindgen`")?;
let mut cmd = Command::new("cargo");
cmd.arg("install")
.arg("--force")
.arg("wasm-bindgen-cli")
.arg("--version")
.arg(version)
.arg("--root")
.arg(&tmp);
child::run(cmd, "cargo install").context("Installing wasm-bindgen with cargo")?;
// `cargo install` will put the installed binaries in `$root/bin/*`, but we
// just want them in `$root/*` directly (which matches how the tarballs are
// laid out, and where the rest of our code expects them to be). So we do a
// little renaming here.
for f in ["wasm-bindgen", "wasm-bindgen-test-runner"].iter().cloned() {
let from = tmp
.join("bin")
.join(f)
.with_extension(env::consts::EXE_EXTENSION);
let to = tmp.join(from.file_name().unwrap());
fs::rename(&from, &to).with_context(|_| {
format!(
"failed to move {} to {} for `cargo install`ed `wasm-bindgen`",
from.display(),
to.display()
)
})?;
}
// Finally, move the `tmp` directory into our binary cache.
fs::rename(&tmp, &destination)?;
Ok(Download::at(&destination))
}
/// Run the `wasm-bindgen` CLI to generate bindings for the current crate's
/// `.wasm`.
@ -175,7 +16,7 @@ pub fn wasm_bindgen_build(
out_dir: &Path,
out_name: &Option<String>,
disable_dts: bool,
target: &Target,
target: Target,
profile: BuildProfile,
) -> Result<(), failure::Error> {
let release_or_debug = match profile {
@ -229,25 +70,3 @@ pub fn wasm_bindgen_build(
child::run(cmd, "wasm-bindgen").context("Running the wasm-bindgen CLI")?;
Ok(())
}
/// Check if the `wasm-bindgen` dependency is locally satisfied.
fn wasm_bindgen_version_check(bindgen_path: &PathBuf, dep_version: &str) -> bool {
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)
})
.unwrap_or(false)
}

@ -81,7 +81,7 @@ fn wasm_pack_local_version() -> Option<String> {
pub fn cargo_build_wasm(
path: &Path,
profile: BuildProfile,
extra_options: &Vec<String>,
extra_options: &[String],
) -> Result<(), Error> {
let msg = format!("{}Compiling to Wasm...", emoji::CYCLONE);
PBAR.info(&msg);

@ -4,6 +4,7 @@
//! properly logged and their output is logged as well.
use failure::Error;
use install::Tool;
use log::info;
use std::process::{Command, Stdio};
@ -41,7 +42,7 @@ pub fn run(mut command: Command, command_name: &str) -> Result<(), Error> {
}
/// Run the given command and return its stdout.
pub fn run_capture_stdout(mut command: Command, command_name: &str) -> Result<String, Error> {
pub fn run_capture_stdout(mut command: Command, command_name: &Tool) -> Result<String, Error> {
info!("Running {:?}", command);
let output = command

@ -7,6 +7,7 @@ use cache;
use command::utils::{create_pkg_dir, set_crate_path};
use emoji;
use failure::Error;
use install::{self, InstallMode, Tool};
use license;
use lockfile::Lockfile;
use log::info;
@ -26,7 +27,7 @@ pub struct Build {
pub disable_dts: bool,
pub target: Target,
pub profile: BuildProfile,
pub mode: BuildMode,
pub mode: InstallMode,
pub out_dir: PathBuf,
pub out_name: Option<String>,
pub bindgen: Option<Download>,
@ -34,37 +35,6 @@ pub struct Build {
pub extra_options: Vec<String>,
}
/// The `BuildMode` determines which mode of initialization we are running, and
/// what build and install steps we perform.
#[derive(Clone, Copy, Debug)]
pub enum BuildMode {
/// Perform all the build and install steps.
Normal,
/// Don't install tools like `wasm-bindgen`, just use the global
/// environment's existing versions to do builds.
Noinstall,
/// Skip the rustc version check
Force,
}
impl Default for BuildMode {
fn default() -> BuildMode {
BuildMode::Normal
}
}
impl FromStr for BuildMode {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Error> {
match s {
"no-install" => Ok(BuildMode::Noinstall),
"normal" => Ok(BuildMode::Normal),
"force" => Ok(BuildMode::Force),
_ => bail!("Unknown build mode: {}", s),
}
}
}
/// What sort of output we're going to be generating and flags we're invoking
/// `wasm-bindgen` with.
#[derive(Clone, Copy, Debug)]
@ -128,7 +98,7 @@ pub struct BuildOptions {
#[structopt(long = "mode", short = "m", default_value = "normal")]
/// Sets steps to be run. [possible values: no-install, normal, force]
pub mode: BuildMode,
pub mode: InstallMode,
#[structopt(long = "no-typescript")]
/// By default a *.d.ts file is generated for the generated JS file, but
@ -174,7 +144,7 @@ impl Default for BuildOptions {
Self {
path: None,
scope: None,
mode: BuildMode::default(),
mode: InstallMode::default(),
disable_dts: false,
target: Target::default(),
debug: false,
@ -255,7 +225,7 @@ impl Build {
Ok(())
}
fn get_process_steps(mode: BuildMode) -> Vec<(&'static str, BuildStep)> {
fn get_process_steps(mode: InstallMode) -> Vec<(&'static str, BuildStep)> {
macro_rules! steps {
($($name:ident),+) => {
{
@ -268,7 +238,7 @@ impl Build {
}
let mut steps = Vec::new();
match &mode {
BuildMode::Force => {}
InstallMode::Force => {}
_ => {
steps.extend(steps![
step_check_rustc_version,
@ -338,7 +308,7 @@ impl Build {
&self.out_dir,
&self.scope,
self.disable_dts,
&self.target,
self.target,
)?;
info!(
"Wrote a package.json at {:#?}.",
@ -366,13 +336,12 @@ impl Build {
let lockfile = Lockfile::new(&self.crate_data)?;
let bindgen_version = lockfile.require_wasm_bindgen()?;
info!("Installing wasm-bindgen-cli...");
let install_permitted = match self.mode {
BuildMode::Normal => true,
BuildMode::Force => true,
BuildMode::Noinstall => false,
};
let bindgen =
bindgen::install_wasm_bindgen(&self.cache, &bindgen_version, install_permitted)?;
let bindgen = install::download_prebuilt_or_cargo_install(
Tool::WasmBindgen,
&self.cache,
&bindgen_version,
self.mode.install_permitted(),
)?;
self.bindgen = Some(bindgen);
info!("Installing wasm-bindgen-cli was successful.");
Ok(())
@ -386,7 +355,7 @@ impl Build {
&self.out_dir,
&self.out_name,
self.disable_dts,
&self.target,
self.target,
self.profile,
)?;
info!("wasm bindings were built at {:#?}.", &self.out_dir);

@ -0,0 +1,28 @@
use cache;
use failure::Error;
use generate;
use install::{self, Tool};
use log::info;
use std::result;
use PBAR;
/// Executes the 'cargo-generate' command in the current directory
/// which generates a new rustwasm project from a template.
pub fn generate(
template: String,
name: String,
install_permitted: bool,
) -> result::Result<(), Error> {
info!("Generating a new rustwasm project...");
let download = install::download_prebuilt_or_cargo_install(
Tool::CargoGenerate,
&cache::get_wasm_pack_cache()?,
"latest",
install_permitted,
)?;
generate::generate(&template, &name, &download)?;
let msg = format!("🐑 Generated new project at /{}", name);
PBAR.info(&msg);
Ok(())
}

@ -1,6 +1,8 @@
//! CLI command structures, parsing, and execution.
#![allow(clippy::redundant_closure)]
pub mod build;
mod generate;
mod login;
mod pack;
/// Data structures and functions for publishing a package.
@ -9,10 +11,12 @@ pub mod test;
pub mod utils;
use self::build::{Build, BuildOptions};
use self::generate::generate;
use self::login::login;
use self::pack::pack;
use self::publish::{access::Access, publish};
use self::test::{Test, TestOptions};
use crate::install::InstallMode;
use failure::Error;
use log::info;
use std::path::PathBuf;
@ -33,6 +37,23 @@ pub enum Command {
path: Option<PathBuf>,
},
#[structopt(name = "new")]
/// 🐑 create a new project with a template
Generate {
/// The name of the project
name: String,
/// The URL to the template
#[structopt(
long = "template",
short = "temp",
default_value = "https://github.com/rustwasm/wasm-pack-template"
)]
template: String,
#[structopt(long = "mode", short = "m", default_value = "normal")]
/// Should we install or check the presence of binary tools. [possible values: no-install, normal, force]
mode: InstallMode,
},
#[structopt(name = "publish")]
/// 🎆 pack up your npm package and publish!
Publish {
@ -100,6 +121,16 @@ pub fn run_wasm_pack(command: Command) -> result::Result<(), Error> {
info!("Path: {:?}", &path);
pack(path)
}
Command::Generate {
template,
name,
mode,
} => {
info!("Running generate command...");
info!("Template: {:?}", &template);
info!("Name: {:?}", &name);
generate(template, name, mode.install_permitted())
}
Command::Publish {
target,
path,

@ -1,13 +1,12 @@
//! Implementation of the `wasm-pack test` command.
use super::build::BuildMode;
use binary_install::Cache;
use bindgen;
use build;
use cache;
use command::utils::set_crate_path;
use console::style;
use failure::Error;
use install::{self, InstallMode, Tool};
use lockfile::Lockfile;
use log::info;
use manifest;
@ -69,7 +68,7 @@ pub struct TestOptions {
#[structopt(long = "mode", short = "m", default_value = "normal")]
/// Sets steps to be run. [possible values: no-install, normal]
pub mode: BuildMode,
pub mode: InstallMode,
#[structopt(long = "release", short = "r")]
/// Build with the release profile.
@ -86,7 +85,7 @@ pub struct Test {
crate_data: manifest::CrateData,
cache: Cache,
node: bool,
mode: BuildMode,
mode: InstallMode,
firefox: bool,
geckodriver: Option<PathBuf>,
chrome: bool,
@ -188,7 +187,7 @@ impl Test {
($($name:ident $(if $e:expr)* ,)*) => (steps![$($name $(if $e)* ),*])
}
match self.mode {
BuildMode::Normal => steps![
InstallMode::Normal => steps![
step_check_rustc_version,
step_check_for_wasm_target,
step_build_tests,
@ -201,7 +200,7 @@ impl Test {
step_get_safaridriver if self.safari && self.safaridriver.is_none(),
step_test_safari if self.safari,
],
BuildMode::Force => steps![
InstallMode::Force => steps![
step_check_for_wasm_target,
step_build_tests,
step_install_wasm_bindgen,
@ -213,7 +212,7 @@ impl Test {
step_get_safaridriver if self.safari && self.safaridriver.is_none(),
step_test_safari if self.safari,
],
BuildMode::Noinstall => steps![
InstallMode::Noinstall => steps![
step_build_tests,
step_install_wasm_bindgen,
step_test_node if self.node,
@ -269,22 +268,12 @@ impl Test {
)
}
let install_permitted = match self.mode {
BuildMode::Normal => {
info!("Ensuring wasm-bindgen-cli is installed...");
true
}
BuildMode::Force => {
info!("Ensuring wasm-bindgen-cli is installed...");
true
}
BuildMode::Noinstall => {
info!("Searching for existing wasm-bindgen-cli install...");
false
}
};
let dl = bindgen::install_wasm_bindgen(&self.cache, &bindgen_version, install_permitted)?;
let dl = install::download_prebuilt_or_cargo_install(
Tool::WasmBindgen,
&self.cache,
&bindgen_version,
self.mode.install_permitted(),
)?;
self.test_runner_path = Some(dl.binary("wasm-bindgen-test-runner")?);
@ -393,6 +382,6 @@ impl Test {
if !self.headless {
envs.push(("NO_HEADLESS", "1"));
}
return envs;
envs
}
}

@ -1,4 +1,5 @@
//! Utility functions for commands.
#![allow(clippy::redundant_closure)]
use failure;
use std::fs;

@ -27,3 +27,4 @@ pub static ERROR: Emoji = Emoji("⛔ ", "");
pub static INFO: Emoji = Emoji("ℹ ", "");
pub static WRENCH: Emoji = Emoji("🔧 ", "");
pub static CRAB: Emoji = Emoji("🦀 ", "");
pub static SHEEP: Emoji = Emoji("🐑 ", "");

@ -0,0 +1,25 @@
//! Functionality related to running `cargo-generate`.
use binary_install::Download;
use child;
use emoji;
use failure::{self, ResultExt};
use std::process::Command;
/// Run `cargo generate` in the current directory to create a new
/// project from a template
pub fn generate(template: &str, name: &str, download: &Download) -> Result<(), failure::Error> {
let bin_path = download.binary("cargo-generate")?;
let mut cmd = Command::new(&bin_path);
cmd.arg("generate");
cmd.arg("--git").arg(&template);
cmd.arg("--name").arg(&name);
println!(
"{} Generating a new rustwasm project with name '{}'...",
emoji::SHEEP,
name
);
child::run(cmd, "cargo-generate").context("Running cargo-generate")?;
Ok(())
}

@ -0,0 +1,24 @@
use install::Tool;
use serde::Deserialize;
#[derive(Debug, Deserialize)]
pub struct Krate {
pub max_version: String,
}
#[derive(Debug, Deserialize)]
pub struct KrateResponse {
#[serde(rename = "crate")]
pub krate: Krate,
}
impl Krate {
pub fn new(name: &Tool) -> Result<Krate, failure::Error> {
let krate_address = format!("https://crates.io/api/v1/crates/{}", name);
let client = reqwest::Client::new();
let mut res = client.get(&krate_address).send()?;
let kr: KrateResponse = serde_json::from_str(&res.text()?)?;
Ok(kr.krate)
}
}

@ -0,0 +1,245 @@
//! Functionality related to installing prebuilt binaries and/or running cargo install.
use self::krate::Krate;
use binary_install::{Cache, Download};
use child;
use emoji;
use failure::{self, ResultExt};
use log::debug;
use log::{info, warn};
use std::env;
use std::fs;
use std::path::PathBuf;
use std::process::Command;
use target;
use which::which;
use PBAR;
mod krate;
mod mode;
mod tool;
pub use self::mode::InstallMode;
pub use self::tool::Tool;
/// Install a cargo CLI tool
///
/// Prefers an existing local install, if any exists. Then checks if there is a
/// global install on `$PATH` that fits the bill. Then attempts to download a
/// tarball from the GitHub releases page, if this target has prebuilt
/// binaries. Finally, falls back to `cargo install`.
pub fn download_prebuilt_or_cargo_install(
tool: Tool,
cache: &Cache,
version: &str,
install_permitted: bool,
) -> Result<Download, failure::Error> {
// If the tool is installed globally and it has the right version, use
// that. Assume that other tools are installed next to it.
//
// This situation can arise if the tool is already installed via
// `cargo install`, for example.
if let Ok(path) = which(tool.to_string()) {
debug!("found global {} binary at: {}", tool, path.display());
if check_version(&tool, &path, version)? {
return Ok(Download::at(path.parent().unwrap()));
}
}
let msg = format!("{}Installing {}...", emoji::DOWN_ARROW, tool);
PBAR.info(&msg);
let dl = download_prebuilt(&tool, &cache, version, install_permitted);
match dl {
Ok(dl) => return Ok(dl),
Err(e) => {
warn!(
"could not download pre-built `{}`: {}. Falling back to `cargo install`.",
tool, e
);
}
}
cargo_install(tool, &cache, version, install_permitted)
}
/// Check if the tool dependency is locally satisfied.
fn check_version(
tool: &Tool,
path: &PathBuf,
expected_version: &str,
) -> Result<bool, failure::Error> {
let expected_version = if expected_version == "latest" {
let krate = Krate::new(tool)?;
krate.max_version
} else {
expected_version.to_string()
};
let mut cmd = Command::new(path);
cmd.arg("--version");
child::run_capture_stdout(cmd, tool)
.map(|stdout| {
stdout
.trim()
.split_whitespace()
.nth(1)
.map(|v| {
info!(
"Checking installed `{}` version == expected version: {} == {}",
tool, v, &expected_version
);
Ok(v == expected_version)
})
.unwrap_or(Ok(false))
})
.unwrap_or(Ok(false))
}
/// Downloads a precompiled copy of the tool, if available.
pub fn download_prebuilt(
tool: &Tool,
cache: &Cache,
version: &str,
install_permitted: bool,
) -> Result<Download, failure::Error> {
let url = match prebuilt_url(tool, version) {
Ok(url) => url,
Err(e) => bail!(
"no prebuilt {} binaries are available for this platform: {}",
tool,
e,
),
};
match tool {
Tool::WasmBindgen => {
let binaries = &["wasm-bindgen", "wasm-bindgen-test-runner"];
match cache.download(install_permitted, "wasm-bindgen", binaries, &url)? {
Some(download) => Ok(download),
None => bail!("wasm-bindgen v{} is not installed!", version),
}
}
Tool::CargoGenerate => {
let binaries = &["cargo-generate"];
match cache.download(install_permitted, "cargo-generate", binaries, &url)? {
Some(download) => Ok(download),
None => bail!("cargo-generate v{} is not installed!", version),
}
}
}
}
/// Returns the URL of a precompiled version of wasm-bindgen, if we have one
/// available for our host platform.
fn prebuilt_url(tool: &Tool, version: &str) -> Result<String, failure::Error> {
let target = if target::LINUX && target::x86_64 {
"x86_64-unknown-linux-musl"
} else if target::MACOS && target::x86_64 {
"x86_64-apple-darwin"
} else if target::WINDOWS && target::x86_64 {
"x86_64-pc-windows-msvc"
} else {
bail!("Unrecognized target!")
};
match tool {
Tool::WasmBindgen => {
Ok(format!(
"https://github.com/rustwasm/wasm-bindgen/releases/download/{0}/wasm-bindgen-{0}-{1}.tar.gz",
version,
target
))
},
Tool::CargoGenerate => {
Ok(format!(
"https://github.com/ashleygwilliams/cargo-generate/releases/download/v{0}/cargo-generate-v{0}-{1}.tar.gz",
Krate::new(&Tool::CargoGenerate)?.max_version,
target
))
}
}
}
/// Use `cargo install` to install the tool locally into the given
/// crate.
pub fn cargo_install(
tool: Tool,
cache: &Cache,
version: &str,
install_permitted: bool,
) -> Result<Download, failure::Error> {
debug!(
"Attempting to use a `cargo install`ed version of `{}={}`",
tool, version,
);
let dirname = format!("{}-cargo-install-{}", tool, version);
let destination = cache.join(dirname.as_ref());
if destination.exists() {
debug!(
"`cargo install`ed `{}={}` already exists at {}",
tool,
version,
destination.display()
);
return Ok(Download::at(&destination));
}
if !install_permitted {
bail!("{} v{} is not installed!", tool, version)
}
// Run `cargo install` to a temporary location to handle ctrl-c gracefully
// and ensure we don't accidentally use stale files in the future
let tmp = cache.join(format!(".{}", dirname).as_ref());
drop(fs::remove_dir_all(&tmp));
debug!("cargo installing {} to tempdir: {}", tool, tmp.display(),);
let context = format!("failed to create temp dir for `cargo install {}`", tool);
fs::create_dir_all(&tmp).context(context)?;
let crate_name = match tool {
Tool::WasmBindgen => "wasm-bindgen-cli".to_string(),
_ => tool.to_string(),
};
let mut cmd = Command::new("cargo");
cmd.arg("install")
.arg("--force")
.arg(crate_name)
.arg("--version")
.arg(version)
.arg("--root")
.arg(&tmp);
let context = format!("Installing {} with cargo", tool);
child::run(cmd, "cargo install").context(context)?;
// `cargo install` will put the installed binaries in `$root/bin/*`, but we
// just want them in `$root/*` directly (which matches how the tarballs are
// laid out, and where the rest of our code expects them to be). So we do a
// little renaming here.
let binaries = match tool {
Tool::WasmBindgen => vec!["wasm-bindgen", "wasm-bindgen-test-runner"],
Tool::CargoGenerate => vec!["cargo-genrate"],
};
for b in binaries.iter().cloned() {
let from = tmp
.join("bin")
.join(b)
.with_extension(env::consts::EXE_EXTENSION);
let to = tmp.join(from.file_name().unwrap());
fs::rename(&from, &to).with_context(|_| {
format!(
"failed to move {} to {} for `cargo install`ed `{}`",
from.display(),
to.display(),
b
)
})?;
}
// Finally, move the `tmp` directory into our binary cache.
fs::rename(&tmp, &destination)?;
Ok(Download::at(&destination))
}

@ -0,0 +1,43 @@
use std::str::FromStr;
/// The `InstallMode` determines which mode of initialization we are running, and
/// what install steps we perform.
#[derive(Clone, Copy, Debug)]
pub enum InstallMode {
/// Perform all the install steps.
Normal,
/// Don't install tools like `wasm-bindgen`, just use the global
/// environment's existing versions to do builds.
Noinstall,
/// Skip the rustc version check
Force,
}
impl Default for InstallMode {
fn default() -> InstallMode {
InstallMode::Normal
}
}
impl FromStr for InstallMode {
type Err = failure::Error;
fn from_str(s: &str) -> Result<Self, failure::Error> {
match s {
"no-install" => Ok(InstallMode::Noinstall),
"normal" => Ok(InstallMode::Normal),
"force" => Ok(InstallMode::Force),
_ => bail!("Unknown build mode: {}", s),
}
}
}
impl InstallMode {
/// Determines if installation is permitted during a function call based on --mode flag
pub fn install_permitted(self) -> bool {
match self {
InstallMode::Normal => true,
InstallMode::Force => true,
InstallMode::Noinstall => false,
}
}
}

@ -0,0 +1,18 @@
use std::fmt;
/// Represents the set of CLI tools wasm-pack uses
pub enum Tool {
/// cargo-generate CLI tool
CargoGenerate,
/// wasm-bindgen CLI tools
WasmBindgen,
}
impl fmt::Display for Tool {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Tool::CargoGenerate => write!(f, "cargo-generate"),
Tool::WasmBindgen => write!(f, "wasm-bindgen"),
}
}
}

@ -31,6 +31,8 @@ pub mod cache;
pub mod child;
pub mod command;
pub mod emoji;
pub mod generate;
pub mod install;
pub mod license;
pub mod lockfile;
pub mod manifest;

@ -1,3 +1,5 @@
#![allow(clippy::redundant_closure, clippy::redundant_pattern_matching)]
extern crate atty;
extern crate env_logger;
#[macro_use]
@ -94,18 +96,15 @@ fn setup_panic_hooks() {
let default_hook = panic::take_hook();
match env::var("RUST_BACKTRACE") {
Err(_) => {
panic::set_hook(Box::new(move |info: &panic::PanicInfo| {
// First call the default hook that prints to standard error.
default_hook(info);
// Then call human_panic.
let file_path = human_panic::handle_dump(&meta, info);
human_panic::print_msg(file_path, &meta)
.expect("human-panic: printing error message to console failed");
}));
}
Ok(_) => {}
if let Err(_) = env::var("RUST_BACKTRACE") {
panic::set_hook(Box::new(move |info: &panic::PanicInfo| {
// First call the default hook that prints to standard error.
default_hook(info);
// Then call human_panic.
let file_path = human_panic::handle_dump(&meta, info);
human_panic::print_msg(file_path, &meta)
.expect("human-panic: printing error message to console failed");
}));
}
}

@ -1,6 +1,6 @@
//! Reading and writing Cargo.toml and package.json manifests.
#![allow(clippy::new_ret_no_self, clippy::needless_pass_by_value)]
#![allow(clippy::new_ret_no_self, clippy::needless_pass_by_value, clippy::redundant_closure)]
mod npm;
@ -175,7 +175,7 @@ impl Crate {
fn override_stamp_file(
current_time: DateTime<offset::Local>,
version: &String,
version: &str,
) -> Result<(), failure::Error> {
let path = env::current_exe()?;
@ -212,15 +212,13 @@ impl Crate {
}
/// Read the stamp file and return value assigned to a certain key.
fn return_stamp_file_value(file: &String, word: &str) -> Option<String> {
fn return_stamp_file_value(file: &str, word: &str) -> Option<String> {
let created = file
.lines()
.find(|line| line.starts_with(word))
.and_then(|l| l.split_whitespace().nth(1));
let value = created.map(|s| s.to_string());
value
created.map(|s| s.to_string())
}
/// Call to the crates.io api and return the latest version of `wasm-pack`
@ -510,7 +508,7 @@ impl CrateData {
out_dir: &Path,
scope: &Option<String>,
disable_dts: bool,
target: &Target,
target: Target,
) -> Result<(), Error> {
let pkg_file_path = out_dir.join("package.json");
let npm_data = match target {

@ -20,10 +20,7 @@ pub fn npm_pack(path: &str) -> Result<(), failure::Error> {
pub fn npm_publish(path: &str, access: Option<Access>) -> Result<(), failure::Error> {
let mut cmd = child::new_command("npm");
match access {
Some(a) => cmd
.current_dir(path)
.arg("publish")
.arg(&format!("{}", a.to_string())),
Some(a) => cmd.current_dir(path).arg("publish").arg(&a.to_string()),
None => cmd.current_dir(path).arg("publish"),
};
@ -38,14 +35,14 @@ pub fn npm_login(
always_auth: bool,
auth_type: &Option<String>,
) -> Result<(), failure::Error> {
let mut args = vec![format!("login"), format!("--registry={}", registry)];
let mut args = vec!["login".to_string(), format!("--registry={}", registry)];
if let Some(scope) = scope {
args.push(format!("--scope={}", scope));
}
if always_auth {
args.push(format!("--always_auth"));
args.push("--always_auth".to_string());
}
if let Some(auth_type) = auth_type {
@ -58,8 +55,9 @@ pub fn npm_login(
cmd.args(args);
info!("Running {:?}", cmd);
match cmd.status()?.success() {
true => Ok(()),
false => bail!("Login to registry {} failed", registry),
if cmd.status()?.success() {
Ok(())
} else {
bail!("Login to registry {} failed", registry)
}
}

@ -1,8 +1,8 @@
//! Getting WebDriver client binaries.
use binary_install::Cache;
use command::build::BuildMode;
use failure;
use install::InstallMode;
use std::path::PathBuf;
use target;
use PBAR;
@ -29,16 +29,12 @@ fn get_and_notify(
/// binary is found.
pub fn get_or_install_chromedriver(
cache: &Cache,
mode: BuildMode,
mode: InstallMode,
) -> Result<PathBuf, failure::Error> {
if let Ok(path) = which::which("chromedriver") {
return Ok(path);
}
let installation_allowed = match mode {
BuildMode::Noinstall => false,
_ => true,
};
install_chromedriver(cache, installation_allowed)
install_chromedriver(cache, mode.install_permitted())
}
/// Download and install a pre-built `chromedriver` binary.
@ -74,16 +70,12 @@ pub fn install_chromedriver(
/// binary is found.
pub fn get_or_install_geckodriver(
cache: &Cache,
mode: BuildMode,
mode: InstallMode,
) -> Result<PathBuf, failure::Error> {
if let Ok(path) = which::which("geckodriver") {
return Ok(path);
}
let installation_allowed = match mode {
BuildMode::Noinstall => false,
_ => true,
};
install_geckodriver(cache, installation_allowed)
install_geckodriver(cache, mode.install_permitted())
}
/// Download and install a pre-built `geckodriver` binary.

@ -1,6 +1,6 @@
use binary_install::Cache;
use tempfile;
use wasm_pack::bindgen;
use wasm_pack::install::{self, Tool};
#[test]
#[cfg(any(
@ -11,7 +11,7 @@ use wasm_pack::bindgen;
fn can_download_prebuilt_wasm_bindgen() {
let dir = tempfile::TempDir::new().unwrap();
let cache = Cache::at(dir.path());
let dl = bindgen::download_prebuilt_wasm_bindgen(&cache, "0.2.37", true).unwrap();
let dl = install::download_prebuilt(&Tool::WasmBindgen, &cache, "0.2.37", true).unwrap();
assert!(dl.binary("wasm-bindgen").unwrap().is_file());
assert!(dl.binary("wasm-bindgen-test-runner").unwrap().is_file())
}
@ -26,7 +26,7 @@ fn downloading_prebuilt_wasm_bindgen_handles_http_errors() {
let dir = tempfile::TempDir::new().unwrap();
let bad_version = "0.2.37-some-trailing-version-stuff-that-does-not-exist";
let cache = Cache::at(dir.path());
let result = bindgen::download_prebuilt_wasm_bindgen(&cache, bad_version, true);
let result = install::download_prebuilt(&Tool::WasmBindgen, &cache, bad_version, true);
assert!(result.is_err());
let error = result.err().unwrap();
@ -35,3 +35,16 @@ fn downloading_prebuilt_wasm_bindgen_handles_http_errors() {
.iter_chain()
.any(|e| e.to_string().contains(bad_version)));
}
#[test]
#[cfg(any(
all(target_os = "linux", target_arch = "x86_64"),
all(target_os = "macos", target_arch = "x86_64"),
all(windows, target_arch = "x86_64"),
))]
fn can_download_prebuilt_cargo_generate() {
let dir = tempfile::TempDir::new().unwrap();
let cache = Cache::at(dir.path());
let dl = install::download_prebuilt(&Tool::CargoGenerate, &cache, "latest", true).unwrap();
assert!(dl.binary("cargo-generate").unwrap().is_file());
}

@ -0,0 +1,21 @@
use assert_cmd::prelude::*;
use utils;
#[test]
fn new_with_no_name_errors() {
let fixture = utils::fixture::not_a_crate();
fixture.install_local_cargo_generate();
fixture.wasm_pack().arg("new").assert().failure();
}
#[test]
fn new_with_name_succeeds() {
let fixture = utils::fixture::not_a_crate();
fixture.install_local_cargo_generate();
fixture
.wasm_pack()
.arg("new")
.arg("hello")
.assert()
.success();
}

@ -11,8 +11,9 @@ extern crate structopt;
extern crate tempfile;
extern crate wasm_pack;
mod bindgen;
mod build;
mod download;
mod generate;
mod license;
mod lockfile;
mod manifest;

@ -78,7 +78,7 @@ fn it_creates_a_package_json_default_path() {
let crate_data = manifest::CrateData::new(&fixture.path, None).unwrap();
wasm_pack::command::utils::create_pkg_dir(&out_dir).unwrap();
assert!(crate_data
.write_package_json(&out_dir, &None, false, &Target::Bundler)
.write_package_json(&out_dir, &None, false, Target::Bundler)
.is_ok());
let package_json_path = &fixture.path.join("pkg").join("package.json");
fs::metadata(package_json_path).unwrap();
@ -113,7 +113,7 @@ fn it_creates_a_package_json_provided_path() {
let crate_data = manifest::CrateData::new(&fixture.path, None).unwrap();
wasm_pack::command::utils::create_pkg_dir(&out_dir).unwrap();
assert!(crate_data
.write_package_json(&out_dir, &None, false, &Target::Bundler)
.write_package_json(&out_dir, &None, false, Target::Bundler)
.is_ok());
let package_json_path = &fixture.path.join("pkg").join("package.json");
fs::metadata(package_json_path).unwrap();
@ -141,7 +141,7 @@ fn it_creates_a_package_json_provided_path_with_scope() {
let crate_data = manifest::CrateData::new(&fixture.path, None).unwrap();
wasm_pack::command::utils::create_pkg_dir(&out_dir).unwrap();
assert!(crate_data
.write_package_json(&out_dir, &Some("test".to_string()), false, &Target::Bundler,)
.write_package_json(&out_dir, &Some("test".to_string()), false, Target::Bundler,)
.is_ok());
let package_json_path = &fixture.path.join("pkg").join("package.json");
fs::metadata(package_json_path).unwrap();
@ -169,7 +169,7 @@ fn it_creates_a_pkg_json_with_correct_files_on_node() {
let crate_data = manifest::CrateData::new(&fixture.path, None).unwrap();
wasm_pack::command::utils::create_pkg_dir(&out_dir).unwrap();
assert!(crate_data
.write_package_json(&out_dir, &None, false, &Target::Nodejs)
.write_package_json(&out_dir, &None, false, Target::Nodejs)
.is_ok());
let package_json_path = &out_dir.join("package.json");
fs::metadata(package_json_path).unwrap();
@ -204,7 +204,7 @@ fn it_creates_a_pkg_json_with_correct_files_on_nomodules() {
let crate_data = manifest::CrateData::new(&fixture.path, None).unwrap();
wasm_pack::command::utils::create_pkg_dir(&out_dir).unwrap();
assert!(crate_data
.write_package_json(&out_dir, &None, false, &Target::NoModules)
.write_package_json(&out_dir, &None, false, Target::NoModules)
.is_ok());
let package_json_path = &out_dir.join("package.json");
fs::metadata(package_json_path).unwrap();
@ -238,7 +238,7 @@ fn it_creates_a_package_json_with_correct_files_when_out_name_is_provided() {
let crate_data = manifest::CrateData::new(&fixture.path, Some("index".to_owned())).unwrap();
wasm_pack::command::utils::create_pkg_dir(&out_dir).unwrap();
assert!(crate_data
.write_package_json(&out_dir, &None, false, &Target::Bundler)
.write_package_json(&out_dir, &None, false, Target::Bundler)
.is_ok());
let package_json_path = &fixture.path.join("pkg").join("package.json");
fs::metadata(package_json_path).unwrap();
@ -269,7 +269,7 @@ fn it_creates_a_pkg_json_in_out_dir() {
let crate_data = manifest::CrateData::new(&fixture.path, None).unwrap();
wasm_pack::command::utils::create_pkg_dir(&out_dir).unwrap();
assert!(crate_data
.write_package_json(&out_dir, &None, false, &Target::Bundler)
.write_package_json(&out_dir, &None, false, Target::Bundler)
.is_ok());
let package_json_path = &fixture.path.join(&out_dir).join("package.json");
@ -284,7 +284,7 @@ fn it_creates_a_package_json_with_correct_keys_when_types_are_skipped() {
let crate_data = manifest::CrateData::new(&fixture.path, None).unwrap();
wasm_pack::command::utils::create_pkg_dir(&out_dir).unwrap();
assert!(crate_data
.write_package_json(&out_dir, &None, true, &Target::Bundler)
.write_package_json(&out_dir, &None, true, Target::Bundler)
.is_ok());
let package_json_path = &out_dir.join("package.json");
fs::metadata(package_json_path).unwrap();
@ -345,7 +345,7 @@ fn it_sets_homepage_field_if_available_in_cargo_toml() {
wasm_pack::command::utils::create_pkg_dir(&out_dir).unwrap();
crate_data
.write_package_json(&out_dir, &None, true, &Target::Bundler)
.write_package_json(&out_dir, &None, true, Target::Bundler)
.unwrap();
let pkg = utils::manifest::read_package_json(&fixture.path, &out_dir).unwrap();
@ -361,7 +361,7 @@ fn it_sets_homepage_field_if_available_in_cargo_toml() {
wasm_pack::command::utils::create_pkg_dir(&out_dir).unwrap();
crate_data
.write_package_json(&out_dir, &None, true, &Target::Bundler)
.write_package_json(&out_dir, &None, true, Target::Bundler)
.unwrap();
let pkg = utils::manifest::read_package_json(&fixture.path, &out_dir).unwrap();
@ -462,7 +462,7 @@ fn it_lists_license_files_in_files_field_of_package_json() {
wasm_pack::command::utils::create_pkg_dir(&out_dir).unwrap();
license::copy_from_crate(&crate_data, &fixture.path, &out_dir).unwrap();
crate_data
.write_package_json(&out_dir, &None, false, &Target::Bundler)
.write_package_json(&out_dir, &None, false, Target::Bundler)
.unwrap();
let package_json_path = &fixture.path.join("pkg").join("package.json");

@ -8,6 +8,7 @@ use std::sync::{MutexGuard, Once, ONCE_INIT};
use std::thread;
use tempfile::TempDir;
use wasm_pack;
use wasm_pack::install::{self, Tool};
/// A test fixture in a temporary directory.
pub struct Fixture {
@ -220,12 +221,12 @@ impl Fixture {
let download = || {
if let Ok(download) =
wasm_pack::bindgen::download_prebuilt_wasm_bindgen(&cache, version, true)
install::download_prebuilt(&Tool::WasmBindgen, &cache, version, true)
{
return Ok(download);
}
wasm_pack::bindgen::cargo_install_wasm_bindgen(&cache, version, true)
install::cargo_install(Tool::WasmBindgen, &cache, version, true)
};
// Only one thread can perform the actual download, and then afterwards
@ -236,6 +237,32 @@ impl Fixture {
download().unwrap().binary("wasm-bindgen").unwrap()
}
/// Install a local cargo-generate for this fixture.
///
/// Takes care not to re-install for every fixture, but only the one time
/// for the whole test suite.
pub fn install_local_cargo_generate(&self) -> PathBuf {
static INSTALL_CARGO_GENERATE: Once = ONCE_INIT;
let cache = self.cache();
let download = || {
if let Ok(download) =
install::download_prebuilt(&Tool::CargoGenerate, &cache, "latest", true)
{
return Ok(download);
}
install::cargo_install(Tool::CargoGenerate, &cache, "latest", true)
};
// Only one thread can perform the actual download, and then afterwards
// everything will hit the cache so we can run the same path.
INSTALL_CARGO_GENERATE.call_once(|| {
download().unwrap();
});
download().unwrap().binary("cargo-generate").unwrap()
}
/// Download `geckodriver` and return its path.
///
/// Takes care to ensure that only one `geckodriver` is downloaded for the whole
@ -297,7 +324,7 @@ impl Fixture {
/// directory and using the test cache.
pub fn wasm_pack(&self) -> Command {
use assert_cmd::prelude::*;
let mut cmd = Command::main_binary().unwrap();
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME")).unwrap();
cmd.current_dir(&self.path);
cmd.env("WASM_PACK_CACHE", self.cache_dir());
cmd

Loading…
Cancel
Save