Skip to content

Load dependencies from wasm-bindgen #116

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 1 commit 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
16 changes: 16 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 @@ -11,6 +11,7 @@ readme = "README.md"
console = "0.6.1"
failure = "0.1.1"
indicatif = "0.9.0"
parity-wasm = "0.28"
quicli = "0.2"
serde = "1.0"
serde_derive = "1.0"
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ extern crate failure;
extern crate indicatif;
#[macro_use]
extern crate lazy_static;
extern crate parity_wasm;
extern crate quicli;
#[macro_use]
extern crate serde_derive;
Expand Down
107 changes: 97 additions & 10 deletions src/manifest.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
use std::collections::BTreeMap;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;

use console::style;
use emoji;
use failure::Error;
use failure::{Error, ResultExt};
use parity_wasm;
use parity_wasm::elements::*;
use serde_json;
use toml;
use PBAR;
Expand Down Expand Up @@ -33,6 +37,7 @@ struct NpmPackage {
repository: Option<Repository>,
files: Vec<String>,
main: String,
dependencies: Option<BTreeMap<String, String>>,
}

#[derive(Serialize)]
Expand All @@ -42,24 +47,100 @@ struct Repository {
url: String,
}

fn read_cargo_toml(path: &str) -> Result<CargoManifest, Error> {
let manifest_path = format!("{}/Cargo.toml", path);
let mut cargo_file = File::open(manifest_path)?;
fn read_cargo_toml(path: &Path) -> Result<CargoManifest, Error> {
let mut cargo_file = File::open(path.join("Cargo.toml"))?;
let mut cargo_contents = String::new();
cargo_file.read_to_string(&mut cargo_contents)?;

Ok(toml::from_str(&cargo_contents)?)
}

/// Locates the `__wasm_pack_unstable` module section inside the wasm file
/// specified, parsing it and returning dependencies found.
///
/// Crates compiled with `wasm-bindgen` can declare dependencies on NPM packages
/// in their code and this is communicated to us, `wasm-pack`, via a custom
/// section in the final binary.
fn read_npm_dependencies(wasm: &Path) -> Result<BTreeMap<String, String>, Error> {
#[derive(Deserialize)]
#[serde(untagged)]
enum Schema<'a> {
V1 {
version: &'a str,
modules: Vec<(String, String)>,
},
Unknown {
version: &'a str,
},
}

let mut module = parity_wasm::deserialize_file(wasm)
.with_context(|_| format!("failed to parse `{}` as wasm", wasm.display()))?;
let wasm_pack_module;
let deps = {
let result = module
.sections()
.iter()
.enumerate()
.filter_map(|(i, s)| match *s {
Section::Custom(ref cs) => Some((i, cs)),
_ => None,
})
.find(|&(_i, section)| section.name() == "__wasm_pack_unstable");
let data = match result {
Some((i, section)) => {
wasm_pack_module = i;
section.payload()
}
None => return Ok(BTreeMap::new()),
};
let schema = serde_json::from_slice(data).with_context(|_| {
"the wasm file emitted by `wasm-bindgen` contains a \
`__wasm_pack_unstable` section which should describe \
js dependencies, but it's in a format that this \
`wasm-pack` tool does not understand; does `wasm-pack` \
need to be updated?"
})?;
let modules = match schema {
Schema::V1 {
version,
ref modules,
} if version == "0.0.1" =>
{
modules.clone()
}
Schema::Unknown { version } | Schema::V1 { version, .. } => bail!(
"the wasm file emitted by `wasm-bindgen` contains a \
`__wasm_pack_unstable` section which should describe \
js dependencies, but it's schema version is `{}` \
while this `wasm-pack` tool only understands the \
schema version 0.0.1; does `wasm-pack` need to be updated?",
version
),
};

modules.into_iter().collect()
};

// Delete the `__wasm_pack_unstable` custom section and rewrite the wasm
// file that we're emitting.
module.sections_mut().remove(wasm_pack_module);
parity_wasm::serialize_to_file(wasm, module)
.with_context(|_| format!("failed to write wasm to `{}`", wasm.display()))?;

Ok(deps)
}

impl CargoManifest {
fn into_npm(mut self, scope: Option<String>) -> NpmPackage {
fn into_npm(mut self, pkg: &Path, scope: Option<String>) -> Result<NpmPackage, Error> {
let filename = self.package.name.replace("-", "_");
let wasm_file = format!("{}_bg.wasm", filename);
let js_file = format!("{}.js", filename);
let dependencies = read_npm_dependencies(&pkg.join(&wasm_file))?;
if let Some(s) = scope {
self.package.name = format!("@{}/{}", s, self.package.name);
}
NpmPackage {
Ok(NpmPackage {
name: self.package.name,
collaborators: self.package.authors,
description: self.package.description,
Expand All @@ -71,12 +152,18 @@ impl CargoManifest {
}),
files: vec![wasm_file],
main: js_file,
}
dependencies: if dependencies.len() == 0 {
None
} else {
Some(dependencies)
},
})
}
}

/// Generate a package.json file inside in `./pkg`.
pub fn write_package_json(path: &str, scope: Option<String>) -> Result<(), Error> {
let path = Path::new(path);
let step = format!(
"{} {}Writing a package.json...",
style("[4/7]").bold().dim(),
Expand All @@ -91,10 +178,10 @@ pub fn write_package_json(path: &str, scope: Option<String>) -> Result<(), Error
};

let pb = PBAR.message(&step);
let pkg_file_path = format!("{}/pkg/package.json", path);
let pkg_file_path = path.join("pkg/package.json");
let mut pkg_file = File::create(pkg_file_path)?;
let crate_data = read_cargo_toml(path)?;
let npm_data = crate_data.into_npm(scope);
let npm_data = crate_data.into_npm(&path.join("pkg"), scope)?;

if npm_data.description.is_none() {
PBAR.warn(&warn_fmt("description"));
Expand All @@ -113,5 +200,5 @@ pub fn write_package_json(path: &str, scope: Option<String>) -> Result<(), Error
}

pub fn get_crate_name(path: &str) -> Result<String, Error> {
Ok(read_cargo_toml(path)?.package.name)
Ok(read_cargo_toml(Path::new(path))?.package.name)
}
Loading