diff --git a/.gitignore b/.gitignore index 69369904..435eeeee 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ /target **/*.rs.bk Cargo.lock +*.ts +*.js +*.wasm diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..41aa192a --- /dev/null +++ b/.travis.yml @@ -0,0 +1,145 @@ +language: rust +sudo: false + +matrix: + include: + - rust: 1.28.0 + env: DESCRIPTION="Linux, 1.28.0" + os: linux + + - rust: 1.28.0 + env: DESCRIPTION="OSX, 1.22.0" + os: osx + + - rust: stable + env: DESCRIPTION="Linux, stable" + + - rust: stable + env: DESCRIPTION="OSX+iOS, stable" + os: osx + install: + - rustup target add aarch64-apple-ios + + - rust: beta + env: DESCRIPTION="Linux, beta" + + - rust: nightly + os: linux + env: DESCRIPTION="Linux, nightly, docs" + install: + - cargo --list | egrep "^\s*deadlinks$" -q || cargo install cargo-deadlinks + - cargo deadlinks -V + script: + - cargo test + - cargo test --benches + - cargo test --examples + # remove cached documentation, otherwise files from previous PRs can get included + - rm -rf target/doc + - cargo doc --no-deps --all --all-features + - cargo deadlinks --dir target/doc + + - rust: nightly + os: osx + env: DESCRIPTION="OSX, nightly, docs" + install: + - cargo --list | egrep "^\s*deadlinks$" -q || cargo install cargo-deadlinks + - cargo deadlinks -V + script: + - cargo test + - cargo test --benches + - cargo test --examples + # remove cached documentation, otherwise files from previous PRs can get included + - rm -rf target/doc + - cargo doc --no-deps --all --all-features + - cargo deadlinks --dir target/doc + + - rust: nightly + env: DESCRIPTION="WASM via emscripten, stdweb and wasm-bindgen" + install: + - rustup target add wasm32-unknown-unknown + - rustup target add wasm32-unknown-emscripten + - nvm install 9 + - ./utils/ci/install_cargo_web.sh + - cargo web prepare-emscripten + - cargo web -V + - cargo list | grep install-update || cargo install -f cargo-update + - cargo install-update -i cargo-update wasm-bindgen-cli wasm-pack + addons: + chrome: stable + script: + # Testing wasm32-unknown-emscripten fails because of rust-lang/rust#49877 + # However, we can still build and link all tests to make sure that works. + # This is actually useful as it finds stuff such as rust-random/rand#669 + - EMCC_CFLAGS="-s ERROR_ON_UNDEFINED_SYMBOLS=0" cargo web test --target wasm32-unknown-emscripten --no-run + #- cargo web test --target wasm32-unknown-emscripten + #- cargo web test --nodejs --target wasm32-unknown-emscripten + #- cargo build --target wasm32-unknown-unknown # without any features + - cargo build --target wasm32-unknown-unknown --features=wasm-bindgen + - cargo web test --target wasm32-unknown-unknown --features=stdweb + - cargo build --manifest-path tests/wasm_bindgen/Cargo.toml --target wasm32-unknown-unknown + - wasm-bindgen --nodejs target/wasm32-unknown-unknown/debug/getrandom_wasm_bindgen_test.wasm --out-dir tests/wasm_bindgen/js + - node tests/wasm_bindgen/js/index.js + - wasm-pack test --node tests/wasm_bindgen + + - rust: nightly + env: DESCRIPTION="cross-platform build only" + install: + - rustup target add x86_64-sun-solaris + - rustup target add x86_64-unknown-cloudabi + - rustup target add x86_64-unknown-freebsd + #- rustup target add x86_64-unknown-fuchsia + - rustup target add x86_64-unknown-netbsd + - rustup target add x86_64-unknown-redox + script: + - cargo build --target=x86_64-sun-solaris --all-features + - cargo build --target=x86_64-unknown-cloudabi --all-features + - cargo build --target=x86_64-unknown-freebsd --all-features + #- cargo build --target=x86_64-unknown-fuchsia --all-features + - cargo build --target=x86_64-unknown-netbsd --all-features + - cargo build --target=x86_64-unknown-redox --all-features + + # Trust cross-built/emulated targets. We must repeat all non-default values. + - rust: stable + sudo: required + dist: trusty + services: docker + env: DESCRIPTION="Linux (MIPS, big-endian)" TARGET=mips-unknown-linux-gnu + install: + - sh utils/ci/install.sh + - source ~/.cargo/env || true + script: + - bash utils/ci/script.sh + + - rust: stable + sudo: required + dist: trusty + services: docker + env: DESCRIPTION="Android (ARMv7)" TARGET=armv7-linux-androideabi + install: + - sh utils/ci/install.sh + - source ~/.cargo/env || true + script: + - bash utils/ci/script.sh + +before_install: + - set -e + - rustup self update + +script: + - cargo test + - cargo test --examples + +after_script: set +e + +cache: + cargo: true + directories: + - .local/share/cargo-web + +before_cache: + # Travis can't cache files that are not readable by "others" + - chmod -R a+r $HOME/.cargo + +notifications: + email: + on_success: never diff --git a/Cargo.toml b/Cargo.toml index 302ea636..71093978 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,12 +9,20 @@ description = "A small cross-platform library to securely get random data (entro travis-ci = { repository = "rust-random/getrandom" } appveyor = { repository = "rust-random/getrandom" } +[workspace] +members = [ + "tests/wasm_bindgen", +] + [target.'cfg(unix)'.dependencies] libc = "0.2" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["minwindef", "ntsecapi", "winnt"] } +[target.'cfg(target_os = "cloudabi")'.dependencies] +cloudabi = "0.0.3" + [target.'cfg(fuchsia)'.dependencies] fuchsia-cprng = "0.1" diff --git a/README.md b/README.md index fc47f2e2..4330a176 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,10 @@ one of the following features must be enabled: - [`wasm-bindgen`](https://crates.io/crates/wasm_bindgen) - [`stdweb`](https://crates.io/crates/stdweb) +## Versions + +This crate requires Rustc version 1.28.0 or later due to usage of `NonZeroU32`. + # License diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000..b318c8e6 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,36 @@ +environment: + + # At the time this was added AppVeyor was having troubles with checking + # revocation of SSL certificates of sites like static.rust-lang.org and what + # we think is crates.io. The libcurl HTTP client by default checks for + # revocation on Windows and according to a mailing list [1] this can be + # disabled. + # + # The `CARGO_HTTP_CHECK_REVOKE` env var here tells cargo to disable SSL + # revocation checking on Windows in libcurl. Note, though, that rustup, which + # we're using to download Rust here, also uses libcurl as the default backend. + # Unlike Cargo, however, rustup doesn't have a mechanism to disable revocation + # checking. To get rustup working we set `RUSTUP_USE_HYPER` which forces it to + # use the Hyper instead of libcurl backend. Both Hyper and libcurl use + # schannel on Windows but it appears that Hyper configures it slightly + # differently such that revocation checking isn't turned on by default. + # + # [1]: https://curl.haxx.se/mail/lib-2016-03/0202.html + RUSTUP_USE_HYPER: 1 + CARGO_HTTP_CHECK_REVOKE: false + + matrix: + - TARGET: x86_64-pc-windows-msvc + - TARGET: i686-pc-windows-msvc +install: + - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe + - rustup-init.exe -y --default-host %TARGET% + - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin + - rustc -V + - cargo -V + +build: false + +test_script: + - cargo test + - cargo test --examples diff --git a/src/cloudabi.rs b/src/cloudabi.rs index f30e064a..1230f31b 100644 --- a/src/cloudabi.rs +++ b/src/cloudabi.rs @@ -5,19 +5,20 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -use error::Error; -extern "C" { - fn cloudabi_sys_random_get(buf: *mut u8, len: usize) -> u16; -} +//! Implementation for CloudABI + +extern crate cloudabi; + +use core::num::NonZeroU32; +use error::Error; pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { - let errno = unsafe { cloudabi_sys_random_get(dest.as_ptr(), dest.len()) }; - if errno == 0 { + let errno = unsafe { cloudabi::random_get(dest) }; + if errno == cloudabi::errno::SUCCESS { Ok(()) } else { - Err(Error(unsafe { - NonZeroU32::new_unchecked(errno as u32) - })) + let code = NonZeroU32::new(errno as u32).unwrap(); + Err(Error::from(code)) } } diff --git a/src/error.rs b/src/error.rs index b3fca9d8..43a03a63 100644 --- a/src/error.rs +++ b/src/error.rs @@ -50,6 +50,12 @@ impl fmt::Display for Error { } } +impl From for Error { + fn from(code: NonZeroU32) -> Self { + Error(code) + } +} + #[cfg(not(target_env = "sgx"))] impl From for Error { fn from(err: io::Error) -> Self { diff --git a/src/lib.rs b/src/lib.rs index ccd0f49a..b6977443 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -91,11 +91,26 @@ //! [15]: https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback //! [16]: #support-for-webassembly-and-amsjs +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico", + html_root_url = "https://rust-random.github.io/rand/")] + #![no_std] +#![cfg_attr(feature = "stdweb", recursion_limit="128")] + #[cfg(not(target_env = "sgx"))] #[macro_use] extern crate std; +// We have to do it here because we load macros +#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten"), + feature = "wasm-bindgen"))] +extern crate wasm_bindgen; +#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten"), + not(feature = "wasm-bindgen"), + feature = "stdweb"))] +#[macro_use] extern crate stdweb; + #[cfg(any( target_os = "android", target_os = "netbsd", @@ -104,8 +119,8 @@ target_os = "redox", target_os = "dragonfly", target_os = "haiku", - target_os = "emscripten", target_os = "linux", + target_arch = "wasm32", ))] mod utils; mod error; @@ -209,3 +224,58 @@ mod_use!( pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> { getrandom_inner(dest) } + +// Due to rustwasm/wasm-bindgen#201 this can't be defined in the inner os +// modules, so hack around it for now and place it at the root. +#[cfg(all(feature = "wasm-bindgen", target_arch = "wasm32"))] +#[doc(hidden)] +#[allow(missing_debug_implementations)] +pub mod __wbg_shims { + + // `extern { type Foo; }` isn't supported on 1.22 syntactically, so use a + // macro to work around that. + macro_rules! rust_122_compat { + ($($t:tt)*) => ($($t)*) + } + + rust_122_compat! { + extern crate wasm_bindgen; + + pub use wasm_bindgen::prelude::*; + + #[wasm_bindgen] + extern "C" { + pub type Function; + #[wasm_bindgen(constructor)] + pub fn new(s: &str) -> Function; + #[wasm_bindgen(method)] + pub fn call(this: &Function, self_: &JsValue) -> JsValue; + + pub type This; + #[wasm_bindgen(method, getter, structural, js_name = self)] + pub fn self_(me: &This) -> JsValue; + #[wasm_bindgen(method, getter, structural)] + pub fn crypto(me: &This) -> JsValue; + + #[derive(Clone, Debug)] + pub type BrowserCrypto; + + // TODO: these `structural` annotations here ideally wouldn't be here to + // avoid a JS shim, but for now with feature detection they're + // unavoidable. + #[wasm_bindgen(method, js_name = getRandomValues, structural, getter)] + pub fn get_random_values_fn(me: &BrowserCrypto) -> JsValue; + #[wasm_bindgen(method, js_name = getRandomValues, structural)] + pub fn get_random_values(me: &BrowserCrypto, buf: &mut [u8]); + + #[wasm_bindgen(js_name = require)] + pub fn node_require(s: &str) -> NodeCrypto; + + #[derive(Clone, Debug)] + pub type NodeCrypto; + + #[wasm_bindgen(method, js_name = randomFillSync, structural)] + pub fn random_fill_sync(me: &NodeCrypto, buf: &mut [u8]); + } + } +} diff --git a/src/linux_android.rs b/src/linux_android.rs index 13dfb3b7..4bad0745 100644 --- a/src/linux_android.rs +++ b/src/linux_android.rs @@ -15,9 +15,9 @@ use std::fs::File; use std::io; use std::io::Read; use std::cell::RefCell; -use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}; +use std::sync::atomic::{AtomicBool, Ordering}; -static RNG_INIT: AtomicBool = ATOMIC_BOOL_INIT; +static RNG_INIT: AtomicBool = AtomicBool::new(false); enum RngSource { GetRandom, @@ -32,7 +32,7 @@ fn syscall_getrandom(dest: &mut [u8]) -> Result<(), io::Error> { let ret = unsafe { libc::syscall(libc::SYS_getrandom, dest.as_mut_ptr(), dest.len(), 0) }; - if ret == -1 || ret != dest.len() as i64 { + if ret < 0 || (ret as usize) != dest.len() { return Err(io::Error::last_os_error()); } Ok(()) @@ -67,7 +67,7 @@ fn is_getrandom_available() -> bool { use std::sync::{Once, ONCE_INIT}; static CHECKER: Once = ONCE_INIT; - static AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT; + static AVAILABLE: AtomicBool = AtomicBool::new(false); CHECKER.call_once(|| { let mut buf: [u8; 0] = []; diff --git a/src/macos.rs b/src/macos.rs index 5cb541e3..fb89fb18 100644 --- a/src/macos.rs +++ b/src/macos.rs @@ -7,10 +7,15 @@ // except according to those terms. //! Implementation for MacOS / iOS +extern crate libc; + use super::Error; use std::io; +use self::libc::{c_int, size_t}; + +enum SecRandom {} -// TODO: check correctness +/// Essentially a null pointer (type `SecRandomRef`) #[allow(non_upper_case_globals)] const kSecRandomDefault: *const SecRandom = 0 as *const SecRandom; diff --git a/src/netbsd.rs b/src/netbsd.rs index 6a59509b..089272a9 100644 --- a/src/netbsd.rs +++ b/src/netbsd.rs @@ -13,9 +13,9 @@ use super::utils::use_init; use std::fs::File; use std::io::Read; use std::cell::RefCell; -use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}; +use std::sync::atomic::{AtomicBool, Ordering}; -static RNG_INIT: AtomicBool = ATOMIC_BOOL_INIT; +static RNG_INIT: AtomicBool = AtomicBool::new(false); thread_local!(static RNG_FILE: RefCell> = RefCell::new(None)); diff --git a/src/wasm32_bindgen.rs b/src/wasm32_bindgen.rs index 6de8f046..3f04d329 100644 --- a/src/wasm32_bindgen.rs +++ b/src/wasm32_bindgen.rs @@ -7,3 +7,86 @@ // except according to those terms. //! Implementation for WASM via wasm-bindgen + +use std::cell::RefCell; +use std::mem; + +use wasm_bindgen::prelude::*; + +use super::__wbg_shims::*; +use super::{Error, UNAVAILABLE_ERROR}; +use super::utils::use_init; + + +#[derive(Clone, Debug)] +pub enum RngSource { + Node(NodeCrypto), + Browser(BrowserCrypto), +} + +thread_local!( + static RNG_SOURCE: RefCell> = RefCell::new(None); +); + +pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { + assert_eq!(mem::size_of::(), 4); + + RNG_SOURCE.with(|f| { + use_init(f, getrandom_init, |source| { + match *source { + RngSource::Node(ref n) => n.random_fill_sync(dest), + RngSource::Browser(ref n) => { + // see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues + // + // where it says: + // + // > A QuotaExceededError DOMException is thrown if the + // > requested length is greater than 65536 bytes. + for chunk in dest.chunks_mut(65536) { + n.get_random_values(chunk) + } + } + } + Ok(()) + }) + }) + +} + +fn getrandom_init() -> Result { + // First up we need to detect if we're running in node.js or a + // browser. To do this we get ahold of the `this` object (in a bit + // of a roundabout fashion). + // + // Once we have `this` we look at its `self` property, which is + // only defined on the web (either a main window or web worker). + let this = Function::new("return this").call(&JsValue::undefined()); + assert!(this != JsValue::undefined()); + let this = This::from(this); + let is_browser = this.self_() != JsValue::undefined(); + + if !is_browser { + return Ok(RngSource::Node(node_require("crypto"))) + } + + // If `self` is defined then we're in a browser somehow (main window + // or web worker). Here we want to try to use + // `crypto.getRandomValues`, but if `crypto` isn't defined we assume + // we're in an older web browser and the OS RNG isn't available. + let crypto = this.crypto(); + if crypto.is_undefined() { + let msg = "self.crypto is undefined"; + return Err(UNAVAILABLE_ERROR) // TODO: report msg + } + + // Test if `crypto.getRandomValues` is undefined as well + let crypto: BrowserCrypto = crypto.into(); + if crypto.get_random_values_fn().is_undefined() { + let msg = "crypto.getRandomValues is undefined"; + return Err(UNAVAILABLE_ERROR) // TODO: report msg + } + + // Ok! `self.crypto.getRandomValues` is a defined value, so let's + // assume we can do browser crypto. + Ok(RngSource::Browser(crypto)) +} diff --git a/src/wasm32_stdweb.rs b/src/wasm32_stdweb.rs index 7db8afea..2606eaa3 100644 --- a/src/wasm32_stdweb.rs +++ b/src/wasm32_stdweb.rs @@ -7,3 +7,101 @@ // except according to those terms. //! Implementation for WASM via stdweb + +use std::cell::RefCell; +use std::mem; + +use stdweb::unstable::TryInto; +use stdweb::web::error::Error as WebError; + +use super::{Error, UNAVAILABLE_ERROR, UNKNOWN_ERROR}; +use super::utils::use_init; + +#[derive(Clone, Debug)] +enum RngSource { + Browser, + Node +} + +thread_local!( + static RNG_SOURCE: RefCell> = RefCell::new(None); +); + +pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { + assert_eq!(mem::size_of::(), 4); + + RNG_SOURCE.with(|f| { + use_init(f, getrandom_init, |source| getrandom_fill(source, dest)) + }) + +} + +fn getrandom_init() -> Result { + let result = js! { + try { + if ( + typeof self === "object" && + typeof self.crypto === "object" && + typeof self.crypto.getRandomValues === "function" + ) { + return { success: true, ty: 1 }; + } + + if (typeof require("crypto").randomBytes === "function") { + return { success: true, ty: 2 }; + } + + return { success: false, error: new Error("not supported") }; + } catch(err) { + return { success: false, error: err }; + } + }; + + if js!{ return @{ result.as_ref() }.success } == true { + let ty = js!{ return @{ result }.ty }; + + if ty == 1 { Ok(RngSource::Browser) } + else if ty == 2 { Ok(RngSource::Node) } + else { unreachable!() } + } else { + let err: WebError = js!{ return @{ result }.error }.try_into().unwrap(); + Err(UNAVAILABLE_ERROR) // TODO: forward err + } +} + +fn getrandom_fill(source: &mut RngSource, dest: &mut [u8]) -> Result<(), Error> { + for chunk in dest.chunks_mut(65536) { + let len = chunk.len() as u32; + let ptr = chunk.as_mut_ptr() as i32; + + let result = match source { + RngSource::Browser => js! { + try { + let array = new Uint8Array(@{ len }); + self.crypto.getRandomValues(array); + HEAPU8.set(array, @{ ptr }); + + return { success: true }; + } catch(err) { + return { success: false, error: err }; + } + }, + RngSource::Node => js! { + try { + let bytes = require("crypto").randomBytes(@{ len }); + HEAPU8.set(new Uint8Array(bytes), @{ ptr }); + + return { success: true }; + } catch(err) { + return { success: false, error: err }; + } + } + }; + + if js!{ return @{ result.as_ref() }.success } != true { + let err: WebError = js!{ return @{ result }.error }.try_into().unwrap(); + return Err(UNKNOWN_ERROR) // TODO: forward err + } + } + Ok(()) +} diff --git a/tests/wasm_bindgen/Cargo.toml b/tests/wasm_bindgen/Cargo.toml new file mode 100644 index 00000000..4b735c85 --- /dev/null +++ b/tests/wasm_bindgen/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "getrandom_wasm_bindgen_test" +description = "Minimal test crate for getrandom using wasm-bindgen" +version = "0.1.0" +authors = ["The Rand Project Developers"] +publish = false +license = "MIT/Apache-2.0" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +getrandom = { path = "../..", features = ["wasm-bindgen"] } +wasm-bindgen = "0.2" +wasm-bindgen-test = "0.2" diff --git a/tests/wasm_bindgen/js/index.js b/tests/wasm_bindgen/js/index.js new file mode 100644 index 00000000..d3390f69 --- /dev/null +++ b/tests/wasm_bindgen/js/index.js @@ -0,0 +1,5 @@ +'use strict'; + +const getrandom_wasm_bindgen_test = require('./getrandom_wasm_bindgen_test'); + +console.log(getrandom_wasm_bindgen_test.test_gen()); diff --git a/tests/wasm_bindgen/src/lib.rs b/tests/wasm_bindgen/src/lib.rs new file mode 100644 index 00000000..2da61271 --- /dev/null +++ b/tests/wasm_bindgen/src/lib.rs @@ -0,0 +1,55 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Crate to test WASM with the `wasm-bindgen` lib. + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png")] + +extern crate getrandom; +extern crate wasm_bindgen; +extern crate wasm_bindgen_test; + +use std::slice; +use wasm_bindgen_test::*; +use wasm_bindgen::prelude::*; + +use getrandom::getrandom; + +#[wasm_bindgen] +pub fn test_gen() -> i32 { + let mut int: i32 = 0; + unsafe { + let ptr = &mut int as *mut i32 as *mut u8; + let slice = slice::from_raw_parts_mut(ptr, 4); + getrandom(slice).unwrap(); + } + int +} + +#[wasm_bindgen_test] +fn test_call() { + let mut buf = [0u8; 0]; + getrandom(&mut buf).unwrap(); +} + +#[wasm_bindgen_test] +fn test_diff() { + let mut v1 = [0u8; 1000]; + getrandom(&mut v1).unwrap(); + + let mut v2 = [0u8; 1000]; + getrandom(&mut v2).unwrap(); + + let mut n_diff_bits = 0; + for i in 0..v1.len() { + n_diff_bits += (v1[i] ^ v2[i]).count_ones(); + } + + // Check at least 1 bit per byte differs. p(failure) < 1e-1000 with random input. + assert!(n_diff_bits >= v1.len() as u32); +} diff --git a/utils/ci/install.sh b/utils/ci/install.sh new file mode 100644 index 00000000..8e636e18 --- /dev/null +++ b/utils/ci/install.sh @@ -0,0 +1,49 @@ +# From https://github.com/japaric/trust + +set -ex + +main() { + local target= + if [ $TRAVIS_OS_NAME = linux ]; then + target=x86_64-unknown-linux-musl + sort=sort + else + target=x86_64-apple-darwin + sort=gsort # for `sort --sort-version`, from brew's coreutils. + fi + + # Builds for iOS are done on OSX, but require the specific target to be + # installed. + case $TARGET in + aarch64-apple-ios) + rustup target install aarch64-apple-ios + ;; + armv7-apple-ios) + rustup target install armv7-apple-ios + ;; + armv7s-apple-ios) + rustup target install armv7s-apple-ios + ;; + i386-apple-ios) + rustup target install i386-apple-ios + ;; + x86_64-apple-ios) + rustup target install x86_64-apple-ios + ;; + esac + + # This fetches latest stable release + local tag=$(git ls-remote --tags --refs --exit-code https://github.com/japaric/cross \ + | cut -d/ -f3 \ + | grep -E '^v[0.1.0-9.]+$' \ + | $sort --version-sort \ + | tail -n1) + curl -LSfs https://japaric.github.io/trust/install.sh | \ + sh -s -- \ + --force \ + --git japaric/cross \ + --tag $tag \ + --target $target +} + +main diff --git a/utils/ci/install_cargo_web.sh b/utils/ci/install_cargo_web.sh new file mode 100755 index 00000000..b35f0691 --- /dev/null +++ b/utils/ci/install_cargo_web.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +set -euo pipefail +IFS=$'\n\t' + +CARGO_WEB_RELEASE=$(curl -L -s -H 'Accept: application/json' https://github.com/koute/cargo-web/releases/latest) +CARGO_WEB_VERSION=$(echo $CARGO_WEB_RELEASE | sed -e 's/.*"tag_name":"\([^"]*\)".*/\1/') +CARGO_WEB_URL="https://github.com/koute/cargo-web/releases/download/$CARGO_WEB_VERSION/cargo-web-x86_64-unknown-linux-gnu.gz" + +echo "Downloading cargo-web from: $CARGO_WEB_URL" +curl -L $CARGO_WEB_URL | gzip -d > cargo-web +chmod +x cargo-web + +mkdir -p ~/.cargo/bin +mv cargo-web ~/.cargo/bin diff --git a/utils/ci/script.sh b/utils/ci/script.sh new file mode 100644 index 00000000..b3e80d4f --- /dev/null +++ b/utils/ci/script.sh @@ -0,0 +1,13 @@ +# Derived from https://github.com/japaric/trust + +set -ex + +main() { + cross test --target $TARGET + cross test --target $TARGET --examples +} + +# we don't run the "test phase" when doing deploys +if [ -z $TRAVIS_TAG ]; then + main +fi