├── npm ├── .gitignore ├── run.js ├── install.js ├── uninstall.js ├── package.json ├── README.md └── binary.js ├── .gitignore ├── src ├── manifest │ ├── npm │ │ ├── repository.rs │ │ ├── mod.rs │ │ └── commonjs.rs │ └── mod.rs ├── cache.rs ├── install │ ├── tool.rs │ ├── krate.rs │ ├── mode.rs │ └── mod.rs ├── target.rs ├── readme.rs ├── emoji.rs ├── command │ ├── mod.rs │ ├── utils.rs │ └── build.rs ├── lib.rs ├── child.rs ├── bindgen.rs ├── main.rs ├── lockfile.rs ├── license.rs ├── progressbar.rs ├── build │ ├── mod.rs │ └── wasm_target.rs ├── wasmedgec.rs ├── wasm_opt.rs └── installer.rs ├── Cargo.toml ├── LICENSE-MIT ├── .github └── workflows │ └── release.yml ├── README.md ├── CODE_OF_CONDUCT.md ├── installer └── init.sh ├── LICENSE-APACHE └── Cargo.lock /npm/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | *.swp 3 | -------------------------------------------------------------------------------- /npm/run.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const { run } = require("./binary"); 4 | run(); 5 | -------------------------------------------------------------------------------- /npm/install.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const { install } = require("./binary"); 4 | install(); 5 | -------------------------------------------------------------------------------- /npm/uninstall.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const { uninstall } = require("./binary"); 4 | uninstall(); 5 | -------------------------------------------------------------------------------- /src/manifest/npm/repository.rs: -------------------------------------------------------------------------------- 1 | #[derive(Serialize)] 2 | pub struct Repository { 3 | #[serde(rename = "type")] 4 | pub ty: String, 5 | pub url: String, 6 | } 7 | -------------------------------------------------------------------------------- /src/manifest/npm/mod.rs: -------------------------------------------------------------------------------- 1 | mod commonjs; 2 | pub mod repository; 3 | 4 | pub use self::commonjs::CommonJSPackage; 5 | 6 | #[derive(Serialize)] 7 | #[serde(untagged)] 8 | pub enum NpmPackage { 9 | CommonJSPackage(CommonJSPackage), 10 | } 11 | -------------------------------------------------------------------------------- /src/cache.rs: -------------------------------------------------------------------------------- 1 | //! Getting and configuring rustwasmc's binary cache. 2 | 3 | use binary_install::Cache; 4 | use std::env; 5 | use std::path::Path; 6 | 7 | /// Get rustwasmc's binary cache. 8 | pub fn get_rustwasmc_cache() -> Result { 9 | if let Ok(path) = env::var("RUSTWASMC_CACHE") { 10 | Ok(Cache::at(Path::new(&path))) 11 | } else { 12 | Cache::new("rustwasmc") 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/install/tool.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | /// Represents the set of CLI tools rustwasmc uses 4 | pub enum Tool { 5 | /// cargo-generate CLI tool 6 | CargoGenerate, 7 | /// wasm-bindgen CLI tools 8 | WasmBindgen, 9 | } 10 | 11 | impl fmt::Display for Tool { 12 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 13 | match self { 14 | Tool::CargoGenerate => write!(f, "cargo-generate"), 15 | Tool::WasmBindgen => write!(f, "wasm-bindgen"), 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/target.rs: -------------------------------------------------------------------------------- 1 | //! Information about the target rustwasmc is currently being compiled for. 2 | //! 3 | //! That is, whether we are building rustwasmc for windows vs linux, and x86 vs 4 | //! x86-64, etc. 5 | 6 | #![allow(missing_docs)] 7 | 8 | pub const LINUX: bool = cfg!(target_os = "linux"); 9 | pub const MACOS: bool = cfg!(target_os = "macos"); 10 | pub const WINDOWS: bool = cfg!(target_os = "windows"); 11 | 12 | #[allow(non_upper_case_globals)] 13 | pub const x86_64: bool = cfg!(target_arch = "x86_64"); 14 | #[allow(non_upper_case_globals)] 15 | pub const x86: bool = cfg!(target_arch = "x86"); 16 | #[allow(non_upper_case_globals)] 17 | pub const aarch64: bool = cfg!(target_arch = "aarch64"); 18 | -------------------------------------------------------------------------------- /src/install/krate.rs: -------------------------------------------------------------------------------- 1 | use install::Tool; 2 | use serde::Deserialize; 3 | 4 | #[derive(Debug, Deserialize)] 5 | pub struct Krate { 6 | pub max_version: String, 7 | } 8 | 9 | #[derive(Debug, Deserialize)] 10 | pub struct KrateResponse { 11 | #[serde(rename = "crate")] 12 | pub krate: Krate, 13 | } 14 | 15 | impl Krate { 16 | pub fn new(name: &Tool) -> Result { 17 | let krate_address = format!("https://crates.io/api/v1/crates/{}", name); 18 | let client = reqwest::Client::new(); 19 | let mut res = client.get(&krate_address).send()?; 20 | 21 | let kr: KrateResponse = serde_json::from_str(&res.text()?)?; 22 | Ok(kr.krate) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/manifest/npm/commonjs.rs: -------------------------------------------------------------------------------- 1 | use manifest::npm::repository::Repository; 2 | 3 | #[derive(Serialize)] 4 | pub struct CommonJSPackage { 5 | pub name: String, 6 | #[serde(skip_serializing_if = "Vec::is_empty")] 7 | pub collaborators: Vec, 8 | #[serde(skip_serializing_if = "Option::is_none")] 9 | pub description: Option, 10 | pub version: String, 11 | #[serde(skip_serializing_if = "Option::is_none")] 12 | pub license: Option, 13 | #[serde(skip_serializing_if = "Option::is_none")] 14 | pub repository: Option, 15 | #[serde(skip_serializing_if = "Vec::is_empty")] 16 | pub files: Vec, 17 | pub main: String, 18 | #[serde(skip_serializing_if = "Option::is_none")] 19 | pub homepage: Option, 20 | #[serde(skip_serializing_if = "Option::is_none")] 21 | pub types: Option, 22 | } 23 | -------------------------------------------------------------------------------- /npm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rustwasmc", 3 | "version": "0.1.29", 4 | "description": "WasmEdge ready tool", 5 | "main": "binary.js", 6 | "scripts": { 7 | "postinstall": "node ./install.js", 8 | "preuninstall": "node ./uninstall.js" 9 | }, 10 | "bin": { 11 | "rustwasmc": "./run.js" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/second-state/rustwasmc.git" 16 | }, 17 | "keywords": [ 18 | "wasm", 19 | "registry", 20 | "cli", 21 | "rust", 22 | "npm", 23 | "package" 24 | ], 25 | "author": "wangshishuo ", 26 | "license": "MIT OR Apache-2.0", 27 | "bugs": { 28 | "url": "https://github.com/second-state/rustwasmc/issues" 29 | }, 30 | "homepage": "https://github.com/second-state/rustwasmc#readme", 31 | "dependencies": { 32 | "binary-install": "0.0.1" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/readme.rs: -------------------------------------------------------------------------------- 1 | //! Generating `README` files for the packaged wasm. 2 | 3 | use failure::{self, ResultExt}; 4 | use std::fs; 5 | use std::path::Path; 6 | 7 | use PBAR; 8 | 9 | /// Copy the crate's README into the `pkg` directory. 10 | pub fn copy_from_crate(path: &Path, out_dir: &Path) -> Result<(), failure::Error> { 11 | assert!( 12 | fs::metadata(path).ok().map_or(false, |m| m.is_dir()), 13 | "crate directory should exist" 14 | ); 15 | assert!( 16 | fs::metadata(&out_dir).ok().map_or(false, |m| m.is_dir()), 17 | "crate's pkg directory should exist" 18 | ); 19 | 20 | let crate_readme_path = path.join("README.md"); 21 | let new_readme_path = out_dir.join("README.md"); 22 | if crate_readme_path.exists() { 23 | fs::copy(&crate_readme_path, &new_readme_path).context("failed to copy README")?; 24 | } else { 25 | PBAR.warn("origin crate has no README"); 26 | } 27 | Ok(()) 28 | } 29 | -------------------------------------------------------------------------------- /npm/README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |

rustwasmc

4 | 5 |

6 | WasmEdge ready tool 7 |

