1
+ use std:: collections:: BTreeMap ;
1
2
use std:: fs:: File ;
2
3
use std:: io:: prelude:: * ;
4
+ use std:: path:: Path ;
3
5
4
6
use console:: style;
5
7
use emoji;
6
- use failure:: Error ;
8
+ use failure:: { Error , ResultExt } ;
9
+ use parity_wasm;
10
+ use parity_wasm:: elements:: * ;
7
11
use serde_json;
8
12
use toml;
9
13
use PBAR ;
@@ -33,6 +37,7 @@ struct NpmPackage {
33
37
repository : Option < Repository > ,
34
38
files : Vec < String > ,
35
39
main : String ,
40
+ dependencies : Option < BTreeMap < String , String > > ,
36
41
}
37
42
38
43
#[ derive( Serialize ) ]
@@ -42,24 +47,100 @@ struct Repository {
42
47
url : String ,
43
48
}
44
49
45
- fn read_cargo_toml ( path : & str ) -> Result < CargoManifest , Error > {
46
- let manifest_path = format ! ( "{}/Cargo.toml" , path) ;
47
- let mut cargo_file = File :: open ( manifest_path) ?;
50
+ fn read_cargo_toml ( path : & Path ) -> Result < CargoManifest , Error > {
51
+ let mut cargo_file = File :: open ( path. join ( "Cargo.toml" ) ) ?;
48
52
let mut cargo_contents = String :: new ( ) ;
49
53
cargo_file. read_to_string ( & mut cargo_contents) ?;
50
54
51
55
Ok ( toml:: from_str ( & cargo_contents) ?)
52
56
}
53
57
58
+ /// Locates the `__wasm_pack_unstable` module section inside the wasm file
59
+ /// specified, parsing it and returning dependencies found.
60
+ ///
61
+ /// Crates compiled with `wasm-bindgen` can declare dependencies on NPM packages
62
+ /// in their code and this is communicated to us, `wasm-pack`, via a custom
63
+ /// section in the final binary.
64
+ fn read_npm_dependencies ( wasm : & Path ) -> Result < BTreeMap < String , String > , Error > {
65
+ #[ derive( Deserialize ) ]
66
+ #[ serde( untagged) ]
67
+ enum Schema < ' a > {
68
+ V1 {
69
+ version : & ' a str ,
70
+ modules : Vec < ( String , String ) > ,
71
+ } ,
72
+ Unknown {
73
+ version : & ' a str ,
74
+ } ,
75
+ }
76
+
77
+ let mut module = parity_wasm:: deserialize_file ( wasm)
78
+ . with_context ( |_| format ! ( "failed to parse `{}` as wasm" , wasm. display( ) ) ) ?;
79
+ let wasm_pack_module;
80
+ let deps = {
81
+ let result = module
82
+ . sections ( )
83
+ . iter ( )
84
+ . enumerate ( )
85
+ . filter_map ( |( i, s) | match * s {
86
+ Section :: Custom ( ref cs) => Some ( ( i, cs) ) ,
87
+ _ => None ,
88
+ } )
89
+ . find ( |& ( _i, section) | section. name ( ) == "__wasm_pack_unstable" ) ;
90
+ let data = match result {
91
+ Some ( ( i, section) ) => {
92
+ wasm_pack_module = i;
93
+ section. payload ( )
94
+ }
95
+ None => return Ok ( BTreeMap :: new ( ) ) ,
96
+ } ;
97
+ let schema = serde_json:: from_slice ( data) . with_context ( |_| {
98
+ "the wasm file emitted by `wasm-bindgen` contains a \
99
+ `__wasm_pack_unstable` section which should describe \
100
+ js dependencies, but it's in a format that this \
101
+ `wasm-pack` tool does not understand; does `wasm-pack` \
102
+ need to be updated?"
103
+ } ) ?;
104
+ let modules = match schema {
105
+ Schema :: V1 {
106
+ version,
107
+ ref modules,
108
+ } if version == "0.0.1" =>
109
+ {
110
+ modules. clone ( )
111
+ }
112
+ Schema :: Unknown { version } | Schema :: V1 { version, .. } => bail ! (
113
+ "the wasm file emitted by `wasm-bindgen` contains a \
114
+ `__wasm_pack_unstable` section which should describe \
115
+ js dependencies, but it's schema version is `{}` \
116
+ while this `wasm-pack` tool only understands the \
117
+ schema version 0.0.1; does `wasm-pack` need to be updated?",
118
+ version
119
+ ) ,
120
+ } ;
121
+
122
+ modules. into_iter ( ) . collect ( )
123
+ } ;
124
+
125
+ // Delete the `__wasm_pack_unstable` custom section and rewrite the wasm
126
+ // file that we're emitting.
127
+ module. sections_mut ( ) . remove ( wasm_pack_module) ;
128
+ parity_wasm:: serialize_to_file ( wasm, module)
129
+ . with_context ( |_| format ! ( "failed to write wasm to `{}`" , wasm. display( ) ) ) ?;
130
+
131
+ Ok ( deps)
132
+ }
133
+
54
134
impl CargoManifest {
55
- fn into_npm ( mut self , scope : Option < String > ) -> NpmPackage {
135
+ fn into_npm ( mut self , pkg : & Path , scope : Option < String > ) -> Result < NpmPackage , Error > {
56
136
let filename = self . package . name . replace ( "-" , "_" ) ;
57
137
let wasm_file = format ! ( "{}_bg.wasm" , filename) ;
58
138
let js_file = format ! ( "{}.js" , filename) ;
139
+ let dependencies = read_npm_dependencies ( & pkg. join ( & wasm_file) ) ?;
59
140
if let Some ( s) = scope {
60
141
self . package . name = format ! ( "@{}/{}" , s, self . package. name) ;
61
142
}
62
- NpmPackage {
143
+ Ok ( NpmPackage {
63
144
name : self . package . name ,
64
145
collaborators : self . package . authors ,
65
146
description : self . package . description ,
@@ -71,12 +152,18 @@ impl CargoManifest {
71
152
} ) ,
72
153
files : vec ! [ wasm_file] ,
73
154
main : js_file,
74
- }
155
+ dependencies : if dependencies. len ( ) == 0 {
156
+ None
157
+ } else {
158
+ Some ( dependencies)
159
+ } ,
160
+ } )
75
161
}
76
162
}
77
163
78
164
/// Generate a package.json file inside in `./pkg`.
79
165
pub fn write_package_json ( path : & str , scope : Option < String > ) -> Result < ( ) , Error > {
166
+ let path = Path :: new ( path) ;
80
167
let step = format ! (
81
168
"{} {}Writing a package.json..." ,
82
169
style( "[4/7]" ) . bold( ) . dim( ) ,
@@ -91,10 +178,10 @@ pub fn write_package_json(path: &str, scope: Option<String>) -> Result<(), Error
91
178
} ;
92
179
93
180
let pb = PBAR . message ( & step) ;
94
- let pkg_file_path = format ! ( "{}/ pkg/package.json", path ) ;
181
+ let pkg_file_path = path . join ( " pkg/package.json") ;
95
182
let mut pkg_file = File :: create ( pkg_file_path) ?;
96
183
let crate_data = read_cargo_toml ( path) ?;
97
- let npm_data = crate_data. into_npm ( scope) ;
184
+ let npm_data = crate_data. into_npm ( & path . join ( "pkg" ) , scope) ? ;
98
185
99
186
if npm_data. description . is_none ( ) {
100
187
PBAR . warn ( & warn_fmt ( "description" ) ) ;
@@ -113,5 +200,5 @@ pub fn write_package_json(path: &str, scope: Option<String>) -> Result<(), Error
113
200
}
114
201
115
202
pub fn get_crate_name ( path : & str ) -> Result < String , Error > {
116
- Ok ( read_cargo_toml ( path) ?. package . name )
203
+ Ok ( read_cargo_toml ( Path :: new ( path) ) ?. package . name )
117
204
}
0 commit comments