From 4eb1ac306e5747e54362cb2e6cda284e576dfe37 Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Tue, 17 Jul 2018 00:49:55 +0800 Subject: [PATCH] Split init and build --- src/command/build.rs | 274 +++++++++++++++++++++++++++++++++++++++++++ src/command/init.rs | 265 ++++++++--------------------------------- src/command/mod.rs | 66 +++-------- src/command/utils.rs | 15 +++ src/logger.rs | 3 +- 5 files changed, 359 insertions(+), 264 deletions(-) create mode 100644 src/command/build.rs diff --git a/src/command/build.rs b/src/command/build.rs new file mode 100644 index 000000000..8832cefe9 --- /dev/null +++ b/src/command/build.rs @@ -0,0 +1,274 @@ +//! Initializing a crate for packing `.wasm`s. + +use bindgen; +use build; +use command::utils::{set_crate_path, create_pkg_dir}; +use emoji; +use error::Error; +use indicatif::HumanDuration; +use manifest; +use progressbar::Step; +use readme; +use slog::Logger; +use std::time::Instant; +use PBAR; + +/// Everything required to configure and run the `wasm-pack init` command. +pub(crate) struct Build { + pub crate_path: String, + pub scope: Option, + pub disable_dts: bool, + pub target: String, + pub debug: bool, + // build_config: Option, + pub crate_name: String, +} + +/// The `BuildMode` determines which mode of initialization we are running, and +/// what build and install steps we perform. +pub enum BuildMode { + /// Perform all the build and install steps. + Normal, + /// Don't install tools like `wasm-bindgen`, just use the global + /// environment's existing versions to do builds. + Noinstall, +} + +/// Everything required to configure and run the `wasm-pack build` command. +#[derive(Debug,StructOpt)] +pub struct BuildOptions { + /// The path to the Rust crate. + pub path: Option, + + /// The npm scope to use in package.json, if any. + #[structopt(long = "scope", short = "s")] + pub scope: Option, + + #[structopt(long = "mode", short = "m", default_value = "normal")] + /// Sets steps to be run. [possible values: no-install, normal] + pub mode: String, + + #[structopt(long = "no-typescript")] + /// By default a *.d.ts file is generated for the generated JS file, but + /// this flag will disable generating this TypeScript file. + pub disable_dts: bool, + + #[structopt(long = "target", short = "t", default_value = "browser")] + /// Sets the target environment. [possible values: browser, nodejs] + pub target: String, + + #[structopt(long = "debug")] + /// Build without --release. + debug: bool, + + // build config from manifest + // build_config: Option, +} + +impl From for Build { + fn from(build_opts: BuildOptions) -> Self { + let crate_path = set_crate_path(build_opts.path); + let crate_name = manifest::get_crate_name(&crate_path).unwrap(); + // let build_config = manifest::xxx(&crate_path).xxx(); + Build { + crate_path, + scope:build_opts.scope, + disable_dts:build_opts.disable_dts, + target:build_opts.target, + debug:build_opts.debug, + // build_config, + crate_name, + } + } +} + +type BuildStep = fn(&mut Build, &Step, &Logger) -> Result<(), Error>; + +impl Build { + /// Execute this `Init` command. + pub fn run(&mut self, log: &Logger, mode: BuildMode) -> Result<(), Error> { + let process_steps = Build::get_process_steps(mode); + + let mut step_counter = Step::new(process_steps.len()); + + let started = Instant::now(); + + for (_, process_step) in process_steps { + process_step(self, &step_counter, log)?; + step_counter.inc(); + } + + let duration = HumanDuration(started.elapsed()); + info!(&log, "Done in {}.", &duration); + info!( + &log, + "Your WASM pkg is ready to publish at {}/pkg.", &self.crate_path + ); + + PBAR.message(&format!("{} Done in {}", emoji::SPARKLE, &duration)); + + PBAR.message(&format!( + "{} Your WASM pkg is ready to publish at {}/pkg.", + emoji::PACKAGE, + &self.crate_path + )); + Ok(()) + } + + fn get_process_steps(mode: BuildMode) -> Vec<(&'static str, BuildStep)> { + macro_rules! steps { + ($($name:ident),+) => { + { + let mut steps: Vec<(&'static str, BuildStep)> = Vec::new(); + $(steps.push((stringify!($name), Build::$name));)* + steps + } + }; + ($($name:ident,)*) => (steps![$($name),*]) + } + match mode { + BuildMode::Normal => steps![ + step_check_crate_config, + step_add_wasm_target, + step_build_wasm, + step_create_dir, + step_create_json, + step_copy_readme, + step_install_wasm_bindgen, + step_run_wasm_bindgen, + ], + BuildMode::Noinstall => steps![ + step_check_crate_config, + step_build_wasm, + step_create_dir, + step_create_json, + step_copy_readme, + step_run_wasm_bindgen + ], + } + } + + + fn step_check_crate_config(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { + info!(&log, "Checking crate configuration..."); + manifest::check_crate_config(&self.crate_path, step)?; + info!(&log, "Crate is correctly configured."); + Ok(()) + } + + fn step_add_wasm_target(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { + info!(&log, "Adding wasm-target..."); + build::rustup_add_wasm_target(step)?; + info!(&log, "Adding wasm-target was successful."); + Ok(()) + } + + fn step_build_wasm(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { + info!(&log, "Building wasm..."); + build::cargo_build_wasm(&self.crate_path, self.debug, step)?; + + #[cfg(not(target_os = "windows"))] + info!( + &log, + "wasm built at {}/target/wasm32-unknown-unknown/release.", &self.crate_path + ); + #[cfg(target_os = "windows")] + info!( + &log, + "wasm built at {}\\target\\wasm32-unknown-unknown\\release.", &self.crate_path + ); + Ok(()) + } + + fn step_create_dir(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { + info!(&log, "Creating a pkg directory..."); + create_pkg_dir(&self.crate_path, step)?; + info!(&log, "Created a pkg directory at {}.", &self.crate_path); + Ok(()) + } + + fn step_create_json(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { + info!(&log, "Writing a package.json..."); + manifest::write_package_json( + &self.crate_path, + &self.scope, + self.disable_dts, + &self.target, + step, + )?; + #[cfg(not(target_os = "windows"))] + info!( + &log, + "Wrote a package.json at {}/pkg/package.json.", &self.crate_path + ); + #[cfg(target_os = "windows")] + info!( + &log, + "Wrote a package.json at {}\\pkg\\package.json.", &self.crate_path + ); + Ok(()) + } + + fn step_copy_readme(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { + info!(&log, "Copying readme from crate..."); + readme::copy_from_crate(&self.crate_path, step)?; + #[cfg(not(target_os = "windows"))] + info!( + &log, + "Copied readme from crate to {}/pkg.", &self.crate_path + ); + #[cfg(target_os = "windows")] + info!( + &log, + "Copied readme from crate to {}\\pkg.", &self.crate_path + ); + Ok(()) + } + + fn step_install_wasm_bindgen(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { + info!(&log, "Installing wasm-bindgen-cli..."); + bindgen::cargo_install_wasm_bindgen(step)?; + info!(&log, "Installing wasm-bindgen-cli was successful."); + + info!(&log, "Getting the crate name from the manifest..."); + self.crate_name = manifest::get_crate_name(&self.crate_path)?; + #[cfg(not(target_os = "windows"))] + info!( + &log, + "Got crate name {} from the manifest at {}/Cargo.toml.", + &self.crate_name, + &self.crate_path + ); + #[cfg(target_os = "windows")] + info!( + &log, + "Got crate name {} from the manifest at {}\\Cargo.toml.", + &self.crate_name, + &self.crate_path + ); + Ok(()) + } + + fn step_run_wasm_bindgen(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { + info!(&log, "Building the wasm bindings..."); + bindgen::wasm_bindgen_build( + &self.crate_path, + &self.crate_name, + self.disable_dts, + &self.target, + self.debug, + step, + )?; + #[cfg(not(target_os = "windows"))] + info!( + &log, + "wasm bindings were built at {}/pkg.", &self.crate_path + ); + #[cfg(target_os = "windows")] + info!( + &log, + "wasm bindings were built at {}\\pkg.", &self.crate_path + ); + Ok(()) + } +} diff --git a/src/command/init.rs b/src/command/init.rs index bec96f89d..f2bef530d 100644 --- a/src/command/init.rs +++ b/src/command/init.rs @@ -1,8 +1,6 @@ //! Initializing a crate for packing `.wasm`s. -use bindgen; -use build; -use command::utils::set_crate_path; +use command::utils::{set_crate_path,create_pkg_dir}; use emoji; use error::Error; use indicatif::HumanDuration; @@ -10,103 +8,63 @@ use manifest; use progressbar::Step; use readme; use slog::Logger; -use std::fs; use std::time::Instant; use PBAR; -/// Construct our `pkg` directory in the crate. -pub fn create_pkg_dir(path: &str, step: &Step) -> Result<(), Error> { - let msg = format!("{}Creating a pkg directory...", emoji::FOLDER); - PBAR.step(step, &msg); - let pkg_dir_path = format!("{}/pkg", path); - fs::create_dir_all(pkg_dir_path)?; - Ok(()) -} - -/// The `InitMode` determines which mode of initialization we are running, and -/// what build and install steps we perform. -pub enum InitMode { - /// Perform all the build and install steps. - Normal, - /// Don't build the crate as a `.wasm` but do install tools and create - /// meta-data. - Nobuild, - /// Don't install tools like `wasm-bindgen`, just use the global - /// environment's existing versions to do builds. - Noinstall, -} - /// Everything required to configure and run the `wasm-pack init` command. pub struct Init { crate_path: String, scope: Option, disable_dts: bool, target: String, + // build without --release. debug: bool, - crate_name: String, } -type InitStep = fn(&mut Init, &Step, &Logger) -> Result<(), Error>; +/// `Init` options +#[derive(Debug, StructOpt)] +pub struct InitOptions { + /// The path to the Rust crate. + pub path: Option, -impl Init { - /// Construct a new `Init` command. - pub fn new( - path: Option, - scope: Option, - disable_dts: bool, - target: String, - debug: bool, - ) -> Result { - let crate_path = set_crate_path(path); - let crate_name = manifest::get_crate_name(&crate_path)?; - Ok(Init { - crate_path, - scope, - disable_dts, - target, - debug, - crate_name, - }) - } + /// The npm scope to use in package.json, if any. + #[structopt(long = "scope", short = "s")] + pub scope: Option, - fn get_process_steps(mode: InitMode) -> Vec<(&'static str, InitStep)> { - macro_rules! steps { - ($($name:ident),+) => { - { - let mut steps: Vec<(&'static str, InitStep)> = Vec::new(); - $(steps.push((stringify!($name), Init::$name));)* - steps - } - }; - ($($name:ident,)*) => (steps![$($name),*]) - } + #[structopt(long = "no-typescript")] + /// By default a *.d.ts file is generated for the generated JS file, but + /// this flag will disable generating this TypeScript file. + pub disable_dts: bool, + + #[structopt(long = "target", short = "t", default_value = "browser")] + /// Sets the target environment. [possible values: browser, nodejs] + pub target: String, + + #[structopt(long = "debug")] + /// Build without --release. + pub debug: bool, +} - match mode { - InitMode::Normal => steps![ - step_check_crate_config, - step_add_wasm_target, - step_build_wasm, - step_create_dir, - step_create_json, - step_copy_readme, - step_install_wasm_bindgen, - step_run_wasm_bindgen, - ], - InitMode::Nobuild => steps![step_create_dir, step_create_json, step_copy_readme,], - InitMode::Noinstall => steps![ - step_check_crate_config, - step_build_wasm, - step_create_dir, - step_create_json, - step_copy_readme, - step_run_wasm_bindgen - ], +impl From for Init { + fn from(init_opts: InitOptions) -> Self { + let crate_path = set_crate_path(init_opts.path); + let crate_name = manifest::get_crate_name(&crate_path).unwrap(); + Init { + crate_path, + scope: init_opts.scope, + disable_dts:init_opts.disable_dts, + target:init_opts.target, + debug:init_opts.debug, } } +} +type InitStep = fn(&mut Init, &Step, &Logger) -> Result<(), Error>; + +impl Init { /// Execute this `Init` command. - pub fn process(&mut self, log: &Logger, mode: InitMode) -> Result<(), Error> { - let process_steps = Init::get_process_steps(mode); + pub fn run(&mut self, log: &Logger) -> Result<(), Error> { + let process_steps = Init::set_process_steps(); let mut step_counter = Step::new(process_steps.len()); @@ -134,35 +92,18 @@ impl Init { Ok(()) } - fn step_check_crate_config(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { - info!(&log, "Checking crate configuration..."); - manifest::check_crate_config(&self.crate_path, step)?; - info!(&log, "Crate is correctly configured."); - Ok(()) - } - - fn step_add_wasm_target(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { - info!(&log, "Adding wasm-target..."); - build::rustup_add_wasm_target(step)?; - info!(&log, "Adding wasm-target was successful."); - Ok(()) - } - - fn step_build_wasm(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { - info!(&log, "Building wasm..."); - build::cargo_build_wasm(&self.crate_path, self.debug, step)?; - - #[cfg(not(target_os = "windows"))] - info!( - &log, - "wasm built at {}/target/wasm32-unknown-unknown/release.", &self.crate_path - ); - #[cfg(target_os = "windows")] - info!( - &log, - "wasm built at {}\\target\\wasm32-unknown-unknown\\release.", &self.crate_path - ); - Ok(()) + fn set_process_steps() -> Vec<(&'static str, InitStep)> { + macro_rules! steps { + ($($name:ident),+) => { + { + let mut steps: Vec<(&'static str, InitStep)> = Vec::new(); + $(steps.push((stringify!($name), Init::$name));)* + steps + } + }; + ($($name:ident,)*) => (steps![$($name),*]) + } + steps![step_create_dir, step_create_json, step_copy_readme,] } fn step_create_dir(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { @@ -209,108 +150,4 @@ impl Init { ); Ok(()) } - - fn step_install_wasm_bindgen(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { - info!(&log, "Installing wasm-bindgen-cli..."); - bindgen::cargo_install_wasm_bindgen(step)?; - info!(&log, "Installing wasm-bindgen-cli was successful."); - - info!(&log, "Getting the crate name from the manifest..."); - self.crate_name = manifest::get_crate_name(&self.crate_path)?; - #[cfg(not(target_os = "windows"))] - info!( - &log, - "Got crate name {} from the manifest at {}/Cargo.toml.", - &self.crate_name, - &self.crate_path - ); - #[cfg(target_os = "windows")] - info!( - &log, - "Got crate name {} from the manifest at {}\\Cargo.toml.", - &self.crate_name, - &self.crate_path - ); - Ok(()) - } - - fn step_run_wasm_bindgen(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { - info!(&log, "Building the wasm bindings..."); - bindgen::wasm_bindgen_build( - &self.crate_path, - &self.crate_name, - self.disable_dts, - &self.target, - self.debug, - step, - )?; - #[cfg(not(target_os = "windows"))] - info!( - &log, - "wasm bindings were built at {}/pkg.", &self.crate_path - ); - #[cfg(target_os = "windows")] - info!( - &log, - "wasm bindings were built at {}\\pkg.", &self.crate_path - ); - Ok(()) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn init_normal_build() { - let steps: Vec<&str> = Init::get_process_steps(InitMode::Normal) - .into_iter() - .map(|(n, _)| n) - .collect(); - assert_eq!( - steps, - [ - "step_check_crate_config", - "step_add_wasm_target", - "step_build_wasm", - "step_create_dir", - "step_create_json", - "step_copy_readme", - "step_install_wasm_bindgen", - "step_run_wasm_bindgen" - ] - ); - } - - #[test] - fn init_skip_build() { - let steps: Vec<&str> = Init::get_process_steps(InitMode::Nobuild) - .into_iter() - .map(|(n, _)| n) - .collect(); - assert_eq!( - steps, - ["step_create_dir", "step_create_json", "step_copy_readme"] - ); - } - - #[test] - fn init_skip_install() { - let steps: Vec<&str> = Init::get_process_steps(InitMode::Noinstall) - .into_iter() - .map(|(n, _)| n) - .collect(); - assert_eq!( - steps, - [ - "step_check_crate_config", - "step_build_wasm", - "step_create_dir", - "step_create_json", - "step_copy_readme", - "step_run_wasm_bindgen" - ] - ); - } } diff --git a/src/command/mod.rs b/src/command/mod.rs index 2f477b9b9..513dd7a22 100644 --- a/src/command/mod.rs +++ b/src/command/mod.rs @@ -1,15 +1,17 @@ //! CLI command structures, parsing, and execution. +mod build; pub mod init; mod login; mod pack; mod publish; pub mod utils; -use self::init::{Init, InitMode}; use self::login::login; use self::pack::pack; use self::publish::publish; +use self::build::{Build,BuildMode}; +use self::init::Init; use error::Error; use slog::Logger; use std::result; @@ -20,31 +22,11 @@ use PBAR; pub enum Command { #[structopt(name = "init")] /// 🐣 initialize a package.json based on your compiled wasm! - Init { - /// The path to the Rust crate. - path: Option, - - /// The npm scope to use in package.json, if any. - #[structopt(long = "scope", short = "s")] - scope: Option, - - #[structopt(long = "mode", short = "m", default_value = "normal")] - /// Sets steps to be run. [possible values: no-build, no-install, normal] - mode: String, - - #[structopt(long = "no-typescript")] - /// By default a *.d.ts file is generated for the generated JS file, but - /// this flag will disable generating this TypeScript file. - disable_dts: bool, - - #[structopt(long = "target", short = "t", default_value = "browser")] - /// Sets the target environment. [possible values: browser, nodejs] - target: String, + Init(init::InitOptions), - #[structopt(long = "debug")] - /// Build without --release. - debug: bool, - }, + /// build + #[structopt(name = "build")] + Build(self::build::BuildOptions), #[structopt(name = "pack")] /// 🍱 create a tar of your npm package but don't publish! @@ -98,32 +80,18 @@ pub fn run_wasm_pack(command: Command, log: &Logger) -> result::Result<(), Error // Run the correct command based off input and store the result of it so that we can clear // the progress bar then return it let status = match command { - Command::Init { - path, - scope, - mode, - disable_dts, - target, - debug, - } => { + Command::Init(init_opts) => { info!(&log, "Running init command..."); - info!( - &log, - "Path: {:?}, Scope: {:?}, Skip build: {}, Disable Dts: {}, Target: {}, Debug: {}", - &path, - &scope, - &mode, - &disable_dts, - &target, - debug - ); - let modetype = match &*mode { - "no-build" => InitMode::Nobuild, - "no-install" => InitMode::Noinstall, - "normal" => InitMode::Normal, - _ => InitMode::Normal, + Init::from(init_opts).run(&log) + } + Command::Build(build_opts) => { + info!(&log, "Running build command..."); + let build_mode = match build_opts.mode.as_str() { + "no-install" => BuildMode::Noinstall, + "normal" => BuildMode::Normal, + _ => BuildMode::Normal, }; - Init::new(path, scope, disable_dts, target, debug)?.process(&log, modetype) + Build::from(build_opts).run(&log, build_mode) } Command::Pack { path } => { info!(&log, "Running pack command..."); diff --git a/src/command/utils.rs b/src/command/utils.rs index 92695344f..650878ea1 100644 --- a/src/command/utils.rs +++ b/src/command/utils.rs @@ -1,5 +1,11 @@ //! Utility functions for commands. +use error::Error; +use progressbar::Step; +use PBAR; +use std::fs; +use emoji; + /// If an explicit path is given, then use it, otherwise assume the current /// directory is the crate path. pub fn set_crate_path(path: Option) -> String { @@ -10,3 +16,12 @@ pub fn set_crate_path(path: Option) -> String { crate_path } + +/// Construct our `pkg` directory in the crate. +pub fn create_pkg_dir(path: &str, step: &Step) -> Result<(), Error> { + let msg = format!("{}Creating a pkg directory...", emoji::FOLDER); + PBAR.step(step, &msg); + let pkg_dir_path = format!("{}/pkg", path); + fs::create_dir_all(pkg_dir_path)?; + Ok(()) +} diff --git a/src/logger.rs b/src/logger.rs index 3ddea3a7d..1ceae4912 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -33,7 +33,8 @@ pub fn new(cmd: &Command, verbosity: u8) -> Result { /// Figure out where to stick the log based off the command arguments given fn log_file_path(cmd: &Command) -> PathBuf { let path = match cmd { - Command::Init { path, .. } => path, + Command::Init(init_opts) => &init_opts.path, + Command::Build(build_opts) => &build_opts.path, Command::Pack { path } => path, Command::Publish { path } => path, Command::Login { .. } => &None,