6666//! - `WASM_BUILD_NO_COLOR` - Disable color output of the wasm build.
6767//! - `WASM_TARGET_DIRECTORY` - Will copy any build wasm binary to the given directory. The path needs
6868//! to be absolute.
69+ //! - `WASM_BUILD_TOOLCHAIN` - The toolchain that should be used to build the wasm binaries. The
70+ //! format needs to be the same as used by cargo, e.g. `nightly-2020-02-20`.
6971//!
7072//! Each project can be skipped individually by using the environment variable `SKIP_PROJECT_NAME_WASM_BUILD`.
7173//! Where `PROJECT_NAME` needs to be replaced by the name of the cargo project, e.g. `node-runtime` will
7779//!
7880//! - rust nightly + `wasm32-unknown-unknown` toolchain
7981//!
82+ //! If a specific rust nightly is installed with `rustup`, it is important that the wasm target is installed
83+ //! as well. For example if installing the rust nightly from 20.02.2020 using `rustup install nightly-2020-02-20`,
84+ //! the wasm target needs to be installed as well `rustup target add wasm32-unknown-unknown --toolchain nightly-2020-02-20`.
8085
81- use std:: { env, fs, path:: PathBuf , process:: { Command , Stdio , self } } ;
86+ use std:: { env, fs, path:: PathBuf , process:: { Command , self } , io :: BufRead } ;
8287
8388mod prerequisites;
8489mod wasm_project;
@@ -103,6 +108,9 @@ const WASM_TARGET_DIRECTORY: &str = "WASM_TARGET_DIRECTORY";
103108/// Environment variable to disable color output of the wasm build.
104109const WASM_BUILD_NO_COLOR : & str = "WASM_BUILD_NO_COLOR" ;
105110
111+ /// Environment variable to set the toolchain used to compile the wasm binary.
112+ const WASM_BUILD_TOOLCHAIN : & str = "WASM_BUILD_TOOLCHAIN" ;
113+
106114/// Build the currently built project as wasm binary.
107115///
108116/// The current project is determined by using the `CARGO_MANIFEST_DIR` environment variable.
@@ -178,19 +186,56 @@ fn write_file_if_changed(file: PathBuf, content: String) {
178186
179187/// Get a cargo command that compiles with nightly
180188fn get_nightly_cargo ( ) -> CargoCommand {
189+ let env_cargo = CargoCommand :: new (
190+ & env:: var ( "CARGO" ) . expect ( "`CARGO` env variable is always set by cargo" ) ,
191+ ) ;
181192 let default_cargo = CargoCommand :: new ( "cargo" ) ;
182- let mut rustup_run_nightly = CargoCommand :: new ( "rustup" ) ;
183- rustup_run_nightly . args ( & [ "run" , "nightly" , "cargo" ] ) ;
193+ let rustup_run_nightly = CargoCommand :: new_with_args ( "rustup" , & [ "run" , "nightly" , "cargo" ] ) ;
194+ let wasm_toolchain = env :: var ( WASM_BUILD_TOOLCHAIN ) . ok ( ) ;
184195
185- if default_cargo. is_nightly ( ) {
196+ // First check if the user requested a specific toolchain
197+ if let Some ( cmd) = wasm_toolchain. and_then ( |t| get_rustup_nightly ( Some ( t) ) ) {
198+ cmd
199+ } else if env_cargo. is_nightly ( ) {
200+ env_cargo
201+ } else if default_cargo. is_nightly ( ) {
186202 default_cargo
187- } else if rustup_run_nightly. works ( ) {
203+ } else if rustup_run_nightly. is_nightly ( ) {
188204 rustup_run_nightly
189205 } else {
190- default_cargo
206+ // If no command before provided us with a nightly compiler, we try to search one
207+ // with rustup. If that fails as well, we return the default cargo and let the prequisities
208+ // check fail.
209+ get_rustup_nightly ( None ) . unwrap_or ( default_cargo)
191210 }
192211}
193212
213+ /// Get a nightly from rustup. If `selected` is `Some(_)`, a `CargoCommand` using the given
214+ /// nightly is returned.
215+ fn get_rustup_nightly ( selected : Option < String > ) -> Option < CargoCommand > {
216+ let host = format ! ( "-{}" , env:: var( "HOST" ) . expect( "`HOST` is always set by cargo" ) ) ;
217+
218+ let version = match selected {
219+ Some ( selected) => selected,
220+ None => {
221+ let output = Command :: new ( "rustup" ) . args ( & [ "toolchain" , "list" ] ) . output ( ) . ok ( ) ?. stdout ;
222+ let lines = output. as_slice ( ) . lines ( ) ;
223+
224+ let mut latest_nightly = None ;
225+ for line in lines. filter_map ( |l| l. ok ( ) ) {
226+ if line. starts_with ( "nightly-" ) && line. ends_with ( & host) {
227+ // Rustup prints them sorted
228+ latest_nightly = Some ( line. clone ( ) ) ;
229+ }
230+ }
231+
232+ latest_nightly?. trim_end_matches ( & host) . into ( )
233+ }
234+ } ;
235+
236+ Some ( CargoCommand :: new_with_args ( "rustup" , & [ "run" , & version, "cargo" ] ) )
237+ }
238+
194239/// Builder for cargo commands
195240#[ derive( Debug ) ]
196241struct CargoCommand {
@@ -203,14 +248,11 @@ impl CargoCommand {
203248 CargoCommand { program : program. into ( ) , args : Vec :: new ( ) }
204249 }
205250
206- fn arg ( & mut self , arg : & str ) -> & mut Self {
207- self . args . push ( arg. into ( ) ) ;
208- self
209- }
210-
211- fn args ( & mut self , args : & [ & str ] ) -> & mut Self {
212- args. into_iter ( ) . for_each ( |a| { self . arg ( a) ; } ) ;
213- self
251+ fn new_with_args ( program : & str , args : & [ & str ] ) -> Self {
252+ CargoCommand {
253+ program : program. into ( ) ,
254+ args : args. iter ( ) . map ( ToString :: to_string) . collect ( ) ,
255+ }
214256 }
215257
216258 fn command ( & self ) -> Command {
@@ -219,14 +261,6 @@ impl CargoCommand {
219261 cmd
220262 }
221263
222- fn works ( & self ) -> bool {
223- self . command ( )
224- . stdout ( Stdio :: null ( ) )
225- . stderr ( Stdio :: null ( ) )
226- . status ( )
227- . map ( |s| s. success ( ) ) . unwrap_or ( false )
228- }
229-
230264 /// Check if the supplied cargo command is a nightly version
231265 fn is_nightly ( & self ) -> bool {
232266 // `RUSTC_BOOTSTRAP` tells a stable compiler to behave like a nightly. So, when this env
0 commit comments