8 |
9 | 10 | ## About 11 | 12 | This tool seeks to be a one-stop shop for building and working with rust- 13 | generated WebAssembly that you would like to interop with JavaScript in [WasmEdge]. 14 | 15 | [WasmEdge]: https://github.com/WasmEdge/WasmEdge 16 | 17 | ## Acknowledgment 18 | 19 | Most of the code for this project comes from [wasm-pack]. 20 | 21 | [wasm-pack]: https://github.com/rustwasm/wasm-pack 22 | 23 | ## Install 24 | 25 | curl https://raw.githubusercontent.com/second-state/rustwasmc/master/installer/init.sh -sSf | sh 26 | 27 | ## Commands 28 | 29 | - `build`: Generate an npm wasm pkg from a rustwasm crate 30 | 31 | ## Logging 32 | 33 | `rustwasmc` uses [`env_logger`] to produce logs when `rustwasmc` runs. 34 | 35 | To configure your log level, use the `RUST_LOG` environment variable. For example: 36 | 37 | ``` 38 | RUST_LOG=info rustwasmc build 39 | ``` 40 | 41 | [`env_logger`]: https://crates.io/crates/env_logger 42 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rustwasmc" 3 | version = "0.1.29" 4 | authors = ["wangshishuo"] 5 | repository = "https://github.com/second-state/rustwasmc.git" 6 | license = "MIT/Apache-2.0" 7 | 8 | [dependencies] 9 | atty = "0.2.11" 10 | cargo_metadata = "0.8.0" 11 | console = "0.6.1" 12 | dialoguer = "0.3.0" 13 | curl = "0.4.13" 14 | dirs = "1.0.4" 15 | env_logger = { version = "0.5.13", default-features = false } 16 | failure = "0.1.2" 17 | human-panic = "1.0.1" 18 | glob = "0.2" 19 | log = "0.4.6" 20 | openssl = { version = '0.10.11', optional = true } 21 | parking_lot = "0.6" 22 | reqwest = "0.9.14" 23 | semver = "0.9.0" 24 | serde = "1.0.74" 25 | serde_derive = "1.0.74" 26 | serde_ignored = "0.0.4" 27 | serde_json = "1.0.26" 28 | strsim = "0.8.0" 29 | siphasher = "0.2.3" 30 | structopt = "0.3" 31 | toml = "0.4" 32 | which = "2.0.0" 33 | binary-install = "0.0.2" 34 | walkdir = "2" 35 | chrono = "0.4.6" 36 | 37 | [dev-dependencies] 38 | assert_cmd = "0.11" 39 | lazy_static = "1.1.0" 40 | predicates = "1.0.0" 41 | serial_test = "0.2" 42 | serial_test_derive = "0.2" 43 | tempfile = "3" 44 | 45 | [features] 46 | vendored-openssl = ['openssl/vendored'] 47 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 Ashley Williams 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /src/emoji.rs: -------------------------------------------------------------------------------- 1 | //! Emoji contants used by `rustwasmc`. 2 | //! 3 | //! For the woefully unfamiliar: 4 | //! 5 | //! > Emoji are ideograms and smileys used in electronic messages and web 6 | //! > pages. Emoji exist in various genres, including facial expressions, common 7 | //! > objects, places and types of weather, and animals. They are much like 8 | //! > emoticons, but emoji are actual pictures instead of typographics. 9 | //! 10 | //! -- https://en.wikipedia.org/wiki/Emoji 11 | 12 | #![allow(missing_docs)] 13 | 14 | use console::Emoji; 15 | 16 | pub static TARGET: Emoji = Emoji("🎯 ", ""); 17 | pub static CYCLONE: Emoji = Emoji("🌀 ", ""); 18 | pub static FOLDER: Emoji = Emoji("📂 ", ""); 19 | pub static MEMO: Emoji = Emoji("📝 ", ""); 20 | pub static DOWN_ARROW: Emoji = Emoji("⬇️ ", ""); 21 | pub static RUNNER: Emoji = Emoji("🏃‍♀️ ", ""); 22 | pub static SPARKLE: Emoji = Emoji("✨ ", ":-)"); 23 | pub static PACKAGE: Emoji = Emoji("📦 ", ":-)"); 24 | pub static WARN: Emoji = Emoji("⚠️ ", ":-)"); 25 | pub static DANCERS: Emoji = Emoji("👯 ", ""); 26 | pub static ERROR: Emoji = Emoji("⛔ ", ""); 27 | pub static INFO: Emoji = Emoji("ℹ️ ", ""); 28 | pub static WRENCH: Emoji = Emoji("🔧 ", ""); 29 | pub static CRAB: Emoji = Emoji("🦀 ", ""); 30 | pub static SHEEP: Emoji = Emoji("🐑 ", ""); 31 | -------------------------------------------------------------------------------- /src/install/mode.rs: -------------------------------------------------------------------------------- 1 | use std::str::FromStr; 2 | 3 | /// The `InstallMode` determines which mode of initialization we are running, and 4 | /// what install steps we perform. 5 | #[derive(Clone, Copy, Debug)] 6 | pub enum InstallMode { 7 | /// Perform all the install steps. 8 | Normal, 9 | /// Don't install tools like `wasm-bindgen`, just use the global 10 | /// environment's existing versions to do builds. 11 | Noinstall, 12 | /// Skip the rustc version check 13 | Force, 14 | } 15 | 16 | impl Default for InstallMode { 17 | fn default() -> InstallMode { 18 | InstallMode::Normal 19 | } 20 | } 21 | 22 | impl FromStr for InstallMode { 23 | type Err = failure::Error; 24 | fn from_str(s: &str) -> Result { 25 | match s { 26 | "no-install" => Ok(InstallMode::Noinstall), 27 | "normal" => Ok(InstallMode::Normal), 28 | "force" => Ok(InstallMode::Force), 29 | _ => bail!("Unknown build mode: {}", s), 30 | } 31 | } 32 | } 33 | 34 | impl InstallMode { 35 | /// Determines if installation is permitted during a function call based on --mode flag 36 | pub fn install_permitted(self) -> bool { 37 | match self { 38 | InstallMode::Normal => true, 39 | InstallMode::Force => true, 40 | InstallMode::Noinstall => false, 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /npm/binary.js: -------------------------------------------------------------------------------- 1 | const { Binary } = require("binary-install"); 2 | const os = require("os"); 3 | const { join } = require("path"); 4 | 5 | const getPlatform = () => { 6 | const type = os.type(); 7 | const arch = os.arch(); 8 | 9 | if (type === "Windows_NT" && arch === "x64") { 10 | return "x86_64-pc-windows-msvc"; 11 | } 12 | if (type === "Linux" && arch === "x64") { 13 | return "x86_64-unknown-linux-gnu"; 14 | } 15 | if (type === "Darwin" && arch === "x64") { 16 | return "x86_64-apple-darwin"; 17 | } 18 | if (type === "Linux" && arch === "arm64") { 19 | return "aarch64-unknown-linux-gnu"; 20 | } 21 | 22 | throw new Error(`Unsupported platform: ${type} ${arch}`); 23 | }; 24 | 25 | const getBinary = () => { 26 | const platform = getPlatform(); 27 | const version = require("./package.json").version; 28 | const author = "second-state"; 29 | const name = "rustwasmc"; 30 | const url = `https://github.com/${author}/${name}/releases/download/v${version}/${name}-v${version}-${platform}.tar.gz`; 31 | return new Binary(url, { name }); 32 | }; 33 | 34 | const run = () => { 35 | const binary = getBinary(); 36 | binary.run(); 37 | }; 38 | 39 | const install = () => { 40 | const binary = getBinary(); 41 | binary.install(); 42 | }; 43 | 44 | const uninstall = () => { 45 | const binary = getBinary(); 46 | binary.uninstall(); 47 | }; 48 | 49 | module.exports = { 50 | install, 51 | run, 52 | uninstall 53 | }; 54 | -------------------------------------------------------------------------------- /src/command/mod.rs: -------------------------------------------------------------------------------- 1 | //! CLI command structures, parsing, and execution. 2 | #![allow(clippy::redundant_closure)] 3 | 4 | pub mod build; 5 | pub mod utils; 6 | 7 | use self::build::{Build, BuildOptions}; 8 | use failure::Error; 9 | use log::info; 10 | use std::result; 11 | 12 | /// The various kinds of commands that `rustwasmc` can execute. 13 | #[derive(Debug, StructOpt)] 14 | pub enum Command { 15 | /// 🏗️ build your npm package! 16 | #[structopt(name = "build")] 17 | Build(BuildOptions), 18 | 19 | /// clean the pkg and target dir 20 | #[structopt(name = "clean")] 21 | Clean{}, 22 | } 23 | 24 | /// Run a command with the given logger! 25 | pub fn run_rustwasmc(command: Command) -> result::Result<(), Error> { 26 | // Run the correct command based off input and store the result of it so that we can clear 27 | // the progress bar then return it 28 | match command { 29 | Command::Build(build_opts) => { 30 | info!("Running build command..."); 31 | // Check rust toolchain first 32 | let o = std::process::Command::new("rustc").arg("--version").output(); 33 | match o { 34 | Err(_e) => bail!("Please follow instructions to install Rust language tools first. https://www.secondstate.io/articles/rustwasmc/ Thank you."), 35 | _ => {} 36 | } 37 | Build::try_from_opts(build_opts).and_then(|mut b| b.run()) 38 | } 39 | Command::Clean{} => { 40 | Build::clean() 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Your favorite rust -> wasmedge workflow tool! 2 | 3 | #![deny(missing_docs)] 4 | 5 | extern crate cargo_metadata; 6 | extern crate console; 7 | extern crate strsim; 8 | #[macro_use] 9 | extern crate failure; 10 | extern crate glob; 11 | extern crate parking_lot; 12 | extern crate semver; 13 | extern crate serde; 14 | extern crate which; 15 | #[macro_use] 16 | extern crate serde_derive; 17 | extern crate serde_ignored; 18 | extern crate serde_json; 19 | #[macro_use] 20 | extern crate structopt; 21 | extern crate binary_install; 22 | extern crate chrono; 23 | extern crate curl; 24 | extern crate dialoguer; 25 | extern crate log; 26 | extern crate toml; 27 | extern crate walkdir; 28 | 29 | pub mod bindgen; 30 | pub mod build; 31 | pub mod cache; 32 | pub mod child; 33 | pub mod command; 34 | pub mod emoji; 35 | pub mod install; 36 | pub mod license; 37 | pub mod lockfile; 38 | pub mod manifest; 39 | pub mod progressbar; 40 | pub mod readme; 41 | pub mod target; 42 | pub mod wasm_opt; 43 | pub mod wasmedgec; 44 | 45 | use progressbar::{LogLevel, ProgressOutput}; 46 | 47 | /// The global progress bar and user-facing message output. 48 | pub static PBAR: ProgressOutput = ProgressOutput::new(); 49 | 50 | /// 📦 ✨ pack and publish your wasm! 51 | #[derive(Debug, StructOpt)] 52 | pub struct Cli { 53 | /// The subcommand to run. 54 | #[structopt(subcommand)] // Note that we mark a field as a subcommand 55 | pub cmd: command::Command, 56 | 57 | /// Log verbosity is based off the number of v used 58 | #[structopt(long = "verbose", short = "v", parse(from_occurrences))] 59 | pub verbosity: u8, 60 | 61 | #[structopt(long = "quiet", short = "q")] 62 | /// No output printed to stdout 63 | pub quiet: bool, 64 | 65 | #[structopt(long = "log-level", default_value = "info")] 66 | /// The maximum level of messages that should be logged by rustwasmc. [possible values: info, warn, error] 67 | pub log_level: LogLevel, 68 | } 69 | -------------------------------------------------------------------------------- /src/child.rs: -------------------------------------------------------------------------------- 1 | //! Utilties for managing child processes. 2 | //! 3 | //! This module helps us ensure that all child processes that we spawn get 4 | //! properly logged and their output is logged as well. 5 | 6 | use failure::Error; 7 | use install::Tool; 8 | use log::info; 9 | use std::process::{Command, Stdio}; 10 | 11 | /// Return a new Command object 12 | pub fn new_command(program: &str) -> Command { 13 | // On Windows, initializes launching as `cmd /c `. 14 | // Initializing only with `Command::new("npm")` will launch 15 | // `npm` with quotes, `"npm"`, causing a run-time error on Windows. 16 | // See rustc: #42436, #42791, #44542 17 | 18 | if cfg!(windows) { 19 | let mut cmd = Command::new("cmd"); 20 | cmd.arg("/c").arg(program); 21 | cmd 22 | } else { 23 | Command::new(program) 24 | } 25 | } 26 | 27 | /// Run the given command and return on success. 28 | pub fn run(mut command: Command, command_name: &str) -> Result<(), Error> { 29 | info!("Running {:?}", command); 30 | 31 | let status = command.status()?; 32 | 33 | if status.success() { 34 | Ok(()) 35 | } else { 36 | bail!( 37 | "failed to execute `{}`: exited with {}\n full command: {:?}", 38 | command_name, 39 | status, 40 | command, 41 | ) 42 | } 43 | } 44 | 45 | /// Run the given command and return its stdout. 46 | pub fn run_capture_stdout(mut command: Command, command_name: &Tool) -> Result { 47 | info!("Running {:?}", command); 48 | 49 | let output = command 50 | .stderr(Stdio::inherit()) 51 | .stdin(Stdio::inherit()) 52 | .output()?; 53 | 54 | if output.status.success() { 55 | Ok(String::from_utf8_lossy(&output.stdout).into_owned()) 56 | } else { 57 | bail!( 58 | "failed to execute `{}`: exited with {}\n full command: {:?}", 59 | command_name, 60 | output.status, 61 | command, 62 | ) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | on: 3 | push: 4 | tags: 5 | - '*' 6 | jobs: 7 | build: 8 | runs-on: ${{ matrix.os }} 9 | strategy: 10 | matrix: 11 | 12 | include: 13 | - os: macos-latest 14 | TARGET: x86_64-apple-darwin 15 | 16 | - os: ubuntu-latest 17 | TARGET: x86_64-unknown-linux-gnu 18 | 19 | - os: windows-latest 20 | TARGET: x86_64-pc-windows-msvc 21 | EXE_SUFFIX: .exe 22 | 23 | steps: 24 | - uses: actions/checkout@v2 25 | - name: Install Rust 26 | uses: actions-rs/toolchain@v1 27 | with: 28 | toolchain: stable 29 | profile: minimal 30 | - name: Get the tag name 31 | shell: bash 32 | id: tag_name 33 | run: echo ::set-output name=version::${GITHUB_REF/refs\/tags\//} 34 | - name: Build 35 | shell: bash 36 | run: | 37 | cargo build --release 38 | mkdir rustwasmc-${{ steps.tag_name.outputs.version }}-${{matrix.TARGET}} 39 | cp ./target/release/rustwasmc${{matrix.EXE_SUFFIX}} rustwasmc-${{ steps.tag_name.outputs.version }}-${{matrix.TARGET}} 40 | tar -czf rustwasmc-${{ steps.tag_name.outputs.version }}-${{matrix.TARGET}}.tar.gz rustwasmc-${{ steps.tag_name.outputs.version }}-${{matrix.TARGET}} 41 | 42 | - name: Release 43 | uses: softprops/action-gh-release@v1 44 | with: 45 | tag_name: ${{ steps.tag_name.outputs.version }} 46 | name: Release ${{ steps.tag_name.outputs.version }} 47 | draft: false 48 | files: rustwasmc-${{ steps.tag_name.outputs.version }}-${{matrix.TARGET}}.tar.gz 49 | env: 50 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 51 | 52 | # Setup .npmrc file to publish to npm 53 | - name: Setup node 54 | if: runner.os == 'Linux' 55 | uses: actions/setup-node@v2 56 | with: 57 | node-version: '12.x' 58 | registry-url: 'https://registry.npmjs.org' 59 | - name: Publish npm 60 | if: runner.os == 'Linux' 61 | run: | 62 | cd npm 63 | npm publish 64 | env: 65 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} -------------------------------------------------------------------------------- /src/bindgen.rs: -------------------------------------------------------------------------------- 1 | //! Functionality related to running `wasm-bindgen`. 2 | 3 | use binary_install::Download; 4 | use child; 5 | use command::build::{BuildProfile}; 6 | use failure::{self, ResultExt}; 7 | use manifest::CrateData; 8 | use std::path::{Path}; 9 | use std::process::Command; 10 | 11 | /// Run the `wasm-bindgen` CLI to generate bindings for the current crate's 12 | /// `.wasm`. 13 | pub fn wasm_bindgen_build( 14 | data: &CrateData, 15 | bindgen: &Download, 16 | out_dir: &Path, 17 | out_name: &Option, 18 | disable_dts: bool, 19 | profile: BuildProfile, 20 | target: &str, 21 | run_target: &str, 22 | enable_aot: bool, 23 | enable_ext: bool, 24 | ) -> Result<(), failure::Error> { 25 | let release_or_debug = match profile { 26 | BuildProfile::Release | BuildProfile::Profiling => "release", 27 | BuildProfile::Dev => "debug", 28 | }; 29 | 30 | let out_dir = out_dir.to_str().unwrap(); 31 | 32 | let dts_arg = if disable_dts { 33 | "--no-typescript" 34 | } else { 35 | "--typescript" 36 | }; 37 | let bindgen_path = bindgen.binary("wasm-bindgen")?; 38 | 39 | for c in data.crate_name().iter() { 40 | let mut cmd = Command::new(&bindgen_path); 41 | cmd.arg("--out-dir") 42 | .arg(out_dir) 43 | .arg(dts_arg); 44 | 45 | cmd.arg("--target").arg(run_target); 46 | 47 | if let Some(value) = out_name { 48 | cmd.arg("--out-name").arg(value); 49 | } 50 | 51 | let profile = data.configured_profile(profile); 52 | if profile.wasm_bindgen_debug_js_glue() { 53 | cmd.arg("--debug"); 54 | } 55 | if !profile.wasm_bindgen_demangle_name_section() { 56 | cmd.arg("--no-demangle"); 57 | } 58 | if profile.wasm_bindgen_dwarf_debug_info() { 59 | cmd.arg("--keep-debug"); 60 | } 61 | if enable_aot { 62 | cmd.arg("--enable-aot"); 63 | } 64 | if enable_ext { 65 | cmd.arg("--enable-ext"); 66 | } 67 | let wasm_path = data 68 | .target_directory() 69 | .join(target) 70 | .join(release_or_debug) 71 | .join(c.as_str()) 72 | .with_extension("wasm"); 73 | cmd.arg(&wasm_path); 74 | child::run(cmd, "wasm-bindgen").context("Running the wasm-bindgen CLI")?; 75 | } 76 | 77 | Ok(()) 78 | } 79 | -------------------------------------------------------------------------------- /src/command/utils.rs: -------------------------------------------------------------------------------- 1 | //! Utility functions for commands. 2 | #![allow(clippy::redundant_closure)] 3 | 4 | use failure; 5 | use std::fs; 6 | use std::path::{Path, PathBuf}; 7 | use std::time::Duration; 8 | use walkdir::WalkDir; 9 | 10 | /// If an explicit path is given, then use it, otherwise assume the current 11 | /// directory is the crate path. 12 | pub fn get_crate_path(path: Option) -> Result { 13 | match path { 14 | Some(p) => Ok(p), 15 | None => find_manifest_from_cwd(), 16 | } 17 | } 18 | 19 | /// Search up the path for the manifest file from the current working directory 20 | /// If we don't find the manifest file then return back the current working directory 21 | /// to provide the appropriate error 22 | fn find_manifest_from_cwd() -> Result { 23 | let mut parent_path = std::env::current_dir()?; 24 | let mut manifest_path = parent_path.join("Cargo.toml"); 25 | loop { 26 | if !manifest_path.is_file() { 27 | if parent_path.pop() { 28 | manifest_path = parent_path.join("Cargo.toml"); 29 | } else { 30 | return Ok(PathBuf::from(".")); 31 | } 32 | } else { 33 | return Ok(parent_path); 34 | } 35 | } 36 | } 37 | 38 | /// Construct our `pkg` directory in the crate. 39 | pub fn create_pkg_dir(out_dir: &Path) -> Result<(), failure::Error> { 40 | fs::create_dir_all(&out_dir)?; 41 | fs::write(out_dir.join(".gitignore"), "*")?; 42 | Ok(()) 43 | } 44 | 45 | /// Locates the pkg directory from a specific path 46 | /// Returns None if unable to find the 'pkg' directory 47 | pub fn find_pkg_directory(path: &Path) -> Option { 48 | if is_pkg_directory(path) { 49 | return Some(path.to_owned()); 50 | } 51 | 52 | WalkDir::new(path) 53 | .into_iter() 54 | .filter_map(|x| x.ok().map(|e| e.into_path())) 55 | .find(|x| is_pkg_directory(&x)) 56 | } 57 | 58 | fn is_pkg_directory(path: &Path) -> bool { 59 | path.exists() && path.is_dir() && path.ends_with("pkg") 60 | } 61 | 62 | /// Render a `Duration` to a form suitable for display on a console 63 | pub fn elapsed(duration: Duration) -> String { 64 | let secs = duration.as_secs(); 65 | 66 | if secs >= 60 { 67 | format!("{}m {:02}s", secs / 60, secs % 60) 68 | } else { 69 | format!("{}.{:02}s", secs, duration.subsec_nanos() / 10_000_000) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::redundant_closure, clippy::redundant_pattern_matching)] 2 | 3 | extern crate atty; 4 | extern crate env_logger; 5 | #[macro_use] 6 | extern crate failure; 7 | extern crate human_panic; 8 | extern crate log; 9 | extern crate structopt; 10 | extern crate rustwasmc; 11 | extern crate which; 12 | 13 | use std::env; 14 | use std::panic; 15 | use structopt::StructOpt; 16 | use rustwasmc::{ 17 | command::run_rustwasmc, 18 | Cli, PBAR, 19 | }; 20 | 21 | mod installer; 22 | 23 | fn main() { 24 | env_logger::init(); 25 | 26 | setup_panic_hooks(); 27 | 28 | if let Err(e) = run() { 29 | eprintln!("Error: {}", e); 30 | for cause in e.iter_causes() { 31 | eprintln!("Caused by: {}", cause); 32 | } 33 | ::std::process::exit(1); 34 | } 35 | } 36 | 37 | fn run() -> Result<(), failure::Error> { 38 | if let Ok(me) = env::current_exe() { 39 | // If we're actually running as the installer then execute our 40 | // self-installation, otherwise just continue as usual. 41 | if me 42 | .file_stem() 43 | .and_then(|s| s.to_str()) 44 | .expect("executable should have a filename") 45 | .starts_with("rustwasmc-init") 46 | { 47 | installer::install(); 48 | } 49 | } 50 | 51 | let args = Cli::from_args(); 52 | 53 | PBAR.set_log_level(args.log_level); 54 | 55 | if args.quiet { 56 | PBAR.set_quiet(true); 57 | } 58 | 59 | run_rustwasmc(args.cmd)?; 60 | 61 | Ok(()) 62 | } 63 | 64 | fn setup_panic_hooks() { 65 | let meta = human_panic::Metadata { 66 | version: env!("CARGO_PKG_VERSION").into(), 67 | name: env!("CARGO_PKG_NAME").into(), 68 | authors: env!("CARGO_PKG_AUTHORS").replace(":", ", ").into(), 69 | homepage: env!("CARGO_PKG_HOMEPAGE").into(), 70 | }; 71 | 72 | let default_hook = panic::take_hook(); 73 | 74 | if let Err(_) = env::var("RUST_BACKTRACE") { 75 | panic::set_hook(Box::new(move |info: &panic::PanicInfo| { 76 | // First call the default hook that prints to standard error. 77 | default_hook(info); 78 | 79 | // Then call human_panic. 80 | let file_path = human_panic::handle_dump(&meta, info); 81 | human_panic::print_msg(file_path, &meta) 82 | .expect("human-panic: printing error message to console failed"); 83 | })); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/lockfile.rs: -------------------------------------------------------------------------------- 1 | //! Reading Cargo.lock lock file. 2 | 3 | #![allow(clippy::new_ret_no_self)] 4 | 5 | use std::fs; 6 | use std::path::PathBuf; 7 | 8 | use console::style; 9 | use failure::{Error, ResultExt}; 10 | use manifest::CrateData; 11 | use toml; 12 | 13 | /// This struct represents the contents of `Cargo.lock`. 14 | #[derive(Clone, Debug, Deserialize)] 15 | pub struct Lockfile { 16 | package: Vec, 17 | } 18 | 19 | /// This struct represents a single package entry in `Cargo.lock` 20 | #[derive(Clone, Debug, Deserialize)] 21 | struct Package { 22 | name: String, 23 | version: String, 24 | } 25 | 26 | impl Lockfile { 27 | /// Read the `Cargo.lock` file for the crate at the given path. 28 | pub fn new(crate_data: &CrateData) -> Result { 29 | let lock_path = get_lockfile_path(crate_data)?; 30 | let lockfile = fs::read_to_string(&lock_path) 31 | .with_context(|_| format!("failed to read: {}", lock_path.display()))?; 32 | let lockfile = toml::from_str(&lockfile) 33 | .with_context(|_| format!("failed to parse: {}", lock_path.display()))?; 34 | Ok(lockfile) 35 | } 36 | 37 | /// Get the version of `wasm-bindgen` dependency used in the `Cargo.lock`. 38 | pub fn wasm_bindgen_version(&self) -> Option<&str> { 39 | self.get_package_version("wasm-bindgen") 40 | } 41 | 42 | /// Like `wasm_bindgen_version`, except it returns an error instead of 43 | /// `None`. 44 | pub fn require_wasm_bindgen(&self) -> Result<&str, Error> { 45 | self.wasm_bindgen_version().ok_or_else(|| { 46 | format_err!( 47 | "Ensure that you have \"{}\" as a dependency in your Cargo.toml file:\n\ 48 | [dependencies]\n\ 49 | wasm-bindgen = \"=0.2.61\"", 50 | style("wasm-bindgen 0.2.61").bold().dim(), 51 | ) 52 | }) 53 | } 54 | 55 | /// Get the version of `wasm-bindgen` dependency used in the `Cargo.lock`. 56 | pub fn wasm_bindgen_test_version(&self) -> Option<&str> { 57 | self.get_package_version("wasm-bindgen-test") 58 | } 59 | 60 | fn get_package_version(&self, package: &str) -> Option<&str> { 61 | self.package 62 | .iter() 63 | .find(|p| p.name == package) 64 | .map(|p| &p.version[..]) 65 | } 66 | } 67 | 68 | /// Given the path to the crate that we are buliding, return a `PathBuf` 69 | /// containing the location of the lock file, by finding the workspace root. 70 | fn get_lockfile_path(crate_data: &CrateData) -> Result { 71 | // Check that a lock file can be found in the directory. Return an error 72 | // if it cannot, otherwise return the path buffer. 73 | let lockfile_path = crate_data.workspace_root().join("Cargo.lock"); 74 | if !lockfile_path.is_file() { 75 | bail!("Could not find lockfile at {:?}", lockfile_path) 76 | } else { 77 | Ok(lockfile_path) 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/license.rs: -------------------------------------------------------------------------------- 1 | //! Copy `LICENSE` file(s) for the packaged wasm. 2 | 3 | use failure; 4 | use std::fs; 5 | use std::path::Path; 6 | 7 | use glob::glob; 8 | use manifest::CrateData; 9 | use PBAR; 10 | 11 | fn glob_license_files(path: &Path) -> Result, failure::Error> { 12 | let mut license_files: Vec = Vec::new(); 13 | let path_string = match path.join("LICENSE*").to_str() { 14 | Some(path_string) => path_string.to_owned(), 15 | None => { 16 | return Err(format_err!( 17 | "Could not convert joined license path to String" 18 | )); 19 | } 20 | }; 21 | 22 | for entry in glob(&path_string)? { 23 | match entry { 24 | Ok(globed_path) => { 25 | let file_name = match globed_path.file_name() { 26 | Some(file_name) => file_name, 27 | None => return Err(format_err!("Could not get file name from path")), 28 | }; 29 | let file_name_string = match file_name.to_str() { 30 | Some(file_name_string) => file_name_string.to_owned(), 31 | None => return Err(format_err!("Could not convert filename to String")), 32 | }; 33 | license_files.push(file_name_string); 34 | } 35 | Err(e) => println!("{:?}", e), 36 | } 37 | } 38 | Ok(license_files) 39 | } 40 | 41 | /// Copy the crate's license into the `pkg` directory. 42 | pub fn copy_from_crate( 43 | crate_data: &CrateData, 44 | path: &Path, 45 | out_dir: &Path, 46 | ) -> Result<(), failure::Error> { 47 | assert!( 48 | fs::metadata(path).ok().map_or(false, |m| m.is_dir()), 49 | "crate directory should exist" 50 | ); 51 | 52 | assert!( 53 | fs::metadata(&out_dir).ok().map_or(false, |m| m.is_dir()), 54 | "crate's pkg directory should exist" 55 | ); 56 | 57 | match (crate_data.crate_license(), crate_data.crate_license_file()) { 58 | (Some(_), _) => { 59 | let license_files = glob_license_files(path); 60 | 61 | match license_files { 62 | Ok(files) => { 63 | if files.is_empty() { 64 | PBAR.info("License key is set in Cargo.toml but no LICENSE file(s) were found; Please add the LICENSE file(s) to your project directory"); 65 | return Ok(()); 66 | } 67 | for license_file in files { 68 | let crate_license_path = path.join(&license_file); 69 | let new_license_path = out_dir.join(&license_file); 70 | if fs::copy(&crate_license_path, &new_license_path).is_err() { 71 | PBAR.info("origin crate has no LICENSE"); 72 | } 73 | } 74 | } 75 | Err(_) => PBAR.info("origin crate has no LICENSE"), 76 | } 77 | } 78 | (None, Some(license_file)) => { 79 | let crate_license_path = path.join(&license_file); 80 | let new_license_path = out_dir.join(&license_file); 81 | if fs::copy(&crate_license_path, &new_license_path).is_err() { 82 | PBAR.info("origin crate has no LICENSE"); 83 | } 84 | } 85 | (None, None) => {} 86 | }; 87 | 88 | Ok(()) 89 | } 90 | -------------------------------------------------------------------------------- /src/progressbar.rs: -------------------------------------------------------------------------------- 1 | //! Fancy progress bar functionality. 2 | 3 | use console::style; 4 | use emoji; 5 | use std::sync::atomic::{AtomicBool, AtomicU8, Ordering}; 6 | 7 | #[repr(u8)] 8 | #[derive(Debug, Clone, Copy)] 9 | /// The maximum log level for rustwasmc 10 | // The ordering is important: the least verbose must be at 11 | // the top and the most verbose at the bottom 12 | pub enum LogLevel { 13 | /// Logs only error 14 | Error, 15 | /// Logs only warn and error 16 | Warn, 17 | /// Logs everything 18 | Info, 19 | } 20 | 21 | impl std::str::FromStr for LogLevel { 22 | type Err = failure::Error; 23 | fn from_str(s: &str) -> Result { 24 | match s { 25 | "error" => Ok(LogLevel::Error), 26 | "warn" => Ok(LogLevel::Warn), 27 | "info" => Ok(LogLevel::Info), 28 | _ => bail!("Unknown log-level: {}", s), 29 | } 30 | } 31 | } 32 | 33 | /// Synchronized progress bar and status message printing. 34 | pub struct ProgressOutput { 35 | quiet: AtomicBool, 36 | log_level: AtomicU8, 37 | } 38 | 39 | impl ProgressOutput { 40 | /// Returns a new ProgressOutput 41 | pub const fn new() -> Self { 42 | Self { 43 | quiet: AtomicBool::new(false), 44 | log_level: AtomicU8::new(LogLevel::Info as u8), 45 | } 46 | } 47 | 48 | /// Print the given message. 49 | fn message(&self, message: &str) { 50 | eprintln!("{}", message); 51 | } 52 | 53 | /// Returns whether it should silence stdout or not 54 | pub fn quiet(&self) -> bool { 55 | self.quiet.load(Ordering::SeqCst) 56 | } 57 | 58 | /// Causes it to silence stdout 59 | pub fn set_quiet(&self, quiet: bool) { 60 | self.quiet.store(quiet, Ordering::SeqCst); 61 | } 62 | 63 | /// Returns whether the specified log level is enabled or not 64 | pub fn is_log_enabled(&self, level: LogLevel) -> bool { 65 | (level as u8) <= self.log_level.load(Ordering::SeqCst) 66 | } 67 | 68 | /// Sets the log level for rustwasmc 69 | pub fn set_log_level(&self, log_level: LogLevel) { 70 | self.log_level.store(log_level as u8, Ordering::SeqCst); 71 | } 72 | 73 | /// Add an informational message. 74 | pub fn info(&self, message: &str) { 75 | if !self.quiet() && self.is_log_enabled(LogLevel::Info) { 76 | let info = format!("{}: {}", style("[INFO]").bold().dim(), message,); 77 | self.message(&info); 78 | } 79 | } 80 | 81 | /// Add a warning message. 82 | pub fn warn(&self, message: &str) { 83 | if !self.quiet() && self.is_log_enabled(LogLevel::Warn) { 84 | let warn = format!( 85 | "{} {}: {}", 86 | emoji::WARN, 87 | style("[WARN]").bold().dim(), 88 | message 89 | ); 90 | self.message(&warn); 91 | } 92 | } 93 | 94 | /// Add an error message. 95 | pub fn error(&self, message: &str) { 96 | if self.is_log_enabled(LogLevel::Error) { 97 | let err = format!( 98 | "{} {}: {}", 99 | emoji::ERROR, 100 | style("[ERR]").bold().dim(), 101 | message 102 | ); 103 | self.message(&err); 104 | } 105 | } 106 | } 107 | 108 | impl Default for ProgressOutput { 109 | fn default() -> Self { 110 | ProgressOutput::new() 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/build/mod.rs: -------------------------------------------------------------------------------- 1 | //! Building a Rust crate into a `.wasm` binary. 2 | 3 | use child; 4 | use command::build::BuildProfile; 5 | use emoji; 6 | use failure::{Error, ResultExt}; 7 | use std::path::Path; 8 | use std::process::Command; 9 | use std::str; 10 | use PBAR; 11 | 12 | pub mod wasm_target; 13 | 14 | /// Ensure that `rustc` is present and that it is >= 1.30.0 15 | pub fn check_rustc_version() -> Result { 16 | let local_minor_version = rustc_minor_version(); 17 | match local_minor_version { 18 | Some(mv) => { 19 | if mv < 30 { 20 | bail!( 21 | "Your version of Rust, '1.{}', is not supported. Please install Rust version 1.30.0 or higher.", 22 | mv.to_string() 23 | ) 24 | } else { 25 | Ok(mv) 26 | } 27 | } 28 | None => bail!("We can't figure out what your Rust version is- which means you might not have Rust installed. Please install Rust version 1.30.0 or higher."), 29 | } 30 | } 31 | 32 | // from https://github.com/alexcrichton/proc-macro2/blob/79e40a113b51836f33214c6d00228934b41bd4ad/build.rs#L44-L61 33 | fn rustc_minor_version() -> Option { 34 | macro_rules! otry { 35 | ($e:expr) => { 36 | match $e { 37 | Some(e) => e, 38 | None => return None, 39 | } 40 | }; 41 | } 42 | let output = otry!(Command::new("rustc").arg("--version").output().ok()); 43 | let version = otry!(str::from_utf8(&output.stdout).ok()); 44 | let mut pieces = version.split('.'); 45 | if pieces.next() != Some("rustc 1") { 46 | return None; 47 | } 48 | otry!(pieces.next()).parse().ok() 49 | } 50 | 51 | /// Run `cargo build`. 52 | pub fn cargo_build_wasm( 53 | path: &Path, 54 | profile: BuildProfile, 55 | target: &str, 56 | extra_options: &[String], 57 | ) -> Result<(), Error> { 58 | let msg = format!("{}Compiling to Wasm...", emoji::CYCLONE); 59 | PBAR.info(&msg); 60 | 61 | let mut cmd = Command::new("cargo"); 62 | cmd.current_dir(path).arg("build").arg("--all-targets"); 63 | 64 | if PBAR.quiet() { 65 | cmd.arg("--quiet"); 66 | } 67 | 68 | match profile { 69 | BuildProfile::Profiling => { 70 | // Once there are DWARF debug info consumers, force enable debug 71 | // info, because builds that use the release cargo profile disables 72 | // debug info. 73 | // 74 | // cmd.env("RUSTFLAGS", "-g"); 75 | cmd.arg("--release"); 76 | } 77 | BuildProfile::Release => { 78 | cmd.arg("--release"); 79 | } 80 | BuildProfile::Dev => { 81 | // Plain cargo builds use the dev cargo profile, which includes 82 | // debug info by default. 83 | } 84 | } 85 | 86 | cmd.arg("--target").arg(target); 87 | cmd.args(extra_options); 88 | child::run(cmd, "cargo build").context("Compiling your crate to WebAssembly failed")?; 89 | Ok(()) 90 | } 91 | 92 | /// Run `cargo build --tests` targetting `wasm32-unknown-unknown`. 93 | /// 94 | /// This generates the `Cargo.lock` file that we use in order to know which version of 95 | /// wasm-bindgen-cli to use when running tests. 96 | pub fn cargo_build_wasm_tests(path: &Path, debug: bool) -> Result<(), Error> { 97 | let mut cmd = Command::new("cargo"); 98 | 99 | cmd.current_dir(path).arg("build").arg("--tests"); 100 | 101 | if PBAR.quiet() { 102 | cmd.arg("--quiet"); 103 | } 104 | 105 | if !debug { 106 | cmd.arg("--release"); 107 | } 108 | 109 | cmd.arg("--target").arg("wasm32-known-known"); 110 | 111 | child::run(cmd, "cargo build").context("Compilation of your program failed")?; 112 | Ok(()) 113 | } 114 | -------------------------------------------------------------------------------- /src/wasmedgec.rs: -------------------------------------------------------------------------------- 1 | //! Support for downloading and executing `wasmedgec` 2 | 3 | use crate::child; 4 | use crate::emoji; 5 | use crate::target; 6 | use crate::PBAR; 7 | use binary_install::Cache; 8 | use log::debug; 9 | use std::path::{Path, PathBuf}; 10 | use std::process::Command; 11 | 12 | /// Execute `wasmedgec` over wasm binaries found in `out_dir`, downloading if 13 | /// necessary into `cache`. Passes `args` to each invocation of `wasmedgec`. 14 | pub fn run( 15 | cache: &Cache, 16 | out_dir: &Path, 17 | install_permitted: bool, 18 | ) -> Result<(), failure::Error> { 19 | let wasmedgec = match find_wasmedgec(cache, install_permitted)? { 20 | SsvmcOpt::Found(path) => path, 21 | SsvmcOpt::CannotInstall => { 22 | PBAR.info("Skipping wasmedgec as no downloading was requested"); 23 | return Ok(()); 24 | } 25 | SsvmcOpt::PlatformNotSupported => { 26 | PBAR.info("You need Ubuntu 20.04 to compile the AOT binary. Please see https://www.secondstate.io/articles/setup-rust-nodejs/"); 27 | return Ok(()); 28 | } 29 | }; 30 | 31 | PBAR.info("Compiling AOT binaries with `wasmedgec`..."); 32 | 33 | for file in out_dir.read_dir()? { 34 | let file = file?; 35 | let path = file.path(); 36 | if path.extension().and_then(|s| s.to_str()) != Some("wasm") { 37 | continue; 38 | } 39 | 40 | let tmp = path.with_extension("so"); 41 | let mut cmd = Command::new(&wasmedgec); 42 | cmd.arg(&path).arg(&tmp); 43 | if let Err(e) = child::run(cmd, "wasmedgec") { 44 | PBAR.info("You need Ubuntu 20.04 to compile the AOT binary. Please see https://www.secondstate.io/articles/setup-rust-nodejs/"); 45 | return Err(e) 46 | } 47 | } 48 | 49 | Ok(()) 50 | } 51 | 52 | /// Possible results of `find_wasmedgec` 53 | pub enum SsvmcOpt { 54 | /// Couldn't install wasmedgec because downloads are forbidden 55 | CannotInstall, 56 | /// The current platform doesn't support precompiled binaries 57 | PlatformNotSupported, 58 | /// We found `wasmedgec` at the specified path 59 | Found(PathBuf), 60 | } 61 | 62 | /// Attempts to find `wasmedgec` in `PATH` locally, or failing that downloads a 63 | /// precompiled binary. 64 | /// 65 | /// Returns `Some` if a binary was found or it was successfully downloaded. 66 | /// Returns `None` if a binary wasn't found in `PATH` and this platform doesn't 67 | /// have precompiled binaries. Returns an error if we failed to download the 68 | /// binary. 69 | pub fn find_wasmedgec(cache: &Cache, install_permitted: bool) -> Result { 70 | // First attempt to look up in PATH. If found assume it works. 71 | if let Ok(path) = which::which("wasmedgec") { 72 | debug!("found wasmedgec at {:?}", path); 73 | return Ok(SsvmcOpt::Found(path)); 74 | } 75 | 76 | // ... and if that fails download a precompiled version. 77 | if target::LINUX && target::x86_64 { 78 | "x86_64-linux" 79 | } else { 80 | return Ok(SsvmcOpt::PlatformNotSupported); 81 | }; 82 | let url = format!( 83 | "https://github.com/WasmEdge/WasmEdge/releases/download/{vers}/WasmEdge-{vers}-manylinux2014_x86_64.tar.gz", 84 | vers = "0.8.1", 85 | ); 86 | 87 | let download = |permit_install| cache.download(permit_install, "wasmedgec", &["wasmedgec"], &url); 88 | 89 | let dl = match download(false)? { 90 | Some(dl) => dl, 91 | None if !install_permitted => return Ok(SsvmcOpt::CannotInstall), 92 | None => { 93 | let msg = format!("{}Installing wasmedgec...", emoji::DOWN_ARROW); 94 | PBAR.info(&msg); 95 | 96 | match download(install_permitted)? { 97 | Some(dl) => dl, 98 | None => return Ok(SsvmcOpt::CannotInstall), 99 | } 100 | } 101 | }; 102 | 103 | Ok(SsvmcOpt::Found(dl.binary("wasmedgec")?)) 104 | } 105 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |

rustwasmc

3 |

4 | Rust compiler toolkit for WebAssembly apps in the WasmEdge Runtime 5 |

