Merge pull request #307 from alexcrichton/installers

Add an experimental installer for wasm-pack
master
ashley williams 7 years ago committed by GitHub
commit 5304a49625
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      .appveyor.yml
  2. 1
      .gitignore
  3. 18
      .travis.yml
  4. 1
      Cargo.lock
  5. 1
      Cargo.toml
  6. 30
      docs/installer/build-installer.rs
  7. 106
      docs/installer/index.html
  8. 190
      docs/installer/init.sh
  9. 92
      docs/installer/wasm-pack.js
  10. 122
      src/installer.rs
  11. 20
      src/main.rs

@ -19,23 +19,25 @@ test_script:
before_deploy:
- ps: |
$NAME = "wasm-pack-${env:APPVEYOR_REPO_TAG_NAME}-${env:TARGET}"
$NAME = "wasm-pack-${env:APPVEYOR_REPO_TAG_NAME}-x86_64-pc-windows-msvc"
New-Item -Path $NAME -ItemType directory
Copy-Item target/release/wasm-pack.exe "${NAME}/"
Copy-Item target/release/wasm-pack.exe wasm-pack-init.exe
Copy-Item LICENSE-MIT "${NAME}/"
Copy-Item LICENSE-APACHE "${NAME}/"
Copy-Item README.md "${NAME}/"
7z a -ttar "${NAME}.tar" "${NAME}"
7z a "${NAME}.tar.gz" "${NAME}.tar"
Push-AppveyorArtifact "${NAME}.tar.gz"
Push-AppveyorArtifact wasm-pack-init.exe
deploy:
artifact: /.*\.tar.gz/
artifact: /.*\.tar.gz/, /.*\.exe/
description: 'Appveyor Automated Release'
provider: GitHub
draft: false
prerelease: false
autho_token:
auth_token:
secure: iHsRUqwGf/Zh7OuYpHOWQL8buaOL+c8/6kXLRly8V2j0LCUo7CcDs0NxQ0vl2bhZ
on:
appveyor_repo_tag: true

1
.gitignore vendored

@ -3,3 +3,4 @@ target/
tests/.crates.toml
tests/bin
wasm-pack.log
/build-installer

