Skip to content

feat(lockfiles): Use Cargo.lock to identify wasm-bindgen versions #324

New issue

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

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

Already on GitHub? Sign in to your account

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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ categories = ["wasm"]

[dependencies]
atty = "0.2.11"
cargo_metadata = "0.6.0"
console = "0.6.1"
curl = "0.4.13"
failure = "0.1.2"
Expand Down
4 changes: 3 additions & 1 deletion src/command/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use command::utils::{create_pkg_dir, set_crate_path};
use emoji;
use error::Error;
use indicatif::HumanDuration;
use lockfile::Lockfile;
use manifest;
use progressbar::Step;
use readme;
Expand Down Expand Up @@ -239,7 +240,8 @@ impl Build {

fn step_install_wasm_bindgen(&mut self, step: &Step, log: &Logger) -> Result<(), Error> {
info!(&log, "Identifying wasm-bindgen dependency...");
let bindgen_version = manifest::get_wasm_bindgen_version(&self.crate_path)?;
let lockfile = Lockfile::new(&self.crate_path)?;
let bindgen_version = lockfile.require_wasm_bindgen()?;
info!(&log, "Installing wasm-bindgen-cli...");
let install_permitted = match self.mode {
BuildMode::Normal => true,
Expand Down
33 changes: 28 additions & 5 deletions src/command/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ use super::build::BuildMode;
use bindgen;
use build;
use command::utils::set_crate_path;
use console::style;
use emoji;
use error::Error;
use indicatif::HumanDuration;
use lockfile::Lockfile;
use manifest;
use progressbar::Step;
use slog::Logger;
Expand Down Expand Up @@ -238,12 +240,33 @@ impl Test {

fn step_install_wasm_bindgen(&mut self, step: &Step, log: &Logger) -> Result<(), Error> {
info!(&log, "Identifying wasm-bindgen dependency...");
let bindgen_version = manifest::get_wasm_bindgen_version(&self.crate_path)?;
info!(&log, "Installing wasm-bindgen-cli...");
let lockfile = Lockfile::new(&self.crate_path)?;
let bindgen_version = lockfile.require_wasm_bindgen()?;

// Unlike `wasm-bindgen` and `wasm-bindgen-cli`, `wasm-bindgen-test`
// will work with any semver compatible `wasm-bindgen-cli`, so just make
// sure that it is depended upon, so we can run tests on
// `wasm32-unkown-unknown`. Don't enforce that it is the same version as
// `wasm-bindgen`.
if lockfile.wasm_bindgen_test_version().is_none() {
let message = format!(
"Ensure that you have \"{}\" as a dependency in your Cargo.toml file:\n\
[dev-dependencies]\n\
wasm-bindgen-test = \"0.2\"",
style("wasm-bindgen").bold().dim(),
);
return Err(Error::CrateConfig { message })
}

let install_permitted = match self.mode {
BuildMode::Normal => true,
BuildMode::Noinstall => false,
BuildMode::Normal => {
info!(&log, "Ensuring wasm-bindgen-cli is installed...");
true
}
BuildMode::Noinstall => {
info!(&log, "Searching for existing wasm-bindgen-cli install...");
false
}
};

bindgen::install_wasm_bindgen(
Expand All @@ -257,7 +280,7 @@ impl Test {
self.test_runner_path = Some(bindgen::wasm_bindgen_test_runner_path(log, &self.crate_path)
.expect("if installing wasm-bindgen succeeded, then we should have wasm-bindgen-test-runner too"));

info!(&log, "Installing wasm-bindgen-cli was successful.");
info!(&log, "Getting wasm-bindgen-cli was successful.");
Ok(())
}

Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#![deny(missing_docs)]

extern crate cargo_metadata;
extern crate console;
extern crate curl;
#[macro_use]
Expand Down Expand Up @@ -31,6 +32,7 @@ pub mod build;
pub mod command;
pub mod emoji;
pub mod error;
pub mod lockfile;
pub mod logger;
pub mod manifest;
pub mod npm;
Expand Down
83 changes: 83 additions & 0 deletions src/lockfile.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
//! Reading Cargo.lock lock file.

use std::fs;
use std::path::{Path, PathBuf};

use cargo_metadata;
use console::style;
use error::Error;
use toml;

/// This struct represents the contents of `Cargo.lock`.
#[derive(Clone, Debug, Deserialize)]
pub struct Lockfile {
package: Vec<Package>,
}

/// This struct represents a single package entry in `Cargo.lock`
#[derive(Clone, Debug, Deserialize)]
struct Package {
name: String,
version: String,
}

impl Lockfile {
/// Read the `Cargo.lock` file for the crate at the given path.
pub fn new(crate_path: &Path) -> Result<Lockfile, Error> {
let lock_path = get_lockfile_path(crate_path)?;
let lockfile = fs::read_to_string(lock_path)?;
toml::from_str(&lockfile).map_err(Error::from)
}

/// Get the version of `wasm-bindgen` dependency used in the `Cargo.lock`.
pub fn wasm_bindgen_version(&self) -> Option<&str> {
self.get_package_version("wasm-bindgen")
}

/// Like `wasm_bindgen_version`, except it returns an error instead of
/// `None`.
pub fn require_wasm_bindgen(&self) -> Result<&str, Error> {
self.wasm_bindgen_version().ok_or_else(|| {
let message = format!(
"Ensure that you have \"{}\" as a dependency in your Cargo.toml file:\n\
[dependencies]\n\
wasm-bindgen = \"0.2\"",
style("wasm-bindgen").bold().dim(),
);
Error::CrateConfig { message }
})
}

/// Get the version of `wasm-bindgen` dependency used in the `Cargo.lock`.
pub fn wasm_bindgen_test_version(&self) -> Option<&str> {
self.get_package_version("wasm-bindgen-test")
}

fn get_package_version(&self, package: &str) -> Option<&str> {
self.package
.iter()
.find(|p| p.name == package)
.map(|p| &p.version[..])
}
}

/// Given the path to the crate that we are buliding, return a `PathBuf`
/// containing the location of the lock file, by finding the workspace root.
fn get_lockfile_path(crate_path: &Path) -> Result<PathBuf, Error> {
// Identify the crate's root directory, or return an error.
let manifest = crate_path.join("Cargo.toml");
let crate_root = cargo_metadata::metadata(Some(&manifest))
.map_err(|_| Error::CrateConfig {
message: String::from("Error while processing crate metadata"),
})?.workspace_root;
// Check that a lock file can be found in the directory. Return an error
// if it cannot, otherwise return the path buffer.
let lockfile_path = Path::new(&crate_root).join("Cargo.lock");
if !lockfile_path.is_file() {
Err(Error::CrateConfig {
message: format!("Could not find lockfile at {:?}", lockfile_path),
})
} else {
Ok(lockfile_path)
}
}
Loading