6 |
7 | 8 | ![npm](https://img.shields.io/npm/v/rustwasmc) 9 | ![npm](https://img.shields.io/npm/dt/rustwasmc) 10 | ![GitHub language count](https://img.shields.io/github/languages/count/second-state/rustwasmc) 11 | ![GitHub top language](https://img.shields.io/github/languages/top/second-state/rustwasmc) 12 | 13 | Developers: Getting started with the [Second State Functions](https://www.secondstate.io/articles/getting-started-with-function-as-a-service-in-rust/) (a serverless FaaS service), [Tencent Serverless Functions for AI inference](https://github.com/second-state/tencent-tensorflow-scf/blob/main/README-en.md), or [your own Node.js server](https://www.secondstate.io/articles/getting-started-with-rust-function/). 14 | 15 | ## About 16 | 17 | A one-stop tool for building Rust functions into WebAssembly for deployment on the [WasmEdge Runtime](https://github.com/WasmEdge/WasmEdge). 18 | 19 | ## Prerequisite 20 | 21 | You will need to install the Rust compiler in order to use `rustwasmc`. Currently, we support up to Rust 1.50.0. 22 | 23 | ``` 24 | $ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh 25 | $ source $HOME/.cargo/env 26 | ``` 27 | 28 | ## Install 29 | 30 | From Linux command line 31 | 32 | ``` 33 | $ curl https://raw.githubusercontent.com/second-state/rustwasmc/master/installer/init.sh -sSf | sh 34 | ``` 35 | 36 | From NPM and Node.js 37 | 38 | ``` 39 | $ npm install -g rustwasmc # Append --unsafe-perm if permission denied 40 | ``` 41 | 42 | ## Usage 43 | 44 | To build [Rust functions for Node.js](https://www.secondstate.io/articles/getting-started-with-rust-function/) applications, use the following command. See a [template application](https://github.com/second-state/wasmedge-nodejs-starter). The `rustwasmc` compiles and generates the wasm file, and the corresponding JavaScript file to call wasm functions from JavaScript. If the rust package contains only binary crate(s) and there are no library crate, the build command will only generate a `wasm-wasi` file for running as a standalone command program in the WasmEdge VM. 45 | 46 | ``` 47 | $ rustwasmc build 48 | ``` 49 | 50 | In most cases, you will want to enable AOT optimization in order to improve performance. 51 | 52 | ``` 53 | $ rustwasmc build --enable-aot 54 | ``` 55 | 56 | If you would like to use WasmEdge's extended APIs including Tensorflow, enable the extensions. Make sure that you install the `wasmedge-extensions` NPM module in this case. 57 | 58 | ``` 59 | $ rustwasmc build --enable-aot --enable-ext 60 | ``` 61 | 62 | To build Rust functions for Deno applications, use the following command. See a [template application](https://github.com/second-state/ssvm-deno-starter). 63 | 64 | ``` 65 | $ rustwasmc build --target deno 66 | ``` 67 | 68 | By default, rustwasmc will generate a directory for it's build output called pkg. If you'd like to customize this you can use the --out-dir flag. 69 | 70 | ``` 71 | $ rustwasmc build --out-dir out 72 | ``` 73 | 74 | Use clean subcommand to remove pkg and target directories. 75 | ``` 76 | $ rustwasmc clean 77 | ``` 78 | 79 | ## Logging 80 | 81 | `rustwasmc` uses [`env_logger`] to produce logs when `rustwasmc` runs. 82 | 83 | To configure your log level, use the `RUST_LOG` environment variable. For example: 84 | 85 | ``` 86 | $ RUST_LOG=info rustwasmc build 87 | ``` 88 | 89 | [`env_logger`]: https://crates.io/crates/env_logger 90 | 91 | ## Known issues 92 | 93 | For Rust version 1.51 and above, `rustwasmc` generates bytecode without WASI support. That means programs that access the file system, date and time, environment variables, and command line arguments would *fail* on Rust 1.50+. This should not affect most application use cases. We are working on a solution. 94 | 95 | ## Acknowledgment 96 | 97 | This project is derived from the open source [wasm-pack]. 98 | 99 | [wasm-pack]: https://github.com/rustwasm/wasm-pack 100 | -------------------------------------------------------------------------------- /src/wasm_opt.rs: -------------------------------------------------------------------------------- 1 | //! Support for downloading and executing `wasm-opt` 2 | 3 | use crate::child; 4 | use crate::emoji; 5 | use crate::target; 6 | use crate::PBAR; 7 | use binary_install::Cache; 8 | use log::debug; 9 | use std::path::{Path, PathBuf}; 10 | use std::process::Command; 11 | 12 | /// Execute `wasm-opt` over wasm binaries found in `out_dir`, downloading if 13 | /// necessary into `cache`. Passes `args` to each invocation of `wasm-opt`. 14 | pub fn run( 15 | cache: &Cache, 16 | out_dir: &Path, 17 | args: &[String], 18 | install_permitted: bool, 19 | ) -> Result<(), failure::Error> { 20 | let wasm_opt = match find_wasm_opt(cache, install_permitted)? { 21 | WasmOpt::Found(path) => path, 22 | WasmOpt::CannotInstall => { 23 | PBAR.info("Skipping wasm-opt as no downloading was requested"); 24 | return Ok(()); 25 | } 26 | WasmOpt::PlatformNotSupported => { 27 | PBAR.info("Skipping wasm-opt because it is not supported on this platform"); 28 | return Ok(()); 29 | } 30 | }; 31 | 32 | PBAR.info("Optimizing wasm binaries with `wasm-opt`..."); 33 | 34 | for file in out_dir.read_dir()? { 35 | let file = file?; 36 | let path = file.path(); 37 | if path.extension().and_then(|s| s.to_str()) != Some("wasm") { 38 | continue; 39 | } 40 | 41 | let tmp = path.with_extension("wasm-opt.wasm"); 42 | let mut cmd = Command::new(&wasm_opt); 43 | cmd.arg(&path).arg("-o").arg(&tmp).args(args); 44 | child::run(cmd, "wasm-opt")?; 45 | std::fs::rename(&tmp, &path)?; 46 | } 47 | 48 | Ok(()) 49 | } 50 | 51 | /// Possible results of `find_wasm_opt` 52 | pub enum WasmOpt { 53 | /// Couldn't install wasm-opt because downloads are forbidden 54 | CannotInstall, 55 | /// The current platform doesn't support precompiled binaries 56 | PlatformNotSupported, 57 | /// We found `wasm-opt` at the specified path 58 | Found(PathBuf), 59 | } 60 | 61 | /// Attempts to find `wasm-opt` in `PATH` locally, or failing that downloads a 62 | /// precompiled binary. 63 | /// 64 | /// Returns `Some` if a binary was found or it was successfully downloaded. 65 | /// Returns `None` if a binary wasn't found in `PATH` and this platform doesn't 66 | /// have precompiled binaries. Returns an error if we failed to download the 67 | /// binary. 68 | pub fn find_wasm_opt(cache: &Cache, install_permitted: bool) -> Result { 69 | // First attempt to look up in PATH. If found assume it works. 70 | if let Ok(path) = which::which("wasm-opt") { 71 | debug!("found wasm-opt at {:?}", path); 72 | return Ok(WasmOpt::Found(path)); 73 | } 74 | 75 | // ... and if that fails download a precompiled version. 76 | let target = if target::LINUX && target::x86_64 { 77 | "x86_64-linux" 78 | } else if target::MACOS && target::x86_64 { 79 | "x86_64-apple-darwin" 80 | } else if target::WINDOWS && target::x86_64 { 81 | "x86_64-windows" 82 | } else { 83 | return Ok(WasmOpt::PlatformNotSupported); 84 | }; 85 | let url = format!( 86 | "https://github.com/WebAssembly/binaryen/releases/download/{vers}/binaryen-{vers}-{target}.tar.gz", 87 | vers = "version_90", 88 | target = target, 89 | ); 90 | 91 | let download = |permit_install| cache.download(permit_install, "wasm-opt", &["wasm-opt"], &url); 92 | 93 | let dl = match download(false)? { 94 | Some(dl) => dl, 95 | None if !install_permitted => return Ok(WasmOpt::CannotInstall), 96 | None => { 97 | let msg = format!("{}Installing wasm-opt...", emoji::DOWN_ARROW); 98 | PBAR.info(&msg); 99 | 100 | match download(install_permitted)? { 101 | Some(dl) => dl, 102 | None => return Ok(WasmOpt::CannotInstall), 103 | } 104 | } 105 | }; 106 | 107 | Ok(WasmOpt::Found(dl.binary("wasm-opt")?)) 108 | } 109 | -------------------------------------------------------------------------------- /src/installer.rs: -------------------------------------------------------------------------------- 1 | //! Self-installation of `rustwasmc` 2 | //! 3 | //! This module contains one public function which will self-install the 4 | //! currently running executable as `rustwasmc`. Our goal is to install this in 5 | //! a place that's already in `PATH`, ideally in an idiomatic location. To that 6 | //! end we place `rustwasmc` next to the `rustup` executable in `PATH`. 7 | //! 8 | //! This installer is run directly (probably by clicking on it) on Windows, 9 | //! meaning it will pop up a console (as we're a console app). Output goes to 10 | //! the console and users interact with it through the console. On Unix this is 11 | //! intended to be run from a shell script (docs/installer/init.sh) which is 12 | //! downloaded via curl/sh, and then the shell script downloads this executable 13 | //! and runs it. 14 | //! 15 | //! This may get more complicated over time (self upates anyone?) but for now 16 | //! it's pretty simple! We're largely just moving over our currently running 17 | //! executable to a different path. 18 | 19 | use std::env; 20 | use std::fs; 21 | use std::io; 22 | use std::path::Path; 23 | use std::process; 24 | 25 | use atty; 26 | use failure::{self, ResultExt}; 27 | use which; 28 | 29 | pub fn install() -> ! { 30 | if let Err(e) = do_install() { 31 | eprintln!("{}", e); 32 | for cause in e.iter_causes() { 33 | eprintln!("Caused by: {}", cause); 34 | } 35 | } 36 | 37 | // On Windows we likely popped up a console for the installation. If we were 38 | // to exit here immediately then the user wouldn't see any error that 39 | // happened above or any successful message. Let's wait for them to say 40 | // they've read everything and then continue. 41 | if cfg!(windows) { 42 | println!("Press enter to close this window..."); 43 | let mut line = String::new(); 44 | drop(io::stdin().read_line(&mut line)); 45 | } 46 | 47 | process::exit(0); 48 | } 49 | 50 | fn do_install() -> Result<(), failure::Error> { 51 | // Find `rustup.exe` in PATH, we'll be using its installation directory as 52 | // our installation directory. 53 | let rustup = match which::which("rustup") { 54 | Ok(path) => path, 55 | Err(_) => { 56 | bail!( 57 | "failed to find an installation of `rustup` in `PATH`, \ 58 | is rustup already installed?" 59 | ); 60 | } 61 | }; 62 | let installation_dir = match rustup.parent() { 63 | Some(parent) => parent, 64 | None => bail!("can't install when `rustup` is at the root of the filesystem"), 65 | }; 66 | let destination = installation_dir 67 | .join("rustwasmc") 68 | .with_extension(env::consts::EXE_EXTENSION); 69 | 70 | if destination.exists() { 71 | confirm_can_overwrite(&destination)?; 72 | } 73 | 74 | // Our relatively simple install step! 75 | let me = env::current_exe()?; 76 | fs::copy(&me, &destination) 77 | .with_context(|_| format!("failed to copy executable to `{}`", destination.display()))?; 78 | println!( 79 | "info: successfully installed rustwasmc to `{}`", 80 | destination.display() 81 | ); 82 | 83 | // ... and that's it! 84 | 85 | Ok(()) 86 | } 87 | 88 | fn confirm_can_overwrite(dst: &Path) -> Result<(), failure::Error> { 89 | // If the `-f` argument was passed, we can always overwrite everything. 90 | if env::args().any(|arg| arg == "-f") { 91 | return Ok(()); 92 | } 93 | 94 | // If we're not attached to a TTY then we can't get user input, so there's 95 | // nothing to do except inform the user about the `-f` flag. 96 | if !atty::is(atty::Stream::Stdin) { 97 | bail!( 98 | "existing rustwasmc installation found at `{}`, pass `-f` to \ 99 | force installation over this file, otherwise aborting \ 100 | installation now", 101 | dst.display() 102 | ); 103 | } 104 | 105 | // It looks like we're at an interactive prompt, so ask the user if they'd 106 | // like to overwrite the previous installation. 107 | eprintln!( 108 | "info: existing rustwasmc installation found at `{}`", 109 | dst.display() 110 | ); 111 | eprint!("info: would you like to overwrite this file? [y/N]: "); 112 | let mut line = String::new(); 113 | io::stdin() 114 | .read_line(&mut line) 115 | .with_context(|_| "failed to read stdin")?; 116 | 117 | if line.starts_with('y') || line.starts_with('Y') { 118 | return Ok(()); 119 | } 120 | 121 | bail!("aborting installation"); 122 | } 123 | -------------------------------------------------------------------------------- /src/build/wasm_target.rs: -------------------------------------------------------------------------------- 1 | //! Checking for the wasm32 target 2 | 3 | use child; 4 | use emoji; 5 | use failure::{Error, ResultExt}; 6 | use log::info; 7 | use std::fmt; 8 | use std::path::PathBuf; 9 | use std::process::Command; 10 | use PBAR; 11 | 12 | struct Wasm32Check { 13 | rustc_path: PathBuf, 14 | sysroot: PathBuf, 15 | found: bool, 16 | is_rustup: bool, 17 | target: String, 18 | } 19 | 20 | impl fmt::Display for Wasm32Check { 21 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 22 | let target = &self.target; 23 | 24 | if !self.found { 25 | let rustup_string = if self.is_rustup { 26 | "It looks like Rustup is being used.".to_owned() 27 | } else { 28 | format!("It looks like Rustup is not being used. For non-Rustup setups, the {} target needs to be installed manually. See https://rustwasm.github.io/wasm-pack/book/prerequisites/non-rustup-setups.html on how to do this.", target) 29 | }; 30 | 31 | writeln!( 32 | f, 33 | "{} target not found in sysroot: {:?}", 34 | target, self.sysroot 35 | ) 36 | .and_then(|_| { 37 | writeln!( 38 | f, 39 | "\nUsed rustc from the following path: {:?}", 40 | self.rustc_path 41 | ) 42 | }) 43 | .and_then(|_| writeln!(f, "{}", rustup_string)) 44 | } else { 45 | write!( 46 | f, 47 | "sysroot: {:?}, rustc path: {:?}, was found: {}, isRustup: {}", 48 | self.sysroot, self.rustc_path, self.found, self.is_rustup 49 | ) 50 | } 51 | } 52 | } 53 | 54 | /// Ensure that `rustup` has the `wasm32-*` target installed for 55 | /// current toolchain 56 | pub fn check_for_wasm32_target(target: &str) -> Result<(), Error> { 57 | let msg = format!("{}Checking for the Wasm target...", emoji::TARGET); 58 | PBAR.info(&msg); 59 | 60 | // Check if wasm32 target is present, otherwise bail. 61 | match check_wasm32_target(target) { 62 | Ok(ref wasm32_check) if wasm32_check.found => Ok(()), 63 | Ok(wasm32_check) => bail!("{}", wasm32_check), 64 | Err(err) => Err(err), 65 | } 66 | } 67 | 68 | /// Get rustc's sysroot as a PathBuf 69 | fn get_rustc_sysroot() -> Result { 70 | let command = Command::new("rustc") 71 | .args(&["--print", "sysroot"]) 72 | .output()?; 73 | 74 | if command.status.success() { 75 | Ok(String::from_utf8(command.stdout)?.trim().into()) 76 | } else { 77 | Err(format_err!( 78 | "Getting rustc's sysroot wasn't successful. Got {}", 79 | command.status 80 | )) 81 | } 82 | } 83 | 84 | /// Checks if the wasm32 target is present in rustc's sysroot. 85 | fn is_wasm32_target_in_sysroot(sysroot: &PathBuf, wasm32_target: &str) -> bool { 86 | let rustlib_path = sysroot.join("lib/rustlib"); 87 | 88 | info!("Looking for {} in {:?}", wasm32_target, rustlib_path); 89 | 90 | if rustlib_path.join(wasm32_target).exists() { 91 | info!("Found {} in {:?}", wasm32_target, rustlib_path); 92 | true 93 | } else { 94 | info!("Failed to find {} in {:?}", wasm32_target, rustlib_path); 95 | false 96 | } 97 | } 98 | 99 | fn check_wasm32_target(targ: &str) -> Result { 100 | let sysroot = get_rustc_sysroot()?; 101 | let rustc_path = which::which("rustc")?; 102 | let target = targ.to_string(); 103 | 104 | // If wasm32 target already exists we're ok. 105 | if is_wasm32_target_in_sysroot(&sysroot, targ) { 106 | Ok(Wasm32Check { 107 | rustc_path, 108 | sysroot, 109 | found: true, 110 | is_rustup: false, 111 | target, 112 | }) 113 | // If it doesn't exist, then we need to check if we're using rustup. 114 | } else { 115 | // If sysroot contains "rustup", then we can assume we're using rustup 116 | // and use rustup to add the wasm32 target. 117 | if sysroot.to_string_lossy().contains("rustup") { 118 | rustup_add_wasm_target(targ).map(|()| Wasm32Check { 119 | rustc_path, 120 | sysroot, 121 | found: true, 122 | is_rustup: true, 123 | target, 124 | }) 125 | } else { 126 | Ok(Wasm32Check { 127 | rustc_path, 128 | sysroot, 129 | found: false, 130 | is_rustup: false, 131 | target, 132 | }) 133 | } 134 | } 135 | } 136 | 137 | /// Add wasm32 target using `rustup`. 138 | fn rustup_add_wasm_target(target: &str) -> Result<(), Error> { 139 | let mut cmd = Command::new("rustup"); 140 | cmd.arg("target").arg("add").arg(target); 141 | child::run(cmd, "rustup").context(format!("Adding the {} target with rustup", target))?; 142 | 143 | Ok(()) 144 | } 145 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # The Rust Code of Conduct 2 | 3 | A version of this document [can be found online](https://www.rust-lang.org/conduct.html). 4 | 5 | ## Conduct 6 | 7 | **Contact**: [rust-mods@rust-lang.org](mailto:rust-mods@rust-lang.org) 8 | 9 | * We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic. 10 | * On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all. 11 | * Please be kind and courteous. There's no need to be mean or rude. 12 | * Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer. 13 | * Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works. 14 | * We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the Citizen Code of Conduct; if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups. 15 | * Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [Rust moderation team][mod_team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back. 16 | * Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome. 17 | 18 | ## Moderation 19 | 20 | 21 | These are the policies for upholding our community's standards of conduct. If you feel that a thread needs moderation, please contact the [Rust moderation team][mod_team]. 22 | 23 | 1. Remarks that violate the Rust standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.) 24 | 2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed. 25 | 3. Moderators will first respond to such remarks with a warning. 26 | 4. If the warning is unheeded, the user will be "kicked," i.e., kicked out of the communication channel to cool off. 27 | 5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded. 28 | 6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology. 29 | 7. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a different moderator, **in private**. Complaints about bans in-channel are not allowed. 30 | 8. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others. 31 | 32 | In the Rust community we strive to go the extra step to look out for each other. Don't just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they're off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely. 33 | 34 | And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could've communicated better — remember that it's your responsibility to make your fellow Rustaceans comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust. 35 | 36 | The enforcement policies listed above apply to all official Rust venues; including official IRC channels (#rust, #rust-internals, #rust-tools, #rust-libs, #rustc, #rust-beginners, #rust-docs, #rust-community, #rust-lang, and #cargo); GitHub repositories under rust-lang, rust-lang-nursery, and rust-lang-deprecated; and all forums under rust-lang.org (users.rust-lang.org, internals.rust-lang.org). For other projects adopting the Rust Code of Conduct, please contact the maintainers of those projects for enforcement. If you wish to use this code of conduct for your own project, consider explicitly mentioning your moderation policy or making a copy with your own moderation policy so as to avoid confusion. 37 | 38 | *Adapted from the [Node.js Policy on Trolling](http://blog.izs.me/post/30036893703/policy-on-trolling) as well as the [Contributor Covenant v1.3.0](https://www.contributor-covenant.org/version/1/3/0/).* 39 | 40 | [mod_team]: https://www.rust-lang.org/team.html#Moderation-team 41 | -------------------------------------------------------------------------------- /installer/init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2016 The Rust Project Developers. See the COPYRIGHT 3 | # file at the top-level directory of this distribution and at 4 | # http://rust-lang.org/COPYRIGHT. 5 | # 6 | # Licensed under the Apache License, Version 2.0 or the MIT license 8 | # , at your 9 | # option. This file may not be copied, modified, or distributed 10 | # except according to those terms. 11 | 12 | # This is just a little script that can be downloaded from the internet to 13 | # install rustwasmc. It just does platform detection, downloads the installer 14 | # and runs it. 15 | 16 | set -u 17 | 18 | UPDATE_ROOT="https://github.com/second-state/rustwasmc/releases/download/v0.1.29" 19 | 20 | main() { 21 | downloader --check 22 | need_cmd uname 23 | need_cmd mktemp 24 | need_cmd chmod 25 | need_cmd mkdir 26 | need_cmd rm 27 | need_cmd rmdir 28 | need_cmd tar 29 | need_cmd which 30 | need_cmd dirname 31 | 32 | get_architecture || return 1 33 | local _arch="$RETVAL" 34 | assert_nz "$_arch" "arch" 35 | 36 | local _ext="" 37 | case "$_arch" in 38 | *windows*) 39 | _ext=".exe" 40 | ;; 41 | esac 42 | 43 | which rustup > /dev/null 2>&1 44 | need_ok "failed to find Rust installation, is rustup installed?" 45 | local _rustup=`which rustup` 46 | local _tardir="rustwasmc-v0.1.29-${_arch}" 47 | local _url="$UPDATE_ROOT/${_tardir}.tar.gz" 48 | local _dir="$(mktemp -d 2>/dev/null || ensure mktemp -d -t rustwasmc)" 49 | local _file="$_dir/input.tar.gz" 50 | local _rustwasmc="$_dir/rustwasmc$_ext" 51 | local _rustwasmcinit="$_dir/rustwasmc-init$_ext" 52 | 53 | printf '%s\n' 'info: downloading rustwasmc' 1>&2 54 | 55 | ensure mkdir -p "$_dir" 56 | downloader "$_url" "$_file" 57 | if [ $? != 0 ]; then 58 | say "failed to download $_url" 59 | say "this may be a standard network error, but it may also indicate" 60 | say "that rustwasmc's release process is not working. When in doubt" 61 | say "please feel free to open an issue!" 62 | exit 1 63 | fi 64 | ensure tar xf "$_file" --strip-components 1 -C "$_dir" 65 | mv "$_rustwasmc" "$_rustwasmcinit" 66 | 67 | # The installer may want to ask for confirmation on stdin for various 68 | # operations. We were piped through `sh` though so we probably don't have 69 | # access to a tty naturally. If it looks like we're attached to a terminal 70 | # (`-t 1`) then pass the tty down to the installer explicitly. 71 | if [ -t 1 ]; then 72 | "$_rustwasmcinit" "$@" < /dev/tty 73 | else 74 | "$_rustwasmcinit" "$@" 75 | fi 76 | 77 | local _retval=$? 78 | 79 | ignore rm -rf "$_dir" 80 | 81 | return "$_retval" 82 | } 83 | 84 | get_architecture() { 85 | local _ostype="$(uname -s)" 86 | local _cputype="$(uname -m)" 87 | 88 | if [ "$_ostype" = Darwin -a "$_cputype" = i386 ]; then 89 | # Darwin `uname -s` lies 90 | if sysctl hw.optional.x86_64 | grep -q ': 1'; then 91 | local _cputype=x86_64 92 | fi 93 | fi 94 | 95 | case "$_ostype" in 96 | Linux) 97 | local _ostype=unknown-linux-gnu 98 | ;; 99 | 100 | Darwin) 101 | local _ostype=apple-darwin 102 | ;; 103 | 104 | MINGW* | MSYS* | CYGWIN*) 105 | local _ostype=pc-windows-msvc 106 | ;; 107 | 108 | *) 109 | err "no precompiled binaries available for OS: $_ostype" 110 | ;; 111 | esac 112 | 113 | case "$_cputype" in 114 | x86_64 | x86-64 | x64 | amd64) 115 | local _cputype=x86_64 116 | ;; 117 | 118 | aarch64) 119 | local _cputype=aarch64 120 | ;; 121 | 122 | *) 123 | err "no precompiled binaries available for CPU architecture: $_cputype" 124 | 125 | esac 126 | 127 | local _arch="$_cputype-$_ostype" 128 | 129 | RETVAL="$_arch" 130 | } 131 | 132 | say() { 133 | echo "rustwasmc-init: $1" 134 | } 135 | 136 | err() { 137 | say "$1" >&2 138 | exit 1 139 | } 140 | 141 | need_cmd() { 142 | if ! check_cmd "$1" 143 | then err "need '$1' (command not found)" 144 | fi 145 | } 146 | 147 | check_cmd() { 148 | command -v "$1" > /dev/null 2>&1 149 | return $? 150 | } 151 | 152 | need_ok() { 153 | if [ $? != 0 ]; then err "$1"; fi 154 | } 155 | 156 | assert_nz() { 157 | if [ -z "$1" ]; then err "assert_nz $2"; fi 158 | } 159 | 160 | # Run a command that should never fail. If the command fails execution 161 | # will immediately terminate with an error showing the failing 162 | # command. 163 | ensure() { 164 | "$@" 165 | need_ok "command failed: $*" 166 | } 167 | 168 | # This is just for indicating that commands' results are being 169 | # intentionally ignored. Usually, because it's being executed 170 | # as part of error handling. 171 | ignore() { 172 | "$@" 173 | } 174 | 175 | # This wraps curl or wget. Try curl first, if not installed, 176 | # use wget instead. 177 | downloader() { 178 | if check_cmd curl 179 | then _dld=curl 180 | elif check_cmd wget 181 | then _dld=wget 182 | else _dld='curl or wget' # to be used in error message of need_cmd 183 | fi 184 | 185 | if [ "$1" = --check ] 186 | then need_cmd "$_dld" 187 | elif [ "$_dld" = curl ] 188 | then curl -sSfL "$1" -o "$2" 189 | elif [ "$_dld" = wget ] 190 | then wget "$1" -O "$2" 191 | else err "Unknown downloader" # should not reach here 192 | fi 193 | } 194 | 195 | main "$@" || exit 1 196 | -------------------------------------------------------------------------------- /src/install/mod.rs: -------------------------------------------------------------------------------- 1 | //! Functionality related to installing prebuilt binaries and/or running cargo install. 2 | 3 | use self::krate::Krate; 4 | use binary_install::{Cache, Download}; 5 | use child; 6 | use emoji; 7 | use failure::{self, ResultExt}; 8 | use log::debug; 9 | use log::{info}; 10 | use std::env; 11 | use std::fs; 12 | use std::path::PathBuf; 13 | use std::process::Command; 14 | use target; 15 | use which::which; 16 | use PBAR; 17 | use semver::Version; 18 | use curl::easy::Easy; 19 | use serde_json::Value; 20 | 21 | mod krate; 22 | mod mode; 23 | mod tool; 24 | pub use self::mode::InstallMode; 25 | pub use self::tool::Tool; 26 | 27 | /// Install a cargo CLI tool 28 | /// 29 | /// Prefers an existing local install, if any exists. Then checks if there is a 30 | /// global install on `$PATH` that fits the bill. Then attempts to download a 31 | /// tarball from the GitHub releases page, if this target has prebuilt 32 | /// binaries. Finally, falls back to `cargo install`. 33 | pub fn download_prebuilt_or_cargo_install( 34 | tool: Tool, 35 | cache: &Cache, 36 | version: &str, 37 | install_permitted: bool, 38 | ) -> Result { 39 | // If the tool is installed globally and it has the right version, use 40 | // that. Assume that other tools are installed next to it. 41 | // 42 | // This situation can arise if the tool is already installed via 43 | // `cargo install`, for example. 44 | if let Ok(path) = which(tool.to_string()) { 45 | debug!("found global {} binary at: {}", tool, path.display()); 46 | if check_version(&tool, &path, version)? { 47 | return Ok(Download::at(path.parent().unwrap())); 48 | } 49 | } 50 | 51 | let msg = format!("{}Installing {}...", emoji::DOWN_ARROW, tool); 52 | PBAR.info(&msg); 53 | 54 | let dl = download_prebuilt(&tool, &cache, version, install_permitted); 55 | match dl { 56 | Ok(dl) => return Ok(dl), 57 | Err(e) => { 58 | panic!( 59 | "could not download pre-built `{}`: {}.", 60 | tool, e 61 | ); 62 | } 63 | } 64 | 65 | // cargo_install(tool, &cache, version, install_permitted) 66 | } 67 | 68 | /// Check if the tool dependency is locally satisfied. 69 | pub fn check_version( 70 | tool: &Tool, 71 | path: &PathBuf, 72 | expected_version: &str, 73 | ) -> Result { 74 | let expected_version = if expected_version == "latest" { 75 | let krate = Krate::new(tool)?; 76 | krate.max_version 77 | } else { 78 | expected_version.to_string() 79 | }; 80 | 81 | let v = get_cli_version(tool, path)?; 82 | info!( 83 | "Checking installed `{}` version == expected version: {} == {}", 84 | tool, v, &expected_version 85 | ); 86 | Ok(v == expected_version) 87 | } 88 | 89 | /// Fetches the version of a CLI tool 90 | pub fn get_cli_version(tool: &Tool, path: &PathBuf) -> Result { 91 | let mut cmd = Command::new(path); 92 | cmd.arg("--version"); 93 | let stdout = child::run_capture_stdout(cmd, tool)?; 94 | let version = stdout.trim().split_whitespace().nth(1); 95 | match version { 96 | Some(v) => Ok(v.to_string()), 97 | None => bail!("Something went wrong! We couldn't determine your version of the wasm-bindgen CLI. We were supposed to set that up for you, so it's likely not your fault! You should file an issue: https://github.com/second-state/rustwasmc/issues/new?template=bug_report.md.") 98 | } 99 | } 100 | 101 | /// Downloads a precompiled copy of the tool, if available. 102 | pub fn download_prebuilt( 103 | tool: &Tool, 104 | cache: &Cache, 105 | version: &str, 106 | install_permitted: bool, 107 | ) -> Result { 108 | let url = match prebuilt_url(tool, version) { 109 | Ok(url) => url, 110 | Err(e) => bail!( 111 | "no prebuilt {} binaries are available for this platform: {}", 112 | tool, 113 | e, 114 | ), 115 | }; 116 | match tool { 117 | Tool::WasmBindgen => { 118 | // let binaries = &["wasm-bindgen", "wasm-bindgen-test-runner"]; 119 | let binaries = &["wasm-bindgen"]; 120 | match cache.download(install_permitted, "wasm-bindgen", binaries, &url)? { 121 | Some(download) => Ok(download), 122 | None => bail!("wasm-bindgen v{} is not installed!", version), 123 | } 124 | } 125 | Tool::CargoGenerate => { 126 | let binaries = &["cargo-generate"]; 127 | match cache.download(install_permitted, "cargo-generate", binaries, &url)? { 128 | Some(download) => Ok(download), 129 | None => bail!("cargo-generate v{} is not installed!", version), 130 | } 131 | } 132 | } 133 | } 134 | 135 | /// Returns the URL of a precompiled version of wasm-bindgen, if we have one 136 | /// available for our host platform. 137 | fn prebuilt_url(tool: &Tool, version: &str) -> Result { 138 | let target = if target::LINUX && target::x86_64 { 139 | "x86_64-unknown-linux-gnu" 140 | } else if target::MACOS && target::x86_64 { 141 | "x86_64-apple-darwin" 142 | } else if target::WINDOWS && target::x86_64 { 143 | "x86_64-pc-windows-msvc" 144 | } else if target::LINUX && target::aarch64 { 145 | "aarch64-unknown-linux-gnu" 146 | } else { 147 | bail!("Unrecognized target!") 148 | }; 149 | 150 | let semv = Version::parse(version).unwrap(); 151 | let ssvm_ver = get_ssvm_ver(&format!("{}.{}.{}", semv.major, semv.minor, semv.patch)).unwrap(); 152 | 153 | match tool { 154 | Tool::WasmBindgen => { 155 | Ok(format!( 156 | "https://github.com/second-state/wasm-bindgen/releases/download/{0}/wasm-bindgen-{0}-{1}.tar.gz", 157 | ssvm_ver, 158 | target 159 | )) 160 | }, 161 | Tool::CargoGenerate => { 162 | Ok(format!( 163 | "https://github.com/ashleygwilliams/cargo-generate/releases/download/v{0}/cargo-generate-v{0}-{1}.tar.gz", 164 | Krate::new(&Tool::CargoGenerate)?.max_version, 165 | target 166 | )) 167 | } 168 | } 169 | } 170 | 171 | fn get_ssvm_ver(bindgen_semver: &str) -> Result { 172 | let mut vers = String::new(); 173 | let mut retry = false; 174 | 175 | { 176 | let mut handle = Easy::new(); 177 | handle.url("https://raw.githubusercontent.com/second-state/wasm-bindgen/ssvm/bindgen-ssvm-vers.json").unwrap(); 178 | let mut transfer = handle.transfer(); 179 | transfer.write_function(|data| { 180 | vers = String::from_utf8(data.to_vec()).unwrap(); 181 | Ok(data.len()) 182 | }).unwrap(); 183 | if transfer.perform().is_err() { 184 | retry = true; 185 | } 186 | } 187 | if retry { 188 | let mut handle = Easy::new(); 189 | handle.url("https://wasm-bindgen-1302969175.cos.ap-beijing.myqcloud.com/bindgen-ssvm-vers.json").unwrap(); 190 | { 191 | let mut transfer = handle.transfer(); 192 | transfer.write_function(|data| { 193 | vers = String::from_utf8(data.to_vec()).unwrap(); 194 | Ok(data.len()) 195 | }).unwrap(); 196 | transfer.perform().unwrap(); 197 | } 198 | } 199 | 200 | let vers: Value = serde_json::from_str(&vers).unwrap(); 201 | match &vers[bindgen_semver] { 202 | Value::String(sv) => Ok(sv.to_string()), 203 | _ => bail!("no wasmedge mapping for bindgen {}", bindgen_semver) 204 | } 205 | } 206 | 207 | /// Use `cargo install` to install the tool locally into the given 208 | /// crate. 209 | pub fn cargo_install( 210 | tool: Tool, 211 | cache: &Cache, 212 | version: &str, 213 | install_permitted: bool, 214 | ) -> Result { 215 | debug!( 216 | "Attempting to use a `cargo install`ed version of `{}={}`", 217 | tool, version, 218 | ); 219 | 220 | let dirname = format!("{}-cargo-install-{}", tool, version); 221 | let destination = cache.join(dirname.as_ref()); 222 | if destination.exists() { 223 | debug!( 224 | "`cargo install`ed `{}={}` already exists at {}", 225 | tool, 226 | version, 227 | destination.display() 228 | ); 229 | return Ok(Download::at(&destination)); 230 | } 231 | 232 | if !install_permitted { 233 | bail!("{} v{} is not installed!", tool, version) 234 | } 235 | 236 | // Run `cargo install` to a temporary location to handle ctrl-c gracefully 237 | // and ensure we don't accidentally use stale files in the future 238 | let tmp = cache.join(format!(".{}", dirname).as_ref()); 239 | drop(fs::remove_dir_all(&tmp)); 240 | debug!("cargo installing {} to tempdir: {}", tool, tmp.display(),); 241 | 242 | let context = format!("failed to create temp dir for `cargo install {}`", tool); 243 | fs::create_dir_all(&tmp).context(context)?; 244 | 245 | let crate_name = match tool { 246 | Tool::WasmBindgen => "wasm-bindgen-cli".to_string(), 247 | _ => tool.to_string(), 248 | }; 249 | let mut cmd = Command::new("cargo"); 250 | cmd.arg("install") 251 | .arg("--force") 252 | .arg(crate_name) 253 | .arg("--version") 254 | .arg(version) 255 | .arg("--root") 256 | .arg(&tmp); 257 | 258 | if PBAR.quiet() { 259 | cmd.arg("--quiet"); 260 | } 261 | 262 | let context = format!("Installing {} with cargo", tool); 263 | child::run(cmd, "cargo install").context(context)?; 264 | 265 | // `cargo install` will put the installed binaries in `$root/bin/*`, but we 266 | // just want them in `$root/*` directly (which matches how the tarballs are 267 | // laid out, and where the rest of our code expects them to be). So we do a 268 | // little renaming here. 269 | let binaries = match tool { 270 | Tool::WasmBindgen => vec!["wasm-bindgen", "wasm-bindgen-test-runner"], 271 | Tool::CargoGenerate => vec!["cargo-genrate"], 272 | }; 273 | 274 | for b in binaries.iter().cloned() { 275 | let from = tmp 276 | .join("bin") 277 | .join(b) 278 | .with_extension(env::consts::EXE_EXTENSION); 279 | let to = tmp.join(from.file_name().unwrap()); 280 | fs::rename(&from, &to).with_context(|_| { 281 | format!( 282 | "failed to move {} to {} for `cargo install`ed `{}`", 283 | from.display(), 284 | to.display(), 285 | b 286 | ) 287 | })?; 288 | } 289 | 290 | // Finally, move the `tmp` directory into our binary cache. 291 | fs::rename(&tmp, &destination)?; 292 | 293 | Ok(Download::at(&destination)) 294 | } 295 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /src/command/build.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of the `rustwasmc build` command. 2 | 3 | use crate::wasm_opt; 4 | use crate::wasmedgec; 5 | use binary_install::{Cache, Download}; 6 | use bindgen; 7 | use build; 8 | use cache; 9 | use command::utils::{create_pkg_dir, get_crate_path}; 10 | use emoji; 11 | use failure::Error; 12 | use install::{self, InstallMode, Tool}; 13 | use license; 14 | use lockfile::Lockfile; 15 | use log::info; 16 | use manifest; 17 | use readme; 18 | use std::fs; 19 | use std::path::PathBuf; 20 | use std::time::Instant; 21 | use PBAR; 22 | 23 | /// Everything required to configure and run the `rustwasmc build` command. 24 | #[allow(missing_docs)] 25 | pub struct Build { 26 | pub crate_path: PathBuf, 27 | pub crate_data: manifest::CrateData, 28 | pub scope: Option, 29 | pub disable_dts: bool, 30 | pub profile: BuildProfile, 31 | pub mode: InstallMode, 32 | pub target: String, 33 | pub enable_aot: bool, 34 | pub enable_ext: bool, 35 | pub no_wasi: bool, 36 | pub run_target: String, 37 | pub out_dir: PathBuf, 38 | pub out_name: Option, 39 | pub bindgen: Option, 40 | pub cache: Cache, 41 | pub extra_options: Vec, 42 | } 43 | 44 | /// The build profile controls whether optimizations, debug info, and assertions 45 | /// are enabled or disabled. 46 | #[derive(Clone, Copy, Debug)] 47 | pub enum BuildProfile { 48 | /// Enable assertions and debug info. Disable optimizations. 49 | Dev, 50 | /// Enable optimizations. Disable assertions and debug info. 51 | Release, 52 | /// Enable optimizations and debug info. Disable assertions. 53 | Profiling, 54 | } 55 | 56 | /// Everything required to configure and run the `rustwasmc build` command. 57 | #[derive(Debug, StructOpt)] 58 | pub struct BuildOptions { 59 | /// The path to the Rust crate. If not set, searches up the path from the current directory. 60 | #[structopt(parse(from_os_str))] 61 | pub path: Option, 62 | 63 | /// The npm scope to use in package.json, if any. 64 | #[structopt(long = "scope", short = "s")] 65 | pub scope: Option, 66 | 67 | #[structopt(long = "mode", short = "m", default_value = "normal")] 68 | /// Sets steps to be run. [possible values: no-install, normal, force] 69 | pub mode: InstallMode, 70 | 71 | #[structopt(long = "target", default_value = "wasmedge")] 72 | /// Sets the runtime target. [possible values: wasmedge(default), nodejs, deno]. 73 | pub target: String, 74 | 75 | #[structopt(long = "enable-aot")] 76 | /// Enable AOT in WasmEdge 77 | pub enable_aot: bool, 78 | 79 | #[structopt(long = "enable-ext")] 80 | /// Requiring wasmedge-extensions instead of wasmedge 81 | pub enable_ext: bool, 82 | 83 | #[structopt(long = "no-wasi")] 84 | /// Force compiled to target wasm32-unknown-unknown 85 | pub no_wasi: bool, 86 | 87 | #[structopt(skip = true)] 88 | /// By default a *.d.ts file is generated for the generated JS file, but 89 | /// this flag will disable generating this TypeScript file. 90 | pub disable_dts: bool, 91 | 92 | #[structopt(long = "dev")] 93 | /// Create a development build. Enable debug info, and disable 94 | /// optimizations. 95 | pub dev: bool, 96 | 97 | #[structopt(long = "release")] 98 | /// Create a release build. Enable optimizations and disable debug info. 99 | pub release: bool, 100 | 101 | #[structopt(long = "profiling")] 102 | /// Create a profiling build. Enable optimizations and debug info. 103 | pub profiling: bool, 104 | 105 | #[structopt(long = "out-dir", short = "d", default_value = "pkg")] 106 | /// Sets the output directory with a relative path. 107 | pub out_dir: String, 108 | 109 | #[structopt(long = "out-name")] 110 | /// Sets the output file names. Defaults to package name. 111 | pub out_name: Option, 112 | 113 | #[structopt(last = true)] 114 | /// List of extra options to pass to `cargo build` 115 | pub extra_options: Vec, 116 | } 117 | 118 | impl Default for BuildOptions { 119 | fn default() -> Self { 120 | Self { 121 | path: None, 122 | scope: None, 123 | mode: InstallMode::default(), 124 | target: String::from("wasmedge"), 125 | enable_aot: false, 126 | enable_ext: false, 127 | no_wasi: false, 128 | disable_dts: true, 129 | dev: false, 130 | release: false, 131 | profiling: false, 132 | out_dir: String::from("pkg"), 133 | out_name: None, 134 | extra_options: Vec::new(), 135 | } 136 | } 137 | } 138 | 139 | type BuildStep = fn(&mut Build) -> Result<(), Error>; 140 | 141 | impl Build { 142 | /// Construct a build command from the given options. 143 | pub fn try_from_opts(build_opts: BuildOptions) -> Result { 144 | let crate_path = get_crate_path(build_opts.path)?; 145 | let crate_data = manifest::CrateData::new(&crate_path, build_opts.out_name.clone())?; 146 | let out_dir = crate_path.join(PathBuf::from(build_opts.out_dir)); 147 | 148 | let profile = match (build_opts.dev, build_opts.release, build_opts.profiling) { 149 | (false, false, false) | (false, true, false) => BuildProfile::Release, 150 | (true, false, false) => BuildProfile::Dev, 151 | (false, false, true) => BuildProfile::Profiling, 152 | // Unfortunately, `structopt` doesn't expose clap's `conflicts_with` 153 | // functionality yet, so we have to implement it ourselves. 154 | _ => bail!("Can only supply one of the --dev, --release, or --profiling flags"), 155 | }; 156 | 157 | let target = match build_opts.no_wasi { 158 | true => String::from("wasm32-unknown-unknown"), 159 | false => String::from("wasm32-wasi") 160 | }; 161 | 162 | Ok(Build { 163 | crate_path, 164 | crate_data, 165 | scope: build_opts.scope, 166 | disable_dts: build_opts.disable_dts, 167 | profile, 168 | mode: build_opts.mode, 169 | target: target, 170 | enable_aot: build_opts.enable_aot, 171 | enable_ext: build_opts.enable_ext, 172 | no_wasi: build_opts.no_wasi, 173 | run_target: build_opts.target, 174 | out_dir, 175 | out_name: build_opts.out_name, 176 | bindgen: None, 177 | cache: cache::get_rustwasmc_cache()?, 178 | extra_options: build_opts.extra_options, 179 | }) 180 | } 181 | 182 | /// Configures the global binary cache used for this build 183 | pub fn set_cache(&mut self, cache: Cache) { 184 | self.cache = cache; 185 | } 186 | 187 | /// Execute this `Build` command. 188 | pub fn run(&mut self) -> Result<(), Error> { 189 | let process_steps = Build::get_process_steps(self.mode); 190 | 191 | let started = Instant::now(); 192 | 193 | for (_, process_step) in process_steps { 194 | process_step(self)?; 195 | } 196 | 197 | let duration = crate::command::utils::elapsed(started.elapsed()); 198 | info!("Done in {}.", &duration); 199 | info!( 200 | "Your wasm pkg is ready to publish at {}.", 201 | self.out_dir.display() 202 | ); 203 | 204 | PBAR.info(&format!("{} Done in {}", emoji::SPARKLE, &duration)); 205 | 206 | PBAR.info(&format!( 207 | "{} Your wasm pkg is ready to publish at {}.", 208 | emoji::PACKAGE, 209 | self.out_dir.display() 210 | )); 211 | Ok(()) 212 | } 213 | 214 | /// Execute the "clean" command 215 | pub fn clean() -> Result<(), Error> { 216 | let bo = BuildOptions::default(); 217 | let b = Build::try_from_opts(bo)?; 218 | info!("Removing the {} directory...", b.out_dir.display()); 219 | fs::remove_dir_all(b.out_dir)?; 220 | info!("Removing the {} directory...", b.crate_data.target_directory().display()); 221 | fs::remove_dir_all(b.crate_data.target_directory())?; 222 | Ok(()) 223 | } 224 | 225 | fn get_process_steps(mode: InstallMode) -> Vec<(&'static str, BuildStep)> { 226 | macro_rules! steps { 227 | ($($name:ident),+) => { 228 | { 229 | let mut steps: Vec<(&'static str, BuildStep)> = Vec::new(); 230 | $(steps.push((stringify!($name), Build::$name));)* 231 | steps 232 | } 233 | }; 234 | ($($name:ident,)*) => (steps![$($name),*]) 235 | } 236 | let mut steps = Vec::new(); 237 | match &mode { 238 | InstallMode::Force => {} 239 | _ => { 240 | steps.extend(steps![ 241 | step_check_rustc_version, 242 | step_check_crate_config, 243 | step_check_for_wasm_target, 244 | ]); 245 | } 246 | } 247 | steps.extend(steps![ 248 | step_build_wasm, 249 | step_create_dir, 250 | step_copy_readme, 251 | step_copy_license, 252 | step_copy_wasm, 253 | step_install_wasm_bindgen, 254 | step_run_wasm_bindgen, 255 | step_run_wasm_opt, 256 | step_run_wasmedgec, 257 | step_create_json, 258 | ]); 259 | steps 260 | } 261 | 262 | fn step_check_rustc_version(&mut self) -> Result<(), Error> { 263 | info!("Checking rustc version..."); 264 | let version = build::check_rustc_version()?; 265 | let msg = format!("rustc version is {}.", version); 266 | info!("{}", &msg); 267 | Ok(()) 268 | } 269 | 270 | fn step_check_crate_config(&mut self) -> Result<(), Error> { 271 | info!("Checking crate configuration..."); 272 | 273 | // If crate type only contains [bin], which means it will only run in wasi 274 | // then we don't need bindgen as well 275 | if !self.crate_data.check_crate_type()? { 276 | // wasmedge only support wasm-bindgen 0.2.61 277 | let lockfile = Lockfile::new(&self.crate_data)?; 278 | let bindgen_version = lockfile.require_wasm_bindgen()?; 279 | if bindgen_version != "0.2.61" { 280 | bail!("Sorry, rustwasmc only supports wasm-bindgen 0.2.61 at this time. Please fix your Cargo.toml to wasm-bindgen = \"=0.2.61\"") 281 | } 282 | 283 | // wasi lib is not supported from rustc 1.51.0 284 | let rustc_minor_version = build::check_rustc_version().unwrap(); 285 | if rustc_minor_version > 50 && self.target == String::from("wasm32-wasi") { 286 | bail!( 287 | r#"At this time, we can only support Rust compiler version 1.50 and below in order to support WASI features in WasmEdge. Please use this command to set Rust version: 288 | $ rustup override set 1.50.0 289 | If you do not need WASI features, you can use the —no-wasi flag to override this behavior. See more here: https://github.com/WasmEdge/WasmEdge/issues/264"# 290 | ); 291 | } 292 | } 293 | info!("Crate is correctly configured."); 294 | Ok(()) 295 | } 296 | 297 | fn step_check_for_wasm_target(&mut self) -> Result<(), Error> { 298 | info!("Checking for wasm-target..."); 299 | build::wasm_target::check_for_wasm32_target(&self.target)?; 300 | info!("Checking for wasm-target was successful."); 301 | Ok(()) 302 | } 303 | 304 | fn step_build_wasm(&mut self) -> Result<(), Error> { 305 | info!("Building wasm..."); 306 | build::cargo_build_wasm(&self.crate_path, self.profile, &self.target, &self.extra_options)?; 307 | 308 | info!( 309 | "wasm built at {:#?}.", 310 | &self 311 | .crate_path 312 | .join("target") 313 | .join(&self.target) 314 | .join("release") 315 | ); 316 | Ok(()) 317 | } 318 | 319 | fn step_create_dir(&mut self) -> Result<(), Error> { 320 | info!("Creating a pkg directory..."); 321 | create_pkg_dir(&self.out_dir)?; 322 | info!("Created a pkg directory at {:#?}.", &self.crate_path); 323 | Ok(()) 324 | } 325 | 326 | fn step_create_json(&mut self) -> Result<(), Error> { 327 | self.crate_data.write_package_json( 328 | &self.out_dir, 329 | &self.scope, 330 | self.disable_dts, 331 | )?; 332 | info!( 333 | "Wrote a package.json at {:#?}.", 334 | &self.out_dir.join("package.json") 335 | ); 336 | Ok(()) 337 | } 338 | 339 | fn step_copy_readme(&mut self) -> Result<(), Error> { 340 | info!("Copying readme from crate..."); 341 | readme::copy_from_crate(&self.crate_path, &self.out_dir)?; 342 | info!("Copied readme from crate to {:#?}.", &self.out_dir); 343 | Ok(()) 344 | } 345 | 346 | fn step_copy_license(&mut self) -> Result<(), failure::Error> { 347 | info!("Copying license from crate..."); 348 | license::copy_from_crate(&self.crate_data, &self.crate_path, &self.out_dir)?; 349 | info!("Copied license from crate to {:#?}.", &self.out_dir); 350 | Ok(()) 351 | } 352 | 353 | fn step_install_wasm_bindgen(&mut self) -> Result<(), failure::Error> { 354 | // bindgen is only needed in cdylib target 355 | if self.crate_data.check_crate_type()? { 356 | return Ok(()); 357 | } 358 | info!("Identifying wasm-bindgen dependency..."); 359 | let lockfile = Lockfile::new(&self.crate_data)?; 360 | let bindgen_version = lockfile.require_wasm_bindgen()?; 361 | info!("Installing wasm-bindgen-cli..."); 362 | let bindgen = install::download_prebuilt_or_cargo_install( 363 | Tool::WasmBindgen, 364 | &self.cache, 365 | &bindgen_version, 366 | self.mode.install_permitted() 367 | )?; 368 | self.bindgen = Some(bindgen); 369 | info!("Installing wasm-bindgen-cli was successful."); 370 | Ok(()) 371 | } 372 | 373 | fn step_copy_wasm(&mut self) -> Result<(), Error> { 374 | // Only needed in bin target 375 | if !self.crate_data.check_crate_type()? { 376 | return Ok(()); 377 | } 378 | 379 | let release_or_debug = match self.profile { 380 | BuildProfile::Release | BuildProfile::Profiling => "release", 381 | BuildProfile::Dev => "debug", 382 | }; 383 | 384 | for c in self.crate_data.crate_name().iter() { 385 | let wasm_path = self.crate_data 386 | .target_directory() 387 | .join(&self.target) 388 | .join(release_or_debug) 389 | .join(c.as_str()) 390 | .with_extension("wasm"); 391 | let out_wasm_path = self.out_dir.join(c.as_str()).with_extension("wasm"); 392 | fs::copy(&wasm_path, &out_wasm_path)?; 393 | } 394 | 395 | Ok(()) 396 | } 397 | 398 | fn step_run_wasm_bindgen(&mut self) -> Result<(), Error> { 399 | // bindgen is only needed in cdylib target 400 | if self.crate_data.check_crate_type()? { 401 | return Ok(()); 402 | } 403 | info!("Building the wasm bindings..."); 404 | bindgen::wasm_bindgen_build( 405 | &self.crate_data, 406 | self.bindgen.as_ref().unwrap(), 407 | &self.out_dir, 408 | &self.out_name, 409 | self.disable_dts, 410 | self.profile, 411 | &self.target, 412 | &self.run_target, 413 | self.enable_aot, 414 | self.enable_ext, 415 | )?; 416 | info!("wasm bindings were built at {:#?}.", &self.out_dir); 417 | Ok(()) 418 | } 419 | 420 | fn step_run_wasm_opt(&mut self) -> Result<(), Error> { 421 | let args = match self 422 | .crate_data 423 | .configured_profile(self.profile) 424 | .wasm_opt_args() 425 | { 426 | Some(args) => args, 427 | None => return Ok(()), 428 | }; 429 | info!("executing wasm-opt with {:?}", args); 430 | wasm_opt::run( 431 | &self.cache, 432 | &self.out_dir, 433 | &args, 434 | self.mode.install_permitted(), 435 | ).map_err(|e| { 436 | format_err!( 437 | "{}\nTo disable `wasm-opt`, add `wasm-opt = false` to your package metadata in your `Cargo.toml`.", e 438 | ) 439 | }) 440 | } 441 | 442 | fn step_run_wasmedgec(&mut self) -> Result<(), Error> { 443 | if !self.enable_aot { 444 | return Ok(()) 445 | } 446 | wasmedgec::run( 447 | &self.cache, 448 | &self.out_dir, 449 | self.mode.install_permitted(), 450 | )?; 451 | 452 | Ok(()) 453 | } 454 | } 455 | -------------------------------------------------------------------------------- /src/manifest/mod.rs: -------------------------------------------------------------------------------- 1 | //! Reading and writing Cargo.toml and package.json manifests. 2 | 3 | #![allow( 4 | clippy::new_ret_no_self, 5 | clippy::needless_pass_by_value, 6 | clippy::redundant_closure 7 | )] 8 | 9 | mod npm; 10 | 11 | use std::fs; 12 | use std::path::Path; 13 | 14 | use self::npm::{ 15 | repository::Repository, CommonJSPackage, NpmPackage, 16 | }; 17 | use cargo_metadata::Metadata; 18 | use chrono::offset; 19 | use chrono::DateTime; 20 | use command::build::{BuildProfile}; 21 | use curl::easy; 22 | use failure::{Error, ResultExt}; 23 | use serde::{self, Deserialize}; 24 | use serde_json; 25 | use std::collections::BTreeSet; 26 | use std::env; 27 | use std::io::Write; 28 | use strsim::levenshtein; 29 | use toml; 30 | use PBAR; 31 | 32 | const RUSTWASMC_METADATA_KEY: &str = "package.metadata.rustwasmc"; 33 | const RUSTWASMC_VERSION: Option<&'static str> = option_env!("CARGO_PKG_VERSION"); 34 | const RUSTWASMC_REPO_URL: &str = "https://github.com/second-state/rustwasmc"; 35 | 36 | /// Store for metadata learned about a crate 37 | pub struct CrateData { 38 | data: Metadata, 39 | current_idx: usize, 40 | manifest: CargoManifest, 41 | out_name: Option, 42 | } 43 | 44 | #[doc(hidden)] 45 | #[derive(Deserialize)] 46 | pub struct CargoManifest { 47 | package: CargoPackage, 48 | } 49 | 50 | #[derive(Deserialize)] 51 | struct CargoPackage { 52 | name: String, 53 | description: Option, 54 | license: Option, 55 | #[serde(rename = "license-file")] 56 | license_file: Option, 57 | repository: Option, 58 | homepage: Option, 59 | 60 | #[serde(default)] 61 | metadata: CargoMetadata, 62 | } 63 | 64 | #[derive(Default, Deserialize)] 65 | struct CargoMetadata { 66 | #[serde(default, rename = "rustwasmc")] 67 | rustwasmc: CargoRustWasmc, 68 | } 69 | 70 | #[derive(Default, Deserialize)] 71 | struct CargoRustWasmc { 72 | #[serde(default)] 73 | profile: CargoRustWasmcProfiles, 74 | } 75 | 76 | #[derive(Deserialize)] 77 | struct CargoRustWasmcProfiles { 78 | #[serde( 79 | default = "CargoRustWasmcProfile::default_dev", 80 | deserialize_with = "CargoRustWasmcProfile::deserialize_dev" 81 | )] 82 | dev: CargoRustWasmcProfile, 83 | 84 | #[serde( 85 | default = "CargoRustWasmcProfile::default_release", 86 | deserialize_with = "CargoRustWasmcProfile::deserialize_release" 87 | )] 88 | release: CargoRustWasmcProfile, 89 | 90 | #[serde( 91 | default = "CargoRustWasmcProfile::default_profiling", 92 | deserialize_with = "CargoRustWasmcProfile::deserialize_profiling" 93 | )] 94 | profiling: CargoRustWasmcProfile, 95 | } 96 | 97 | impl Default for CargoRustWasmcProfiles { 98 | fn default() -> CargoRustWasmcProfiles { 99 | CargoRustWasmcProfiles { 100 | dev: CargoRustWasmcProfile::default_dev(), 101 | release: CargoRustWasmcProfile::default_release(), 102 | profiling: CargoRustWasmcProfile::default_profiling(), 103 | } 104 | } 105 | } 106 | 107 | /// This is where configuration goes for wasm-bindgen, wasm-opt, wasm-snip, or 108 | /// anything else that rustwasmc runs. 109 | #[derive(Default, Deserialize)] 110 | pub struct CargoRustWasmcProfile { 111 | #[serde(default, rename = "wasm-bindgen")] 112 | wasm_bindgen: CargoRustWasmcProfileWasmBindgen, 113 | #[serde(default, rename = "wasm-opt")] 114 | wasm_opt: Option, 115 | } 116 | 117 | #[derive(Default, Deserialize)] 118 | struct CargoRustWasmcProfileWasmBindgen { 119 | #[serde(default, rename = "debug-js-glue")] 120 | debug_js_glue: Option, 121 | 122 | #[serde(default, rename = "demangle-name-section")] 123 | demangle_name_section: Option, 124 | 125 | #[serde(default, rename = "dwarf-debug-info")] 126 | dwarf_debug_info: Option, 127 | } 128 | 129 | struct Collector(Vec); 130 | 131 | impl easy::Handler for Collector { 132 | fn write(&mut self, data: &[u8]) -> Result { 133 | self.0.extend_from_slice(data); 134 | Ok(data.len()) 135 | } 136 | } 137 | 138 | /// Struct for storing information received from crates.io 139 | #[derive(Deserialize, Debug)] 140 | pub struct Crate { 141 | #[serde(rename = "crate")] 142 | crt: CrateInformation, 143 | } 144 | 145 | #[derive(Deserialize, Debug)] 146 | struct CrateInformation { 147 | max_version: String, 148 | } 149 | 150 | impl Crate { 151 | /// Returns latest rustwasmc version 152 | pub fn return_rustwasmc_latest_version() -> Result, failure::Error> { 153 | let current_time = chrono::offset::Local::now(); 154 | let old_metadata_file = Self::return_rustwasmc_file(); 155 | 156 | match old_metadata_file { 157 | Some(ref file_contents) => { 158 | let last_updated = Self::return_stamp_file_value(&file_contents, "created") 159 | .and_then(|t| DateTime::parse_from_str(t.as_str(), "%+").ok()); 160 | 161 | last_updated 162 | .map(|last_updated| { 163 | if current_time.signed_duration_since(last_updated).num_hours() > 24 { 164 | Self::return_api_call_result(current_time).map(Some) 165 | } else { 166 | Ok(Self::return_stamp_file_value(&file_contents, "version")) 167 | } 168 | }) 169 | .unwrap_or_else(|| Ok(None)) 170 | } 171 | None => Self::return_api_call_result(current_time).map(Some), 172 | } 173 | } 174 | 175 | fn return_api_call_result( 176 | current_time: DateTime, 177 | ) -> Result { 178 | let version = Self::return_latest_rustwasmc_version(); 179 | 180 | // We always override the stamp file with the current time because we don't 181 | // want to hit the API all the time if it fails. It should follow the same 182 | // "policy" as the success. This means that the 24 hours rate limiting 183 | // will be active regardless if the check succeeded or failed. 184 | match version { 185 | Ok(ref version) => Self::override_stamp_file(current_time, Some(&version)).ok(), 186 | Err(_) => Self::override_stamp_file(current_time, None).ok(), 187 | }; 188 | 189 | version 190 | } 191 | 192 | fn override_stamp_file( 193 | current_time: DateTime, 194 | version: Option<&str>, 195 | ) -> Result<(), failure::Error> { 196 | let path = env::current_exe()?; 197 | 198 | let mut file = fs::OpenOptions::new() 199 | .read(true) 200 | .write(true) 201 | .append(true) 202 | .create(true) 203 | .open(path.with_extension("stamp"))?; 204 | 205 | file.set_len(0)?; 206 | 207 | write!(file, "created {:?}", current_time)?; 208 | 209 | if let Some(version) = version { 210 | write!(file, "\nversion {}", version)?; 211 | } 212 | 213 | Ok(()) 214 | } 215 | 216 | /// Return stamp file where metadata is stored. 217 | fn return_rustwasmc_file() -> Option { 218 | if let Ok(path) = env::current_exe() { 219 | if let Ok(file) = fs::read_to_string(path.with_extension("stamp")) { 220 | return Some(file); 221 | } 222 | } 223 | None 224 | } 225 | 226 | /// Returns rustwasmc latest version (if it's received) by executing check_rustwasmc_latest_version function. 227 | fn return_latest_rustwasmc_version() -> Result { 228 | Self::check_rustwasmc_latest_version().map(|crt| crt.crt.max_version) 229 | } 230 | 231 | /// Read the stamp file and return value assigned to a certain key. 232 | fn return_stamp_file_value(file: &str, word: &str) -> Option { 233 | let created = file 234 | .lines() 235 | .find(|line| line.starts_with(word)) 236 | .and_then(|l| l.split_whitespace().nth(1)); 237 | 238 | created.map(|s| s.to_string()) 239 | } 240 | 241 | /// Call to the crates.io api and return the latest version of `rustwasmc` 242 | fn check_rustwasmc_latest_version() -> Result { 243 | let url = "https://crates.io/api/v1/crates/rustwasmc"; 244 | 245 | let mut easy = easy::Easy2::new(Collector(Vec::new())); 246 | 247 | easy.useragent(&format!( 248 | "rustwasmc/{} ({})", 249 | RUSTWASMC_VERSION.unwrap_or_else(|| "unknown"), 250 | RUSTWASMC_REPO_URL 251 | ))?; 252 | 253 | easy.url(url)?; 254 | easy.get(true)?; 255 | easy.perform()?; 256 | 257 | let status_code = easy.response_code()?; 258 | 259 | if 200 <= status_code && status_code < 300 { 260 | let contents = easy.get_ref(); 261 | let result = String::from_utf8_lossy(&contents.0); 262 | 263 | Ok(serde_json::from_str(result.into_owned().as_str())?) 264 | } else { 265 | bail!( 266 | "Received a bad HTTP status code ({}) when checking for newer rustwasmc version at: {}", 267 | status_code, 268 | url 269 | ) 270 | } 271 | } 272 | } 273 | 274 | #[derive(Clone, Deserialize)] 275 | #[serde(untagged)] 276 | enum CargoRustWasmcProfileWasmOpt { 277 | Enabled(bool), 278 | ExplicitArgs(Vec), 279 | } 280 | 281 | impl Default for CargoRustWasmcProfileWasmOpt { 282 | fn default() -> Self { 283 | CargoRustWasmcProfileWasmOpt::Enabled(false) 284 | } 285 | } 286 | 287 | impl CargoRustWasmcProfile { 288 | fn default_dev() -> Self { 289 | CargoRustWasmcProfile { 290 | wasm_bindgen: CargoRustWasmcProfileWasmBindgen { 291 | debug_js_glue: Some(true), 292 | demangle_name_section: Some(true), 293 | dwarf_debug_info: Some(false), 294 | }, 295 | wasm_opt: None, 296 | } 297 | } 298 | 299 | fn default_release() -> Self { 300 | CargoRustWasmcProfile { 301 | wasm_bindgen: CargoRustWasmcProfileWasmBindgen { 302 | debug_js_glue: Some(false), 303 | demangle_name_section: Some(true), 304 | dwarf_debug_info: Some(false), 305 | }, 306 | wasm_opt: Some(CargoRustWasmcProfileWasmOpt::Enabled(true)), 307 | } 308 | } 309 | 310 | fn default_profiling() -> Self { 311 | CargoRustWasmcProfile { 312 | wasm_bindgen: CargoRustWasmcProfileWasmBindgen { 313 | debug_js_glue: Some(false), 314 | demangle_name_section: Some(true), 315 | dwarf_debug_info: Some(false), 316 | }, 317 | wasm_opt: Some(CargoRustWasmcProfileWasmOpt::Enabled(true)), 318 | } 319 | } 320 | 321 | fn deserialize_dev<'de, D>(deserializer: D) -> Result 322 | where 323 | D: serde::Deserializer<'de>, 324 | { 325 | let mut profile = >::deserialize(deserializer)?.unwrap_or_default(); 326 | profile.update_with_defaults(&Self::default_dev()); 327 | Ok(profile) 328 | } 329 | 330 | fn deserialize_release<'de, D>(deserializer: D) -> Result 331 | where 332 | D: serde::Deserializer<'de>, 333 | { 334 | let mut profile = >::deserialize(deserializer)?.unwrap_or_default(); 335 | profile.update_with_defaults(&Self::default_release()); 336 | Ok(profile) 337 | } 338 | 339 | fn deserialize_profiling<'de, D>(deserializer: D) -> Result 340 | where 341 | D: serde::Deserializer<'de>, 342 | { 343 | let mut profile = >::deserialize(deserializer)?.unwrap_or_default(); 344 | profile.update_with_defaults(&Self::default_profiling()); 345 | Ok(profile) 346 | } 347 | 348 | fn update_with_defaults(&mut self, defaults: &Self) { 349 | macro_rules! d { 350 | ( $( $path:ident ).* ) => { 351 | self. $( $path ).* .get_or_insert(defaults. $( $path ).* .unwrap()); 352 | } 353 | } 354 | d!(wasm_bindgen.debug_js_glue); 355 | d!(wasm_bindgen.demangle_name_section); 356 | d!(wasm_bindgen.dwarf_debug_info); 357 | 358 | if self.wasm_opt.is_none() { 359 | self.wasm_opt = defaults.wasm_opt.clone(); 360 | } 361 | } 362 | 363 | /// Get this profile's configured `[wasm-bindgen.debug-js-glue]` value. 364 | pub fn wasm_bindgen_debug_js_glue(&self) -> bool { 365 | self.wasm_bindgen.debug_js_glue.unwrap() 366 | } 367 | 368 | /// Get this profile's configured `[wasm-bindgen.demangle-name-section]` value. 369 | pub fn wasm_bindgen_demangle_name_section(&self) -> bool { 370 | self.wasm_bindgen.demangle_name_section.unwrap() 371 | } 372 | 373 | /// Get this profile's configured `[wasm-bindgen.dwarf-debug-info]` value. 374 | pub fn wasm_bindgen_dwarf_debug_info(&self) -> bool { 375 | self.wasm_bindgen.dwarf_debug_info.unwrap() 376 | } 377 | 378 | /// Get this profile's configured arguments for `wasm-opt`, if enabled. 379 | pub fn wasm_opt_args(&self) -> Option> { 380 | match self.wasm_opt.as_ref()? { 381 | CargoRustWasmcProfileWasmOpt::Enabled(false) => None, 382 | CargoRustWasmcProfileWasmOpt::Enabled(true) => Some(vec!["-O".to_string()]), 383 | CargoRustWasmcProfileWasmOpt::ExplicitArgs(s) => Some(s.clone()), 384 | } 385 | } 386 | } 387 | 388 | struct NpmData { 389 | name: String, 390 | files: Vec, 391 | dts_file: Option, 392 | main: String, 393 | homepage: Option, // https://docs.npmjs.com/files/package.json#homepage 394 | } 395 | 396 | #[doc(hidden)] 397 | pub struct ManifestAndUnsedKeys { 398 | pub manifest: CargoManifest, 399 | pub unused_keys: BTreeSet, 400 | } 401 | 402 | impl CrateData { 403 | /// Reads all metadata for the crate whose manifest is inside the directory 404 | /// specified by `path`. 405 | pub fn new(crate_path: &Path, out_name: Option) -> Result { 406 | let manifest_path = crate_path.join("Cargo.toml"); 407 | if !manifest_path.is_file() { 408 | bail!( 409 | "crate directory is missing a `Cargo.toml` file; is `{}` the \ 410 | wrong directory?", 411 | crate_path.display() 412 | ) 413 | } 414 | 415 | let data = cargo_metadata::MetadataCommand::new() 416 | .manifest_path(&manifest_path) 417 | .exec()?; 418 | 419 | let manifest_and_keys = CrateData::parse_crate_data(&manifest_path)?; 420 | CrateData::warn_for_unused_keys(&manifest_and_keys); 421 | 422 | let manifest = manifest_and_keys.manifest; 423 | let current_idx = data 424 | .packages 425 | .iter() 426 | .position(|pkg| pkg.name == manifest.package.name) 427 | .ok_or_else(|| format_err!("failed to find package in metadata"))?; 428 | 429 | Ok(CrateData { 430 | data, 431 | manifest, 432 | current_idx, 433 | out_name, 434 | }) 435 | } 436 | 437 | /// Read the `manifest_path` file and deserializes it using the toml Deserializer. 438 | /// Returns a Result containing `ManifestAndUnsedKeys` which contains `CargoManifest` 439 | /// and a `BTreeSet` containing the unused keys from the parsed file. 440 | /// 441 | /// # Errors 442 | /// Will return Err if the file (manifest_path) couldn't be read or 443 | /// if deserialize to `CargoManifest` fails. 444 | pub fn parse_crate_data(manifest_path: &Path) -> Result { 445 | let manifest = fs::read_to_string(&manifest_path) 446 | .with_context(|_| format!("failed to read: {}", manifest_path.display()))?; 447 | let manifest = &mut toml::Deserializer::new(&manifest); 448 | 449 | let mut unused_keys = BTreeSet::new(); 450 | let levenshtein_threshold = 1; 451 | 452 | let manifest: CargoManifest = serde_ignored::deserialize(manifest, |path| { 453 | let path_string = path.to_string(); 454 | 455 | if path_string.starts_with("package.metadata") 456 | && (path_string.contains("rustwasmc") 457 | || levenshtein(RUSTWASMC_METADATA_KEY, &path_string) <= levenshtein_threshold) 458 | { 459 | unused_keys.insert(path_string); 460 | } 461 | }) 462 | .with_context(|_| format!("failed to parse manifest: {}", manifest_path.display()))?; 463 | 464 | Ok(ManifestAndUnsedKeys { 465 | manifest, 466 | unused_keys, 467 | }) 468 | } 469 | 470 | /// Iterating through all the passed `unused_keys` and output 471 | /// a warning for each unknown key. 472 | pub fn warn_for_unused_keys(manifest_and_keys: &ManifestAndUnsedKeys) { 473 | manifest_and_keys.unused_keys.iter().for_each(|path| { 474 | PBAR.warn(&format!( 475 | "\"{}\" is an unknown key and will be ignored. Please check your Cargo.toml.", 476 | path 477 | )); 478 | }); 479 | } 480 | 481 | /// Get the configured profile. 482 | pub fn configured_profile(&self, profile: BuildProfile) -> &CargoRustWasmcProfile { 483 | match profile { 484 | BuildProfile::Dev => &self.manifest.package.metadata.rustwasmc.profile.dev, 485 | BuildProfile::Profiling => &self.manifest.package.metadata.rustwasmc.profile.profiling, 486 | BuildProfile::Release => &self.manifest.package.metadata.rustwasmc.profile.release, 487 | } 488 | } 489 | 490 | /// Check that the crate the given path is properly configured. 491 | pub fn check_crate_config(&self) -> Result<(), Error> { 492 | self.check_crate_type()?; 493 | Ok(()) 494 | } 495 | 496 | /// Check the crate type is valid. 497 | /// Return whether [bin] is the only crate type. 498 | pub fn check_crate_type(&self) -> Result { 499 | let pkg = &self.data.packages[self.current_idx]; 500 | let any_cdylib = pkg 501 | .targets 502 | .iter() 503 | .filter(|target| target.kind.iter().any(|k| k == "cdylib")) 504 | .any(|target| target.crate_types.iter().any(|s| s == "cdylib")); 505 | let any_bin = pkg 506 | .targets 507 | .iter() 508 | .filter(|target| target.kind.iter().any(|k| k == "bin")) 509 | .any(|target| target.crate_types.iter().any(|s| s == "bin")); 510 | if any_cdylib || any_bin { 511 | return Ok(!any_cdylib); 512 | } 513 | bail!( 514 | "crate-type must be cdylib or bin to compile to wasm32. Add the following to your \ 515 | Cargo.toml file:\n\n\ 516 | [lib]\n\ 517 | crate-type = [\"cdylib\", \"rlib\"]\n\ 518 | or\n\ 519 | [[bin]]" 520 | ) 521 | } 522 | 523 | /// Get the crate name for the crate at the given path. 524 | pub fn crate_name(&self) -> Vec { 525 | let pkg = &self.data.packages[self.current_idx]; 526 | return pkg 527 | .targets 528 | .iter() 529 | .filter(|t| t.kind.iter().any(|k| k == "cdylib" || k == "bin")) 530 | .map(|t| { 531 | if t.kind.iter().any(|k| k == "bin") { 532 | t.name.clone() 533 | } else { 534 | t.name.replace("-", "_") 535 | } 536 | }) 537 | .collect(); 538 | } 539 | 540 | /// Get the prefix for output file names 541 | pub fn name_prefix(&self) -> String { 542 | match &self.out_name { 543 | Some(value) => value.clone(), 544 | None => self.data.packages[self.current_idx].name.replace("-", "_"), 545 | } 546 | } 547 | 548 | /// Get the license for the crate at the given path. 549 | pub fn crate_license(&self) -> &Option { 550 | &self.manifest.package.license 551 | } 552 | 553 | /// Get the license file path for the crate at the given path. 554 | pub fn crate_license_file(&self) -> &Option { 555 | &self.manifest.package.license_file 556 | } 557 | 558 | /// Returns the path to this project's target directory where artifacts are 559 | /// located after a cargo build. 560 | pub fn target_directory(&self) -> &Path { 561 | Path::new(&self.data.target_directory) 562 | } 563 | 564 | /// Returns the path to this project's root cargo workspace directory 565 | pub fn workspace_root(&self) -> &Path { 566 | Path::new(&self.data.workspace_root) 567 | } 568 | 569 | /// Generate a package.json file inside in `./pkg`. 570 | pub fn write_package_json( 571 | &self, 572 | out_dir: &Path, 573 | scope: &Option, 574 | disable_dts: bool 575 | ) -> Result<(), Error> { 576 | let pkg_file_path = out_dir.join("package.json"); 577 | let npm_data = self.to_commonjs(scope, disable_dts, out_dir); 578 | 579 | let npm_json = serde_json::to_string_pretty(&npm_data)?; 580 | fs::write(&pkg_file_path, npm_json) 581 | .with_context(|_| format!("failed to write: {}", pkg_file_path.display()))?; 582 | Ok(()) 583 | } 584 | 585 | fn npm_data( 586 | &self, 587 | scope: &Option, 588 | include_commonjs_shim: bool, 589 | disable_dts: bool, 590 | out_dir: &Path, 591 | ) -> NpmData { 592 | let name_prefix = self.name_prefix(); 593 | let wasm_file = format!("{}_bg.wasm", name_prefix); 594 | let js_file = format!("{}.js", name_prefix); 595 | let mut files = vec![wasm_file]; 596 | 597 | files.push(js_file.clone()); 598 | if include_commonjs_shim { 599 | let js_bg_file = format!("{}_bg.js", name_prefix); 600 | files.push(js_bg_file); 601 | } 602 | 603 | let pkg = &self.data.packages[self.current_idx]; 604 | let npm_name = match scope { 605 | Some(s) => format!("@{}/{}", s, pkg.name), 606 | None => pkg.name.clone(), 607 | }; 608 | 609 | let dts_file = if !disable_dts { 610 | let file = format!("{}.d.ts", name_prefix); 611 | files.push(file.to_string()); 612 | Some(file) 613 | } else { 614 | None 615 | }; 616 | 617 | if let Ok(entries) = fs::read_dir(out_dir) { 618 | let file_names = entries 619 | .filter_map(|e| e.ok()) 620 | .filter(|e| e.metadata().map(|m| m.is_file()).unwrap_or(false)) 621 | .filter_map(|e| e.file_name().into_string().ok()) 622 | .filter(|f| f.starts_with("LICENSE")) 623 | .filter(|f| f != "LICENSE"); 624 | for file_name in file_names { 625 | files.push(file_name); 626 | } 627 | } 628 | 629 | NpmData { 630 | name: npm_name, 631 | dts_file, 632 | files, 633 | main: js_file, 634 | homepage: self.manifest.package.homepage.clone(), 635 | } 636 | } 637 | 638 | fn license(&self) -> Option { 639 | self.manifest.package.license.clone().or_else(|| { 640 | self.manifest.package.license_file.clone().map(|file| { 641 | // When license is written in file: https://docs.npmjs.com/files/package.json#license 642 | format!("SEE LICENSE IN {}", file) 643 | }) 644 | }) 645 | } 646 | 647 | fn to_commonjs(&self, scope: &Option, disable_dts: bool, out_dir: &Path) -> NpmPackage { 648 | let data = self.npm_data(scope, true, disable_dts, out_dir); 649 | let pkg = &self.data.packages[self.current_idx]; 650 | 651 | self.check_optional_fields(); 652 | 653 | NpmPackage::CommonJSPackage(CommonJSPackage { 654 | name: data.name, 655 | collaborators: pkg.authors.clone(), 656 | description: self.manifest.package.description.clone(), 657 | version: pkg.version.to_string(), 658 | license: self.license(), 659 | repository: self 660 | .manifest 661 | .package 662 | .repository 663 | .clone() 664 | .map(|repo_url| Repository { 665 | ty: "git".to_string(), 666 | url: repo_url, 667 | }), 668 | files: data.files, 669 | main: data.main, 670 | homepage: data.homepage, 671 | types: data.dts_file, 672 | }) 673 | } 674 | 675 | fn check_optional_fields(&self) { 676 | let mut messages = vec![]; 677 | if self.manifest.package.description.is_none() { 678 | messages.push("description"); 679 | } 680 | if self.manifest.package.repository.is_none() { 681 | messages.push("repository"); 682 | } 683 | if self.manifest.package.license.is_none() && self.manifest.package.license_file.is_none() { 684 | messages.push("license"); 685 | } 686 | 687 | match messages.len() { 688 | 1 => PBAR.info(&format!("Optional field missing from Cargo.toml: '{}'. This is not necessary, but recommended", messages[0])), 689 | 2 => PBAR.info(&format!("Optional fields missing from Cargo.toml: '{}', '{}'. These are not necessary, but recommended", messages[0], messages[1])), 690 | 3 => PBAR.info(&format!("Optional fields missing from Cargo.toml: '{}', '{}', and '{}'. These are not necessary, but recommended", messages[0], messages[1], messages[2])), 691 | _ => () 692 | }; 693 | } 694 | } 695 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "adler32" 5 | version = "1.0.4" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | checksum = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2" 8 | 9 | [[package]] 10 | name = "aho-corasick" 11 | version = "0.7.10" 12 | source = "registry+https://github.com/rust-lang/crates.io-index" 13 | checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" 14 | dependencies = [ 15 | "memchr", 16 | ] 17 | 18 | [[package]] 19 | name = "ansi_term" 20 | version = "0.11.0" 21 | source = "registry+https://github.com/rust-lang/crates.io-index" 22 | checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" 23 | dependencies = [ 24 | "winapi 0.3.8", 25 | ] 26 | 27 | [[package]] 28 | name = "arrayref" 29 | version = "0.3.6" 30 | source = "registry+https://github.com/rust-lang/crates.io-index" 31 | checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" 32 | 33 | [[package]] 34 | name = "arrayvec" 35 | version = "0.5.1" 36 | source = "registry+https://github.com/rust-lang/crates.io-index" 37 | checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" 38 | 39 | [[package]] 40 | name = "assert_cmd" 41 | version = "0.11.1" 42 | source = "registry+https://github.com/rust-lang/crates.io-index" 43 | checksum = "2dc477793bd82ec39799b6f6b3df64938532fdf2ab0d49ef817eac65856a5a1e" 44 | dependencies = [ 45 | "escargot", 46 | "predicates", 47 | "predicates-core", 48 | "predicates-tree", 49 | ] 50 | 51 | [[package]] 52 | name = "atty" 53 | version = "0.2.14" 54 | source = "registry+https://github.com/rust-lang/crates.io-index" 55 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 56 | dependencies = [ 57 | "hermit-abi", 58 | "libc", 59 | "winapi 0.3.8", 60 | ] 61 | 62 | [[package]] 63 | name = "autocfg" 64 | version = "0.1.7" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" 67 | 68 | [[package]] 69 | name = "autocfg" 70 | version = "1.0.0" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" 73 | 74 | [[package]] 75 | name = "backtrace" 76 | version = "0.3.45" 77 | source = "registry+https://github.com/rust-lang/crates.io-index" 78 | checksum = "ad235dabf00f36301792cfe82499880ba54c6486be094d1047b02bacb67c14e8" 79 | dependencies = [ 80 | "backtrace-sys", 81 | "cfg-if", 82 | "libc", 83 | "rustc-demangle", 84 | ] 85 | 86 | [[package]] 87 | name = "backtrace-sys" 88 | version = "0.1.34" 89 | source = "registry+https://github.com/rust-lang/crates.io-index" 90 | checksum = "ca797db0057bae1a7aa2eef3283a874695455cecf08a43bfb8507ee0ebc1ed69" 91 | dependencies = [ 92 | "cc", 93 | "libc", 94 | ] 95 | 96 | [[package]] 97 | name = "base64" 98 | version = "0.10.1" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" 101 | dependencies = [ 102 | "byteorder", 103 | ] 104 | 105 | [[package]] 106 | name = "base64" 107 | version = "0.11.0" 108 | source = "registry+https://github.com/rust-lang/crates.io-index" 109 | checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" 110 | 111 | [[package]] 112 | name = "binary-install" 113 | version = "0.0.2" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "7b5bc5f8c50dd6a80d0b303ddab79f42ddcb52fd43d68107ecf622c551fd4cd4" 116 | dependencies = [ 117 | "curl", 118 | "dirs", 119 | "failure", 120 | "flate2", 121 | "hex", 122 | "is_executable", 123 | "siphasher", 124 | "tar", 125 | "zip", 126 | ] 127 | 128 | [[package]] 129 | name = "bitflags" 130 | version = "1.2.1" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 133 | 134 | [[package]] 135 | name = "blake2b_simd" 136 | version = "0.5.10" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" 139 | dependencies = [ 140 | "arrayref", 141 | "arrayvec", 142 | "constant_time_eq", 143 | ] 144 | 145 | [[package]] 146 | name = "byteorder" 147 | version = "1.3.4" 148 | source = "registry+https://github.com/rust-lang/crates.io-index" 149 | checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" 150 | 151 | [[package]] 152 | name = "bytes" 153 | version = "0.4.12" 154 | source = "registry+https://github.com/rust-lang/crates.io-index" 155 | checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" 156 | dependencies = [ 157 | "byteorder", 158 | "either", 159 | "iovec", 160 | ] 161 | 162 | [[package]] 163 | name = "bzip2" 164 | version = "0.3.3" 165 | source = "registry+https://github.com/rust-lang/crates.io-index" 166 | checksum = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b" 167 | dependencies = [ 168 | "bzip2-sys", 169 | "libc", 170 | ] 171 | 172 | [[package]] 173 | name = "bzip2-sys" 174 | version = "0.1.8+1.0.8" 175 | source = "registry+https://github.com/rust-lang/crates.io-index" 176 | checksum = "05305b41c5034ff0e93937ac64133d109b5a2660114ec45e9760bc6816d83038" 177 | dependencies = [ 178 | "cc", 179 | "libc", 180 | ] 181 | 182 | [[package]] 183 | name = "cargo_metadata" 184 | version = "0.8.2" 185 | source = "registry+https://github.com/rust-lang/crates.io-index" 186 | checksum = "700b3731fd7d357223d0000f4dbf1808401b694609035c3c411fbc0cd375c426" 187 | dependencies = [ 188 | "semver", 189 | "serde", 190 | "serde_derive", 191 | "serde_json", 192 | ] 193 | 194 | [[package]] 195 | name = "cc" 196 | version = "1.0.50" 197 | source = "registry+https://github.com/rust-lang/crates.io-index" 198 | checksum = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" 199 | 200 | [[package]] 201 | name = "cfg-if" 202 | version = "0.1.10" 203 | source = "registry+https://github.com/rust-lang/crates.io-index" 204 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 205 | 206 | [[package]] 207 | name = "chrono" 208 | version = "0.4.11" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | checksum = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" 211 | dependencies = [ 212 | "num-integer", 213 | "num-traits", 214 | "time", 215 | ] 216 | 217 | [[package]] 218 | name = "clap" 219 | version = "2.33.0" 220 | source = "registry+https://github.com/rust-lang/crates.io-index" 221 | checksum = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" 222 | dependencies = [ 223 | "ansi_term", 224 | "atty", 225 | "bitflags", 226 | "strsim", 227 | "textwrap", 228 | "unicode-width", 229 | "vec_map", 230 | ] 231 | 232 | [[package]] 233 | name = "clicolors-control" 234 | version = "0.2.0" 235 | source = "registry+https://github.com/rust-lang/crates.io-index" 236 | checksum = "1f84dec9bc083ce2503908cd305af98bd363da6f54bf8d4bf0ac14ee749ad5d1" 237 | dependencies = [ 238 | "kernel32-sys", 239 | "lazy_static 0.2.11", 240 | "libc", 241 | "winapi 0.3.8", 242 | ] 243 | 244 | [[package]] 245 | name = "clicolors-control" 246 | version = "1.0.1" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | checksum = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e" 249 | dependencies = [ 250 | "atty", 251 | "lazy_static 1.4.0", 252 | "libc", 253 | "winapi 0.3.8", 254 | ] 255 | 256 | [[package]] 257 | name = "cloudabi" 258 | version = "0.0.3" 259 | source = "registry+https://github.com/rust-lang/crates.io-index" 260 | checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" 261 | dependencies = [ 262 | "bitflags", 263 | ] 264 | 265 | [[package]] 266 | name = "console" 267 | version = "0.6.2" 268 | source = "registry+https://github.com/rust-lang/crates.io-index" 269 | checksum = "ecd48adf136733979b49e15bc3b4c43cc0d3c85ece7bd08e6daa414c6fcb13e6" 270 | dependencies = [ 271 | "atty", 272 | "clicolors-control 0.2.0", 273 | "lazy_static 1.4.0", 274 | "libc", 275 | "parking_lot 0.10.0", 276 | "regex", 277 | "termios", 278 | "unicode-width", 279 | "winapi 0.3.8", 280 | ] 281 | 282 | [[package]] 283 | name = "console" 284 | version = "0.10.0" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | checksum = "6728a28023f207181b193262711102bfbaf47cc9d13bc71d0736607ef8efe88c" 287 | dependencies = [ 288 | "clicolors-control 1.0.1", 289 | "encode_unicode", 290 | "lazy_static 1.4.0", 291 | "libc", 292 | "regex", 293 | "termios", 294 | "unicode-width", 295 | "winapi 0.3.8", 296 | ] 297 | 298 | [[package]] 299 | name = "constant_time_eq" 300 | version = "0.1.5" 301 | source = "registry+https://github.com/rust-lang/crates.io-index" 302 | checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" 303 | 304 | [[package]] 305 | name = "cookie" 306 | version = "0.12.0" 307 | source = "registry+https://github.com/rust-lang/crates.io-index" 308 | checksum = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5" 309 | dependencies = [ 310 | "time", 311 | "url 1.7.2", 312 | ] 313 | 314 | [[package]] 315 | name = "cookie_store" 316 | version = "0.7.0" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | checksum = "46750b3f362965f197996c4448e4a0935e791bf7d6631bfce9ee0af3d24c919c" 319 | dependencies = [ 320 | "cookie", 321 | "failure", 322 | "idna 0.1.5", 323 | "log", 324 | "publicsuffix", 325 | "serde", 326 | "serde_json", 327 | "time", 328 | "try_from", 329 | "url 1.7.2", 330 | ] 331 | 332 | [[package]] 333 | name = "core-foundation" 334 | version = "0.7.0" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" 337 | dependencies = [ 338 | "core-foundation-sys", 339 | "libc", 340 | ] 341 | 342 | [[package]] 343 | name = "core-foundation-sys" 344 | version = "0.7.0" 345 | source = "registry+https://github.com/rust-lang/crates.io-index" 346 | checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" 347 | 348 | [[package]] 349 | name = "crc32fast" 350 | version = "1.2.0" 351 | source = "registry+https://github.com/rust-lang/crates.io-index" 352 | checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" 353 | dependencies = [ 354 | "cfg-if", 355 | ] 356 | 357 | [[package]] 358 | name = "crossbeam-deque" 359 | version = "0.7.3" 360 | source = "registry+https://github.com/rust-lang/crates.io-index" 361 | checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" 362 | dependencies = [ 363 | "crossbeam-epoch", 364 | "crossbeam-utils", 365 | "maybe-uninit", 366 | ] 367 | 368 | [[package]] 369 | name = "crossbeam-epoch" 370 | version = "0.8.2" 371 | source = "registry+https://github.com/rust-lang/crates.io-index" 372 | checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" 373 | dependencies = [ 374 | "autocfg 1.0.0", 375 | "cfg-if", 376 | "crossbeam-utils", 377 | "lazy_static 1.4.0", 378 | "maybe-uninit", 379 | "memoffset", 380 | "scopeguard 1.1.0", 381 | ] 382 | 383 | [[package]] 384 | name = "crossbeam-queue" 385 | version = "0.2.1" 386 | source = "registry+https://github.com/rust-lang/crates.io-index" 387 | checksum = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db" 388 | dependencies = [ 389 | "cfg-if", 390 | "crossbeam-utils", 391 | ] 392 | 393 | [[package]] 394 | name = "crossbeam-utils" 395 | version = "0.7.2" 396 | source = "registry+https://github.com/rust-lang/crates.io-index" 397 | checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" 398 | dependencies = [ 399 | "autocfg 1.0.0", 400 | "cfg-if", 401 | "lazy_static 1.4.0", 402 | ] 403 | 404 | [[package]] 405 | name = "curl" 406 | version = "0.4.28" 407 | source = "registry+https://github.com/rust-lang/crates.io-index" 408 | checksum = "eda1c0c03cacf3365d84818a40293f0e3f3953db8759c9c565a3b434edf0b52e" 409 | dependencies = [ 410 | "curl-sys", 411 | "libc", 412 | "openssl-probe", 413 | "openssl-sys", 414 | "schannel", 415 | "socket2", 416 | "winapi 0.3.8", 417 | ] 418 | 419 | [[package]] 420 | name = "curl-sys" 421 | version = "0.4.30+curl-7.69.1" 422 | source = "registry+https://github.com/rust-lang/crates.io-index" 423 | checksum = "923b38e423a8f47a4058e96f2a1fa2865a6231097ee860debd678d244277d50c" 424 | dependencies = [ 425 | "cc", 426 | "libc", 427 | "libz-sys", 428 | "openssl-sys", 429 | "pkg-config", 430 | "vcpkg", 431 | "winapi 0.3.8", 432 | ] 433 | 434 | [[package]] 435 | name = "dialoguer" 436 | version = "0.3.0" 437 | source = "registry+https://github.com/rust-lang/crates.io-index" 438 | checksum = "1ad1c29a0368928e78c551354dbff79f103a962ad820519724ef0d74f1c62fa9" 439 | dependencies = [ 440 | "console 0.10.0", 441 | "lazy_static 1.4.0", 442 | "tempfile 2.2.0", 443 | ] 444 | 445 | [[package]] 446 | name = "difference" 447 | version = "2.0.0" 448 | source = "registry+https://github.com/rust-lang/crates.io-index" 449 | checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" 450 | 451 | [[package]] 452 | name = "dirs" 453 | version = "1.0.5" 454 | source = "registry+https://github.com/rust-lang/crates.io-index" 455 | checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" 456 | dependencies = [ 457 | "libc", 458 | "redox_users", 459 | "winapi 0.3.8", 460 | ] 461 | 462 | [[package]] 463 | name = "dtoa" 464 | version = "0.4.5" 465 | source = "registry+https://github.com/rust-lang/crates.io-index" 466 | checksum = "4358a9e11b9a09cf52383b451b49a169e8d797b68aa02301ff586d70d9661ea3" 467 | 468 | [[package]] 469 | name = "either" 470 | version = "1.5.3" 471 | source = "registry+https://github.com/rust-lang/crates.io-index" 472 | checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" 473 | 474 | [[package]] 475 | name = "encode_unicode" 476 | version = "0.3.6" 477 | source = "registry+https://github.com/rust-lang/crates.io-index" 478 | checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" 479 | 480 | [[package]] 481 | name = "encoding_rs" 482 | version = "0.8.22" 483 | source = "registry+https://github.com/rust-lang/crates.io-index" 484 | checksum = "cd8d03faa7fe0c1431609dfad7bbe827af30f82e1e2ae6f7ee4fca6bd764bc28" 485 | dependencies = [ 486 | "cfg-if", 487 | ] 488 | 489 | [[package]] 490 | name = "env_logger" 491 | version = "0.5.13" 492 | source = "registry+https://github.com/rust-lang/crates.io-index" 493 | checksum = "15b0a4d2e39f8420210be8b27eeda28029729e2fd4291019455016c348240c38" 494 | dependencies = [ 495 | "atty", 496 | "humantime", 497 | "log", 498 | "termcolor 1.1.0", 499 | ] 500 | 501 | [[package]] 502 | name = "error-chain" 503 | version = "0.12.2" 504 | source = "registry+https://github.com/rust-lang/crates.io-index" 505 | checksum = "d371106cc88ffdfb1eabd7111e432da544f16f3e2d7bf1dfe8bf575f1df045cd" 506 | dependencies = [ 507 | "version_check", 508 | ] 509 | 510 | [[package]] 511 | name = "escargot" 512 | version = "0.4.0" 513 | source = "registry+https://github.com/rust-lang/crates.io-index" 514 | checksum = "ceb9adbf9874d5d028b5e4c5739d22b71988252b25c9c98fe7cf9738bee84597" 515 | dependencies = [ 516 | "lazy_static 1.4.0", 517 | "log", 518 | "serde", 519 | "serde_json", 520 | ] 521 | 522 | [[package]] 523 | name = "failure" 524 | version = "0.1.7" 525 | source = "registry+https://github.com/rust-lang/crates.io-index" 526 | checksum = "b8529c2421efa3066a5cbd8063d2244603824daccb6936b079010bb2aa89464b" 527 | dependencies = [ 528 | "backtrace", 529 | "failure_derive", 530 | ] 531 | 532 | [[package]] 533 | name = "failure_derive" 534 | version = "0.1.7" 535 | source = "registry+https://github.com/rust-lang/crates.io-index" 536 | checksum = "030a733c8287d6213886dd487564ff5c8f6aae10278b3588ed177f9d18f8d231" 537 | dependencies = [ 538 | "proc-macro2 1.0.9", 539 | "quote 1.0.3", 540 | "syn 1.0.16", 541 | "synstructure", 542 | ] 543 | 544 | [[package]] 545 | name = "filetime" 546 | version = "0.2.8" 547 | source = "registry+https://github.com/rust-lang/crates.io-index" 548 | checksum = "1ff6d4dab0aa0c8e6346d46052e93b13a16cf847b54ed357087c35011048cc7d" 549 | dependencies = [ 550 | "cfg-if", 551 | "libc", 552 | "redox_syscall", 553 | "winapi 0.3.8", 554 | ] 555 | 556 | [[package]] 557 | name = "flate2" 558 | version = "1.0.13" 559 | source = "registry+https://github.com/rust-lang/crates.io-index" 560 | checksum = "6bd6d6f4752952feb71363cffc9ebac9411b75b87c6ab6058c40c8900cf43c0f" 561 | dependencies = [ 562 | "cfg-if", 563 | "crc32fast", 564 | "libc", 565 | "miniz_oxide", 566 | ] 567 | 568 | [[package]] 569 | name = "float-cmp" 570 | version = "0.6.0" 571 | source = "registry+https://github.com/rust-lang/crates.io-index" 572 | checksum = "da62c4f1b81918835a8c6a484a397775fff5953fe83529afd51b05f5c6a6617d" 573 | dependencies = [ 574 | "num-traits", 575 | ] 576 | 577 | [[package]] 578 | name = "fnv" 579 | version = "1.0.6" 580 | source = "registry+https://github.com/rust-lang/crates.io-index" 581 | checksum = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" 582 | 583 | [[package]] 584 | name = "foreign-types" 585 | version = "0.3.2" 586 | source = "registry+https://github.com/rust-lang/crates.io-index" 587 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 588 | dependencies = [ 589 | "foreign-types-shared", 590 | ] 591 | 592 | [[package]] 593 | name = "foreign-types-shared" 594 | version = "0.1.1" 595 | source = "registry+https://github.com/rust-lang/crates.io-index" 596 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 597 | 598 | [[package]] 599 | name = "fuchsia-cprng" 600 | version = "0.1.1" 601 | source = "registry+https://github.com/rust-lang/crates.io-index" 602 | checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" 603 | 604 | [[package]] 605 | name = "fuchsia-zircon" 606 | version = "0.3.3" 607 | source = "registry+https://github.com/rust-lang/crates.io-index" 608 | checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" 609 | dependencies = [ 610 | "bitflags", 611 | "fuchsia-zircon-sys", 612 | ] 613 | 614 | [[package]] 615 | name = "fuchsia-zircon-sys" 616 | version = "0.3.3" 617 | source = "registry+https://github.com/rust-lang/crates.io-index" 618 | checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" 619 | 620 | [[package]] 621 | name = "futures" 622 | version = "0.1.29" 623 | source = "registry+https://github.com/rust-lang/crates.io-index" 624 | checksum = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef" 625 | 626 | [[package]] 627 | name = "futures-cpupool" 628 | version = "0.1.8" 629 | source = "registry+https://github.com/rust-lang/crates.io-index" 630 | checksum = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" 631 | dependencies = [ 632 | "futures", 633 | "num_cpus", 634 | ] 635 | 636 | [[package]] 637 | name = "getrandom" 638 | version = "0.1.14" 639 | source = "registry+https://github.com/rust-lang/crates.io-index" 640 | checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" 641 | dependencies = [ 642 | "cfg-if", 643 | "libc", 644 | "wasi", 645 | ] 646 | 647 | [[package]] 648 | name = "glob" 649 | version = "0.2.11" 650 | source = "registry+https://github.com/rust-lang/crates.io-index" 651 | checksum = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" 652 | 653 | [[package]] 654 | name = "h2" 655 | version = "0.1.26" 656 | source = "registry+https://github.com/rust-lang/crates.io-index" 657 | checksum = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462" 658 | dependencies = [ 659 | "byteorder", 660 | "bytes", 661 | "fnv", 662 | "futures", 663 | "http", 664 | "indexmap", 665 | "log", 666 | "slab", 667 | "string", 668 | "tokio-io", 669 | ] 670 | 671 | [[package]] 672 | name = "heck" 673 | version = "0.3.1" 674 | source = "registry+https://github.com/rust-lang/crates.io-index" 675 | checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" 676 | dependencies = [ 677 | "unicode-segmentation", 678 | ] 679 | 680 | [[package]] 681 | name = "hermit-abi" 682 | version = "0.1.8" 683 | source = "registry+https://github.com/rust-lang/crates.io-index" 684 | checksum = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8" 685 | dependencies = [ 686 | "libc", 687 | ] 688 | 689 | [[package]] 690 | name = "hex" 691 | version = "0.3.2" 692 | source = "registry+https://github.com/rust-lang/crates.io-index" 693 | checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" 694 | 695 | [[package]] 696 | name = "http" 697 | version = "0.1.21" 698 | source = "registry+https://github.com/rust-lang/crates.io-index" 699 | checksum = "d6ccf5ede3a895d8856620237b2f02972c1bbc78d2965ad7fe8838d4a0ed41f0" 700 | dependencies = [ 701 | "bytes", 702 | "fnv", 703 | "itoa", 704 | ] 705 | 706 | [[package]] 707 | name = "http-body" 708 | version = "0.1.0" 709 | source = "registry+https://github.com/rust-lang/crates.io-index" 710 | checksum = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" 711 | dependencies = [ 712 | "bytes", 713 | "futures", 714 | "http", 715 | "tokio-buf", 716 | ] 717 | 718 | [[package]] 719 | name = "httparse" 720 | version = "1.3.4" 721 | source = "registry+https://github.com/rust-lang/crates.io-index" 722 | checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" 723 | 724 | [[package]] 725 | name = "human-panic" 726 | version = "1.0.1" 727 | source = "registry+https://github.com/rust-lang/crates.io-index" 728 | checksum = "21638c5955a6daf3ecc42cae702335fc37a72a4abcc6959ce457b31a7d43bbdd" 729 | dependencies = [ 730 | "backtrace", 731 | "failure", 732 | "os_type", 733 | "serde", 734 | "serde_derive", 735 | "tempdir", 736 | "termcolor 0.3.6", 737 | "toml", 738 | "uuid 0.6.5", 739 | ] 740 | 741 | [[package]] 742 | name = "humantime" 743 | version = "1.3.0" 744 | source = "registry+https://github.com/rust-lang/crates.io-index" 745 | checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" 746 | dependencies = [ 747 | "quick-error", 748 | ] 749 | 750 | [[package]] 751 | name = "hyper" 752 | version = "0.12.35" 753 | source = "registry+https://github.com/rust-lang/crates.io-index" 754 | checksum = "9dbe6ed1438e1f8ad955a4701e9a944938e9519f6888d12d8558b645e247d5f6" 755 | dependencies = [ 756 | "bytes", 757 | "futures", 758 | "futures-cpupool", 759 | "h2", 760 | "http", 761 | "http-body", 762 | "httparse", 763 | "iovec", 764 | "itoa", 765 | "log", 766 | "net2", 767 | "rustc_version", 768 | "time", 769 | "tokio", 770 | "tokio-buf", 771 | "tokio-executor", 772 | "tokio-io", 773 | "tokio-reactor", 774 | "tokio-tcp", 775 | "tokio-threadpool", 776 | "tokio-timer", 777 | "want", 778 | ] 779 | 780 | [[package]] 781 | name = "hyper-tls" 782 | version = "0.3.2" 783 | source = "registry+https://github.com/rust-lang/crates.io-index" 784 | checksum = "3a800d6aa50af4b5850b2b0f659625ce9504df908e9733b635720483be26174f" 785 | dependencies = [ 786 | "bytes", 787 | "futures", 788 | "hyper", 789 | "native-tls", 790 | "tokio-io", 791 | ] 792 | 793 | [[package]] 794 | name = "idna" 795 | version = "0.1.5" 796 | source = "registry+https://github.com/rust-lang/crates.io-index" 797 | checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" 798 | dependencies = [ 799 | "matches", 800 | "unicode-bidi", 801 | "unicode-normalization", 802 | ] 803 | 804 | [[package]] 805 | name = "idna" 806 | version = "0.2.0" 807 | source = "registry+https://github.com/rust-lang/crates.io-index" 808 | checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" 809 | dependencies = [ 810 | "matches", 811 | "unicode-bidi", 812 | "unicode-normalization", 813 | ] 814 | 815 | [[package]] 816 | name = "indexmap" 817 | version = "1.3.2" 818 | source = "registry+https://github.com/rust-lang/crates.io-index" 819 | checksum = "076f042c5b7b98f31d205f1249267e12a6518c1481e9dae9764af19b707d2292" 820 | dependencies = [ 821 | "autocfg 1.0.0", 822 | ] 823 | 824 | [[package]] 825 | name = "iovec" 826 | version = "0.1.4" 827 | source = "registry+https://github.com/rust-lang/crates.io-index" 828 | checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" 829 | dependencies = [ 830 | "libc", 831 | ] 832 | 833 | [[package]] 834 | name = "is_executable" 835 | version = "0.1.2" 836 | source = "registry+https://github.com/rust-lang/crates.io-index" 837 | checksum = "302d553b8abc8187beb7d663e34c065ac4570b273bc9511a50e940e99409c577" 838 | dependencies = [ 839 | "winapi 0.3.8", 840 | ] 841 | 842 | [[package]] 843 | name = "itoa" 844 | version = "0.4.5" 845 | source = "registry+https://github.com/rust-lang/crates.io-index" 846 | checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" 847 | 848 | [[package]] 849 | name = "kernel32-sys" 850 | version = "0.2.2" 851 | source = "registry+https://github.com/rust-lang/crates.io-index" 852 | checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" 853 | dependencies = [ 854 | "winapi 0.2.8", 855 | "winapi-build", 856 | ] 857 | 858 | [[package]] 859 | name = "lazy_static" 860 | version = "0.2.11" 861 | source = "registry+https://github.com/rust-lang/crates.io-index" 862 | checksum = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" 863 | 864 | [[package]] 865 | name = "lazy_static" 866 | version = "1.4.0" 867 | source = "registry+https://github.com/rust-lang/crates.io-index" 868 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 869 | 870 | [[package]] 871 | name = "libc" 872 | version = "0.2.67" 873 | source = "registry+https://github.com/rust-lang/crates.io-index" 874 | checksum = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018" 875 | 876 | [[package]] 877 | name = "libz-sys" 878 | version = "1.0.25" 879 | source = "registry+https://github.com/rust-lang/crates.io-index" 880 | checksum = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe" 881 | dependencies = [ 882 | "cc", 883 | "libc", 884 | "pkg-config", 885 | "vcpkg", 886 | ] 887 | 888 | [[package]] 889 | name = "lock_api" 890 | version = "0.1.5" 891 | source = "registry+https://github.com/rust-lang/crates.io-index" 892 | checksum = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" 893 | dependencies = [ 894 | "owning_ref", 895 | "scopeguard 0.3.3", 896 | ] 897 | 898 | [[package]] 899 | name = "lock_api" 900 | version = "0.3.3" 901 | source = "registry+https://github.com/rust-lang/crates.io-index" 902 | checksum = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b" 903 | dependencies = [ 904 | "scopeguard 1.1.0", 905 | ] 906 | 907 | [[package]] 908 | name = "log" 909 | version = "0.4.8" 910 | source = "registry+https://github.com/rust-lang/crates.io-index" 911 | checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" 912 | dependencies = [ 913 | "cfg-if", 914 | ] 915 | 916 | [[package]] 917 | name = "matches" 918 | version = "0.1.8" 919 | source = "registry+https://github.com/rust-lang/crates.io-index" 920 | checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" 921 | 922 | [[package]] 923 | name = "maybe-uninit" 924 | version = "2.0.0" 925 | source = "registry+https://github.com/rust-lang/crates.io-index" 926 | checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" 927 | 928 | [[package]] 929 | name = "memchr" 930 | version = "2.3.3" 931 | source = "registry+https://github.com/rust-lang/crates.io-index" 932 | checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" 933 | 934 | [[package]] 935 | name = "memoffset" 936 | version = "0.5.4" 937 | source = "registry+https://github.com/rust-lang/crates.io-index" 938 | checksum = "b4fc2c02a7e374099d4ee95a193111f72d2110197fe200272371758f6c3643d8" 939 | dependencies = [ 940 | "autocfg 1.0.0", 941 | ] 942 | 943 | [[package]] 944 | name = "mime" 945 | version = "0.3.16" 946 | source = "registry+https://github.com/rust-lang/crates.io-index" 947 | checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" 948 | 949 | [[package]] 950 | name = "mime_guess" 951 | version = "2.0.3" 952 | source = "registry+https://github.com/rust-lang/crates.io-index" 953 | checksum = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212" 954 | dependencies = [ 955 | "mime", 956 | "unicase", 957 | ] 958 | 959 | [[package]] 960 | name = "miniz_oxide" 961 | version = "0.3.6" 962 | source = "registry+https://github.com/rust-lang/crates.io-index" 963 | checksum = "aa679ff6578b1cddee93d7e82e263b94a575e0bfced07284eb0c037c1d2416a5" 964 | dependencies = [ 965 | "adler32", 966 | ] 967 | 968 | [[package]] 969 | name = "mio" 970 | version = "0.6.21" 971 | source = "registry+https://github.com/rust-lang/crates.io-index" 972 | checksum = "302dec22bcf6bae6dfb69c647187f4b4d0fb6f535521f7bc022430ce8e12008f" 973 | dependencies = [ 974 | "cfg-if", 975 | "fuchsia-zircon", 976 | "fuchsia-zircon-sys", 977 | "iovec", 978 | "kernel32-sys", 979 | "libc", 980 | "log", 981 | "miow", 982 | "net2", 983 | "slab", 984 | "winapi 0.2.8", 985 | ] 986 | 987 | [[package]] 988 | name = "miow" 989 | version = "0.2.1" 990 | source = "registry+https://github.com/rust-lang/crates.io-index" 991 | checksum = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" 992 | dependencies = [ 993 | "kernel32-sys", 994 | "net2", 995 | "winapi 0.2.8", 996 | "ws2_32-sys", 997 | ] 998 | 999 | [[package]] 1000 | name = "native-tls" 1001 | version = "0.2.4" 1002 | source = "registry+https://github.com/rust-lang/crates.io-index" 1003 | checksum = "2b0d88c06fe90d5ee94048ba40409ef1d9315d86f6f38c2efdaad4fb50c58b2d" 1004 | dependencies = [ 1005 | "lazy_static 1.4.0", 1006 | "libc", 1007 | "log", 1008 | "openssl", 1009 | "openssl-probe", 1010 | "openssl-sys", 1011 | "schannel", 1012 | "security-framework", 1013 | "security-framework-sys", 1014 | "tempfile 3.1.0", 1015 | ] 1016 | 1017 | [[package]] 1018 | name = "net2" 1019 | version = "0.2.33" 1020 | source = "registry+https://github.com/rust-lang/crates.io-index" 1021 | checksum = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" 1022 | dependencies = [ 1023 | "cfg-if", 1024 | "libc", 1025 | "winapi 0.3.8", 1026 | ] 1027 | 1028 | [[package]] 1029 | name = "normalize-line-endings" 1030 | version = "0.3.0" 1031 | source = "registry+https://github.com/rust-lang/crates.io-index" 1032 | checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" 1033 | 1034 | [[package]] 1035 | name = "num-integer" 1036 | version = "0.1.42" 1037 | source = "registry+https://github.com/rust-lang/crates.io-index" 1038 | checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" 1039 | dependencies = [ 1040 | "autocfg 1.0.0", 1041 | "num-traits", 1042 | ] 1043 | 1044 | [[package]] 1045 | name = "num-traits" 1046 | version = "0.2.11" 1047 | source = "registry+https://github.com/rust-lang/crates.io-index" 1048 | checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" 1049 | dependencies = [ 1050 | "autocfg 1.0.0", 1051 | ] 1052 | 1053 | [[package]] 1054 | name = "num_cpus" 1055 | version = "1.12.0" 1056 | source = "registry+https://github.com/rust-lang/crates.io-index" 1057 | checksum = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" 1058 | dependencies = [ 1059 | "hermit-abi", 1060 | "libc", 1061 | ] 1062 | 1063 | [[package]] 1064 | name = "openssl" 1065 | version = "0.10.28" 1066 | source = "registry+https://github.com/rust-lang/crates.io-index" 1067 | checksum = "973293749822d7dd6370d6da1e523b0d1db19f06c459134c658b2a4261378b52" 1068 | dependencies = [ 1069 | "bitflags", 1070 | "cfg-if", 1071 | "foreign-types", 1072 | "lazy_static 1.4.0", 1073 | "libc", 1074 | "openssl-sys", 1075 | ] 1076 | 1077 | [[package]] 1078 | name = "openssl-probe" 1079 | version = "0.1.2" 1080 | source = "registry+https://github.com/rust-lang/crates.io-index" 1081 | checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" 1082 | 1083 | [[package]] 1084 | name = "openssl-src" 1085 | version = "111.6.1+1.1.1d" 1086 | source = "registry+https://github.com/rust-lang/crates.io-index" 1087 | checksum = "c91b04cb43c1a8a90e934e0cd612e2a5715d976d2d6cff4490278a0cddf35005" 1088 | dependencies = [ 1089 | "cc", 1090 | ] 1091 | 1092 | [[package]] 1093 | name = "openssl-sys" 1094 | version = "0.9.54" 1095 | source = "registry+https://github.com/rust-lang/crates.io-index" 1096 | checksum = "1024c0a59774200a555087a6da3f253a9095a5f344e353b212ac4c8b8e450986" 1097 | dependencies = [ 1098 | "autocfg 1.0.0", 1099 | "cc", 1100 | "libc", 1101 | "openssl-src", 1102 | "pkg-config", 1103 | "vcpkg", 1104 | ] 1105 | 1106 | [[package]] 1107 | name = "os_type" 1108 | version = "2.2.0" 1109 | source = "registry+https://github.com/rust-lang/crates.io-index" 1110 | checksum = "7edc011af0ae98b7f88cf7e4a83b70a54a75d2b8cb013d6efd02e5956207e9eb" 1111 | dependencies = [ 1112 | "regex", 1113 | ] 1114 | 1115 | [[package]] 1116 | name = "owning_ref" 1117 | version = "0.4.1" 1118 | source = "registry+https://github.com/rust-lang/crates.io-index" 1119 | checksum = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce" 1120 | dependencies = [ 1121 | "stable_deref_trait", 1122 | ] 1123 | 1124 | [[package]] 1125 | name = "parking_lot" 1126 | version = "0.6.4" 1127 | source = "registry+https://github.com/rust-lang/crates.io-index" 1128 | checksum = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5" 1129 | dependencies = [ 1130 | "lock_api 0.1.5", 1131 | "parking_lot_core 0.3.1", 1132 | ] 1133 | 1134 | [[package]] 1135 | name = "parking_lot" 1136 | version = "0.9.0" 1137 | source = "registry+https://github.com/rust-lang/crates.io-index" 1138 | checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" 1139 | dependencies = [ 1140 | "lock_api 0.3.3", 1141 | "parking_lot_core 0.6.2", 1142 | "rustc_version", 1143 | ] 1144 | 1145 | [[package]] 1146 | name = "parking_lot" 1147 | version = "0.10.0" 1148 | source = "registry+https://github.com/rust-lang/crates.io-index" 1149 | checksum = "92e98c49ab0b7ce5b222f2cc9193fc4efe11c6d0bd4f648e374684a6857b1cfc" 1150 | dependencies = [ 1151 | "lock_api 0.3.3", 1152 | "parking_lot_core 0.7.0", 1153 | ] 1154 | 1155 | [[package]] 1156 | name = "parking_lot_core" 1157 | version = "0.3.1" 1158 | source = "registry+https://github.com/rust-lang/crates.io-index" 1159 | checksum = "ad7f7e6ebdc79edff6fdcb87a55b620174f7a989e3eb31b65231f4af57f00b8c" 1160 | dependencies = [ 1161 | "libc", 1162 | "rand 0.5.6", 1163 | "rustc_version", 1164 | "smallvec 0.6.13", 1165 | "winapi 0.3.8", 1166 | ] 1167 | 1168 | [[package]] 1169 | name = "parking_lot_core" 1170 | version = "0.6.2" 1171 | source = "registry+https://github.com/rust-lang/crates.io-index" 1172 | checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" 1173 | dependencies = [ 1174 | "cfg-if", 1175 | "cloudabi", 1176 | "libc", 1177 | "redox_syscall", 1178 | "rustc_version", 1179 | "smallvec 0.6.13", 1180 | "winapi 0.3.8", 1181 | ] 1182 | 1183 | [[package]] 1184 | name = "parking_lot_core" 1185 | version = "0.7.0" 1186 | source = "registry+https://github.com/rust-lang/crates.io-index" 1187 | checksum = "7582838484df45743c8434fbff785e8edf260c28748353d44bc0da32e0ceabf1" 1188 | dependencies = [ 1189 | "cfg-if", 1190 | "cloudabi", 1191 | "libc", 1192 | "redox_syscall", 1193 | "smallvec 1.2.0", 1194 | "winapi 0.3.8", 1195 | ] 1196 | 1197 | [[package]] 1198 | name = "percent-encoding" 1199 | version = "1.0.1" 1200 | source = "registry+https://github.com/rust-lang/crates.io-index" 1201 | checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" 1202 | 1203 | [[package]] 1204 | name = "percent-encoding" 1205 | version = "2.1.0" 1206 | source = "registry+https://github.com/rust-lang/crates.io-index" 1207 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 1208 | 1209 | [[package]] 1210 | name = "pkg-config" 1211 | version = "0.3.17" 1212 | source = "registry+https://github.com/rust-lang/crates.io-index" 1213 | checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" 1214 | 1215 | [[package]] 1216 | name = "podio" 1217 | version = "0.1.6" 1218 | source = "registry+https://github.com/rust-lang/crates.io-index" 1219 | checksum = "780fb4b6698bbf9cf2444ea5d22411cef2953f0824b98f33cf454ec5615645bd" 1220 | 1221 | [[package]] 1222 | name = "ppv-lite86" 1223 | version = "0.2.6" 1224 | source = "registry+https://github.com/rust-lang/crates.io-index" 1225 | checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" 1226 | 1227 | [[package]] 1228 | name = "predicates" 1229 | version = "1.0.4" 1230 | source = "registry+https://github.com/rust-lang/crates.io-index" 1231 | checksum = "347a1b6f0b21e636bc9872fb60b83b8e185f6f5516298b8238699f7f9a531030" 1232 | dependencies = [ 1233 | "difference", 1234 | "float-cmp", 1235 | "normalize-line-endings", 1236 | "predicates-core", 1237 | "regex", 1238 | ] 1239 | 1240 | [[package]] 1241 | name = "predicates-core" 1242 | version = "1.0.0" 1243 | source = "registry+https://github.com/rust-lang/crates.io-index" 1244 | checksum = "06075c3a3e92559ff8929e7a280684489ea27fe44805174c3ebd9328dcb37178" 1245 | 1246 | [[package]] 1247 | name = "predicates-tree" 1248 | version = "1.0.0" 1249 | source = "registry+https://github.com/rust-lang/crates.io-index" 1250 | checksum = "8e63c4859013b38a76eca2414c64911fba30def9e3202ac461a2d22831220124" 1251 | dependencies = [ 1252 | "predicates-core", 1253 | "treeline", 1254 | ] 1255 | 1256 | [[package]] 1257 | name = "proc-macro-error" 1258 | version = "0.4.12" 1259 | source = "registry+https://github.com/rust-lang/crates.io-index" 1260 | checksum = "18f33027081eba0a6d8aba6d1b1c3a3be58cbb12106341c2d5759fcd9b5277e7" 1261 | dependencies = [ 1262 | "proc-macro-error-attr", 1263 | "proc-macro2 1.0.9", 1264 | "quote 1.0.3", 1265 | "syn 1.0.16", 1266 | "version_check", 1267 | ] 1268 | 1269 | [[package]] 1270 | name = "proc-macro-error-attr" 1271 | version = "0.4.12" 1272 | source = "registry+https://github.com/rust-lang/crates.io-index" 1273 | checksum = "8a5b4b77fdb63c1eca72173d68d24501c54ab1269409f6b672c85deb18af69de" 1274 | dependencies = [ 1275 | "proc-macro2 1.0.9", 1276 | "quote 1.0.3", 1277 | "syn 1.0.16", 1278 | "syn-mid", 1279 | "version_check", 1280 | ] 1281 | 1282 | [[package]] 1283 | name = "proc-macro2" 1284 | version = "0.4.30" 1285 | source = "registry+https://github.com/rust-lang/crates.io-index" 1286 | checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" 1287 | dependencies = [ 1288 | "unicode-xid 0.1.0", 1289 | ] 1290 | 1291 | [[package]] 1292 | name = "proc-macro2" 1293 | version = "1.0.9" 1294 | source = "registry+https://github.com/rust-lang/crates.io-index" 1295 | checksum = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435" 1296 | dependencies = [ 1297 | "unicode-xid 0.2.0", 1298 | ] 1299 | 1300 | [[package]] 1301 | name = "publicsuffix" 1302 | version = "1.5.4" 1303 | source = "registry+https://github.com/rust-lang/crates.io-index" 1304 | checksum = "3bbaa49075179162b49acac1c6aa45fb4dafb5f13cf6794276d77bc7fd95757b" 1305 | dependencies = [ 1306 | "error-chain", 1307 | "idna 0.2.0", 1308 | "lazy_static 1.4.0", 1309 | "regex", 1310 | "url 2.1.1", 1311 | ] 1312 | 1313 | [[package]] 1314 | name = "quick-error" 1315 | version = "1.2.3" 1316 | source = "registry+https://github.com/rust-lang/crates.io-index" 1317 | checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" 1318 | 1319 | [[package]] 1320 | name = "quote" 1321 | version = "0.6.13" 1322 | source = "registry+https://github.com/rust-lang/crates.io-index" 1323 | checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" 1324 | dependencies = [ 1325 | "proc-macro2 0.4.30", 1326 | ] 1327 | 1328 | [[package]] 1329 | name = "quote" 1330 | version = "1.0.3" 1331 | source = "registry+https://github.com/rust-lang/crates.io-index" 1332 | checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" 1333 | dependencies = [ 1334 | "proc-macro2 1.0.9", 1335 | ] 1336 | 1337 | [[package]] 1338 | name = "rand" 1339 | version = "0.3.23" 1340 | source = "registry+https://github.com/rust-lang/crates.io-index" 1341 | checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" 1342 | dependencies = [ 1343 | "libc", 1344 | "rand 0.4.6", 1345 | ] 1346 | 1347 | [[package]] 1348 | name = "rand" 1349 | version = "0.4.6" 1350 | source = "registry+https://github.com/rust-lang/crates.io-index" 1351 | checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" 1352 | dependencies = [ 1353 | "fuchsia-cprng", 1354 | "libc", 1355 | "rand_core 0.3.1", 1356 | "rdrand", 1357 | "winapi 0.3.8", 1358 | ] 1359 | 1360 | [[package]] 1361 | name = "rand" 1362 | version = "0.5.6" 1363 | source = "registry+https://github.com/rust-lang/crates.io-index" 1364 | checksum = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" 1365 | dependencies = [ 1366 | "cloudabi", 1367 | "fuchsia-cprng", 1368 | "libc", 1369 | "rand_core 0.3.1", 1370 | "winapi 0.3.8", 1371 | ] 1372 | 1373 | [[package]] 1374 | name = "rand" 1375 | version = "0.6.5" 1376 | source = "registry+https://github.com/rust-lang/crates.io-index" 1377 | checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" 1378 | dependencies = [ 1379 | "autocfg 0.1.7", 1380 | "libc", 1381 | "rand_chacha 0.1.1", 1382 | "rand_core 0.4.2", 1383 | "rand_hc 0.1.0", 1384 | "rand_isaac", 1385 | "rand_jitter", 1386 | "rand_os", 1387 | "rand_pcg", 1388 | "rand_xorshift", 1389 | "winapi 0.3.8", 1390 | ] 1391 | 1392 | [[package]] 1393 | name = "rand" 1394 | version = "0.7.3" 1395 | source = "registry+https://github.com/rust-lang/crates.io-index" 1396 | checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" 1397 | dependencies = [ 1398 | "getrandom", 1399 | "libc", 1400 | "rand_chacha 0.2.2", 1401 | "rand_core 0.5.1", 1402 | "rand_hc 0.2.0", 1403 | ] 1404 | 1405 | [[package]] 1406 | name = "rand_chacha" 1407 | version = "0.1.1" 1408 | source = "registry+https://github.com/rust-lang/crates.io-index" 1409 | checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" 1410 | dependencies = [ 1411 | "autocfg 0.1.7", 1412 | "rand_core 0.3.1", 1413 | ] 1414 | 1415 | [[package]] 1416 | name = "rand_chacha" 1417 | version = "0.2.2" 1418 | source = "registry+https://github.com/rust-lang/crates.io-index" 1419 | checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" 1420 | dependencies = [ 1421 | "ppv-lite86", 1422 | "rand_core 0.5.1", 1423 | ] 1424 | 1425 | [[package]] 1426 | name = "rand_core" 1427 | version = "0.3.1" 1428 | source = "registry+https://github.com/rust-lang/crates.io-index" 1429 | checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" 1430 | dependencies = [ 1431 | "rand_core 0.4.2", 1432 | ] 1433 | 1434 | [[package]] 1435 | name = "rand_core" 1436 | version = "0.4.2" 1437 | source = "registry+https://github.com/rust-lang/crates.io-index" 1438 | checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" 1439 | 1440 | [[package]] 1441 | name = "rand_core" 1442 | version = "0.5.1" 1443 | source = "registry+https://github.com/rust-lang/crates.io-index" 1444 | checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" 1445 | dependencies = [ 1446 | "getrandom", 1447 | ] 1448 | 1449 | [[package]] 1450 | name = "rand_hc" 1451 | version = "0.1.0" 1452 | source = "registry+https://github.com/rust-lang/crates.io-index" 1453 | checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" 1454 | dependencies = [ 1455 | "rand_core 0.3.1", 1456 | ] 1457 | 1458 | [[package]] 1459 | name = "rand_hc" 1460 | version = "0.2.0" 1461 | source = "registry+https://github.com/rust-lang/crates.io-index" 1462 | checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" 1463 | dependencies = [ 1464 | "rand_core 0.5.1", 1465 | ] 1466 | 1467 | [[package]] 1468 | name = "rand_isaac" 1469 | version = "0.1.1" 1470 | source = "registry+https://github.com/rust-lang/crates.io-index" 1471 | checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" 1472 | dependencies = [ 1473 | "rand_core 0.3.1", 1474 | ] 1475 | 1476 | [[package]] 1477 | name = "rand_jitter" 1478 | version = "0.1.4" 1479 | source = "registry+https://github.com/rust-lang/crates.io-index" 1480 | checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" 1481 | dependencies = [ 1482 | "libc", 1483 | "rand_core 0.4.2", 1484 | "winapi 0.3.8", 1485 | ] 1486 | 1487 | [[package]] 1488 | name = "rand_os" 1489 | version = "0.1.3" 1490 | source = "registry+https://github.com/rust-lang/crates.io-index" 1491 | checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" 1492 | dependencies = [ 1493 | "cloudabi", 1494 | "fuchsia-cprng", 1495 | "libc", 1496 | "rand_core 0.4.2", 1497 | "rdrand", 1498 | "winapi 0.3.8", 1499 | ] 1500 | 1501 | [[package]] 1502 | name = "rand_pcg" 1503 | version = "0.1.2" 1504 | source = "registry+https://github.com/rust-lang/crates.io-index" 1505 | checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" 1506 | dependencies = [ 1507 | "autocfg 0.1.7", 1508 | "rand_core 0.4.2", 1509 | ] 1510 | 1511 | [[package]] 1512 | name = "rand_xorshift" 1513 | version = "0.1.1" 1514 | source = "registry+https://github.com/rust-lang/crates.io-index" 1515 | checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" 1516 | dependencies = [ 1517 | "rand_core 0.3.1", 1518 | ] 1519 | 1520 | [[package]] 1521 | name = "rdrand" 1522 | version = "0.4.0" 1523 | source = "registry+https://github.com/rust-lang/crates.io-index" 1524 | checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" 1525 | dependencies = [ 1526 | "rand_core 0.3.1", 1527 | ] 1528 | 1529 | [[package]] 1530 | name = "redox_syscall" 1531 | version = "0.1.56" 1532 | source = "registry+https://github.com/rust-lang/crates.io-index" 1533 | checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" 1534 | 1535 | [[package]] 1536 | name = "redox_users" 1537 | version = "0.3.4" 1538 | source = "registry+https://github.com/rust-lang/crates.io-index" 1539 | checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" 1540 | dependencies = [ 1541 | "getrandom", 1542 | "redox_syscall", 1543 | "rust-argon2", 1544 | ] 1545 | 1546 | [[package]] 1547 | name = "regex" 1548 | version = "1.3.5" 1549 | source = "registry+https://github.com/rust-lang/crates.io-index" 1550 | checksum = "8900ebc1363efa7ea1c399ccc32daed870b4002651e0bed86e72d501ebbe0048" 1551 | dependencies = [ 1552 | "aho-corasick", 1553 | "memchr", 1554 | "regex-syntax", 1555 | "thread_local", 1556 | ] 1557 | 1558 | [[package]] 1559 | name = "regex-syntax" 1560 | version = "0.6.17" 1561 | source = "registry+https://github.com/rust-lang/crates.io-index" 1562 | checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae" 1563 | 1564 | [[package]] 1565 | name = "remove_dir_all" 1566 | version = "0.5.2" 1567 | source = "registry+https://github.com/rust-lang/crates.io-index" 1568 | checksum = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" 1569 | dependencies = [ 1570 | "winapi 0.3.8", 1571 | ] 1572 | 1573 | [[package]] 1574 | name = "reqwest" 1575 | version = "0.9.24" 1576 | source = "registry+https://github.com/rust-lang/crates.io-index" 1577 | checksum = "f88643aea3c1343c804950d7bf983bd2067f5ab59db6d613a08e05572f2714ab" 1578 | dependencies = [ 1579 | "base64 0.10.1", 1580 | "bytes", 1581 | "cookie", 1582 | "cookie_store", 1583 | "encoding_rs", 1584 | "flate2", 1585 | "futures", 1586 | "http", 1587 | "hyper", 1588 | "hyper-tls", 1589 | "log", 1590 | "mime", 1591 | "mime_guess", 1592 | "native-tls", 1593 | "serde", 1594 | "serde_json", 1595 | "serde_urlencoded", 1596 | "time", 1597 | "tokio", 1598 | "tokio-executor", 1599 | "tokio-io", 1600 | "tokio-threadpool", 1601 | "tokio-timer", 1602 | "url 1.7.2", 1603 | "uuid 0.7.4", 1604 | "winreg", 1605 | ] 1606 | 1607 | [[package]] 1608 | name = "rust-argon2" 1609 | version = "0.7.0" 1610 | source = "registry+https://github.com/rust-lang/crates.io-index" 1611 | checksum = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" 1612 | dependencies = [ 1613 | "base64 0.11.0", 1614 | "blake2b_simd", 1615 | "constant_time_eq", 1616 | "crossbeam-utils", 1617 | ] 1618 | 1619 | [[package]] 1620 | name = "rustc-demangle" 1621 | version = "0.1.16" 1622 | source = "registry+https://github.com/rust-lang/crates.io-index" 1623 | checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" 1624 | 1625 | [[package]] 1626 | name = "rustc_version" 1627 | version = "0.2.3" 1628 | source = "registry+https://github.com/rust-lang/crates.io-index" 1629 | checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 1630 | dependencies = [ 1631 | "semver", 1632 | ] 1633 | 1634 | [[package]] 1635 | name = "rustwasmc" 1636 | version = "0.1.29" 1637 | dependencies = [ 1638 | "assert_cmd", 1639 | "atty", 1640 | "binary-install", 1641 | "cargo_metadata", 1642 | "chrono", 1643 | "console 0.6.2", 1644 | "curl", 1645 | "dialoguer", 1646 | "dirs", 1647 | "env_logger", 1648 | "failure", 1649 | "glob", 1650 | "human-panic", 1651 | "lazy_static 1.4.0", 1652 | "log", 1653 | "openssl", 1654 | "parking_lot 0.6.4", 1655 | "predicates", 1656 | "reqwest", 1657 | "semver", 1658 | "serde", 1659 | "serde_derive", 1660 | "serde_ignored", 1661 | "serde_json", 1662 | "serial_test", 1663 | "serial_test_derive", 1664 | "siphasher", 1665 | "strsim", 1666 | "structopt", 1667 | "tempfile 3.1.0", 1668 | "toml", 1669 | "walkdir", 1670 | "which", 1671 | ] 1672 | 1673 | [[package]] 1674 | name = "ryu" 1675 | version = "1.0.3" 1676 | source = "registry+https://github.com/rust-lang/crates.io-index" 1677 | checksum = "535622e6be132bccd223f4bb2b8ac8d53cda3c7a6394944d3b2b33fb974f9d76" 1678 | 1679 | [[package]] 1680 | name = "same-file" 1681 | version = "1.0.6" 1682 | source = "registry+https://github.com/rust-lang/crates.io-index" 1683 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 1684 | dependencies = [ 1685 | "winapi-util", 1686 | ] 1687 | 1688 | [[package]] 1689 | name = "schannel" 1690 | version = "0.1.17" 1691 | source = "registry+https://github.com/rust-lang/crates.io-index" 1692 | checksum = "507a9e6e8ffe0a4e0ebb9a10293e62fdf7657c06f1b8bb07a8fcf697d2abf295" 1693 | dependencies = [ 1694 | "lazy_static 1.4.0", 1695 | "winapi 0.3.8", 1696 | ] 1697 | 1698 | [[package]] 1699 | name = "scopeguard" 1700 | version = "0.3.3" 1701 | source = "registry+https://github.com/rust-lang/crates.io-index" 1702 | checksum = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" 1703 | 1704 | [[package]] 1705 | name = "scopeguard" 1706 | version = "1.1.0" 1707 | source = "registry+https://github.com/rust-lang/crates.io-index" 1708 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 1709 | 1710 | [[package]] 1711 | name = "security-framework" 1712 | version = "0.4.1" 1713 | source = "registry+https://github.com/rust-lang/crates.io-index" 1714 | checksum = "97bbedbe81904398b6ebb054b3e912f99d55807125790f3198ac990d98def5b0" 1715 | dependencies = [ 1716 | "bitflags", 1717 | "core-foundation", 1718 | "core-foundation-sys", 1719 | "security-framework-sys", 1720 | ] 1721 | 1722 | [[package]] 1723 | name = "security-framework-sys" 1724 | version = "0.4.1" 1725 | source = "registry+https://github.com/rust-lang/crates.io-index" 1726 | checksum = "06fd2f23e31ef68dd2328cc383bd493142e46107a3a0e24f7d734e3f3b80fe4c" 1727 | dependencies = [ 1728 | "core-foundation-sys", 1729 | "libc", 1730 | ] 1731 | 1732 | [[package]] 1733 | name = "semver" 1734 | version = "0.9.0" 1735 | source = "registry+https://github.com/rust-lang/crates.io-index" 1736 | checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 1737 | dependencies = [ 1738 | "semver-parser", 1739 | "serde", 1740 | ] 1741 | 1742 | [[package]] 1743 | name = "semver-parser" 1744 | version = "0.7.0" 1745 | source = "registry+https://github.com/rust-lang/crates.io-index" 1746 | checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 1747 | 1748 | [[package]] 1749 | name = "serde" 1750 | version = "1.0.104" 1751 | source = "registry+https://github.com/rust-lang/crates.io-index" 1752 | checksum = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" 1753 | dependencies = [ 1754 | "serde_derive", 1755 | ] 1756 | 1757 | [[package]] 1758 | name = "serde_derive" 1759 | version = "1.0.104" 1760 | source = "registry+https://github.com/rust-lang/crates.io-index" 1761 | checksum = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" 1762 | dependencies = [ 1763 | "proc-macro2 1.0.9", 1764 | "quote 1.0.3", 1765 | "syn 1.0.16", 1766 | ] 1767 | 1768 | [[package]] 1769 | name = "serde_ignored" 1770 | version = "0.0.4" 1771 | source = "registry+https://github.com/rust-lang/crates.io-index" 1772 | checksum = "190e9765dcedb56be63b6e0993a006c7e3b071a016a304736e4a315dc01fb142" 1773 | dependencies = [ 1774 | "serde", 1775 | ] 1776 | 1777 | [[package]] 1778 | name = "serde_json" 1779 | version = "1.0.48" 1780 | source = "registry+https://github.com/rust-lang/crates.io-index" 1781 | checksum = "9371ade75d4c2d6cb154141b9752cf3781ec9c05e0e5cf35060e1e70ee7b9c25" 1782 | dependencies = [ 1783 | "itoa", 1784 | "ryu", 1785 | "serde", 1786 | ] 1787 | 1788 | [[package]] 1789 | name = "serde_urlencoded" 1790 | version = "0.5.5" 1791 | source = "registry+https://github.com/rust-lang/crates.io-index" 1792 | checksum = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a" 1793 | dependencies = [ 1794 | "dtoa", 1795 | "itoa", 1796 | "serde", 1797 | "url 1.7.2", 1798 | ] 1799 | 1800 | [[package]] 1801 | name = "serial_test" 1802 | version = "0.2.0" 1803 | source = "registry+https://github.com/rust-lang/crates.io-index" 1804 | checksum = "50bfbc39343545618d97869d77f38ed43e48dd77432717dbc7ed39d797f3ecbe" 1805 | dependencies = [ 1806 | "lazy_static 1.4.0", 1807 | ] 1808 | 1809 | [[package]] 1810 | name = "serial_test_derive" 1811 | version = "0.2.0" 1812 | source = "registry+https://github.com/rust-lang/crates.io-index" 1813 | checksum = "89dd85be2e2ad75b041c9df2892ac078fa6e0b90024028b2b9fb4125b7530f01" 1814 | dependencies = [ 1815 | "quote 0.6.13", 1816 | "syn 0.15.44", 1817 | ] 1818 | 1819 | [[package]] 1820 | name = "siphasher" 1821 | version = "0.2.3" 1822 | source = "registry+https://github.com/rust-lang/crates.io-index" 1823 | checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" 1824 | 1825 | [[package]] 1826 | name = "slab" 1827 | version = "0.4.2" 1828 | source = "registry+https://github.com/rust-lang/crates.io-index" 1829 | checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" 1830 | 1831 | [[package]] 1832 | name = "smallvec" 1833 | version = "0.6.13" 1834 | source = "registry+https://github.com/rust-lang/crates.io-index" 1835 | checksum = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" 1836 | dependencies = [ 1837 | "maybe-uninit", 1838 | ] 1839 | 1840 | [[package]] 1841 | name = "smallvec" 1842 | version = "1.2.0" 1843 | source = "registry+https://github.com/rust-lang/crates.io-index" 1844 | checksum = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" 1845 | 1846 | [[package]] 1847 | name = "socket2" 1848 | version = "0.3.11" 1849 | source = "registry+https://github.com/rust-lang/crates.io-index" 1850 | checksum = "e8b74de517221a2cb01a53349cf54182acdc31a074727d3079068448c0676d85" 1851 | dependencies = [ 1852 | "cfg-if", 1853 | "libc", 1854 | "redox_syscall", 1855 | "winapi 0.3.8", 1856 | ] 1857 | 1858 | [[package]] 1859 | name = "stable_deref_trait" 1860 | version = "1.1.1" 1861 | source = "registry+https://github.com/rust-lang/crates.io-index" 1862 | checksum = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" 1863 | 1864 | [[package]] 1865 | name = "string" 1866 | version = "0.2.1" 1867 | source = "registry+https://github.com/rust-lang/crates.io-index" 1868 | checksum = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" 1869 | dependencies = [ 1870 | "bytes", 1871 | ] 1872 | 1873 | [[package]] 1874 | name = "strsim" 1875 | version = "0.8.0" 1876 | source = "registry+https://github.com/rust-lang/crates.io-index" 1877 | checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 1878 | 1879 | [[package]] 1880 | name = "structopt" 1881 | version = "0.3.12" 1882 | source = "registry+https://github.com/rust-lang/crates.io-index" 1883 | checksum = "c8faa2719539bbe9d77869bfb15d4ee769f99525e707931452c97b693b3f159d" 1884 | dependencies = [ 1885 | "clap", 1886 | "lazy_static 1.4.0", 1887 | "structopt-derive", 1888 | ] 1889 | 1890 | [[package]] 1891 | name = "structopt-derive" 1892 | version = "0.4.5" 1893 | source = "registry+https://github.com/rust-lang/crates.io-index" 1894 | checksum = "3f88b8e18c69496aad6f9ddf4630dd7d585bcaf765786cb415b9aec2fe5a0430" 1895 | dependencies = [ 1896 | "heck", 1897 | "proc-macro-error", 1898 | "proc-macro2 1.0.9", 1899 | "quote 1.0.3", 1900 | "syn 1.0.16", 1901 | ] 1902 | 1903 | [[package]] 1904 | name = "syn" 1905 | version = "0.15.44" 1906 | source = "registry+https://github.com/rust-lang/crates.io-index" 1907 | checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" 1908 | dependencies = [ 1909 | "proc-macro2 0.4.30", 1910 | "quote 0.6.13", 1911 | "unicode-xid 0.1.0", 1912 | ] 1913 | 1914 | [[package]] 1915 | name = "syn" 1916 | version = "1.0.16" 1917 | source = "registry+https://github.com/rust-lang/crates.io-index" 1918 | checksum = "123bd9499cfb380418d509322d7a6d52e5315f064fe4b3ad18a53d6b92c07859" 1919 | dependencies = [ 1920 | "proc-macro2 1.0.9", 1921 | "quote 1.0.3", 1922 | "unicode-xid 0.2.0", 1923 | ] 1924 | 1925 | [[package]] 1926 | name = "syn-mid" 1927 | version = "0.5.0" 1928 | source = "registry+https://github.com/rust-lang/crates.io-index" 1929 | checksum = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a" 1930 | dependencies = [ 1931 | "proc-macro2 1.0.9", 1932 | "quote 1.0.3", 1933 | "syn 1.0.16", 1934 | ] 1935 | 1936 | [[package]] 1937 | name = "synstructure" 1938 | version = "0.12.3" 1939 | source = "registry+https://github.com/rust-lang/crates.io-index" 1940 | checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" 1941 | dependencies = [ 1942 | "proc-macro2 1.0.9", 1943 | "quote 1.0.3", 1944 | "syn 1.0.16", 1945 | "unicode-xid 0.2.0", 1946 | ] 1947 | 1948 | [[package]] 1949 | name = "tar" 1950 | version = "0.4.26" 1951 | source = "registry+https://github.com/rust-lang/crates.io-index" 1952 | checksum = "b3196bfbffbba3e57481b6ea32249fbaf590396a52505a2615adbb79d9d826d3" 1953 | dependencies = [ 1954 | "filetime", 1955 | "libc", 1956 | "redox_syscall", 1957 | "xattr", 1958 | ] 1959 | 1960 | [[package]] 1961 | name = "tempdir" 1962 | version = "0.3.7" 1963 | source = "registry+https://github.com/rust-lang/crates.io-index" 1964 | checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" 1965 | dependencies = [ 1966 | "rand 0.4.6", 1967 | "remove_dir_all", 1968 | ] 1969 | 1970 | [[package]] 1971 | name = "tempfile" 1972 | version = "2.2.0" 1973 | source = "registry+https://github.com/rust-lang/crates.io-index" 1974 | checksum = "11ce2fe9db64b842314052e2421ac61a73ce41b898dc8e3750398b219c5fc1e0" 1975 | dependencies = [ 1976 | "kernel32-sys", 1977 | "libc", 1978 | "rand 0.3.23", 1979 | "redox_syscall", 1980 | "winapi 0.2.8", 1981 | ] 1982 | 1983 | [[package]] 1984 | name = "tempfile" 1985 | version = "3.1.0" 1986 | source = "registry+https://github.com/rust-lang/crates.io-index" 1987 | checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" 1988 | dependencies = [ 1989 | "cfg-if", 1990 | "libc", 1991 | "rand 0.7.3", 1992 | "redox_syscall", 1993 | "remove_dir_all", 1994 | "winapi 0.3.8", 1995 | ] 1996 | 1997 | [[package]] 1998 | name = "termcolor" 1999 | version = "0.3.6" 2000 | source = "registry+https://github.com/rust-lang/crates.io-index" 2001 | checksum = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83" 2002 | dependencies = [ 2003 | "wincolor", 2004 | ] 2005 | 2006 | [[package]] 2007 | name = "termcolor" 2008 | version = "1.1.0" 2009 | source = "registry+https://github.com/rust-lang/crates.io-index" 2010 | checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" 2011 | dependencies = [ 2012 | "winapi-util", 2013 | ] 2014 | 2015 | [[package]] 2016 | name = "termios" 2017 | version = "0.3.1" 2018 | source = "registry+https://github.com/rust-lang/crates.io-index" 2019 | checksum = "72b620c5ea021d75a735c943269bb07d30c9b77d6ac6b236bc8b5c496ef05625" 2020 | dependencies = [ 2021 | "libc", 2022 | ] 2023 | 2024 | [[package]] 2025 | name = "textwrap" 2026 | version = "0.11.0" 2027 | source = "registry+https://github.com/rust-lang/crates.io-index" 2028 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 2029 | dependencies = [ 2030 | "unicode-width", 2031 | ] 2032 | 2033 | [[package]] 2034 | name = "thread_local" 2035 | version = "1.0.1" 2036 | source = "registry+https://github.com/rust-lang/crates.io-index" 2037 | checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" 2038 | dependencies = [ 2039 | "lazy_static 1.4.0", 2040 | ] 2041 | 2042 | [[package]] 2043 | name = "time" 2044 | version = "0.1.42" 2045 | source = "registry+https://github.com/rust-lang/crates.io-index" 2046 | checksum = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" 2047 | dependencies = [ 2048 | "libc", 2049 | "redox_syscall", 2050 | "winapi 0.3.8", 2051 | ] 2052 | 2053 | [[package]] 2054 | name = "tokio" 2055 | version = "0.1.22" 2056 | source = "registry+https://github.com/rust-lang/crates.io-index" 2057 | checksum = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" 2058 | dependencies = [ 2059 | "bytes", 2060 | "futures", 2061 | "mio", 2062 | "num_cpus", 2063 | "tokio-current-thread", 2064 | "tokio-executor", 2065 | "tokio-io", 2066 | "tokio-reactor", 2067 | "tokio-tcp", 2068 | "tokio-threadpool", 2069 | "tokio-timer", 2070 | ] 2071 | 2072 | [[package]] 2073 | name = "tokio-buf" 2074 | version = "0.1.1" 2075 | source = "registry+https://github.com/rust-lang/crates.io-index" 2076 | checksum = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46" 2077 | dependencies = [ 2078 | "bytes", 2079 | "either", 2080 | "futures", 2081 | ] 2082 | 2083 | [[package]] 2084 | name = "tokio-current-thread" 2085 | version = "0.1.7" 2086 | source = "registry+https://github.com/rust-lang/crates.io-index" 2087 | checksum = "b1de0e32a83f131e002238d7ccde18211c0a5397f60cbfffcb112868c2e0e20e" 2088 | dependencies = [ 2089 | "futures", 2090 | "tokio-executor", 2091 | ] 2092 | 2093 | [[package]] 2094 | name = "tokio-executor" 2095 | version = "0.1.10" 2096 | source = "registry+https://github.com/rust-lang/crates.io-index" 2097 | checksum = "fb2d1b8f4548dbf5e1f7818512e9c406860678f29c300cdf0ebac72d1a3a1671" 2098 | dependencies = [ 2099 | "crossbeam-utils", 2100 | "futures", 2101 | ] 2102 | 2103 | [[package]] 2104 | name = "tokio-io" 2105 | version = "0.1.13" 2106 | source = "registry+https://github.com/rust-lang/crates.io-index" 2107 | checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" 2108 | dependencies = [ 2109 | "bytes", 2110 | "futures", 2111 | "log", 2112 | ] 2113 | 2114 | [[package]] 2115 | name = "tokio-reactor" 2116 | version = "0.1.12" 2117 | source = "registry+https://github.com/rust-lang/crates.io-index" 2118 | checksum = "09bc590ec4ba8ba87652da2068d150dcada2cfa2e07faae270a5e0409aa51351" 2119 | dependencies = [ 2120 | "crossbeam-utils", 2121 | "futures", 2122 | "lazy_static 1.4.0", 2123 | "log", 2124 | "mio", 2125 | "num_cpus", 2126 | "parking_lot 0.9.0", 2127 | "slab", 2128 | "tokio-executor", 2129 | "tokio-io", 2130 | "tokio-sync", 2131 | ] 2132 | 2133 | [[package]] 2134 | name = "tokio-sync" 2135 | version = "0.1.8" 2136 | source = "registry+https://github.com/rust-lang/crates.io-index" 2137 | checksum = "edfe50152bc8164fcc456dab7891fa9bf8beaf01c5ee7e1dd43a397c3cf87dee" 2138 | dependencies = [ 2139 | "fnv", 2140 | "futures", 2141 | ] 2142 | 2143 | [[package]] 2144 | name = "tokio-tcp" 2145 | version = "0.1.4" 2146 | source = "registry+https://github.com/rust-lang/crates.io-index" 2147 | checksum = "98df18ed66e3b72e742f185882a9e201892407957e45fbff8da17ae7a7c51f72" 2148 | dependencies = [ 2149 | "bytes", 2150 | "futures", 2151 | "iovec", 2152 | "mio", 2153 | "tokio-io", 2154 | "tokio-reactor", 2155 | ] 2156 | 2157 | [[package]] 2158 | name = "tokio-threadpool" 2159 | version = "0.1.18" 2160 | source = "registry+https://github.com/rust-lang/crates.io-index" 2161 | checksum = "df720b6581784c118f0eb4310796b12b1d242a7eb95f716a8367855325c25f89" 2162 | dependencies = [ 2163 | "crossbeam-deque", 2164 | "crossbeam-queue", 2165 | "crossbeam-utils", 2166 | "futures", 2167 | "lazy_static 1.4.0", 2168 | "log", 2169 | "num_cpus", 2170 | "slab", 2171 | "tokio-executor", 2172 | ] 2173 | 2174 | [[package]] 2175 | name = "tokio-timer" 2176 | version = "0.2.13" 2177 | source = "registry+https://github.com/rust-lang/crates.io-index" 2178 | checksum = "93044f2d313c95ff1cb7809ce9a7a05735b012288a888b62d4434fd58c94f296" 2179 | dependencies = [ 2180 | "crossbeam-utils", 2181 | "futures", 2182 | "slab", 2183 | "tokio-executor", 2184 | ] 2185 | 2186 | [[package]] 2187 | name = "toml" 2188 | version = "0.4.10" 2189 | source = "registry+https://github.com/rust-lang/crates.io-index" 2190 | checksum = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" 2191 | dependencies = [ 2192 | "serde", 2193 | ] 2194 | 2195 | [[package]] 2196 | name = "treeline" 2197 | version = "0.1.0" 2198 | source = "registry+https://github.com/rust-lang/crates.io-index" 2199 | checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41" 2200 | 2201 | [[package]] 2202 | name = "try-lock" 2203 | version = "0.2.2" 2204 | source = "registry+https://github.com/rust-lang/crates.io-index" 2205 | checksum = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" 2206 | 2207 | [[package]] 2208 | name = "try_from" 2209 | version = "0.3.2" 2210 | source = "registry+https://github.com/rust-lang/crates.io-index" 2211 | checksum = "283d3b89e1368717881a9d51dad843cc435380d8109c9e47d38780a324698d8b" 2212 | dependencies = [ 2213 | "cfg-if", 2214 | ] 2215 | 2216 | [[package]] 2217 | name = "unicase" 2218 | version = "2.6.0" 2219 | source = "registry+https://github.com/rust-lang/crates.io-index" 2220 | checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" 2221 | dependencies = [ 2222 | "version_check", 2223 | ] 2224 | 2225 | [[package]] 2226 | name = "unicode-bidi" 2227 | version = "0.3.4" 2228 | source = "registry+https://github.com/rust-lang/crates.io-index" 2229 | checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" 2230 | dependencies = [ 2231 | "matches", 2232 | ] 2233 | 2234 | [[package]] 2235 | name = "unicode-normalization" 2236 | version = "0.1.12" 2237 | source = "registry+https://github.com/rust-lang/crates.io-index" 2238 | checksum = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4" 2239 | dependencies = [ 2240 | "smallvec 1.2.0", 2241 | ] 2242 | 2243 | [[package]] 2244 | name = "unicode-segmentation" 2245 | version = "1.6.0" 2246 | source = "registry+https://github.com/rust-lang/crates.io-index" 2247 | checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" 2248 | 2249 | [[package]] 2250 | name = "unicode-width" 2251 | version = "0.1.7" 2252 | source = "registry+https://github.com/rust-lang/crates.io-index" 2253 | checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" 2254 | 2255 | [[package]] 2256 | name = "unicode-xid" 2257 | version = "0.1.0" 2258 | source = "registry+https://github.com/rust-lang/crates.io-index" 2259 | checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 2260 | 2261 | [[package]] 2262 | name = "unicode-xid" 2263 | version = "0.2.0" 2264 | source = "registry+https://github.com/rust-lang/crates.io-index" 2265 | checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" 2266 | 2267 | [[package]] 2268 | name = "url" 2269 | version = "1.7.2" 2270 | source = "registry+https://github.com/rust-lang/crates.io-index" 2271 | checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" 2272 | dependencies = [ 2273 | "idna 0.1.5", 2274 | "matches", 2275 | "percent-encoding 1.0.1", 2276 | ] 2277 | 2278 | [[package]] 2279 | name = "url" 2280 | version = "2.1.1" 2281 | source = "registry+https://github.com/rust-lang/crates.io-index" 2282 | checksum = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb" 2283 | dependencies = [ 2284 | "idna 0.2.0", 2285 | "matches", 2286 | "percent-encoding 2.1.0", 2287 | ] 2288 | 2289 | [[package]] 2290 | name = "uuid" 2291 | version = "0.6.5" 2292 | source = "registry+https://github.com/rust-lang/crates.io-index" 2293 | checksum = "e1436e58182935dcd9ce0add9ea0b558e8a87befe01c1a301e6020aeb0876363" 2294 | dependencies = [ 2295 | "cfg-if", 2296 | "rand 0.4.6", 2297 | ] 2298 | 2299 | [[package]] 2300 | name = "uuid" 2301 | version = "0.7.4" 2302 | source = "registry+https://github.com/rust-lang/crates.io-index" 2303 | checksum = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" 2304 | dependencies = [ 2305 | "rand 0.6.5", 2306 | ] 2307 | 2308 | [[package]] 2309 | name = "vcpkg" 2310 | version = "0.2.8" 2311 | source = "registry+https://github.com/rust-lang/crates.io-index" 2312 | checksum = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168" 2313 | 2314 | [[package]] 2315 | name = "vec_map" 2316 | version = "0.8.1" 2317 | source = "registry+https://github.com/rust-lang/crates.io-index" 2318 | checksum = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" 2319 | 2320 | [[package]] 2321 | name = "version_check" 2322 | version = "0.9.1" 2323 | source = "registry+https://github.com/rust-lang/crates.io-index" 2324 | checksum = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" 2325 | 2326 | [[package]] 2327 | name = "walkdir" 2328 | version = "2.3.1" 2329 | source = "registry+https://github.com/rust-lang/crates.io-index" 2330 | checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" 2331 | dependencies = [ 2332 | "same-file", 2333 | "winapi 0.3.8", 2334 | "winapi-util", 2335 | ] 2336 | 2337 | [[package]] 2338 | name = "want" 2339 | version = "0.2.0" 2340 | source = "registry+https://github.com/rust-lang/crates.io-index" 2341 | checksum = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230" 2342 | dependencies = [ 2343 | "futures", 2344 | "log", 2345 | "try-lock", 2346 | ] 2347 | 2348 | [[package]] 2349 | name = "wasi" 2350 | version = "0.9.0+wasi-snapshot-preview1" 2351 | source = "registry+https://github.com/rust-lang/crates.io-index" 2352 | checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" 2353 | 2354 | [[package]] 2355 | name = "which" 2356 | version = "2.0.1" 2357 | source = "registry+https://github.com/rust-lang/crates.io-index" 2358 | checksum = "b57acb10231b9493c8472b20cb57317d0679a49e0bdbee44b3b803a6473af164" 2359 | dependencies = [ 2360 | "failure", 2361 | "libc", 2362 | ] 2363 | 2364 | [[package]] 2365 | name = "winapi" 2366 | version = "0.2.8" 2367 | source = "registry+https://github.com/rust-lang/crates.io-index" 2368 | checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" 2369 | 2370 | [[package]] 2371 | name = "winapi" 2372 | version = "0.3.8" 2373 | source = "registry+https://github.com/rust-lang/crates.io-index" 2374 | checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" 2375 | dependencies = [ 2376 | "winapi-i686-pc-windows-gnu", 2377 | "winapi-x86_64-pc-windows-gnu", 2378 | ] 2379 | 2380 | [[package]] 2381 | name = "winapi-build" 2382 | version = "0.1.1" 2383 | source = "registry+https://github.com/rust-lang/crates.io-index" 2384 | checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" 2385 | 2386 | [[package]] 2387 | name = "winapi-i686-pc-windows-gnu" 2388 | version = "0.4.0" 2389 | source = "registry+https://github.com/rust-lang/crates.io-index" 2390 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 2391 | 2392 | [[package]] 2393 | name = "winapi-util" 2394 | version = "0.1.3" 2395 | source = "registry+https://github.com/rust-lang/crates.io-index" 2396 | checksum = "4ccfbf554c6ad11084fb7517daca16cfdcaccbdadba4fc336f032a8b12c2ad80" 2397 | dependencies = [ 2398 | "winapi 0.3.8", 2399 | ] 2400 | 2401 | [[package]] 2402 | name = "winapi-x86_64-pc-windows-gnu" 2403 | version = "0.4.0" 2404 | source = "registry+https://github.com/rust-lang/crates.io-index" 2405 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 2406 | 2407 | [[package]] 2408 | name = "wincolor" 2409 | version = "0.1.6" 2410 | source = "registry+https://github.com/rust-lang/crates.io-index" 2411 | checksum = "eeb06499a3a4d44302791052df005d5232b927ed1a9658146d842165c4de7767" 2412 | dependencies = [ 2413 | "winapi 0.3.8", 2414 | ] 2415 | 2416 | [[package]] 2417 | name = "winreg" 2418 | version = "0.6.2" 2419 | source = "registry+https://github.com/rust-lang/crates.io-index" 2420 | checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" 2421 | dependencies = [ 2422 | "winapi 0.3.8", 2423 | ] 2424 | 2425 | [[package]] 2426 | name = "ws2_32-sys" 2427 | version = "0.2.1" 2428 | source = "registry+https://github.com/rust-lang/crates.io-index" 2429 | checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" 2430 | dependencies = [ 2431 | "winapi 0.2.8", 2432 | "winapi-build", 2433 | ] 2434 | 2435 | [[package]] 2436 | name = "xattr" 2437 | version = "0.2.2" 2438 | source = "registry+https://github.com/rust-lang/crates.io-index" 2439 | checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" 2440 | dependencies = [ 2441 | "libc", 2442 | ] 2443 | 2444 | [[package]] 2445 | name = "zip" 2446 | version = "0.5.5" 2447 | source = "registry+https://github.com/rust-lang/crates.io-index" 2448 | checksum = "6df134e83b8f0f8153a094c7b0fd79dfebe437f1d76e7715afa18ed95ebe2fd7" 2449 | dependencies = [ 2450 | "bzip2", 2451 | "crc32fast", 2452 | "flate2", 2453 | "podio", 2454 | "time", 2455 | ] 2456 | --------------------------------------------------------------------------------