Skip to content

Commit

Permalink
Install the exact wasm-bindgen-cli version matching the `wasm-bindg…
Browse files Browse the repository at this point in the history
…en` version (#208)

Closes #202
  • Loading branch information
DaAlbrecht authored Dec 31, 2024
1 parent cbaf595 commit d6034dd
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 18 deletions.
12 changes: 12 additions & 0 deletions src/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,24 @@ pub fn build(args: &BuildArgs) -> anyhow::Result<()> {
}

pub(crate) fn ensure_web_setup(skip_prompts: bool) -> anyhow::Result<()> {
// The resolved dependency graph is needed to ensure the `wasm-bindgen-cli` version matches
// exactly the `wasm-bindgen` version
let metadata = cargo::metadata::metadata()?;

let wasm_bindgen_version = metadata
.packages
.iter()
.find(|package| package.name == "wasm-bindgen")
.map(|package| package.version.to_string())
.ok_or_else(|| anyhow::anyhow!("Failed to find wasm-bindgen"))?;

// `wasm32-unknown-unknown` compilation target
rustup::install_target_if_needed("wasm32-unknown-unknown", skip_prompts)?;
// `wasm-bindgen-cli` for bundling
cargo::install::if_needed(
wasm_bindgen::PROGRAM,
wasm_bindgen::PACKAGE,
Some(&wasm_bindgen_version),
skip_prompts,
false,
)?;
Expand Down
68 changes: 51 additions & 17 deletions src/external_cli/cargo/install.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
use std::process::{exit, Command};
use std::{
process::{exit, Command},
str::FromStr,
};

use dialoguer::Confirm;
use semver::Version;

use crate::external_cli::wasm_bindgen;

use self::wasm_bindgen::wasm_bindgen_cli_version;

/// Check if the given program is installed on the system.
///
/// This assumes that the program offers a `--version` flag.
fn is_installed(program: &str) -> bool {
let output = Command::new(program).arg("--version").output();

if let Ok(output) = output {
output.status.success()
} else {
false
}
fn is_installed(program: &str) -> Option<Vec<u8>> {
Command::new(program)
.arg("--version")
.output()
.map(|output| output.stdout)
.ok()
}

/// Checks if the program is installed and installs it if it isn't.
Expand All @@ -21,19 +27,43 @@ fn is_installed(program: &str) -> bool {
pub(crate) fn if_needed(
program: &str,
package: &str,
package_version: Option<&str>,
skip_prompts: bool,
hidden: bool,
) -> anyhow::Result<bool> {
if is_installed(program) {
return Ok(false);
let mut prompt: Option<String> = None;

if let Some(stdout) = is_installed(program) {
let Some(package_version) = package_version else {
// If no `package_version` is specified and the program is installed,
// there is nothing to do.
return Ok(false);
};

// Its important that the `wasm-bindgen-cli` and the `wasm-bindgen` version match exactly,
// therefore compare the desired `package_version` with the installed
// `wasm-bindgen-cli` version
if package == wasm_bindgen::PACKAGE {
let version = wasm_bindgen_cli_version(&stdout)?;
let desired_version = Version::from_str(package_version)?;
if version == desired_version {
return Ok(false);
}
prompt = Some(format!(
"`{program}:{version}` is installed, but \
version `{desired_version}` is required. Install and replace?"
));
}
}

// Abort if the user doesn't want to install it
if !skip_prompts
&& !Confirm::new()
.with_prompt(format!(
"`{program}` is missing, should I install it for you?"
))
.with_prompt(
prompt.unwrap_or_else(|| {
format!("`{program}` is missing, should I install it for you?")
}),
)
.interact()?
{
exit(1);
Expand All @@ -42,15 +72,19 @@ pub(crate) fn if_needed(
let mut cmd = Command::new(super::program());
cmd.arg("install").arg(package);

if let Some(version) = package_version {
cmd.arg("--version").arg(version);
}

let status = if hidden {
cmd.output()?.status
} else {
cmd.status()?
};

if !status.success() {
Err(anyhow::anyhow!("Failed to install `{program}`."))
} else {
if status.success() {
Ok(true)
} else {
Err(anyhow::anyhow!("Failed to install `{program}`."))
}
}
19 changes: 18 additions & 1 deletion src/external_cli/wasm_bindgen.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::process::Command;
use semver::Version;
use std::{process::Command, str::FromStr};

use crate::{external_cli::CommandHelpers, run::BinTarget};

Expand Down Expand Up @@ -27,3 +28,19 @@ pub(crate) fn bundle(bin_target: &BinTarget) -> anyhow::Result<()> {

Ok(())
}

/// Transforms the output from `wasm-bindgen --version` into a [Version].
pub(crate) fn wasm_bindgen_cli_version(stdout: &[u8]) -> anyhow::Result<Version> {
let stdout = String::from_utf8_lossy(stdout);
// Example stdout from `wasm-bindgen --version`: wasm-bindgen 0.2.99
stdout
.split_whitespace()
.nth(1)
.ok_or_else(|| {
anyhow::anyhow!(
"unexpected output format: {}, expected format to be: `wasm-bindgen <version>`",
stdout
)
})
.and_then(|version| Version::from_str(version).map_err(|e| anyhow::anyhow!(e)))
}

0 comments on commit d6034dd

Please sign in to comment.