@ -14,6 +14,9 @@ cache:
directories:
- /home/travis/.cargo
GH_TOKEN: &GH_TOKEN
secure: fx0rR5Ii1KcsydexE6QpkDbqItNdj3Lt6L5yFZaKKB/ejw9M555NkXA+0GZqV0sLZ54qfR8zTaXAf6eBFKgcG9etaCl7vTXqsvDrlssth82oki1zufP39uuoOy4WgFq8OfACOtUq7opDAgYmpaGzlFiny+c5j7asGwDtAU1Fc3JeJsvAnxHKg9+0spXFD6kBQd5CWpqDXv2rLFK0b8IM2fHAzd0PiJZQWqz//2Cj/r9rTiewtIzqigctAfOgFwYoQvfdM+0mKb4pefG+zXEGfxxQr4r5hqZ6UMO7hto3Jnm9LRjNR8dNaDQCqQ0bkdLTAMTC3nV/gZPM679yQU3KHueVjg9pleNzuKnuBgYmH9+BrlG1dW68kqA+6Xh+wIJYrLuagWhJDlCtiU6PM5QAbFg3mabPIBG3M2IHTrOVATme+iW5vpROARhgjbQEF235DyvZaT+Tml3+PY+PfcRax2DVUhvGQViv4tzppbT0PjjBlEbGct49cFLGdqZIJBiVrYW24I2QkENTnUgZsFIBuJlVCBHZwZlLo9ldVvu4XTMKw65z42zoTzobjtbC1QPEZPiaJXSxC7W569fqL/ORXwGToFk6rQjXwEqDP2okGiusR75LXrZD6qFibNpqeypRFtqOzntsOfTUGrlaN1yTt/6dz0V0j9uI7a9/CHVcblI=
DEPLOY_TO_GITHUB: &DEPLOY_TO_GITHUB
before_deploy:
- git config --local user.name "Ashley Williams"
@ -25,14 +28,11 @@ DEPLOY_TO_GITHUB: &DEPLOY_TO_GITHUB
- tar czvf $name.tar.gz $name
deploy:
provider: releases
api_key:
secure: fx0rR5Ii1KcsydexE6QpkDbqItNdj3Lt6L5yFZaKKB/ejw9M555NkXA+0GZqV0sLZ54qfR8zTaXAf6eBFKgcG9etaCl7vTXqsvDrlssth82oki1zufP39uuoOy4WgFq8OfACOtUq7opDAgYmpaGzlFiny+c5j7asGwDtAU1Fc3JeJsvAnxHKg9+0spXFD6kBQd5CWpqDXv2rLFK0b8IM2fHAzd0PiJZQWqz//2Cj/r9rTiewtIzqigctAfOgFwYoQvfdM+0mKb4pefG+zXEGfxxQr4r5hqZ6UMO7hto3Jnm9LRjNR8dNaDQCqQ0bkdLTAMTC3nV/gZPM679yQU3KHueVjg9pleNzuKnuBgYmH9+BrlG1dW68kqA+6Xh+wIJYrLuagWhJDlCtiU6PM5QAbFg3mabPIBG3M2IHTrOVATme+iW5vpROARhgjbQEF235DyvZaT+Tml3+PY+PfcRax2DVUhvGQViv4tzppbT0PjjBlEbGct49cFLGdqZIJBiVrYW24I2QkENTnUgZsFIBuJlVCBHZwZlLo9ldVvu4XTMKw65z42zoTzobjtbC1QPEZPiaJXSxC7W569fqL/ORXwGToFk6rQjXwEqDP2okGiusR75LXrZD6qFibNpqeypRFtqOzntsOfTUGrlaN1yTt/6dz0V0j9uI7a9/CHVcblI=
file_glob: true
api_key: *GH_TOKEN
file: wasm-pack-$TRAVIS_TAG-$TARGET.tar.gz
skip_cleanup: true
on:
branch: master
condition: $DEPLOY = 1
tags: true
matrix:
@ -59,18 +59,20 @@ matrix:
- (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.1" mdbook)
- cargo install-update -a
script:
- cd docs && mdbook build
- (cd docs && mdbook build)
- rustc ./docs/installer/build-installer.rs
- ./build-installer
deploy:
provider: pages
skip-cleanup: true
github-token: $GITHUB_TOKEN
github-token: *GH_TOKEN
local-dir: docs/book
keep-history: false
on:
branch: master
# dist linux binary
- env: JOB=dist-linux TARGET=x86_64-unknown-linux-musl DEPLOY=1
- env: JOB=dist-linux TARGET=x86_64-unknown-linux-musl
rust: nightly
before_script: rustup target add $TARGET
script: cargo build --release --target $TARGET --locked --features vendored-openssl
@ -81,7 +83,7 @@ matrix:
<<: *DEPLOY_TO_GITHUB
# dist OSX binary
- env: JOB=dist-osx MACOSX_DEPLOYMENT_TARGET=10.7 DEPLOY=1 TARGET=x86_64-apple-darwin
- env: JOB=dist-osx MACOSX_DEPLOYMENT_TARGET=10.7 TARGET=x86_64-apple-darwin
os: osx
rust: nightly
script: cargo build --release --target $TARGET --locked

1
Cargo.lock generated

@ -900,6 +900,7 @@ dependencies = [
name = "wasm-pack"
version = "0.4.2"
dependencies = [
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"console 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"copy_dir 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"curl 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)",

@ -9,6 +9,7 @@ readme = "README.md"
categories = ["wasm"]
[dependencies]
atty = "0.2.11"
console = "0.6.1"
curl = "0.4.13"
failure = "0.1.2"

@ -0,0 +1,30 @@
use std::fs;
fn main() {
fs::create_dir_all("docs/book/installer").unwrap();
fs::copy(
"docs/installer/wasm-pack.js",
"docs/book/installer/wasm-pack.js",
).unwrap();
let index = fs::read_to_string("docs/installer/index.html").unwrap();
fs::write(
"docs/book/installer/index.html",
fixup(&index),
).unwrap();
let init = fs::read_to_string("docs/installer/init.sh").unwrap();
fs::write(
"docs/book/installer/init.sh",
fixup(&init),
).unwrap();
}
fn fixup(input: &str) -> String {
let manifest = fs::read_to_string("Cargo.toml").unwrap();
let version = manifest.lines()
.find(|line| line.starts_with("version ="))
.unwrap();
let version = &version[version.find('"').unwrap() + 1..version.rfind('"').unwrap()];
input.replace("$VERSION", &format!("v{}", version))
}

@ -0,0 +1,106 @@
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<title>wasm-pack</title>
<style>
body {
text-align: center;
margin: 100px;
font-size: 150%;
}
#main {
padding: 100px;
}
.instructions {
padding: 100px;
border: 1px solid black;
}
.winlink {
display: block;
}
</style>
</head>
<body>
<div id='main'>
Install wasm-pack! A tool with a blurb here.
</div>
<div id="platform-instructions-unix" style="display: none;">
<pre>curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh</pre>
<p>
You appear to be running Unix. If not,
<a class="default-platform-button" href="#">display all supported installers</a>.
</p>
</div>
<div id="platform-instructions-win64" class="instructions" style="display: none;">
<p>
You appear to be running windows 64-bit, download and run
<a class='winlink' href="https://github.com/rustwasm/wasm-pack/releases/download/$VERSION/wasm-pack-init.exe">wasm-pack-init.exe</a>
then follow the onscreen
instructions.
</p>
<hr/>
<p>
If you're a Windows Subsystem for Linux user run the following in your
terminal, then follow the onscreen instructions to install wasm-pack.
</p>
<pre>curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh</pre>
<hr/>
<p>
You appear to be running Windows 64-bit. If not,
<a class="default-platform-button" href="#">
display all supported installers
</a>.
</p>
</div>
<div id="platform-instructions-unknown" class="instructions" style="display: none;">
<p>I don't recognize your platform.</p>
<p>
We would appreciate it if you
<a href="https://github.com/rustwasm/wasm-pack/issues/new">reported an issue</a>,
along with the following values:
</p>
<div>
<div>navigator.platform:</div>
<div id="nav-plat"></div>
<div>navigator.appVersion:</div>
<div id="nav-app"></div>
</div>
</div>
<div id="platform-instructions-default" class="instructions">
<div>
<p>
To install wasm-pack, if you are running Unix,<br/>
run the following in your terminal, then follow the onscreen
instructions.
</p>
<pre>curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh</pre>
</div>
<hr/>
<div>
<p>
If you are running Windows 64-bit,<br/>download and run
<a class='winlink' href="https://github.com/rustwasm/wasm-pack/releases/download/$VERSION/wasm-pack-init.exe">wasm-pack-init.exe</a>
then follow the onscreen instructions.
</p>
</div>
<hr/>
<div>
<p>
For all other platforms, run the following in your terminal:
</p>
<pre>cargo install wasm-pack</pre>
</div>
</div>
<script type="text/javascript" src="wasm-pack.js"></script>

@ -0,0 +1,190 @@
#!/bin/bash
# Copyright 2016 The Rust Project Developers. See the COPYRIGHT
# file at the top-level directory of this distribution and at
# http://rust-lang.org/COPYRIGHT.
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.
# This is just a little script that can be downloaded from the internet to
# install wasm-pack. It just does platform detection, downloads the installer
# and runs it.
set -u
UPDATE_ROOT="https://github.com/rustwasm/wasm-pack/releases/download/$VERSION"
main() {
downloader --check
need_cmd uname
need_cmd mktemp
need_cmd chmod
need_cmd mkdir
need_cmd rm
need_cmd rmdir
need_cmd tar
need_cmd which
need_cmd dirname
get_architecture || return 1
local _arch="$RETVAL"
assert_nz "$_arch" "arch"
local _ext=""
case "$_arch" in
*windows*)
_ext=".exe"
;;
esac
which rustup > /dev/null 2>&1
need_ok "failed to find Rust installation, is rustup installed?"
local _rustup=`which rustup`
local _tardir="wasm-pack-$VERSION-${_arch}"
local _url="$UPDATE_ROOT/${_tardir}.tar.gz"
local _dir="$(mktemp -d 2>/dev/null || ensure mktemp -d -t wasm-pack)"
local _file="$_dir/input.tar.gz"
local _wasmpack="$_dir/wasm-pack$_ext"
local _wasmpackinit="$_dir/wasm-pack-init$_ext"
printf '%s\n' 'info: downloading wasm-pack' 1>&2
ensure mkdir -p "$_dir"
downloader "$_url" "$_file"
if [ $? != 0 ]; then
say "failed to download $_url"
say "this may be a standard network error, but it may also indicate"
say "that wasm-pack's release process is not working. When in doubt"
say "please feel free to open an issue!"
exit 1
fi
ensure tar xf "$_file" --strip-components 1 -C "$_dir"
mv "$_wasmpack" "$_wasmpackinit"
# The installer may want to ask for confirmation on stdin for various
# operations. We were piped through `sh` though so we probably don't have
# access to a tty naturally. If it looks like we're attached to a terminal
# (`-t 1`) then pass the tty down to the installer explicitly.
if [ -t 1 ]; then
"$_wasmpackinit" "$@" < /dev/tty
else
"$_wasmpackinit" "$@"
fi
local _retval=$?
ignore rm -rf "$_dir"
return "$_retval"
}
get_architecture() {
local _ostype="$(uname -s)"
local _cputype="$(uname -m)"
if [ "$_ostype" = Darwin -a "$_cputype" = i386 ]; then
# Darwin `uname -s` lies
if sysctl hw.optional.x86_64 | grep -q ': 1'; then
local _cputype=x86_64
fi
fi
case "$_ostype" in
Linux)
local _ostype=unknown-linux-musl
;;
Darwin)
local _ostype=apple-darwin
;;
MINGW* | MSYS* | CYGWIN*)
local _ostype=pc-windows-msvc
;;
*)
err "no precompiled binaries available for OS: $_ostype"
;;
esac
case "$_cputype" in
x86_64 | x86-64 | x64 | amd64)
local _cputype=x86_64
;;
*)
err "no precompiled binaries available for CPU architecture: $_cputype"
esac
local _arch="$_cputype-$_ostype"
RETVAL="$_arch"
}
say() {
echo "wasm-pack-init: $1"
}
err() {
say "$1" >&2
exit 1
}
need_cmd() {
if ! check_cmd "$1"
then err "need '$1' (command not found)"
fi
}
check_cmd() {
command -v "$1" > /dev/null 2>&1
return $?
}
need_ok() {
if [ $? != 0 ]; then err "$1"; fi
}
assert_nz() {
if [ -z "$1" ]; then err "assert_nz $2"; fi
}
# Run a command that should never fail. If the command fails execution
# will immediately terminate with an error showing the failing
# command.
ensure() {
"$@"
need_ok "command failed: $*"
}
# This is just for indicating that commands' results are being
# intentionally ignored. Usually, because it's being executed
# as part of error handling.
ignore() {
"$@"
}
# This wraps curl or wget. Try curl first, if not installed,
# use wget instead.
downloader() {
if check_cmd curl
then _dld=curl
elif check_cmd wget
then _dld=wget
else _dld='curl or wget' # to be used in error message of need_cmd
fi
if [ "$1" = --check ]
then need_cmd "$_dld"
elif [ "$_dld" = curl ]
then curl -sSfL "$1" -o "$2"
elif [ "$_dld" = wget ]
then wget "$1" -O "$2"
else err "Unknown downloader" # should not reach here
fi
}
main "$@" || exit 1

