From 9a220f10dd57cb7cbc9e08b60fc375012cc37e4c Mon Sep 17 00:00:00 2001 From: Michael Gerhaeuser Date: Mon, 11 Jun 2018 21:20:27 +0200 Subject: [PATCH 1/6] Let the spinners spin again This will fix the broken spinners that indicate steps which are currently in progress. To achieve this the behavior of the progressbar helper had to be adjusted. The multibar does not work while a child process is run with `std::process::Command`. Using multiple spinners without a multibar is problematic as well because emitting warnings, infos and errors while a single spinner is active will duplicate the spinners message. The spinner will also absorb the last warning/error/info. Instead of publishing warnings, errors and infos immediately they will now be cached and only output when the current spinner finishes. To make sure we can output all warnings to the user ProgressBars are no longer exposed to the caller. Instead the active spinner will be finished implicitly when a new spinner is allocated with the `message()` function. Instead of relying on the `done()` function to be called the progressbar now implements the `Drop` trait which will finish the last spinner automatically. Unfortunately, this introduces members that have to be mutable. To not have to deal with mutable ProgressOutput all over the place the members were put inside an RwLock. This allows us to use ProgressOutput from inside multiple threads to emit warnings and errors. --- src/bindgen.rs | 8 ++---- src/build.rs | 7 ++--- src/command.rs | 20 +++++-------- src/error.rs | 10 +++++++ src/manifest.rs | 9 +++--- src/progressbar.rs | 71 +++++++++++++++++++++++++++++++++++----------- src/readme.rs | 5 ++-- 7 files changed, 83 insertions(+), 47 deletions(-) diff --git a/src/bindgen.rs b/src/bindgen.rs index 3796b470..7405dde3 100644 --- a/src/bindgen.rs +++ b/src/bindgen.rs @@ -6,17 +6,16 @@ use PBAR; pub fn cargo_install_wasm_bindgen(step: &Step) -> Result<(), Error> { let msg = format!("{}Installing WASM-bindgen...", emoji::DOWN_ARROW); - let pb = PBAR.step(step, &msg); + PBAR.step(step, &msg)?; let output = Command::new("cargo") .arg("install") .arg("wasm-bindgen-cli") .arg("--force") .output()?; - pb.finish(); if !output.status.success() { let s = String::from_utf8_lossy(&output.stderr); if s.contains("already exists") { - PBAR.info("wasm-bindgen already installed"); + PBAR.info("wasm-bindgen already installed")?; return Ok(()); } Error::cli("Installing wasm-bindgen failed", s) @@ -34,7 +33,7 @@ pub fn wasm_bindgen_build( step: &Step, ) -> Result<(), Error> { let msg = format!("{}Running WASM-bindgen...", emoji::RUNNER); - let pb = PBAR.step(step, &msg); + PBAR.step(step, &msg)?; let binary_name = name.replace("-", "_"); let release_or_debug = if debug { "debug" } else { "release" }; let wasm_path = format!( @@ -60,7 +59,6 @@ pub fn wasm_bindgen_build( .arg(dts_arg) .arg(target_arg) .output()?; - pb.finish(); if !output.status.success() { let s = String::from_utf8_lossy(&output.stderr); Error::cli("wasm-bindgen failed to execute properly", s) diff --git a/src/build.rs b/src/build.rs index e85e123b..9ece1abe 100644 --- a/src/build.rs +++ b/src/build.rs @@ -6,7 +6,7 @@ use PBAR; pub fn rustup_add_wasm_target(step: &Step) -> Result<(), Error> { let msg = format!("{}Adding WASM target...", emoji::TARGET); - let pb = PBAR.step(step, &msg); + PBAR.step(step, &msg)?; ensure_nightly()?; let output = Command::new("rustup") .arg("target") @@ -15,7 +15,6 @@ pub fn rustup_add_wasm_target(step: &Step) -> Result<(), Error> { .arg("--toolchain") .arg("nightly") .output()?; - pb.finish(); if !output.status.success() { let s = String::from_utf8_lossy(&output.stderr); Error::cli("Adding the wasm32-unknown-unknown target failed", s) @@ -42,7 +41,7 @@ fn ensure_nightly() -> Result<(), Error> { pub fn cargo_build_wasm(path: &str, debug: bool, step: &Step) -> Result<(), Error> { let msg = format!("{}Compiling to WASM...", emoji::CYCLONE); - let pb = PBAR.step(step, &msg); + PBAR.step(step, &msg)?; let output = { let mut cmd = Command::new("cargo"); cmd.current_dir(path).arg("+nightly").arg("build"); @@ -52,7 +51,7 @@ pub fn cargo_build_wasm(path: &str, debug: bool, step: &Step) -> Result<(), Erro cmd.arg("--target").arg("wasm32-unknown-unknown"); cmd.output()? }; - pb.finish(); + if !output.status.success() { let s = String::from_utf8_lossy(&output.stderr); Error::cli("Compilation of your program failed", s) diff --git a/src/command.rs b/src/command.rs index 310d36c6..1d286d93 100644 --- a/src/command.rs +++ b/src/command.rs @@ -146,15 +146,10 @@ pub fn run_wasm_pack(command: Command, log: &Logger) -> result::Result<(), Error Ok(_) => {} Err(ref e) => { error!(&log, "{}", e); - PBAR.error(e.error_type()); + PBAR.error(e.error_type())?; } } - // Make sure we always clear the progress bar before we abort the program otherwise - // stderr and stdout output get eaten up and nothing will work. If this part fails - // to work and clear the progress bars then you're really having a bad day with your tools. - PBAR.done()?; - // Return the actual status of the program to the main function status } @@ -164,10 +159,9 @@ pub fn run_wasm_pack(command: Command, log: &Logger) -> result::Result<(), Error // the correct type here. pub fn create_pkg_dir(path: &str, step: &Step) -> result::Result<(), Error> { let msg = format!("{}Creating a pkg directory...", emoji::FOLDER); - let pb = PBAR.step(step, &msg); + PBAR.step(step, &msg)?; let pkg_dir_path = format!("{}/pkg", path); fs::create_dir_all(pkg_dir_path)?; - pb.finish(); Ok(()) } @@ -257,13 +251,13 @@ impl Init { "Your WASM pkg is ready to publish at {}/pkg.", &self.crate_path ); - PBAR.message(&format!("{} Done in {}", emoji::SPARKLE, &duration)); + 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(()) } @@ -420,7 +414,7 @@ fn pack(path: Option, log: &Logger) -> result::Result<(), Error> { #[cfg(target_os = "windows")] info!(&log, "Your package is located at {}\\pkg", &crate_path); - PBAR.message("🎒 packed up your package!"); + PBAR.message("🎒 packed up your package!")?; Ok(()) } @@ -432,7 +426,7 @@ fn publish(path: Option, log: &Logger) -> result::Result<(), Error> { npm::npm_publish(&crate_path)?; info!(&log, "Published your package!"); - PBAR.message("💥 published your package!"); + PBAR.message("💥 published your package!")?; Ok(()) } @@ -458,7 +452,7 @@ fn login( npm::npm_login(®istry, &scope, always_auth, &auth_type)?; info!(&log, "Logged you in!"); - PBAR.message(&format!("👋 logged you in!")); + PBAR.message(&format!("👋 logged you in!"))?; Ok(()) } diff --git a/src/error.rs b/src/error.rs index 0bd2ba67..a06b4371 100644 --- a/src/error.rs +++ b/src/error.rs @@ -2,6 +2,7 @@ use serde_json; use std::borrow::Cow; use std::io; +use std::sync::PoisonError; use toml; #[derive(Debug, Fail)] @@ -13,6 +14,8 @@ pub enum Error { SerdeJson(#[cause] serde_json::Error), #[fail(display = "{}", _0)] SerdeToml(#[cause] toml::de::Error), + #[fail(display = "Acquiring lock failed")] + PoisonedLockError, #[fail(display = "{}. stderr:\n\n{}", message, stderr)] Cli { message: String, stderr: String }, #[fail(display = "{}", message)] @@ -38,6 +41,7 @@ impl Error { Error::Io(_) => "There was an I/O error. Details:\n\n", Error::SerdeJson(_) => "There was an JSON error. Details:\n\n", Error::SerdeToml(_) => "There was an TOML error. Details:\n\n", + Error::PoisonedLockError => "There was an RwLock error. Details: \n\n", Error::Cli { message: _, stderr: _, @@ -66,3 +70,9 @@ impl From for Error { Error::SerdeToml(e) } } + +impl From> for Error { + fn from(_: PoisonError) -> Self { + Error::PoisonedLockError + } +} diff --git a/src/manifest.rs b/src/manifest.rs index 668947d6..0da58fc7 100644 --- a/src/manifest.rs +++ b/src/manifest.rs @@ -123,25 +123,24 @@ pub fn write_package_json( ) }; - let pb = PBAR.step(step, &msg); + PBAR.step(step, &msg)?; let pkg_file_path = format!("{}/pkg/package.json", path); let mut pkg_file = File::create(pkg_file_path)?; let crate_data = read_cargo_toml(path)?; let npm_data = crate_data.into_npm(scope, disable_dts); if npm_data.description.is_none() { - PBAR.warn(&warn_fmt("description")); + PBAR.warn(&warn_fmt("description"))?; } if npm_data.repository.is_none() { - PBAR.warn(&warn_fmt("repository")); + PBAR.warn(&warn_fmt("repository"))?; } if npm_data.license.is_none() { - PBAR.warn(&warn_fmt("license")); + PBAR.warn(&warn_fmt("license"))?; } let npm_json = serde_json::to_string_pretty(&npm_data)?; pkg_file.write_all(npm_json.as_bytes())?; - pb.finish(); Ok(()) } diff --git a/src/progressbar.rs b/src/progressbar.rs index a02a548b..4bb49dff 100644 --- a/src/progressbar.rs +++ b/src/progressbar.rs @@ -1,60 +1,90 @@ use console::style; use emoji; use error::Error; -use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; +use indicatif::{ProgressBar, ProgressStyle}; use std::fmt; +use std::sync::RwLock; pub struct ProgressOutput { - bar: MultiProgress, + spinner: RwLock, + messages: RwLock, } impl ProgressOutput { pub fn new() -> Self { Self { - bar: MultiProgress::new(), + spinner: RwLock::new(ProgressBar::new_spinner()), + messages: RwLock::new(String::from("")), } } - pub fn step(&self, step: &Step, message: &str) -> ProgressBar { + pub fn step(&self, step: &Step, message: &str) -> Result<(), Error> { let msg = format!("{} {}", style(step).bold().dim(), message); - self.bar.add(Self::progressbar(&msg)) + self.message(&msg) } - pub fn message(&self, message: &str) -> ProgressBar { - self.bar.add(Self::progressbar(message)) + fn finish(&self) -> Result<(), Error> { + let spinner = self.spinner.read()?; + spinner.finish(); + + let mut message = self.messages.write()?; + print!("{}", message); + message.clear(); + + Ok(()) + } + + pub fn message(&self, message: &str) -> Result<(), Error> { + self.finish()?; + + let mut spinner = self.spinner.write()?; + *spinner = Self::progressbar(message); + Ok(()) + } + + fn add_message(&self, msg: &str) -> Result<(), Error> { + let mut message = self.messages.write()?; + message.push_str(" "); + message.push_str(msg); + message.push('\n'); + + Ok(()) } - pub fn info(&self, message: &str) { + pub fn info(&self, message: &str) -> Result<(), Error> { let info = format!( "{} {}: {}", emoji::INFO, style("[INFO]").bold().dim(), message ); - let bar = self.bar.add(Self::progressbar(&info)); - bar.finish(); + self.add_message(&info)?; + + Ok(()) } - pub fn warn(&self, message: &str) { + pub fn warn(&self, message: &str) -> Result<(), Error> { let warn = format!( "{} {}: {}", emoji::WARN, style("[WARN]").bold().dim(), message ); - let bar = self.bar.add(Self::progressbar(&warn)); - bar.finish(); + self.add_message(&warn)?; + + Ok(()) } - pub fn error(&self, message: String) { + pub fn error(&self, message: String) -> Result<(), Error> { let err = format!( "{} {}: {}", emoji::ERROR, style("[ERR]").bold().dim(), message ); - let bar = self.bar.add(Self::progressbar(&err)); - bar.finish(); + self.add_message(&err)?; + + Ok(()) } fn progressbar(msg: &str) -> ProgressBar { @@ -70,7 +100,8 @@ impl ProgressOutput { } pub fn done(&self) -> Result<(), Error> { - self.bar.join_and_clear().map_err(|e| Error::from(e)) + self.finish()?; + Ok(()) } } @@ -93,3 +124,9 @@ impl fmt::Display for Step { write!(f, "[{}/{}]", self.current, self.total) } } + +impl Drop for ProgressOutput { + fn drop(&mut self) { + self.done().unwrap(); + } +} diff --git a/src/readme.rs b/src/readme.rs index 7e0cae26..5437a937 100644 --- a/src/readme.rs +++ b/src/readme.rs @@ -7,12 +7,11 @@ use PBAR; pub fn copy_from_crate(path: &str, step: &Step) -> Result<(), Error> { let msg = format!("{}Copying over your README...", emoji::DANCERS); - let pb = PBAR.step(step, &msg); + PBAR.step(step, &msg)?; let crate_readme_path = format!("{}/README.md", path); let new_readme_path = format!("{}/pkg/README.md", path); if let Err(_) = fs::copy(&crate_readme_path, &new_readme_path) { - PBAR.warn("origin crate has no README"); + PBAR.warn("origin crate has no README")?; }; - pb.finish(); Ok(()) } From f063f4cfccbb6f6c247ad084c5518d07864de008 Mon Sep 17 00:00:00 2001 From: Ashley Williams Date: Thu, 14 Jun 2018 10:55:31 -0700 Subject: [PATCH 2/6] fix(command): s/create_type/crate_type --- src/command.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/command.rs b/src/command.rs index 1d286d93..35b6d7d6 100644 --- a/src/command.rs +++ b/src/command.rs @@ -219,7 +219,7 @@ impl Init { step_create_dir, step_create_json, step_copy_readme, - step_check_create_type, + step_check_crate_type, step_install_wasm_bindgen, step_running_wasm_bindgen, ], @@ -331,7 +331,7 @@ impl Init { Ok(()) } - fn step_check_create_type(&mut self, _step: &Step, log: &Logger) -> result::Result<(), Error> { + fn step_check_crate_type(&mut self, _step: &Step, log: &Logger) -> result::Result<(), Error> { info!(&log, "Checking the crate type from the manifest..."); manifest::check_crate_type(&self.crate_path)?; #[cfg(not(target_os = "windows"))] @@ -484,7 +484,7 @@ mod test { "step_create_dir", "step_create_json", "step_copy_readme", - "step_check_create_type", + "step_check_crate_type", "step_install_wasm_bindgen", "step_running_wasm_bindgen" ] From c789b6a522e9f619e2fba20e724c0b57b2a85306 Mon Sep 17 00:00:00 2001 From: Ashley Williams Date: Thu, 14 Jun 2018 11:13:29 -0700 Subject: [PATCH 3/6] refactor(crate_type): bring inline with wasm-bindgen check --- src/manifest.rs | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/manifest.rs b/src/manifest.rs index 0da58fc7..cf7c9e4e 100644 --- a/src/manifest.rs +++ b/src/manifest.rs @@ -160,19 +160,14 @@ pub fn check_wasm_bindgen(path: &str) -> Result<(), Error> { )) } -fn has_cdylib(path: &str) -> Result { - Ok(read_cargo_toml(path)?.lib.map_or(false, |lib| { +pub fn check_crate_type(path: &str) -> Result<(), Error> { + if read_cargo_toml(path)?.lib.map_or(false, |lib| { lib.crate_type .map_or(false, |types| types.iter().any(|s| s == "cdylib")) - })) -} - -pub fn check_crate_type(path: &str) -> Result<(), Error> { - if !has_cdylib(path)? { - Error::crate_config( - "crate-type must include cdylib to compile to wasm32-unknown-unknown. Add the following to your Cargo.toml file:\n\n[lib]\ncrate-type = [\"cdylib\"]" - ) - } else { - Ok(()) + }) { + return Ok(()); } + Error::crate_config( + "crate-type must be cdylib to compile to wasm32-unknown-unknown. Add the following to your Cargo.toml file:\n\n[lib]\ncrate-type = [\"cdylib\"]" + ) } From c190d5d44460ba658caad45a28e9e68052b52796 Mon Sep 17 00:00:00 2001 From: Ashley Williams Date: Thu, 14 Jun 2018 13:07:51 -0700 Subject: [PATCH 4/6] fix(nobuild): don't check dependency --- src/command.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/command.rs b/src/command.rs index 35b6d7d6..60ac613b 100644 --- a/src/command.rs +++ b/src/command.rs @@ -224,7 +224,6 @@ impl Init { step_running_wasm_bindgen, ], InitMode::Nobuild => steps![ - step_check_dependency, step_create_dir, step_create_json, step_copy_readme, From d09db166235de6d74dedb2c30260175a111bc819 Mon Sep 17 00:00:00 2001 From: Ashley Williams Date: Thu, 14 Jun 2018 13:39:02 -0700 Subject: [PATCH 5/6] fix(crate_config): combine crate type and dep check, emit step --- src/command.rs | 32 ++++++-------------------------- src/manifest.rs | 12 ++++++++++-- 2 files changed, 16 insertions(+), 28 deletions(-) diff --git a/src/command.rs b/src/command.rs index 60ac613b..5d2ea8e7 100644 --- a/src/command.rs +++ b/src/command.rs @@ -213,13 +213,12 @@ impl Init { match mode { InitMode::Normal => steps![ - step_check_dependency, + step_check_crate_config, step_add_wasm_target, step_build_wasm, step_create_dir, step_create_json, step_copy_readme, - step_check_crate_type, step_install_wasm_bindgen, step_running_wasm_bindgen, ], @@ -260,10 +259,10 @@ impl Init { Ok(()) } - fn step_check_dependency(&mut self, _step: &Step, log: &Logger) -> result::Result<(), Error> { - info!(&log, "Checking wasm-bindgen dependency..."); - manifest::check_wasm_bindgen(&self.crate_path)?; - info!(&log, "wasm-bindgen dependency is correctly declared."); + fn step_check_crate_config(&mut self, step: &Step, log: &Logger) -> result::Result<(), Error> { + info!(&log, "Checking crate configuration..."); + manifest::check_crate_config(&self.crate_path, step)?; + info!(&log, "Crate is correctly configured."); Ok(()) } @@ -330,23 +329,6 @@ impl Init { Ok(()) } - fn step_check_crate_type(&mut self, _step: &Step, log: &Logger) -> result::Result<(), Error> { - info!(&log, "Checking the crate type from the manifest..."); - manifest::check_crate_type(&self.crate_path)?; - #[cfg(not(target_os = "windows"))] - info!( - &log, - "Checked crate type from the manifest at {}/Cargo.toml.", &self.crate_path - ); - #[cfg(target_os = "windows")] - info!( - &log, - "Checked crate type from the manifest at {}\\Cargo.toml.", &self.crate_path - ); - - Ok(()) - } - fn step_install_wasm_bindgen( &mut self, step: &Step, @@ -477,13 +459,12 @@ mod test { assert_eq!( steps, [ - "step_check_dependency", + "step_check_crate_config", "step_add_wasm_target", "step_build_wasm", "step_create_dir", "step_create_json", "step_copy_readme", - "step_check_crate_type", "step_install_wasm_bindgen", "step_running_wasm_bindgen" ] @@ -499,7 +480,6 @@ mod test { assert_eq!( steps, [ - "step_check_dependency", "step_create_dir", "step_create_json", "step_copy_readme" diff --git a/src/manifest.rs b/src/manifest.rs index cf7c9e4e..703fd3f3 100644 --- a/src/manifest.rs +++ b/src/manifest.rs @@ -148,7 +148,15 @@ pub fn get_crate_name(path: &str) -> Result { Ok(read_cargo_toml(path)?.package.name) } -pub fn check_wasm_bindgen(path: &str) -> Result<(), Error> { +pub fn check_crate_config(path: &str, step: &Step) -> Result<(), Error> { + let msg = format!("{}Checking crate configuration...", emoji::WRENCH); + PBAR.step(&step, &msg)?; + check_wasm_bindgen(path)?; + check_crate_type(path)?; + Ok(()) +} + +fn check_wasm_bindgen(path: &str) -> Result<(), Error> { if read_cargo_toml(path)?.dependencies.map_or(false, |x| { !x.wasm_bindgen.unwrap_or("".to_string()).is_empty() }) { @@ -160,7 +168,7 @@ pub fn check_wasm_bindgen(path: &str) -> Result<(), Error> { )) } -pub fn check_crate_type(path: &str) -> Result<(), Error> { +fn check_crate_type(path: &str) -> Result<(), Error> { if read_cargo_toml(path)?.lib.map_or(false, |lib| { lib.crate_type .map_or(false, |types| types.iter().any(|s| s == "cdylib")) From ca0f4693560aaa950f0ad14de22d4eede01f87ed Mon Sep 17 00:00:00 2001 From: Ashley Williams Date: Thu, 14 Jun 2018 14:40:50 -0700 Subject: [PATCH 6/6] refactor(command): modularize command.rs --- src/{command.rs => command/init.rs} | 223 +--------------------------- src/command/login.rs | 31 ++++ src/command/mod.rs | 154 +++++++++++++++++++ src/command/pack.rs | 20 +++ src/command/publish.rs | 18 +++ src/command/utils.rs | 8 + src/manifest.rs | 10 +- tests/manifest/main.rs | 21 ++- 8 files changed, 255 insertions(+), 230 deletions(-) rename src/{command.rs => command/init.rs} (53%) create mode 100644 src/command/login.rs create mode 100644 src/command/mod.rs create mode 100644 src/command/pack.rs create mode 100644 src/command/publish.rs create mode 100644 src/command/utils.rs diff --git a/src/command.rs b/src/command/init.rs similarity index 53% rename from src/command.rs rename to src/command/init.rs index 5d2ea8e7..c409a865 100644 --- a/src/command.rs +++ b/src/command/init.rs @@ -1,159 +1,17 @@ use bindgen; use build; +use command::utils::set_crate_path; use emoji; use error::Error; use indicatif::HumanDuration; use manifest; -use npm; use progressbar::Step; -#[allow(unused)] use readme; use slog::Logger; -use std::fs; -use std::result; use std::time::Instant; +use std::{fs, result}; use PBAR; -#[derive(Debug, StructOpt)] -pub enum Command { - #[structopt(name = "init")] - /// 🐣 initialize a package.json based on your compiled wasm! - Init { - path: Option, - - #[structopt(long = "scope", short = "s")] - scope: Option, - - #[structopt(long = "--skip-build")] - /// Do not build, only update metadata - skip_build: bool, - - #[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, - - #[structopt(long = "debug")] - /// Build without --release. - debug: bool, - }, - - #[structopt(name = "pack")] - /// 🍱 create a tar of your npm package but don't publish! - Pack { path: Option }, - - #[structopt(name = "publish")] - /// 🎆 pack up your npm package and publish! - Publish { path: Option }, - - #[structopt(name = "login", alias = "adduser", alias = "add-user")] - /// 👤 Add a registry user account! (aliases: adduser, add-user) - Login { - #[structopt(long = "registry", short = "r")] - /// Default: 'https://registry.npmjs.org/'. - /// The base URL of the npm package registry. If scope is also - /// specified, this registry will only be used for packages with that - /// scope. scope defaults to the scope of the project directory you're - /// currently in, if any. - registry: Option, - - #[structopt(long = "scope", short = "s")] - /// Default: none. - /// If specified, the user and login credentials given will be - /// associated with the specified scope. - scope: Option, - - #[structopt(long = "always-auth", short = "a")] - /// If specified, save configuration indicating that all requests to the - /// given registry should include authorization information. Useful for - /// private registries. Can be used with --registry and / or --scope - always_auth: bool, - - #[structopt(long = "auth-type", short = "t")] - /// Default: 'legacy'. - /// Type: 'legacy', 'sso', 'saml', 'oauth'. - /// What authentication strategy to use with adduser/login. Some npm - /// registries (for example, npmE) might support alternative auth - /// strategies besides classic username/password entry in legacy npm. - auth_type: Option, - }, -} - -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, - skip_build, - disable_dts, - target, - debug, - } => { - info!(&log, "Running init command..."); - info!( - &log, - "Path: {:?}, Scope: {:?}, Skip build: {}, Disable Dts: {}, Target: {}, Debug: {}", - &path, - &scope, - &skip_build, - &disable_dts, - &target, - debug - ); - let mode = if skip_build { - InitMode::Nobuild - } else { - InitMode::Normal - }; - Init::new(path, scope, disable_dts, target, debug).process(&log, mode) - } - Command::Pack { path } => { - info!(&log, "Running pack command..."); - info!(&log, "Path: {:?}", &path); - pack(path, &log) - } - Command::Publish { path } => { - info!(&log, "Running publish command..."); - info!(&log, "Path: {:?}", &path); - publish(path, &log) - } - Command::Login { - registry, - scope, - always_auth, - auth_type, - } => { - info!(&log, "Running login command..."); - info!( - &log, - "Registry: {:?}, Scope: {:?}, Always Auth: {}, Auth Type: {:?}", - ®istry, - &scope, - &always_auth, - &auth_type - ); - login(registry, scope, always_auth, auth_type, &log) - } - }; - - match status { - Ok(_) => {} - Err(ref e) => { - error!(&log, "{}", e); - PBAR.error(e.error_type())?; - } - } - - // Return the actual status of the program to the main function - status -} - // quicli::prelude::* imports a different result struct which gets // precedence over the std::result::Result, so have had to specify // the correct type here. @@ -165,12 +23,12 @@ pub fn create_pkg_dir(path: &str, step: &Step) -> result::Result<(), Error> { Ok(()) } -enum InitMode { +pub enum InitMode { Normal, Nobuild, } -struct Init { +pub struct Init { crate_path: String, scope: Option, disable_dts: bool, @@ -222,11 +80,7 @@ impl Init { step_install_wasm_bindgen, step_running_wasm_bindgen, ], - InitMode::Nobuild => steps![ - step_create_dir, - step_create_json, - step_copy_readme, - ], + InitMode::Nobuild => steps![step_create_dir, step_create_json, step_copy_readme,], } } @@ -385,67 +239,6 @@ impl Init { } } -fn pack(path: Option, log: &Logger) -> result::Result<(), Error> { - let crate_path = set_crate_path(path); - - info!(&log, "Packing up the npm package..."); - npm::npm_pack(&crate_path)?; - #[cfg(not(target_os = "windows"))] - info!(&log, "Your package is located at {}/pkg", &crate_path); - #[cfg(target_os = "windows")] - info!(&log, "Your package is located at {}\\pkg", &crate_path); - - PBAR.message("🎒 packed up your package!")?; - Ok(()) -} - -fn publish(path: Option, log: &Logger) -> result::Result<(), Error> { - let crate_path = set_crate_path(path); - - info!(&log, "Publishing the npm package..."); - info!(&log, "npm info located in the npm debug log"); - npm::npm_publish(&crate_path)?; - info!(&log, "Published your package!"); - - PBAR.message("💥 published your package!")?; - Ok(()) -} - -fn login( - registry: Option, - scope: Option, - always_auth: bool, - auth_type: Option, - log: &Logger, -) -> result::Result<(), Error> { - let registry = registry.unwrap_or(npm::DEFAULT_NPM_REGISTRY.to_string()); - - info!(&log, "Logging in to npm..."); - info!( - &log, - "Scope: {:?} Registry: {}, Always Auth: {}, Auth Type: {:?}.", - &scope, - ®istry, - always_auth, - &auth_type - ); - info!(&log, "npm info located in the npm debug log"); - npm::npm_login(®istry, &scope, always_auth, &auth_type)?; - info!(&log, "Logged you in!"); - - PBAR.message(&format!("👋 logged you in!"))?; - Ok(()) -} - -fn set_crate_path(path: Option) -> String { - let crate_path = match path { - Some(p) => p, - None => ".".to_string(), - }; - - crate_path -} - #[cfg(test)] mod test { use super::*; @@ -479,11 +272,7 @@ mod test { .collect(); assert_eq!( steps, - [ - "step_create_dir", - "step_create_json", - "step_copy_readme" - ] + ["step_create_dir", "step_create_json", "step_copy_readme"] ); } } diff --git a/src/command/login.rs b/src/command/login.rs new file mode 100644 index 00000000..f28e1ec8 --- /dev/null +++ b/src/command/login.rs @@ -0,0 +1,31 @@ +use error::Error; +use npm; +use slog::Logger; +use std::result; +use PBAR; + +pub fn login( + registry: Option, + scope: Option, + always_auth: bool, + auth_type: Option, + log: &Logger, +) -> result::Result<(), Error> { + let registry = registry.unwrap_or(npm::DEFAULT_NPM_REGISTRY.to_string()); + + info!(&log, "Logging in to npm..."); + info!( + &log, + "Scope: {:?} Registry: {}, Always Auth: {}, Auth Type: {:?}.", + &scope, + ®istry, + always_auth, + &auth_type + ); + info!(&log, "npm info located in the npm debug log"); + npm::npm_login(®istry, &scope, always_auth, &auth_type)?; + info!(&log, "Logged you in!"); + + PBAR.message(&format!("👋 logged you in!"))?; + Ok(()) +} diff --git a/src/command/mod.rs b/src/command/mod.rs new file mode 100644 index 00000000..18da8855 --- /dev/null +++ b/src/command/mod.rs @@ -0,0 +1,154 @@ +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 error::Error; +use slog::Logger; +use std::result; +use PBAR; + +#[derive(Debug, StructOpt)] +pub enum Command { + #[structopt(name = "init")] + /// 🐣 initialize a package.json based on your compiled wasm! + Init { + path: Option, + + #[structopt(long = "scope", short = "s")] + scope: Option, + + #[structopt(long = "--skip-build")] + /// Do not build, only update metadata + skip_build: bool, + + #[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, + + #[structopt(long = "debug")] + /// Build without --release. + debug: bool, + }, + + #[structopt(name = "pack")] + /// 🍱 create a tar of your npm package but don't publish! + Pack { path: Option }, + + #[structopt(name = "publish")] + /// 🎆 pack up your npm package and publish! + Publish { path: Option }, + + #[structopt(name = "login", alias = "adduser", alias = "add-user")] + /// 👤 Add a registry user account! (aliases: adduser, add-user) + Login { + #[structopt(long = "registry", short = "r")] + /// Default: 'https://registry.npmjs.org/'. + /// The base URL of the npm package registry. If scope is also + /// specified, this registry will only be used for packages with that + /// scope. scope defaults to the scope of the project directory you're + /// currently in, if any. + registry: Option, + + #[structopt(long = "scope", short = "s")] + /// Default: none. + /// If specified, the user and login credentials given will be + /// associated with the specified scope. + scope: Option, + + #[structopt(long = "always-auth", short = "a")] + /// If specified, save configuration indicating that all requests to the + /// given registry should include authorization information. Useful for + /// private registries. Can be used with --registry and / or --scope + always_auth: bool, + + #[structopt(long = "auth-type", short = "t")] + /// Default: 'legacy'. + /// Type: 'legacy', 'sso', 'saml', 'oauth'. + /// What authentication strategy to use with adduser/login. Some npm + /// registries (for example, npmE) might support alternative auth + /// strategies besides classic username/password entry in legacy npm. + auth_type: Option, + }, +} + +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, + skip_build, + disable_dts, + target, + debug, + } => { + info!(&log, "Running init command..."); + info!( + &log, + "Path: {:?}, Scope: {:?}, Skip build: {}, Disable Dts: {}, Target: {}, Debug: {}", + &path, + &scope, + &skip_build, + &disable_dts, + &target, + debug + ); + let mode = if skip_build { + InitMode::Nobuild + } else { + InitMode::Normal + }; + Init::new(path, scope, disable_dts, target, debug).process(&log, mode) + } + Command::Pack { path } => { + info!(&log, "Running pack command..."); + info!(&log, "Path: {:?}", &path); + pack(path, &log) + } + Command::Publish { path } => { + info!(&log, "Running publish command..."); + info!(&log, "Path: {:?}", &path); + publish(path, &log) + } + Command::Login { + registry, + scope, + always_auth, + auth_type, + } => { + info!(&log, "Running login command..."); + info!( + &log, + "Registry: {:?}, Scope: {:?}, Always Auth: {}, Auth Type: {:?}", + ®istry, + &scope, + &always_auth, + &auth_type + ); + login(registry, scope, always_auth, auth_type, &log) + } + }; + + match status { + Ok(_) => {} + Err(ref e) => { + error!(&log, "{}", e); + PBAR.error(e.error_type())?; + } + } + + // Return the actual status of the program to the main function + status +} diff --git a/src/command/pack.rs b/src/command/pack.rs new file mode 100644 index 00000000..0c8c989f --- /dev/null +++ b/src/command/pack.rs @@ -0,0 +1,20 @@ +use command::utils::set_crate_path; +use error::Error; +use npm; +use slog::Logger; +use std::result; +use PBAR; + +pub fn pack(path: Option, log: &Logger) -> result::Result<(), Error> { + let crate_path = set_crate_path(path); + + info!(&log, "Packing up the npm package..."); + npm::npm_pack(&crate_path)?; + #[cfg(not(target_os = "windows"))] + info!(&log, "Your package is located at {}/pkg", &crate_path); + #[cfg(target_os = "windows")] + info!(&log, "Your package is located at {}\\pkg", &crate_path); + + PBAR.message("🎒 packed up your package!")?; + Ok(()) +} diff --git a/src/command/publish.rs b/src/command/publish.rs new file mode 100644 index 00000000..dd213d02 --- /dev/null +++ b/src/command/publish.rs @@ -0,0 +1,18 @@ +use command::utils::set_crate_path; +use error::Error; +use npm; +use slog::Logger; +use std::result; +use PBAR; + +pub fn publish(path: Option, log: &Logger) -> result::Result<(), Error> { + let crate_path = set_crate_path(path); + + info!(&log, "Publishing the npm package..."); + info!(&log, "npm info located in the npm debug log"); + npm::npm_publish(&crate_path)?; + info!(&log, "Published your package!"); + + PBAR.message("💥 published your package!")?; + Ok(()) +} diff --git a/src/command/utils.rs b/src/command/utils.rs new file mode 100644 index 00000000..ff85ef0d --- /dev/null +++ b/src/command/utils.rs @@ -0,0 +1,8 @@ +pub fn set_crate_path(path: Option) -> String { + let crate_path = match path { + Some(p) => p, + None => ".".to_string(), + }; + + crate_path +} diff --git a/src/manifest.rs b/src/manifest.rs index 703fd3f3..22c95c4b 100644 --- a/src/manifest.rs +++ b/src/manifest.rs @@ -149,11 +149,11 @@ pub fn get_crate_name(path: &str) -> Result { } pub fn check_crate_config(path: &str, step: &Step) -> Result<(), Error> { - let msg = format!("{}Checking crate configuration...", emoji::WRENCH); - PBAR.step(&step, &msg)?; - check_wasm_bindgen(path)?; - check_crate_type(path)?; - Ok(()) + let msg = format!("{}Checking crate configuration...", emoji::WRENCH); + PBAR.step(&step, &msg)?; + check_wasm_bindgen(path)?; + check_crate_type(path)?; + Ok(()) } fn check_wasm_bindgen(path: &str) -> Result<(), Error> { diff --git a/tests/manifest/main.rs b/tests/manifest/main.rs index ebc3e85d..6f2b0393 100644 --- a/tests/manifest/main.rs +++ b/tests/manifest/main.rs @@ -27,24 +27,27 @@ fn it_gets_the_crate_name_provided_path() { #[test] fn it_checks_has_cdylib_default_path() { - assert!(manifest::check_crate_type(".").is_err()); + let step = wasm_pack::progressbar::Step::new(1); + assert!(manifest::check_crate_config(".", &step).is_err()); } #[test] fn it_checks_has_cdylib_provided_path() { - assert!(manifest::check_crate_type("tests/fixtures/js-hello-world").is_ok()); + let step = wasm_pack::progressbar::Step::new(1); + assert!(manifest::check_crate_config("tests/fixtures/js-hello-world", &step).is_ok()); } #[test] fn it_checks_has_cdylib_wrong_crate_type() { - assert!(manifest::check_crate_type("tests/fixtures/bad-cargo-toml").is_err()); + let step = wasm_pack::progressbar::Step::new(1); + assert!(manifest::check_crate_config("tests/fixtures/bad-cargo-toml", &step).is_err()); } #[test] fn it_creates_a_package_json_default_path() { let step = wasm_pack::progressbar::Step::new(1); let path = ".".to_string(); - wasm_pack::command::create_pkg_dir(&path, &step).unwrap(); + wasm_pack::command::init::create_pkg_dir(&path, &step).unwrap(); assert!(manifest::write_package_json(&path, &None, false, &step).is_ok()); let package_json_path = format!("{}/pkg/package.json", &path); assert!(fs::metadata(package_json_path).is_ok()); @@ -66,7 +69,7 @@ fn it_creates_a_package_json_default_path() { fn it_creates_a_package_json_provided_path() { let step = wasm_pack::progressbar::Step::new(1); let path = "tests/fixtures/js-hello-world".to_string(); - wasm_pack::command::create_pkg_dir(&path, &step).unwrap(); + wasm_pack::command::init::create_pkg_dir(&path, &step).unwrap(); assert!(manifest::write_package_json(&path, &None, false, &step).is_ok()); let package_json_path = format!("{}/pkg/package.json", &path); assert!(fs::metadata(package_json_path).is_ok()); @@ -79,7 +82,7 @@ fn it_creates_a_package_json_provided_path() { fn it_creates_a_package_json_provided_path_with_scope() { let step = wasm_pack::progressbar::Step::new(1); let path = "tests/fixtures/scopes".to_string(); - wasm_pack::command::create_pkg_dir(&path, &step).unwrap(); + wasm_pack::command::init::create_pkg_dir(&path, &step).unwrap(); assert!(manifest::write_package_json(&path, &Some("test".to_string()), false, &step).is_ok()); let package_json_path = format!("{}/pkg/package.json", &path); assert!(fs::metadata(package_json_path).is_ok()); @@ -90,10 +93,12 @@ fn it_creates_a_package_json_provided_path_with_scope() { #[test] fn it_errors_when_wasm_bindgen_is_not_declared() { - assert!(manifest::check_wasm_bindgen("tests/fixtures/bad-cargo-toml").is_err()); + let step = wasm_pack::progressbar::Step::new(1); + assert!(manifest::check_crate_config("tests/fixtures/bad-cargo-toml", &step).is_err()); } #[test] fn it_does_not_error_when_wasm_bindgen_is_declared() { - assert!(manifest::check_wasm_bindgen("tests/fixtures/js-hello-world").is_ok()); + let step = wasm_pack::progressbar::Step::new(1); + assert!(manifest::check_crate_config("tests/fixtures/js-hello-world", &step).is_ok()); }