@ -0,0 +1,92 @@
var platforms = ["default", "unknown", "win64", "unix"];
var platform_override = null;
function detect_platform() {
"use strict";
if (platform_override !== null) {
return platforms[platform_override];
}
var os = "unknown";
if (navigator.platform == "Linux x86_64") {os = "unix";}
if (navigator.platform == "Linux i686") {os = "unix";}
if (navigator.platform == "Linux i686 on x86_64") {os = "unix";}
if (navigator.platform == "Linux aarch64") {os = "unix";}
if (navigator.platform == "Linux armv6l") {os = "unix";}
if (navigator.platform == "Linux armv7l") {os = "unix";}
if (navigator.platform == "Linux armv8l") {os = "unix";}
if (navigator.platform == "Linux ppc64") {os = "unix";}
if (navigator.platform == "Linux mips") {os = "unix";}
if (navigator.platform == "Linux mips64") {os = "unix";}
if (navigator.platform == "Mac") {os = "unix";}
// if (navigator.platform == "Win32") {os = "win32";}
if (navigator.platform == "Win64" ||
navigator.userAgent.indexOf("WOW64") != -1 ||
navigator.userAgent.indexOf("Win64") != -1) { os = "win64"; }
if (navigator.platform == "FreeBSD x86_64") {os = "unix";}
if (navigator.platform == "FreeBSD amd64") {os = "unix";}
if (navigator.platform == "NetBSD x86_64") {os = "unix";}
if (navigator.platform == "NetBSD amd64") {os = "unix";}
// I wish I knew by now, but I don't. Try harder.
if (os == "unknown") {
// if (navigator.appVersion.indexOf("Win")!=-1) {os = "win32";}
if (navigator.appVersion.indexOf("Mac")!=-1) {os = "unix";}
// rust-www/#692 - FreeBSD epiphany!
if (navigator.appVersion.indexOf("FreeBSD")!=-1) {os = "unix";}
}
// Firefox Quantum likes to hide platform and appVersion but oscpu works
if (navigator.oscpu) {
// if (navigator.oscpu.indexOf("Win32")!=-1) {os = "win32";}
if (navigator.oscpu.indexOf("Win64")!=-1) {os = "win64";}
if (navigator.oscpu.indexOf("Mac")!=-1) {os = "unix";}
if (navigator.oscpu.indexOf("Linux")!=-1) {os = "unix";}
if (navigator.oscpu.indexOf("FreeBSD")!=-1) {os = "unix";}
if (navigator.oscpu.indexOf("NetBSD")!=-1) {os = "unix";}
}
return os;
}
function adjust_for_platform() {
"use strict";
var platform = detect_platform();
platforms.forEach(function (platform_elem) {
var platform_div = document.getElementById("platform-instructions-" + platform_elem);
platform_div.style.display = "none";
if (platform == platform_elem ||
(platform == 'unknown' && platform_elem == 'default')) {
platform_div.style.display = "block";
}
});
}
function go_to_default_platform() {
platform_override = 0;
adjust_for_platform();
}
function set_up_default_platform_buttons() {
var defaults_buttons = document.getElementsByClassName('default-platform-button');
for (var i = 0; i < defaults_buttons.length; i++) {
defaults_buttons[i].onclick = go_to_default_platform;
}
}
function fill_in_bug_report_values() {
var nav_plat = document.getElementById("nav-plat");
var nav_app = document.getElementById("nav-app");
nav_plat.textContent = navigator.platform;
nav_app.textContent = navigator.appVersion;
}
(function () {
adjust_for_platform();
set_up_default_platform_buttons();
fill_in_bug_report_values();
}());

@ -0,0 +1,122 @@
//! Self-installation of `wasm-pack`
//!
//! This module contains one public function which will self-install the
//! currently running executable as `wasm-pack`. Our goal is to install this in
//! a place that's already in `PATH`, ideally in an idiomatic location. To that
//! end we place `wasm-pack` next to the `rustup` executable in `PATH`.
//!
//! This installer is run directly (probably by clicking on it) on Windows,
//! meaning it will pop up a console (as we're a console app). Output goes to
//! the console and users interact with it through the console. On Unix this is
//! intended to be run from a shell script (docs/installer/init.sh) which is
//! downloaded via curl/sh, and then the shell script downloads this executable
//! and runs it.
//!
//! This may get more complicated over time (self upates anyone?) but for now
//! it's pretty simple! We're largely just moving over our currently running
//! executable to a different path.
use std::env;
use std::fs;
use std::io;
use std::path::Path;
use std::process;
use atty;
use failure::{Error, ResultExt};
use which;
pub fn install() -> ! {
if let Err(e) = do_install() {
eprintln!("{}", e);
for cause in e.iter_causes() {
eprintln!("Caused by: {}", cause);
}
}
// On Windows we likely popped up a console for the installation. If we were
// to exit here immediately then the user wouldn't see any error that
// happened above or any successful message. Let's wait for them to say
// they've read everything and then continue.
if cfg!(windows) {
println!("Press enter to close this window...");
let mut line = String::new();
drop(io::stdin().read_line(&mut line));
}
process::exit(0);
}
fn do_install() -> Result<(), Error> {
// Find `rustup.exe` in PATH, we'll be using its installation directory as
// our installation directory.
let rustup = match which::which("rustup") {
Ok(path) => path,
Err(_) => {
bail!(
"failed to find an installation of `rustup` in `PATH`, \
is rustup already installed?"
);
}
};
let installation_dir = match rustup.parent() {
Some(parent) => parent,
None => bail!("can't install when `rustup` is at the root of the filesystem"),
};
let destination = installation_dir
.join("wasm-pack")
.with_extension(env::consts::EXE_EXTENSION);
if destination.exists() {
confirm_can_overwrite(&destination)?;
}
// Our relatively simple install step!
let me = env::current_exe()?;
fs::copy(&me, &destination)
.with_context(|_| format!("failed to copy executable to `{}`", destination.display()))?;
println!(
"info: successfully installed wasm-pack to `{}`",
destination.display()
);
// ... and that's it!
Ok(())
}
fn confirm_can_overwrite(dst: &Path) -> Result<(), Error> {
// If the `-f` argument was passed, we can always overwrite everything.
if env::args().any(|arg| arg == "-f") {
return Ok(());
}
// If we're not attached to a TTY then we can't get user input, so there's
// nothing to do except inform the user about the `-f` flag.
if !atty::is(atty::Stream::Stdin) {
bail!(
"existing wasm-pack installation found at `{}`, pass `-f` to \
force installation over this file, otherwise aborting \
installation now",
dst.display()
);
}
// It looks like we're at an interactive prompt, so ask the user if they'd
// like to overwrite the previous installation.
eprintln!(
"info: existing wasm-pack installation found at `{}`",
dst.display()
);
eprint!("info: would you like to overwrite this file? [y/N]: ");
let mut line = String::new();
io::stdin()
.read_line(&mut line)
.with_context(|_| "failed to read stdin")?;
if line.starts_with("y") || line.starts_with("Y") {
return Ok(());
}
bail!("aborting installation");
}

@ -1,31 +1,43 @@
extern crate atty;
#[macro_use]
extern crate failure;
#[macro_use]
extern crate human_panic;
extern crate structopt;
extern crate wasm_pack;
extern crate which;
use failure::Fail;
use std::env;
use structopt::StructOpt;
use wasm_pack::{command::run_wasm_pack, error::Error, logger, Cli};
use wasm_pack::{command::run_wasm_pack, logger, Cli};
mod installer;
fn main() {
setup_panic!();
if let Err(e) = run() {
eprintln!("{}", e);
for cause in Fail::iter_causes(&e) {
for cause in e.iter_causes() {
eprintln!("Caused by: {}", cause);
}
::std::process::exit(1);
}
}
fn run() -> Result<(), Error> {
fn run() -> Result<(), failure::Error> {
// Deprecate `init`
if let Some("init") = env::args().nth(1).as_ref().map(|arg| arg.as_str()) {
println!("wasm-pack init is deprecated, consider using wasm-pack build");
}
if let Ok(me) = env::current_exe() {
// If we're actually running as the installer then execute our
// self-installation, otherwise just continue as usual.
if me.file_stem().and_then(|s| s.to_str()) == Some("wasm-pack-init") {
installer::install();
}
}
let args = Cli::from_args();
let log = logger::new(&args.cmd, args.verbosity)?;
run_wasm_pack(args.cmd, &log)?;

Loading…
Cancel
Save