Merge branch 'master' into fix-create-exe-windows

This commit is contained in:
Felix Schütt
2022-11-18 11:11:04 +01:00
committed by GitHub
43 changed files with 2767 additions and 1706 deletions

View File

@@ -24,7 +24,7 @@ jobs:
- name: Install Rust - name: Install Rust
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable
with: with:
toolchain: 1.61 toolchain: 1.63
- name: Configure cargo data directory - name: Configure cargo data directory
# After this point, all cargo registry and crate data is stored in # After this point, all cargo registry and crate data is stored in
# $GITHUB_WORKSPACE/.cargo_home. This allows us to cache only the files # $GITHUB_WORKSPACE/.cargo_home. This allows us to cache only the files

View File

@@ -100,7 +100,7 @@ jobs:
- name: Install Rust - name: Install Rust
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable
with: with:
toolchain: 1.61 toolchain: 1.63
target: ${{ matrix.target }} target: ${{ matrix.target }}
- uses: Swatinem/rust-cache@v1 - uses: Swatinem/rust-cache@v1
if: matrix.use_sccache != true if: matrix.use_sccache != true

View File

@@ -21,7 +21,7 @@ jobs:
- name: Install Rust - name: Install Rust
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable
with: with:
toolchain: 1.61 toolchain: 1.63
target: ${{ matrix.target }} target: ${{ matrix.target }}
- name: Install wasm32-wasi target - name: Install wasm32-wasi target
shell: bash shell: bash

View File

@@ -21,7 +21,7 @@ jobs:
- name: Install Rust - name: Install Rust
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable
with: with:
toolchain: 1.61 toolchain: 1.63
- name: Install LLVM (Linux) - name: Install LLVM (Linux)
run: | run: |
curl --proto '=https' --tlsv1.2 -sSf https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/clang+llvm-10.0.0-x86_64-linux-gnu-ubuntu-18.04.tar.xz -L -o llvm.tar.xz curl --proto '=https' --tlsv1.2 -sSf https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/clang+llvm-10.0.0-x86_64-linux-gnu-ubuntu-18.04.tar.xz -L -o llvm.tar.xz

View File

@@ -16,7 +16,7 @@ jobs:
- name: Install Rust - name: Install Rust
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable
with: with:
toolchain: 1.61 toolchain: 1.63
- name: Install LLVM - name: Install LLVM
shell: bash shell: bash
run: | run: |

View File

@@ -18,7 +18,7 @@ jobs:
- name: Install Rust - name: Install Rust
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable
with: with:
toolchain: 1.61 toolchain: 1.63
components: rustfmt, clippy components: rustfmt, clippy
- name: Install LLVM (Linux) - name: Install LLVM (Linux)
run: | run: |

View File

@@ -33,7 +33,7 @@ jobs:
- name: Install Rust - name: Install Rust
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable
with: with:
toolchain: 1.61 toolchain: 1.63
- name: Install NodeJS - name: Install NodeJS
uses: actions/setup-node@v2 uses: actions/setup-node@v2

View File

@@ -110,7 +110,7 @@ jobs:
- name: Install Rust - name: Install Rust
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable
with: with:
toolchain: 1.61 toolchain: 1.63
target: ${{ matrix.target }} target: ${{ matrix.target }}
- uses: Swatinem/rust-cache@v1 - uses: Swatinem/rust-cache@v1
if: matrix.use_sccache != true if: matrix.use_sccache != true
@@ -210,17 +210,19 @@ jobs:
TARGET: ${{ matrix.target }} TARGET: ${{ matrix.target }}
TARGET_DIR: target/${{ matrix.target }}/release TARGET_DIR: target/${{ matrix.target }}/release
CARGO_TARGET: --target ${{ matrix.target }} CARGO_TARGET: --target ${{ matrix.target }}
- name: Test integration CLI WAPM_DEV_TOKEN: ${{ secrets.WAPM_DEV_TOKEN }}
if: matrix.run_test && matrix.os == 'windows-2019'
shell: bash #- name: Test integration CLI
run: | # if: matrix.run_test && matrix.os == 'windows-2019'
make && make build-wasmer && make build-capi && make package-capi && make package # shell: bash
export WASMER_DIR=`pwd`/package # run: |
make test-integration-cli # make && make build-wasmer && make build-capi && make package-capi && make package
env: # export WASMER_DIR=`pwd`/package
TARGET: x86_64-pc-windows-msvc # make test-integration-cli
TARGET_DIR: target/x86_64-pc-windows-msvc/release # env:
CARGO_TARGET: --target x86_64-pc-windows-msvc # TARGET: x86_64-pc-windows-msvc
# TARGET_DIR: target/x86_64-pc-windows-msvc/release
# CARGO_TARGET: --target x86_64-pc-windows-msvc
- name: Test - name: Test
if: matrix.run_test && matrix.os != 'windows-2019' if: matrix.run_test && matrix.os != 'windows-2019'
run: | run: |

View File

@@ -10,8 +10,12 @@ Looking for changes that affect our C API? See the [C API Changelog](lib/c-api/C
## Added ## Added
- [#3317](https://github.com/wasmerio/wasmer/pull/3317) Add a `wasmer add` command for adding bindings for a WAPM package to your project (only Python and JavaScript are supported for now)
## Changed ## Changed
- [#3318](https://github.com/wasmerio/wasmer/pull/3318) Bump the Minimum Supported Rust Version (MSRV) to 1.63
## Fixed ## Fixed
## 3.0.0-rc.2 - 2022/11/02 ## 3.0.0-rc.2 - 2022/11/02
@@ -112,8 +116,8 @@ Looking for changes that affect our C API? See the [C API Changelog](lib/c-api/C
- [#3035](https://github.com/wasmerio/wasmer/pull/3035) Added a simple "divide by zero" wast test, for #1899, as the trap information are correctly tracked on singlepass now - [#3035](https://github.com/wasmerio/wasmer/pull/3035) Added a simple "divide by zero" wast test, for #1899, as the trap information are correctly tracked on singlepass now
- [#3021](https://github.com/wasmerio/wasmer/pull/3021) Add back missing Aarch64 relocations (needed for llvm compiler) - [#3021](https://github.com/wasmerio/wasmer/pull/3021) Add back missing Aarch64 relocations (needed for llvm compiler)
- [#3008](https://github.com/wasmerio/wasmer/pull/3008) Add a new cargo public-api CI check - [#3008](https://github.com/wasmerio/wasmer/pull/3008) Add a new cargo public-api CI check
- [#2941](https://github.com/wasmerio/wasmer/pull/2941) Implementation of WASIX and a fully networking for Web Assembly - [#2941](https://github.com/wasmerio/wasmer/pull/2941) Implementation of WASIX and a fully networking for Web Assembly
- [#2952](https://github.com/wasmerio/wasmer/pull/2952) CI: add make build-wasmer-wasm test - [#2952](https://github.com/wasmerio/wasmer/pull/2952) CI: add make build-wasmer-wasm test
- [#2982](https://github.com/wasmerio/wasmer/pull/2982) Add a rustfmt.toml file to the repository - [#2982](https://github.com/wasmerio/wasmer/pull/2982) Add a rustfmt.toml file to the repository
### Changed ### Changed
@@ -133,13 +137,13 @@ Looking for changes that affect our C API? See the [C API Changelog](lib/c-api/C
- [#2946](https://github.com/wasmerio/wasmer/pull/2946) Remove dylib,staticlib engines in favor of a single Universal engine - [#2946](https://github.com/wasmerio/wasmer/pull/2946) Remove dylib,staticlib engines in favor of a single Universal engine
- [#2949](https://github.com/wasmerio/wasmer/pull/2949) Switch back to using custom LLVM builds on CI - [#2949](https://github.com/wasmerio/wasmer/pull/2949) Switch back to using custom LLVM builds on CI
- [#2892](https://github.com/wasmerio/wasmer/pull/2892) Renamed `get_native_function` to `get_typed_function`, marked former as deprecated. - [#2892](https://github.com/wasmerio/wasmer/pull/2892) Renamed `get_native_function` to `get_typed_function`, marked former as deprecated.
- [#2976](https://github.com/wasmerio/wasmer/pull/2976) Upgrade enumset minimum version to one that compiles - [#2976](https://github.com/wasmerio/wasmer/pull/2976) Upgrade enumset minimum version to one that compiles
- [#2974](https://github.com/wasmerio/wasmer/pull/2974) Context api tests - [#2974](https://github.com/wasmerio/wasmer/pull/2974) Context api tests
- [#2973](https://github.com/wasmerio/wasmer/pull/2973) Port C API to new Context API - [#2973](https://github.com/wasmerio/wasmer/pull/2973) Port C API to new Context API
- [#2969](https://github.com/wasmerio/wasmer/pull/2969) Port JS API to new Context API - [#2969](https://github.com/wasmerio/wasmer/pull/2969) Port JS API to new Context API
- [#2966](https://github.com/wasmerio/wasmer/pull/2966) Singlepass nopanic #2966 - [#2966](https://github.com/wasmerio/wasmer/pull/2966) Singlepass nopanic #2966
- [#2957](https://github.com/wasmerio/wasmer/pull/2957) Enable multi-value handling in Singlepass compiler - [#2957](https://github.com/wasmerio/wasmer/pull/2957) Enable multi-value handling in Singlepass compiler
- [#2954](https://github.com/wasmerio/wasmer/pull/2954) Some fixes to x86_64 Singlepass compiler, when using atomics - [#2954](https://github.com/wasmerio/wasmer/pull/2954) Some fixes to x86_64 Singlepass compiler, when using atomics
- [#2953](https://github.com/wasmerio/wasmer/pull/2953) Makefile: add check target - [#2953](https://github.com/wasmerio/wasmer/pull/2953) Makefile: add check target
- [#2950](https://github.com/wasmerio/wasmer/pull/2950) compiler-cranelift: Fix typo in enum variant - [#2950](https://github.com/wasmerio/wasmer/pull/2950) compiler-cranelift: Fix typo in enum variant
- [#2947](https://github.com/wasmerio/wasmer/pull/2947) Converted the WASI js test into a generic stdio test that works for both sys and js versions of wasmer - [#2947](https://github.com/wasmerio/wasmer/pull/2947) Converted the WASI js test into a generic stdio test that works for both sys and js versions of wasmer
@@ -159,9 +163,9 @@ Looking for changes that affect our C API? See the [C API Changelog](lib/c-api/C
- [#2943](https://github.com/wasmerio/wasmer/pull/2943) Fix build error on some archs by using c_char instead of i8 - [#2943](https://github.com/wasmerio/wasmer/pull/2943) Fix build error on some archs by using c_char instead of i8
- [#2976](https://github.com/wasmerio/wasmer/pull/2976) Upgrade minimum enumset to one that compiles - [#2976](https://github.com/wasmerio/wasmer/pull/2976) Upgrade minimum enumset to one that compiles
- [#2988](https://github.com/wasmerio/wasmer/pull/2988) Have make targets install-capi-lib,install-pkgconfig work without building the wasmer binary - [#2988](https://github.com/wasmerio/wasmer/pull/2988) Have make targets install-capi-lib,install-pkgconfig work without building the wasmer binary
- [#2967](https://github.com/wasmerio/wasmer/pull/2967) Fix singlepass on arm64 that was trying to emit a sub opcode with a constant as destination (for #2959) - [#2967](https://github.com/wasmerio/wasmer/pull/2967) Fix singlepass on arm64 that was trying to emit a sub opcode with a constant as destination (for #2959)
- [#2948](https://github.com/wasmerio/wasmer/pull/2948) Fix regression on gen_import_call_trampoline_arm64() - [#2948](https://github.com/wasmerio/wasmer/pull/2948) Fix regression on gen_import_call_trampoline_arm64()
- [#2944](https://github.com/wasmerio/wasmer/pull/2944) Fix duplicate entries in the CHANGELOG - [#2944](https://github.com/wasmerio/wasmer/pull/2944) Fix duplicate entries in the CHANGELOG
## 2.3.0 - 2022/06/06 ## 2.3.0 - 2022/06/06

52
Cargo.lock generated
View File

@@ -467,6 +467,20 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "console"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c050367d967ced717c04b65d8c619d863ef9292ce0c5760028655a2fb298718c"
dependencies = [
"encode_unicode 0.3.6",
"lazy_static",
"libc",
"terminal_size",
"unicode-width",
"winapi",
]
[[package]] [[package]]
name = "console_error_panic_hook" name = "console_error_panic_hook"
version = "0.1.7" version = "0.1.7"
@@ -830,6 +844,17 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "dialoguer"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a92e7e37ecef6857fdc0c0c5d42fd5b0938e46590c2183cc92dd310a6d078eb1"
dependencies = [
"console",
"tempfile",
"zeroize",
]
[[package]] [[package]]
name = "diff" name = "diff"
version = "0.1.13" version = "0.1.13"
@@ -969,6 +994,12 @@ version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
[[package]]
name = "encode_unicode"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
[[package]] [[package]]
name = "encode_unicode" name = "encode_unicode"
version = "1.0.0" version = "1.0.0"
@@ -2250,7 +2281,7 @@ checksum = "5f375cb74c23b51d23937ffdeb48b1fbf5b6409d4b9979c1418c1de58bc8f801"
dependencies = [ dependencies = [
"atty", "atty",
"csv", "csv",
"encode_unicode", "encode_unicode 1.0.0",
"lazy_static", "lazy_static",
"term 0.7.0", "term 0.7.0",
"unicode-width", "unicode-width",
@@ -3214,6 +3245,16 @@ dependencies = [
"winapi-util", "winapi-util",
] ]
[[package]]
name = "terminal_size"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
dependencies = [
"libc",
"winapi",
]
[[package]] [[package]]
name = "termtree" name = "termtree"
version = "0.2.4" version = "0.2.4"
@@ -3937,6 +3978,7 @@ dependencies = [
"chrono", "chrono",
"clap 3.2.23", "clap 3.2.23",
"colored 2.0.0", "colored 2.0.0",
"dialoguer",
"dirs 4.0.0", "dirs 4.0.0",
"distance", "distance",
"fern", "fern",
@@ -4181,7 +4223,9 @@ dependencies = [
"dirs 4.0.0", "dirs 4.0.0",
"flate2", "flate2",
"graphql_client", "graphql_client",
"log",
"lzma-rs", "lzma-rs",
"rand 0.8.5",
"reqwest", "reqwest",
"semver 1.0.14", "semver 1.0.14",
"serde", "serde",
@@ -4858,3 +4902,9 @@ name = "yansi"
version = "0.5.1" version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
[[package]]
name = "zeroize"
version = "1.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f"

View File

@@ -748,3 +748,6 @@ install-local: package
test-minimal-versions: test-minimal-versions:
rm -f Cargo.lock rm -f Cargo.lock
cargo +nightly build --tests -Z minimal-versions --all-features cargo +nightly build --tests -Z minimal-versions --all-features
update-graphql-schema:
curl -sSfL https://registry.wapm.io/graphql/schema.graphql > lib/registry/graphql/schema.graphql

View File

@@ -54,7 +54,7 @@ pub use crate::js::function_env::{FunctionEnv, FunctionEnvMut};
pub use crate::js::imports::Imports; pub use crate::js::imports::Imports;
pub use crate::js::instance::Instance; pub use crate::js::instance::Instance;
pub use crate::js::mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSliceIter}; pub use crate::js::mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSliceIter};
pub use crate::js::module::{Module, ModuleTypeHints}; pub use crate::js::module::{IoCompileError, Module, ModuleTypeHints};
pub use crate::js::native::TypedFunction; pub use crate::js::native::TypedFunction;
pub use crate::js::native_type::NativeWasmTypeInto; pub use crate::js::native_type::NativeWasmTypeInto;
pub use crate::js::ptr::{Memory32, Memory64, MemorySize, WasmPtr, WasmPtr64}; pub use crate::js::ptr::{Memory32, Memory64, MemorySize, WasmPtr, WasmPtr64};

View File

@@ -22,6 +22,7 @@ use wasmer_types::{
Pages, TableType, Type, Pages, TableType, Type,
}; };
/// IO Error on a Module Compilation
#[derive(Debug)] #[derive(Debug)]
#[cfg_attr(feature = "std", derive(Error))] #[cfg_attr(feature = "std", derive(Error))]
pub enum IoCompileError { pub enum IoCompileError {

View File

@@ -23,7 +23,7 @@ pub use crate::sys::function_env::{FunctionEnv, FunctionEnvMut};
pub use crate::sys::imports::Imports; pub use crate::sys::imports::Imports;
pub use crate::sys::instance::{Instance, InstantiationError}; pub use crate::sys::instance::{Instance, InstantiationError};
pub use crate::sys::mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSliceIter}; pub use crate::sys::mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSliceIter};
pub use crate::sys::module::Module; pub use crate::sys::module::{IoCompileError, Module};
pub use crate::sys::native::TypedFunction; pub use crate::sys::native::TypedFunction;
pub use crate::sys::native_type::NativeWasmTypeInto; pub use crate::sys::native_type::NativeWasmTypeInto;
pub use crate::sys::store::{AsStoreMut, AsStoreRef, StoreMut, StoreRef}; pub use crate::sys::store::{AsStoreMut, AsStoreRef, StoreMut, StoreRef};

View File

@@ -18,6 +18,7 @@ use wasmer_types::{
use wasmer_types::{ExportType, ImportType}; use wasmer_types::{ExportType, ImportType};
use wasmer_vm::InstanceHandle; use wasmer_vm::InstanceHandle;
/// IO Error on a Module Compilation
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum IoCompileError { pub enum IoCompileError {
/// An IO error /// An IO error

View File

@@ -44,7 +44,7 @@ atty = "0.2"
colored = "2.0" colored = "2.0"
anyhow = "1.0" anyhow = "1.0"
spinner = "0.5.0" spinner = "0.5.0"
clap = { version = "3.2.22", features = ["derive"] } clap = { version = "3.2.22", features = ["derive", "env"] }
# For the function names autosuggestion # For the function names autosuggestion
distance = "0.4" distance = "0.4"
# For the inspect subcommand # For the inspect subcommand
@@ -56,7 +56,7 @@ log = { version = "0.4", optional = true }
tempfile = "3" tempfile = "3"
tempdir = "0.3.7" tempdir = "0.3.7"
http_req = { version="^0.8", default-features = false, features = ["rust-tls"], optional = true } http_req = { version="^0.8", default-features = false, features = ["rust-tls"], optional = true }
reqwest = { version = "^0.11", default-features = false, feature = ["rustls-tls", "json"], optional = true } reqwest = { version = "^0.11", default-features = false, features = ["rustls-tls", "json"], optional = true }
serde = { version = "1.0.147", features = ["derive"], optional = true } serde = { version = "1.0.147", features = ["derive"], optional = true }
dirs = { version = "4.0", optional = true } dirs = { version = "4.0", optional = true }
serde_json = { version = "1.0", optional = true } serde_json = { version = "1.0", optional = true }
@@ -72,6 +72,7 @@ nuke-dir = { version = "0.1.0", optional = true }
webc = { version = "3.0.1", optional = true } webc = { version = "3.0.1", optional = true }
isatty = "0.1.9" isatty = "0.1.9"
tar = "0.4" tar = "0.4"
dialoguer = "0.10.2"
[build-dependencies] [build-dependencies]
chrono = { version = "^0.4", default-features = false, features = [ "std", "clock" ] } chrono = { version = "^0.4", default-features = false, features = [ "std", "clock" ] }

View File

@@ -10,10 +10,10 @@ use crate::commands::CreateExe;
use crate::commands::CreateObj; use crate::commands::CreateObj;
#[cfg(feature = "wast")] #[cfg(feature = "wast")]
use crate::commands::Wast; use crate::commands::Wast;
use crate::commands::{Cache, Config, Inspect, List, Run, SelfUpdate, Validate}; use crate::commands::{Add, Cache, Config, Inspect, List, Login, Run, SelfUpdate, Validate};
use crate::error::PrettyError; use crate::error::PrettyError;
use clap::{CommandFactory, ErrorKind, Parser}; use clap::{CommandFactory, ErrorKind, Parser};
use std::fmt; use std::{fmt, str::FromStr};
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[cfg_attr( #[cfg_attr(
@@ -44,6 +44,10 @@ enum WasmerCLIOptions {
#[clap(name = "run")] #[clap(name = "run")]
Run(Run), Run(Run),
/// Login into a wapm.io-like registry
#[clap(name = "login")]
Login(Login),
/// Wasmer cache /// Wasmer cache
#[clap(subcommand, name = "cache")] #[clap(subcommand, name = "cache")]
Cache(Cache), Cache(Cache),
@@ -146,6 +150,9 @@ enum WasmerCLIOptions {
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
#[clap(name = "binfmt")] #[clap(name = "binfmt")]
Binfmt(Binfmt), Binfmt(Binfmt),
/// Add a WAPM package's bindings to your application.
Add(Add),
} }
impl WasmerCLIOptions { impl WasmerCLIOptions {
@@ -164,10 +171,12 @@ impl WasmerCLIOptions {
Self::Config(config) => config.execute(), Self::Config(config) => config.execute(),
Self::Inspect(inspect) => inspect.execute(), Self::Inspect(inspect) => inspect.execute(),
Self::List(list) => list.execute(), Self::List(list) => list.execute(),
Self::Login(login) => login.execute(),
#[cfg(feature = "wast")] #[cfg(feature = "wast")]
Self::Wast(wast) => wast.execute(), Self::Wast(wast) => wast.execute(),
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
Self::Binfmt(binfmt) => binfmt.execute(), Self::Binfmt(binfmt) => binfmt.execute(),
Self::Add(install) => install.execute(),
} }
} }
} }
@@ -219,8 +228,10 @@ fn wasmer_main_inner() -> Result<(), anyhow::Error> {
WasmerCLIOptions::Run(Run::from_binfmt_args()) WasmerCLIOptions::Run(Run::from_binfmt_args())
} else { } else {
match command.unwrap_or(&"".to_string()).as_ref() { match command.unwrap_or(&"".to_string()).as_ref() {
"cache" | "compile" | "config" | "create-exe" | "help" | "inspect" | "run" "add" | "cache" | "compile" | "config" | "create-exe" | "help" | "inspect" | "run"
| "self-update" | "validate" | "wast" | "binfmt" | "list" => WasmerCLIOptions::parse(), | "self-update" | "validate" | "wast" | "binfmt" | "list" | "login" => {
WasmerCLIOptions::parse()
}
_ => { _ => {
WasmerCLIOptions::try_parse_from(args.iter()).unwrap_or_else(|e| { WasmerCLIOptions::try_parse_from(args.iter()).unwrap_or_else(|e| {
match e.kind() { match e.kind() {
@@ -271,7 +282,7 @@ impl fmt::Display for SplitVersion {
#[test] #[test]
fn test_split_version() { fn test_split_version() {
assert_eq!( assert_eq!(
SplitVersion::new("registry.wapm.io/graphql/python/python").unwrap(), SplitVersion::parse("registry.wapm.io/graphql/python/python").unwrap(),
SplitVersion { SplitVersion {
original: "registry.wapm.io/graphql/python/python".to_string(), original: "registry.wapm.io/graphql/python/python".to_string(),
registry: Some("https://registry.wapm.io/graphql".to_string()), registry: Some("https://registry.wapm.io/graphql".to_string()),
@@ -281,7 +292,7 @@ fn test_split_version() {
} }
); );
assert_eq!( assert_eq!(
SplitVersion::new("registry.wapm.io/python/python").unwrap(), SplitVersion::parse("registry.wapm.io/python/python").unwrap(),
SplitVersion { SplitVersion {
original: "registry.wapm.io/python/python".to_string(), original: "registry.wapm.io/python/python".to_string(),
registry: Some("https://registry.wapm.io/graphql".to_string()), registry: Some("https://registry.wapm.io/graphql".to_string()),
@@ -291,7 +302,7 @@ fn test_split_version() {
} }
); );
assert_eq!( assert_eq!(
SplitVersion::new("namespace/name@version:command").unwrap(), SplitVersion::parse("namespace/name@version:command").unwrap(),
SplitVersion { SplitVersion {
original: "namespace/name@version:command".to_string(), original: "namespace/name@version:command".to_string(),
registry: None, registry: None,
@@ -301,7 +312,7 @@ fn test_split_version() {
} }
); );
assert_eq!( assert_eq!(
SplitVersion::new("namespace/name@version").unwrap(), SplitVersion::parse("namespace/name@version").unwrap(),
SplitVersion { SplitVersion {
original: "namespace/name@version".to_string(), original: "namespace/name@version".to_string(),
registry: None, registry: None,
@@ -311,7 +322,7 @@ fn test_split_version() {
} }
); );
assert_eq!( assert_eq!(
SplitVersion::new("namespace/name").unwrap(), SplitVersion::parse("namespace/name").unwrap(),
SplitVersion { SplitVersion {
original: "namespace/name".to_string(), original: "namespace/name".to_string(),
registry: None, registry: None,
@@ -321,7 +332,7 @@ fn test_split_version() {
} }
); );
assert_eq!( assert_eq!(
SplitVersion::new("registry.wapm.io/namespace/name").unwrap(), SplitVersion::parse("registry.wapm.io/namespace/name").unwrap(),
SplitVersion { SplitVersion {
original: "registry.wapm.io/namespace/name".to_string(), original: "registry.wapm.io/namespace/name".to_string(),
registry: Some("https://registry.wapm.io/graphql".to_string()), registry: Some("https://registry.wapm.io/graphql".to_string()),
@@ -331,13 +342,21 @@ fn test_split_version() {
} }
); );
assert_eq!( assert_eq!(
format!("{}", SplitVersion::new("namespace").unwrap_err()), format!("{}", SplitVersion::parse("namespace").unwrap_err()),
"Invalid package version: \"namespace\"".to_string(), "Invalid package version: \"namespace\"".to_string(),
); );
} }
impl SplitVersion { impl SplitVersion {
pub fn new(s: &str) -> Result<SplitVersion, anyhow::Error> { pub fn parse(s: &str) -> Result<SplitVersion, anyhow::Error> {
s.parse()
}
}
impl FromStr for SplitVersion {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let command = WasmerCLIOptions::command(); let command = WasmerCLIOptions::command();
let mut prohibited_package_names = command.get_subcommands().map(|s| s.get_name()); let mut prohibited_package_names = command.get_subcommands().map(|s| s.get_name());

View File

@@ -1,4 +1,5 @@
//! The commands available in the Wasmer binary. //! The commands available in the Wasmer binary.
mod add;
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
mod binfmt; mod binfmt;
mod cache; mod cache;
@@ -11,6 +12,7 @@ mod create_exe;
mod create_obj; mod create_obj;
mod inspect; mod inspect;
mod list; mod list;
mod login;
mod run; mod run;
mod self_update; mod self_update;
mod validate; mod validate;
@@ -27,7 +29,9 @@ pub use create_exe::*;
pub use create_obj::*; pub use create_obj::*;
#[cfg(feature = "wast")] #[cfg(feature = "wast")]
pub use wast::*; pub use wast::*;
pub use {cache::*, config::*, inspect::*, list::*, run::*, self_update::*, validate::*}; pub use {
add::*, cache::*, config::*, inspect::*, list::*, login::*, run::*, self_update::*, validate::*,
};
/// The kind of object format to emit. /// The kind of object format to emit.
#[derive(Debug, Copy, Clone, clap::Parser)] #[derive(Debug, Copy, Clone, clap::Parser)]

181
lib/cli/src/commands/add.rs Normal file
View File

@@ -0,0 +1,181 @@
use std::process::{Command, Stdio};
use anyhow::{Context, Error};
use clap::Parser;
use wasmer_registry::{Bindings, PartialWapmConfig, ProgrammingLanguage};
use crate::cli::SplitVersion;
/// Add a WAPM package's bindings to your application.
#[derive(Debug, Parser)]
pub struct Add {
/// The registry to fetch bindings from.
#[clap(long, env = "WAPM_REGISTRY")]
registry: Option<String>,
/// Add the JavaScript bindings using "npm install".
#[clap(long, groups = &["bindings", "js"])]
npm: bool,
/// Add the JavaScript bindings using "yarn add".
#[clap(long, groups = &["bindings", "js"])]
yarn: bool,
/// Add the package as a dev-dependency.
#[clap(long, requires = "js")]
dev: bool,
/// Add the Python bindings using "pip install".
#[clap(long, groups = &["bindings", "py"])]
pip: bool,
/// The packages to add (e.g. "wasmer/wasmer-pack@0.5.0" or "python/python")
#[clap(parse(try_from_str))]
packages: Vec<SplitVersion>,
}
impl Add {
/// Execute [`Add`].
pub fn execute(&self) -> Result<(), Error> {
anyhow::ensure!(!self.packages.is_empty(), "No packages specified");
let registry = self
.registry()
.context("Unable to determine which registry to use")?;
let bindings = self.lookup_bindings(&registry)?;
let mut cmd = self.target().command(&bindings);
#[cfg(feature = "debug")]
log::debug!("Running {cmd:?}");
let status = cmd
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.status()
.with_context(|| {
format!(
"Unable to start \"{:?}\". Is it installed?",
cmd.get_program()
)
})?;
anyhow::ensure!(status.success(), "Command failed: {:?}", cmd);
Ok(())
}
fn lookup_bindings(&self, registry: &str) -> Result<Vec<Bindings>, Error> {
#[cfg(feature = "debug")]
log::debug!("Querying WAPM for the bindings packages");
let mut bindings_to_add = Vec::new();
let language = self.target().language();
for pkg in &self.packages {
let bindings = lookup_bindings_for_package(registry, pkg, &language)
.with_context(|| format!("Unable to find bindings for {pkg}"))?;
bindings_to_add.push(bindings);
}
Ok(bindings_to_add)
}
fn registry(&self) -> Result<String, Error> {
match &self.registry {
Some(r) => Ok(r.clone()),
None => {
let cfg = PartialWapmConfig::from_file()
.map_err(Error::msg)
.context("Unable to load WAPM's config file")?;
Ok(cfg.registry.get_current_registry())
}
}
}
fn target(&self) -> Target {
match (self.pip, self.npm, self.yarn) {
(true, false, false) => Target::Pip,
(false, true, false) => Target::Npm { dev: self.dev },
(false, false, true) => Target::Yarn { dev: self.dev },
_ => unreachable!(
"Clap should ensure at least one item in the \"bindings\" group is specified"
),
}
}
}
fn lookup_bindings_for_package(
registry: &str,
pkg: &SplitVersion,
language: &ProgrammingLanguage,
) -> Result<Bindings, Error> {
let all_bindings =
wasmer_registry::list_bindings(registry, &pkg.package, pkg.version.as_deref())?;
match all_bindings.iter().find(|b| b.language == *language) {
Some(b) => {
#[cfg(feature = "debug")]
{
let Bindings { url, generator, .. } = b;
log::debug!("Found {pkg} bindings generated by {generator} at {url}");
}
Ok(b.clone())
}
None => {
if all_bindings.is_empty() {
anyhow::bail!("The package doesn't contain any bindings");
} else {
todo!();
}
}
}
}
#[derive(Debug, Copy, Clone)]
enum Target {
Pip,
Yarn { dev: bool },
Npm { dev: bool },
}
impl Target {
fn language(self) -> ProgrammingLanguage {
match self {
Target::Pip => ProgrammingLanguage::PYTHON,
Target::Yarn { .. } | Target::Npm { .. } => ProgrammingLanguage::JAVASCRIPT,
}
}
/// Construct a command which we can run to add packages.
///
/// This deliberately runs the command using the OS shell instead of
/// invoking the tool directly. That way we can handle when a version
/// manager (e.g. `nvm` or `asdf`) replaces the tool with a script (e.g.
/// `npm.cmd` or `yarn.ps1`).
///
/// See <https://github.com/wasmerio/wapm-cli/issues/291> for more.
fn command(self, packages: &[Bindings]) -> Command {
let command_line = match self {
Target::Pip => "pip install",
Target::Yarn { dev: true } => "yarn add --dev",
Target::Yarn { dev: false } => "yarn add",
Target::Npm { dev: true } => "npm install --dev",
Target::Npm { dev: false } => "npm install",
};
let mut command_line = command_line.to_string();
for pkg in packages {
command_line.push(' ');
command_line.push_str(&pkg.url);
}
if cfg!(windows) {
let mut cmd = Command::new("cmd");
cmd.arg("/C").arg(command_line);
cmd
} else {
let mut cmd = Command::new("sh");
cmd.arg("-c").arg(command_line);
cmd
}
}
}

View File

@@ -9,6 +9,7 @@ use serde::{Deserialize, Serialize};
#[cfg(feature = "http")] #[cfg(feature = "http")]
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::env; use std::env;
use std::fmt::Write as _;
use std::fs; use std::fs;
use std::fs::File; use std::fs::File;
use std::io::prelude::*; use std::io::prelude::*;
@@ -920,7 +921,8 @@ impl CreateExe {
for atom_name in atom_names.iter() { for atom_name in atom_names.iter() {
let atom_name = Self::normalize_atom_name(atom_name); let atom_name = Self::normalize_atom_name(atom_name);
c_code_to_instantiate.push_str(&format!( write!(
c_code_to_instantiate,
" "
wasm_module_t *atom_{atom_name} = wasmer_object_module_new(store, \"{atom_name}\"); wasm_module_t *atom_{atom_name} = wasmer_object_module_new(store, \"{atom_name}\");
@@ -931,11 +933,16 @@ impl CreateExe {
return -1; return -1;
}} }}
" "
)); )
deallocate_module.push_str(&format!("wasm_module_delete(atom_{atom_name});")); .unwrap();
write!(deallocate_module, "wasm_module_delete(atom_{atom_name});").unwrap();
} }
c_code_to_instantiate.push_str(&format!("wasm_module_t *module = atom_{atom_to_run};")); write!(
c_code_to_instantiate,
"wasm_module_t *module = atom_{atom_to_run};"
)
.unwrap();
WASMER_STATIC_MAIN_C_SOURCE WASMER_STATIC_MAIN_C_SOURCE
.replace("#define WASI", "#define WASI\r\n#define WASI_PIRITA") .replace("#define WASI", "#define WASI\r\n#define WASI_PIRITA")

View File

@@ -36,7 +36,7 @@ impl List {
if empty_table { if empty_table {
table.add_empty_row(); table.add_empty_row();
} }
let _ = table.printstd(); table.printstd();
Ok(()) Ok(())
} }

View File

@@ -0,0 +1,51 @@
use clap::Parser;
use dialoguer::Input;
/// Subcommand for listing packages
#[derive(Debug, Clone, Parser)]
pub struct Login {
/// Registry to log into (default: wapm.io)
#[clap(long, default_value = "wapm.io")]
pub registry: String,
/// Login token
#[clap(name = "TOKEN")]
pub token: Option<String>,
}
impl Login {
fn get_token_or_ask_user(&self) -> Result<String, std::io::Error> {
match self.token.as_ref() {
Some(s) => Ok(s.clone()),
None => {
let registry_host = url::Url::parse(&wasmer_registry::format_graphql(
&self.registry,
))
.map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::Other,
format!("Invalid registry for login {}: {e}", self.registry),
)
})?;
let registry_host = registry_host.host_str().ok_or_else(|| {
std::io::Error::new(
std::io::ErrorKind::Other,
format!("Invalid registry for login {}: no host", self.registry),
)
})?;
Input::new()
.with_prompt(&format!(
"Please paste the login token from https://{}/me:\"",
registry_host
))
.interact_text()
}
}
}
/// execute [List]
pub fn execute(&self) -> Result<(), anyhow::Error> {
let token = self.get_token_or_ask_user()?;
wasmer_registry::login::login_and_save_token(&self.registry, &token)
.map_err(|e| anyhow::anyhow!("{e}"))
}
}

View File

@@ -845,7 +845,7 @@ pub(crate) fn try_run_package_or_file(
let package = format!("{}", r.path.display()); let package = format!("{}", r.path.display());
let mut is_fake_sv = false; let mut is_fake_sv = false;
let mut sv = match SplitVersion::new(&package) { let mut sv = match SplitVersion::parse(&package) {
Ok(o) => o, Ok(o) => o,
Err(_) => { Err(_) => {
let mut fake_sv = SplitVersion { let mut fake_sv = SplitVersion {

View File

@@ -189,7 +189,7 @@ impl ControlStackFrame {
/// Pop values from the value stack so that it is left at the /// Pop values from the value stack so that it is left at the
/// input-parameters to an else-block. /// input-parameters to an else-block.
pub fn truncate_value_stack_to_else_params(&self, stack: &mut Vec<Value>) { pub fn truncate_value_stack_to_else_params(&self, stack: &mut Vec<Value>) {
debug_assert!(matches!(self, &ControlStackFrame::If { .. })); debug_assert!(matches!(self, &Self::If { .. }));
stack.truncate(self.original_stack_size()); stack.truncate(self.original_stack_size());
} }
@@ -202,7 +202,7 @@ impl ControlStackFrame {
// block can see the same number of parameters as the consequent block. As a matter of // block can see the same number of parameters as the consequent block. As a matter of
// fact, we need to substract an extra number of parameter values for if blocks. // fact, we need to substract an extra number of parameter values for if blocks.
let num_duplicated_params = match self { let num_duplicated_params = match self {
&ControlStackFrame::If { &Self::If {
num_param_values, .. num_param_values, ..
} => { } => {
debug_assert!(num_param_values <= self.original_stack_size()); debug_assert!(num_param_values <= self.original_stack_size());

View File

@@ -5,6 +5,9 @@ edition = "2021"
license = "MIT" license = "MIT"
description = "Crate to interact with the wasmer registry (wapm.io), download packages, etc." description = "Crate to interact with the wasmer registry (wapm.io), download packages, etc."
[dev-dependencies]
rand = "0.8.5"
[dependencies] [dependencies]
dirs = "4.0.0" dirs = "4.0.0"
graphql_client = "0.11.0" graphql_client = "0.11.0"
@@ -21,4 +24,5 @@ tar = "0.4.38"
flate2 = "1.0.24" flate2 = "1.0.24"
semver = "1.0.14" semver = "1.0.14"
lzma-rs = "0.2.0" lzma-rs = "0.2.0"
tempdir = "0.3.7" tempdir = "0.3.7"
log = "0.4.17"

View File

@@ -0,0 +1,22 @@
query GetBindingsQuery ($name: String!, $version: String = "latest") {
packageVersion: getPackageVersion(name:$name, version:$version) {
bindings {
id
language
url
generator {
packageVersion {
id
version
package {
name
}
}
commandName
}
__typename
}
}
}

View File

@@ -0,0 +1,5 @@
query WhoAmIQuery {
viewer {
username
}
}

File diff suppressed because it is too large Load Diff

325
lib/registry/src/config.rs Normal file
View File

@@ -0,0 +1,325 @@
use graphql_client::GraphQLQuery;
use serde::Deserialize;
use serde::Serialize;
use std::collections::BTreeMap;
#[cfg(not(test))]
use std::env;
use std::path::{Path, PathBuf};
pub static GLOBAL_CONFIG_FILE_NAME: &str = if cfg!(target_os = "wasi") {
"/.private/wapm.toml"
} else {
"wapm.toml"
};
#[derive(Deserialize, Default, Serialize, Debug, PartialEq, Eq)]
pub struct PartialWapmConfig {
/// The number of seconds to wait before checking the registry for a new
/// version of the package.
#[serde(default = "wax_default_cooldown")]
pub wax_cooldown: i32,
/// The registry that wapm will connect to.
pub registry: Registries,
/// Whether or not telemetry is enabled.
#[cfg(feature = "telemetry")]
#[serde(default)]
pub telemetry: Telemetry,
/// Whether or not updated notifications are enabled.
#[cfg(feature = "update-notifications")]
#[serde(default)]
pub update_notifications: UpdateNotifications,
/// The proxy to use when connecting to the Internet.
#[serde(default)]
pub proxy: Proxy,
}
pub const fn wax_default_cooldown() -> i32 {
5 * 60
}
#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Default)]
pub struct Proxy {
pub url: Option<String>,
}
#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Default)]
pub struct UpdateNotifications {
pub enabled: String,
}
#[cfg(feature = "telemetry")]
#[derive(Deserialize, Serialize, Debug, PartialEq)]
pub struct Telemetry {
pub enabled: String,
}
#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Clone)]
#[serde(untagged)]
pub enum Registries {
Single(Registry),
Multi(MultiRegistry),
}
#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Clone)]
pub struct MultiRegistry {
/// Currently active registry
pub current: String,
/// Map from "RegistryUrl" to "LoginToken", in order to
/// be able to be able to easily switch between registries
pub tokens: BTreeMap<String, String>,
}
impl Default for Registries {
fn default() -> Self {
Registries::Single(Registry {
url: format_graphql("https://registry.wapm.io"),
token: None,
})
}
}
#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Clone)]
pub struct Registry {
pub url: String,
pub token: Option<String>,
}
pub fn format_graphql(registry: &str) -> String {
let mut registry = registry.to_string();
if registry.contains("wapm.dev") {
registry = "https://registry.wapm.dev/graphql".to_string();
} else if registry.contains("wapm.io") {
registry = "https://registry.wapm.io/graphql".to_string();
}
if !registry.starts_with("https://") {
registry = format!("https://{registry}");
}
if registry.ends_with("/graphql") {
registry
} else if registry.ends_with('/') {
format!("{}graphql", registry)
} else {
format!("{}/graphql", registry)
}
}
fn test_if_registry_present(registry: &str) -> Result<(), String> {
crate::utils::get_username_registry_token(registry, "")
.map(|_| ())
.map_err(|e| format!("{e}"))
}
#[derive(PartialEq, Eq, Copy, Clone)]
pub enum UpdateRegistry {
Update,
LeaveAsIs,
}
#[test]
fn test_registries_switch_token() {
let mut registries = Registries::default();
registries.set_current_registry("https://registry.wapm.dev");
assert_eq!(
registries.get_current_registry(),
"https://registry.wapm.dev/graphql".to_string()
);
registries.set_login_token_for_registry(
"https://registry.wapm.io",
"token1",
UpdateRegistry::LeaveAsIs,
);
assert_eq!(
registries.get_current_registry(),
"https://registry.wapm.dev/graphql".to_string()
);
assert_eq!(
registries.get_login_token_for_registry(&registries.get_current_registry()),
None
);
registries.set_current_registry("https://registry.wapm.io");
assert_eq!(
registries.get_login_token_for_registry(&registries.get_current_registry()),
Some("token1".to_string())
);
registries.clear_current_registry_token();
assert_eq!(
registries.get_login_token_for_registry(&registries.get_current_registry()),
None
);
}
impl Registries {
/// Gets the current (active) registry URL
pub fn clear_current_registry_token(&mut self) {
match self {
Registries::Single(s) => {
s.token = None;
}
Registries::Multi(m) => {
m.tokens.remove(&m.current);
m.tokens.remove(&format_graphql(&m.current));
}
}
}
pub fn get_graphql_url(&self) -> String {
let registry = self.get_current_registry();
format_graphql(&registry)
}
/// Gets the current (active) registry URL
pub fn get_current_registry(&self) -> String {
match self {
Registries::Single(s) => format_graphql(&s.url),
Registries::Multi(m) => format_graphql(&m.current),
}
}
/// Sets the current (active) registry URL
pub fn set_current_registry(&mut self, registry: &str) {
let registry = format_graphql(registry);
if let Err(e) = test_if_registry_present(&registry) {
println!("Error when trying to ping registry {registry:?}: {e}");
println!("WARNING: Registry {registry:?} will be used, but commands may not succeed.");
}
match self {
Registries::Single(s) => s.url = registry,
Registries::Multi(m) => m.current = registry,
}
}
/// Returns the login token for the registry
pub fn get_login_token_for_registry(&self, registry: &str) -> Option<String> {
match self {
Registries::Single(s) if s.url == registry || format_graphql(registry) == s.url => {
s.token.clone()
}
Registries::Multi(m) => m
.tokens
.get(registry)
.or_else(|| m.tokens.get(&format_graphql(registry)))
.cloned(),
_ => None,
}
}
/// Sets the login token for the registry URL
pub fn set_login_token_for_registry(
&mut self,
registry: &str,
token: &str,
update_current_registry: UpdateRegistry,
) {
let new_map = match self {
Registries::Single(s) => {
if s.url == registry {
Registries::Single(Registry {
url: format_graphql(registry),
token: Some(token.to_string()),
})
} else {
let mut map = BTreeMap::new();
if let Some(token) = s.token.clone() {
map.insert(format_graphql(&s.url), token);
}
map.insert(format_graphql(registry), token.to_string());
Registries::Multi(MultiRegistry {
current: format_graphql(&s.url),
tokens: map,
})
}
}
Registries::Multi(m) => {
m.tokens.insert(format_graphql(registry), token.to_string());
if update_current_registry == UpdateRegistry::Update {
m.current = format_graphql(registry);
}
Registries::Multi(m.clone())
}
};
*self = new_map;
}
}
impl PartialWapmConfig {
/// Save the config to a file
pub fn save<P: AsRef<Path>>(&self, to: P) -> anyhow::Result<()> {
use std::{fs::File, io::Write};
let config_serialized = toml::to_string(&self)?;
let mut file = File::create(to)?;
file.write_all(config_serialized.as_bytes())?;
Ok(())
}
pub fn from_file(#[cfg(test)] test_name: &str) -> Result<Self, String> {
#[cfg(test)]
let path = Self::get_file_location(test_name)?;
#[cfg(not(test))]
let path = Self::get_file_location()?;
match std::fs::read_to_string(&path) {
Ok(config_toml) => {
toml::from_str(&config_toml).map_err(|e| format!("could not parse {path:?}: {e}"))
}
Err(_e) => Ok(Self::default()),
}
}
pub fn get_current_dir() -> std::io::Result<PathBuf> {
std::env::current_dir()
}
#[cfg(test)]
pub fn get_folder(test_name: &str) -> Result<PathBuf, String> {
let test_dir = std::env::temp_dir().join("test_wasmer").join(test_name);
let _ = std::fs::create_dir_all(&test_dir);
Ok(test_dir)
}
#[cfg(not(test))]
pub fn get_folder() -> Result<PathBuf, String> {
Ok(
if let Some(folder_str) = env::var("WASMER_DIR").ok().filter(|s| !s.is_empty()) {
let folder = PathBuf::from(folder_str);
std::fs::create_dir_all(folder.clone())
.map_err(|e| format!("cannot create config directory: {e}"))?;
folder
} else {
#[allow(unused_variables)]
let default_dir = Self::get_current_dir()
.ok()
.unwrap_or_else(|| PathBuf::from("/".to_string()));
let home_dir =
dirs::home_dir().ok_or_else(|| "cannot find home directory".to_string())?;
let mut folder = home_dir;
folder.push(".wasmer");
std::fs::create_dir_all(folder.clone())
.map_err(|e| format!("cannot create config directory: {e}"))?;
folder
},
)
}
#[cfg(test)]
pub fn get_file_location(test_name: &str) -> Result<PathBuf, String> {
Ok(Self::get_folder(test_name)?.join(GLOBAL_CONFIG_FILE_NAME))
}
#[cfg(not(test))]
pub fn get_file_location() -> Result<PathBuf, String> {
Ok(Self::get_folder()?.join(GLOBAL_CONFIG_FILE_NAME))
}
}
#[derive(GraphQLQuery)]
#[graphql(
schema_path = "graphql/schema.graphql",
query_path = "graphql/queries/test_if_registry_present.graphql",
response_derives = "Debug"
)]
struct TestIfRegistryPresent;

267
lib/registry/src/graphql.rs Normal file
View File

@@ -0,0 +1,267 @@
use graphql_client::*;
#[cfg(not(target_os = "wasi"))]
use reqwest::{
blocking::{multipart::Form, Client},
header::USER_AGENT,
};
use std::env;
use std::time::Duration;
#[cfg(target_os = "wasi")]
use {wasm_bus_reqwest::prelude::header::*, wasm_bus_reqwest::prelude::*};
mod proxy {
//! Code for dealing with setting things up to proxy network requests
use thiserror::Error;
#[derive(Debug, Error)]
pub enum ProxyError {
#[error("Failed to parse URL from {}: {}", url_location, error_message)]
UrlParseError {
url_location: String,
error_message: String,
},
#[error("Could not connect to proxy: {0}")]
ConnectionError(String),
}
/// Tries to set up a proxy
///
/// This function reads from wapm config's `proxy.url` first, then checks
/// `ALL_PROXY`, `HTTPS_PROXY`, and `HTTP_PROXY` environment variables, in both
/// upper case and lower case, in that order.
///
/// If a proxy is specified in wapm config's `proxy.url`, it is assumed
/// to be a general proxy
///
/// A return value of `Ok(None)` means that there was no attempt to set up a proxy,
/// `Ok(Some(proxy))` means that the proxy was set up successfully, and `Err(e)` that
/// there was a failure while attempting to set up the proxy.
pub fn maybe_set_up_proxy() -> anyhow::Result<Option<reqwest::Proxy>> {
use std::env;
let proxy = if let Ok(proxy_url) = env::var("ALL_PROXY").or_else(|_| env::var("all_proxy"))
{
reqwest::Proxy::all(&proxy_url).map(|proxy| (proxy_url, proxy, "ALL_PROXY"))
} else if let Ok(https_proxy_url) =
env::var("HTTPS_PROXY").or_else(|_| env::var("https_proxy"))
{
reqwest::Proxy::https(&https_proxy_url)
.map(|proxy| (https_proxy_url, proxy, "HTTPS_PROXY"))
} else if let Ok(http_proxy_url) =
env::var("HTTP_PROXY").or_else(|_| env::var("http_proxy"))
{
reqwest::Proxy::http(&http_proxy_url).map(|proxy| (http_proxy_url, proxy, "http_proxy"))
} else {
return Ok(None);
}
.map_err(|e| ProxyError::ConnectionError(e.to_string()))
.and_then(
|(proxy_url_str, proxy, url_location): (String, _, &'static str)| {
url::Url::parse(&proxy_url_str)
.map_err(|e| ProxyError::UrlParseError {
url_location: url_location.to_string(),
error_message: e.to_string(),
})
.map(|url| {
if !(url.username().is_empty()) && url.password().is_some() {
proxy.basic_auth(url.username(), url.password().unwrap_or_default())
} else {
proxy
}
})
},
)?;
Ok(Some(proxy))
}
}
#[derive(GraphQLQuery)]
#[graphql(
schema_path = "graphql/schema.graphql",
query_path = "graphql/queries/get_package_version.graphql",
response_derives = "Debug"
)]
pub(crate) struct GetPackageVersionQuery;
#[derive(GraphQLQuery)]
#[graphql(
schema_path = "graphql/schema.graphql",
query_path = "graphql/queries/get_package_by_command.graphql",
response_derives = "Debug"
)]
pub(crate) struct GetPackageByCommandQuery;
#[derive(GraphQLQuery)]
#[graphql(
schema_path = "graphql/schema.graphql",
query_path = "graphql/queries/test_if_registry_present.graphql",
response_derives = "Debug"
)]
pub(crate) struct TestIfRegistryPresent;
#[derive(GraphQLQuery)]
#[graphql(
schema_path = "graphql/schema.graphql",
query_path = "graphql/queries/get_bindings.graphql",
response_derives = "Debug,Clone,PartialEq,Eq"
)]
pub(crate) struct GetBindingsQuery;
#[cfg(target_os = "wasi")]
pub fn whoami_distro() -> String {
whoami::os().to_lowercase()
}
#[cfg(not(target_os = "wasi"))]
pub fn whoami_distro() -> String {
whoami::distro().to_lowercase()
}
fn setup_client() -> Result<Client, anyhow::Error> {
let builder = Client::builder();
let builder = if let Some(proxy) = proxy::maybe_set_up_proxy()? {
builder.proxy(proxy)
} else {
builder
};
builder.build().map_err(|e| e.into())
}
/// This function is being used to "ping" the registry
/// (see test_if_registry_present and see whether the response
/// is valid JSON, it doesn't check the response itself,
/// since the response format might change
pub fn execute_query_modifier_inner_check_json<V, F>(
registry_url: &str,
login_token: &str,
query: &QueryBody<V>,
timeout: Option<Duration>,
form_modifier: F,
) -> anyhow::Result<()>
where
V: serde::Serialize,
F: FnOnce(Form) -> Form,
{
let client = setup_client()?;
let vars = serde_json::to_string(&query.variables).unwrap();
let form = Form::new()
.text("query", query.query.to_string())
.text("operationName", query.operation_name.to_string())
.text("variables", vars);
let form = form_modifier(form);
let user_agent = format!(
"wasmer/{} {} {}",
env!("CARGO_PKG_VERSION"),
whoami::platform(),
whoami_distro(),
);
let mut res = client
.post(registry_url)
.multipart(form)
.bearer_auth(
env::var("WASMER_TOKEN")
.ok()
.or_else(|| env::var("WAPM_REGISTRY_TOKEN").ok())
.unwrap_or_else(|| login_token.to_string()),
)
.header(USER_AGENT, user_agent);
if let Some(t) = timeout {
res = res.timeout(t);
}
let res = res.send()?;
let _: Response<serde_json::Value> = res.json()?;
Ok(())
}
pub fn execute_query_modifier_inner<R, V, F>(
registry_url: &str,
login_token: &str,
query: &QueryBody<V>,
timeout: Option<Duration>,
form_modifier: F,
) -> anyhow::Result<R>
where
for<'de> R: serde::Deserialize<'de>,
V: serde::Serialize,
F: FnOnce(Form) -> Form,
{
let client = setup_client()?;
let vars = serde_json::to_string(&query.variables).unwrap();
let form = Form::new()
.text("query", query.query.to_string())
.text("operationName", query.operation_name.to_string())
.text("variables", vars);
let form = form_modifier(form);
let user_agent = format!(
"wasmer/{} {} {}",
env!("CARGO_PKG_VERSION"),
whoami::platform(),
whoami_distro(),
);
let mut res = client
.post(registry_url)
.multipart(form)
.bearer_auth(
env::var("WASMER_TOKEN")
.ok()
.or_else(|| env::var("WAPM_REGISTRY_TOKEN").ok())
.unwrap_or_else(|| login_token.to_string()),
)
.header(USER_AGENT, user_agent);
if let Some(t) = timeout {
res = res.timeout(t);
}
let res = res.send()?;
let response_body: Response<R> = res.json()?;
if let Some(errors) = response_body.errors {
let error_messages: Vec<String> = errors.into_iter().map(|err| err.message).collect();
return Err(anyhow::anyhow!("{}", error_messages.join(", ")));
}
response_body
.data
.ok_or_else(|| anyhow::anyhow!("missing response data"))
}
pub fn execute_query<R, V>(
registry_url: &str,
login_token: &str,
query: &QueryBody<V>,
) -> anyhow::Result<R>
where
for<'de> R: serde::Deserialize<'de>,
V: serde::Serialize,
{
execute_query_modifier_inner(registry_url, login_token, query, None, |f| f)
}
pub fn execute_query_with_timeout<R, V>(
registry_url: &str,
login_token: &str,
timeout: Duration,
query: &QueryBody<V>,
) -> anyhow::Result<R>
where
for<'de> R: serde::Deserialize<'de>,
V: serde::Serialize,
{
execute_query_modifier_inner(registry_url, login_token, query, Some(timeout), |f| f)
}

View File

@@ -1,273 +1,36 @@
use std::collections::BTreeMap; //! High-level interactions with the WAPM backend.
use std::env; //!
//! The GraphQL schema can be updated by running `make` in the Wasmer repo's
//! root directory.
//!
//! ```console
//! $ make update-graphql-schema
//! curl -sSfL https://registry.wapm.io/graphql/schema.graphql > lib/registry/graphql/schema.graphql
//! ```
use std::fmt; use std::fmt;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::time::Duration; use std::time::Duration;
use std::{
collections::BTreeMap,
fmt::{Display, Formatter},
};
use anyhow::Context; use anyhow::Context;
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
pub mod graphql { pub mod config;
pub mod graphql;
pub mod login;
pub mod utils;
use graphql_client::*; pub use crate::{
#[cfg(not(target_os = "wasi"))] config::{format_graphql, PartialWapmConfig},
use reqwest::{ graphql::get_bindings_query::ProgrammingLanguage,
blocking::{multipart::Form, Client}, };
header::USER_AGENT,
};
use std::env;
use std::time::Duration;
#[cfg(target_os = "wasi")]
use {wasm_bus_reqwest::prelude::header::*, wasm_bus_reqwest::prelude::*};
mod proxy { use crate::config::Registries;
//! Code for dealing with setting things up to proxy network requests use anyhow::Context;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum ProxyError {
#[error("Failed to parse URL from {}: {}", url_location, error_message)]
UrlParseError {
url_location: String,
error_message: String,
},
#[error("Could not connect to proxy: {0}")]
ConnectionError(String),
}
/// Tries to set up a proxy
///
/// This function reads from wapm config's `proxy.url` first, then checks
/// `ALL_PROXY`, `HTTPS_PROXY`, and `HTTP_PROXY` environment variables, in both
/// upper case and lower case, in that order.
///
/// If a proxy is specified in wapm config's `proxy.url`, it is assumed
/// to be a general proxy
///
/// A return value of `Ok(None)` means that there was no attempt to set up a proxy,
/// `Ok(Some(proxy))` means that the proxy was set up successfully, and `Err(e)` that
/// there was a failure while attempting to set up the proxy.
pub fn maybe_set_up_proxy() -> anyhow::Result<Option<reqwest::Proxy>> {
use std::env;
let proxy = if let Ok(proxy_url) =
env::var("ALL_PROXY").or_else(|_| env::var("all_proxy"))
{
reqwest::Proxy::all(&proxy_url).map(|proxy| (proxy_url, proxy, "ALL_PROXY"))
} else if let Ok(https_proxy_url) =
env::var("HTTPS_PROXY").or_else(|_| env::var("https_proxy"))
{
reqwest::Proxy::https(&https_proxy_url)
.map(|proxy| (https_proxy_url, proxy, "HTTPS_PROXY"))
} else if let Ok(http_proxy_url) =
env::var("HTTP_PROXY").or_else(|_| env::var("http_proxy"))
{
reqwest::Proxy::http(&http_proxy_url)
.map(|proxy| (http_proxy_url, proxy, "http_proxy"))
} else {
return Ok(None);
}
.map_err(|e| ProxyError::ConnectionError(e.to_string()))
.and_then(
|(proxy_url_str, proxy, url_location): (String, _, &'static str)| {
url::Url::parse(&proxy_url_str)
.map_err(|e| ProxyError::UrlParseError {
url_location: url_location.to_string(),
error_message: e.to_string(),
})
.map(|url| {
if !(url.username().is_empty()) && url.password().is_some() {
proxy.basic_auth(url.username(), url.password().unwrap_or_default())
} else {
proxy
}
})
},
)?;
Ok(Some(proxy))
}
}
#[derive(GraphQLQuery)]
#[graphql(
schema_path = "graphql/schema.graphql",
query_path = "graphql/queries/get_package_version.graphql",
response_derives = "Debug"
)]
pub(crate) struct GetPackageVersionQuery;
#[derive(GraphQLQuery)]
#[graphql(
schema_path = "graphql/schema.graphql",
query_path = "graphql/queries/get_package_by_command.graphql",
response_derives = "Debug"
)]
pub(crate) struct GetPackageByCommandQuery;
#[derive(GraphQLQuery)]
#[graphql(
schema_path = "graphql/schema.graphql",
query_path = "graphql/queries/test_if_registry_present.graphql",
response_derives = "Debug"
)]
pub(crate) struct TestIfRegistryPresent;
#[cfg(target_os = "wasi")]
pub fn whoami_distro() -> String {
whoami::os().to_lowercase()
}
#[cfg(not(target_os = "wasi"))]
pub fn whoami_distro() -> String {
whoami::distro().to_lowercase()
}
pub fn execute_query_modifier_inner_check_json<V, F>(
registry_url: &str,
login_token: &str,
query: &QueryBody<V>,
timeout: Option<Duration>,
form_modifier: F,
) -> anyhow::Result<()>
where
V: serde::Serialize,
F: FnOnce(Form) -> Form,
{
let client = {
let builder = Client::builder();
#[cfg(not(target_os = "wasi"))]
let builder = if let Some(proxy) = proxy::maybe_set_up_proxy()? {
builder.proxy(proxy)
} else {
builder
};
builder.build()?
};
let vars = serde_json::to_string(&query.variables).unwrap();
let form = Form::new()
.text("query", query.query.to_string())
.text("operationName", query.operation_name.to_string())
.text("variables", vars);
let form = form_modifier(form);
let user_agent = format!(
"wapm/{} {} {}",
env!("CARGO_PKG_VERSION"),
whoami::platform(),
whoami_distro(),
);
let mut res = client
.post(registry_url)
.multipart(form)
.bearer_auth(
env::var("WAPM_REGISTRY_TOKEN").unwrap_or_else(|_| login_token.to_string()),
)
.header(USER_AGENT, user_agent);
if let Some(t) = timeout {
res = res.timeout(t);
}
let res = res.send()?;
let _: Response<serde_json::Value> = res.json()?;
Ok(())
}
pub fn execute_query_modifier_inner<R, V, F>(
registry_url: &str,
login_token: &str,
query: &QueryBody<V>,
timeout: Option<Duration>,
form_modifier: F,
) -> anyhow::Result<R>
where
for<'de> R: serde::Deserialize<'de>,
V: serde::Serialize,
F: FnOnce(Form) -> Form,
{
let client = {
let builder = Client::builder();
#[cfg(not(target_os = "wasi"))]
let builder = if let Some(proxy) = proxy::maybe_set_up_proxy()? {
builder.proxy(proxy)
} else {
builder
};
builder.build()?
};
let vars = serde_json::to_string(&query.variables).unwrap();
let form = Form::new()
.text("query", query.query.to_string())
.text("operationName", query.operation_name.to_string())
.text("variables", vars);
let form = form_modifier(form);
let user_agent = format!(
"wapm/{} {} {}",
env!("CARGO_PKG_VERSION"),
whoami::platform(),
whoami_distro(),
);
let mut res = client
.post(registry_url)
.multipart(form)
.bearer_auth(
env::var("WAPM_REGISTRY_TOKEN").unwrap_or_else(|_| login_token.to_string()),
)
.header(USER_AGENT, user_agent);
if let Some(t) = timeout {
res = res.timeout(t);
}
let res = res.send()?;
let response_body: Response<R> = res.json()?;
if let Some(errors) = response_body.errors {
let error_messages: Vec<String> = errors.into_iter().map(|err| err.message).collect();
return Err(anyhow::anyhow!("{}", error_messages.join(", ")));
}
Ok(response_body.data.expect("missing response data"))
}
pub fn execute_query<R, V>(
registry_url: &str,
login_token: &str,
query: &QueryBody<V>,
) -> anyhow::Result<R>
where
for<'de> R: serde::Deserialize<'de>,
V: serde::Serialize,
{
execute_query_modifier_inner(registry_url, login_token, query, None, |f| f)
}
pub fn execute_query_with_timeout<R, V>(
registry_url: &str,
login_token: &str,
timeout: Duration,
query: &QueryBody<V>,
) -> anyhow::Result<R>
where
for<'de> R: serde::Deserialize<'de>,
V: serde::Serialize,
{
execute_query_modifier_inner(registry_url, login_token, query, Some(timeout), |f| f)
}
}
pub static GLOBAL_CONFIG_FILE_NAME: &str = if cfg!(target_os = "wasi") { pub static GLOBAL_CONFIG_FILE_NAME: &str = if cfg!(target_os = "wasi") {
"/.private/wapm.toml" "/.private/wapm.toml"
@@ -275,145 +38,6 @@ pub static GLOBAL_CONFIG_FILE_NAME: &str = if cfg!(target_os = "wasi") {
"wapm.toml" "wapm.toml"
}; };
#[derive(Deserialize, Default, Serialize, Debug, PartialEq)]
pub struct PartialWapmConfig {
/// The number of seconds to wait before checking the registry for a new
/// version of the package.
#[serde(default = "wax_default_cooldown")]
pub wax_cooldown: i32,
/// The registry that wapm will connect to.
pub registry: Registries,
/// Whether or not telemetry is enabled.
#[cfg(feature = "telemetry")]
#[serde(default)]
pub telemetry: Telemetry,
/// Whether or not updated notifications are enabled.
#[cfg(feature = "update-notifications")]
#[serde(default)]
pub update_notifications: UpdateNotifications,
/// The proxy to use when connecting to the Internet.
#[serde(default)]
pub proxy: Proxy,
}
pub const fn wax_default_cooldown() -> i32 {
5 * 60
}
#[derive(Deserialize, Serialize, Debug, PartialEq, Default)]
pub struct Proxy {
pub url: Option<String>,
}
#[derive(Deserialize, Serialize, Debug, PartialEq, Default)]
pub struct UpdateNotifications {
pub enabled: String,
}
#[cfg(feature = "telemetry")]
#[derive(Deserialize, Serialize, Debug, PartialEq)]
pub struct Telemetry {
pub enabled: String,
}
#[derive(Deserialize, Serialize, Debug, PartialEq, Clone)]
#[serde(untagged)]
pub enum Registries {
Single(Registry),
Multi(MultiRegistry),
}
#[derive(Deserialize, Serialize, Debug, PartialEq, Clone)]
pub struct MultiRegistry {
/// Currently active registry
pub current: String,
/// Map from "RegistryUrl" to "LoginToken", in order to
/// be able to be able to easily switch between registries
pub tokens: BTreeMap<String, String>,
}
impl Default for Registries {
fn default() -> Self {
Registries::Single(Registry {
url: format_graphql("https://registry.wapm.io"),
token: None,
})
}
}
#[derive(Deserialize, Serialize, Debug, PartialEq, Clone)]
pub struct Registry {
pub url: String,
pub token: Option<String>,
}
fn format_graphql(registry: &str) -> String {
if registry.ends_with("/graphql") {
registry.to_string()
} else if registry.ends_with('/') {
format!("{}graphql", registry)
} else {
format!("{}/graphql", registry)
}
}
impl PartialWapmConfig {
pub fn from_file() -> Result<Self, String> {
let path = Self::get_file_location()?;
match std::fs::read_to_string(&path) {
Ok(config_toml) => {
toml::from_str(&config_toml).map_err(|e| format!("could not parse {path:?}: {e}"))
}
Err(_e) => Ok(Self::default()),
}
}
pub fn get_current_dir() -> std::io::Result<PathBuf> {
#[cfg(target_os = "wasi")]
if let Some(pwd) = std::env::var("PWD").ok() {
return Ok(PathBuf::from(pwd));
}
std::env::current_dir()
}
pub fn get_folder() -> Result<PathBuf, String> {
Ok(
if let Some(folder_str) = env::var("WASMER_DIR").ok().filter(|s| !s.is_empty()) {
let folder = PathBuf::from(folder_str);
std::fs::create_dir_all(folder.clone())
.map_err(|e| format!("cannot create config directory: {e}"))?;
folder
} else {
#[allow(unused_variables)]
let default_dir = Self::get_current_dir()
.ok()
.unwrap_or_else(|| PathBuf::from("/".to_string()));
#[cfg(feature = "dirs")]
let home_dir =
dirs::home_dir().ok_or(GlobalConfigError::CannotFindHomeDirectory)?;
#[cfg(not(feature = "dirs"))]
let home_dir = std::env::var("HOME")
.ok()
.unwrap_or_else(|| default_dir.to_string_lossy().to_string());
let mut folder = PathBuf::from(home_dir);
folder.push(".wasmer");
std::fs::create_dir_all(folder.clone())
.map_err(|e| format!("cannot create config directory: {e}"))?;
folder
},
)
}
fn get_file_location() -> Result<PathBuf, String> {
Ok(Self::get_folder()?.join(GLOBAL_CONFIG_FILE_NAME))
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord)] #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord)]
pub struct PackageDownloadInfo { pub struct PackageDownloadInfo {
pub registry: String, pub registry: String,
@@ -426,6 +50,7 @@ pub struct PackageDownloadInfo {
} }
pub fn get_package_local_dir( pub fn get_package_local_dir(
#[cfg(test)] test_name: &str,
registry_host: &str, registry_host: &str,
name: &str, name: &str,
version: &str, version: &str,
@@ -438,18 +63,26 @@ pub fn get_package_local_dir(
let (namespace, name) = name let (namespace, name) = name
.split_once('/') .split_once('/')
.ok_or_else(|| format!("missing namespace / name for {name:?}"))?; .ok_or_else(|| format!("missing namespace / name for {name:?}"))?;
let install_dir = get_global_install_dir(registry_host) #[cfg(test)]
.ok_or_else(|| format!("no install dir for {name:?}"))?; let global_install_dir = get_global_install_dir(test_name, registry_host);
#[cfg(not(test))]
let global_install_dir = get_global_install_dir(registry_host);
let install_dir = global_install_dir.ok_or_else(|| format!("no install dir for {name:?}"))?;
Ok(install_dir.join(namespace).join(name).join(version)) Ok(install_dir.join(namespace).join(name).join(version))
} }
pub fn try_finding_local_command(cmd: &str) -> Option<LocalPackage> { pub fn try_finding_local_command(#[cfg(test)] test_name: &str, cmd: &str) -> Option<LocalPackage> {
for p in get_all_local_packages(None) { #[cfg(test)]
if p.get_commands() let local_packages = get_all_local_packages(test_name, None);
.unwrap_or_default() #[cfg(not(test))]
.iter() let local_packages = get_all_local_packages(None);
.any(|c| c == cmd) for p in local_packages {
{ #[cfg(not(test))]
let commands = p.get_commands();
#[cfg(test)]
let commands = p.get_commands(test_name);
if commands.unwrap_or_default().iter().any(|c| c == cmd) {
return Some(p); return Some(p);
} }
} }
@@ -464,16 +97,28 @@ pub struct LocalPackage {
} }
impl LocalPackage { impl LocalPackage {
pub fn get_path(&self) -> Result<PathBuf, String> { pub fn get_path(&self, #[cfg(test)] test_name: &str) -> Result<PathBuf, String> {
let host = url::Url::parse(&self.registry) let host = url::Url::parse(&self.registry)
.ok() .ok()
.and_then(|o| o.host_str().map(|s| s.to_string())) .and_then(|o| o.host_str().map(|s| s.to_string()))
.unwrap_or_else(|| self.registry.clone()); .unwrap_or_else(|| self.registry.clone());
get_package_local_dir(&host, &self.name, &self.version) #[cfg(test)]
{
get_package_local_dir(test_name, &host, &self.name, &self.version)
}
#[cfg(not(test))]
{
get_package_local_dir(&host, &self.name, &self.version)
}
} }
pub fn get_commands(&self) -> Result<Vec<String>, String> { pub fn get_commands(&self, #[cfg(test)] test_name: &str) -> Result<Vec<String>, String> {
let toml_path = self.get_path()?.join("wapm.toml"); #[cfg(not(test))]
let path = self.get_path()?;
#[cfg(test)]
let path = self.get_path(test_name)?;
let toml_path = path.join("wapm.toml");
let toml = std::fs::read_to_string(&toml_path) let toml = std::fs::read_to_string(&toml_path)
.map_err(|e| format!("error reading {}: {e}", toml_path.display()))?; .map_err(|e| format!("error reading {}: {e}", toml_path.display()))?;
let toml_parsed = toml::from_str::<wapm_toml::Manifest>(&toml) let toml_parsed = toml::from_str::<wapm_toml::Manifest>(&toml)
@@ -553,11 +198,23 @@ fn get_all_names_in_dir(dir: &PathBuf) -> Vec<(PathBuf, String)> {
} }
/// Returns a list of all locally installed packages /// Returns a list of all locally installed packages
pub fn get_all_local_packages(registry: Option<&str>) -> Vec<LocalPackage> { pub fn get_all_local_packages(
#[cfg(test)] test_name: &str,
registry: Option<&str>,
) -> Vec<LocalPackage> {
let mut packages = Vec::new(); let mut packages = Vec::new();
let registries = match registry { let registries = match registry {
Some(s) => vec![s.to_string()], Some(s) => vec![s.to_string()],
None => get_all_available_registries().unwrap_or_default(), None => {
#[cfg(test)]
{
get_all_available_registries(test_name).unwrap_or_default()
}
#[cfg(not(test))]
{
get_all_available_registries().unwrap_or_default()
}
}
}; };
let mut registry_hosts = registries let mut registry_hosts = registries
@@ -565,7 +222,12 @@ pub fn get_all_local_packages(registry: Option<&str>) -> Vec<LocalPackage> {
.filter_map(|s| url::Url::parse(&s).ok()?.host_str().map(|s| s.to_string())) .filter_map(|s| url::Url::parse(&s).ok()?.host_str().map(|s| s.to_string()))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let mut registries_in_root_dir = get_checkouts_dir() #[cfg(not(test))]
let checkouts_dir = get_checkouts_dir();
#[cfg(test)]
let checkouts_dir = get_checkouts_dir(test_name);
let mut registries_in_root_dir = checkouts_dir
.as_ref() .as_ref()
.map(get_all_names_in_dir) .map(get_all_names_in_dir)
.unwrap_or_default() .unwrap_or_default()
@@ -578,7 +240,11 @@ pub fn get_all_local_packages(registry: Option<&str>) -> Vec<LocalPackage> {
registry_hosts.dedup(); registry_hosts.dedup();
for host in registry_hosts { for host in registry_hosts {
let root_dir = match get_global_install_dir(&host) { #[cfg(not(test))]
let global_install_dir = get_global_install_dir(&host);
#[cfg(test)]
let global_install_dir = get_global_install_dir(test_name, &host);
let root_dir = match global_install_dir {
Some(o) => o, Some(o) => o,
None => continue, None => continue,
}; };
@@ -604,11 +270,17 @@ pub fn get_all_local_packages(registry: Option<&str>) -> Vec<LocalPackage> {
} }
pub fn get_local_package( pub fn get_local_package(
#[cfg(test)] test_name: &str,
registry: Option<&str>, registry: Option<&str>,
name: &str, name: &str,
version: Option<&str>, version: Option<&str>,
) -> Option<LocalPackage> { ) -> Option<LocalPackage> {
get_all_local_packages(registry) #[cfg(not(test))]
let local_packages = get_all_local_packages(registry);
#[cfg(test)]
let local_packages = get_all_local_packages(test_name, registry);
local_packages
.iter() .iter()
.find(|p| { .find(|p| {
if p.name != name { if p.name != name {
@@ -657,7 +329,7 @@ pub fn query_command_from_registry(
}) })
} }
#[derive(Debug, Clone, PartialEq, PartialOrd)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd)]
pub enum QueryPackageError { pub enum QueryPackageError {
ErrorSendingQuery(String), ErrorSendingQuery(String),
NoPackageFound { NoPackageFound {
@@ -667,7 +339,7 @@ pub enum QueryPackageError {
} }
impl fmt::Display for QueryPackageError { impl fmt::Display for QueryPackageError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { match self {
QueryPackageError::ErrorSendingQuery(q) => write!(f, "error sending query: {q}"), QueryPackageError::ErrorSendingQuery(q) => write!(f, "error sending query: {q}"),
QueryPackageError::NoPackageFound { name, version } => { QueryPackageError::NoPackageFound { name, version } => {
@@ -677,7 +349,7 @@ impl fmt::Display for QueryPackageError {
} }
} }
#[derive(Debug, Clone, PartialEq, PartialOrd)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd)]
pub enum GetIfPackageHasNewVersionResult { pub enum GetIfPackageHasNewVersionResult {
// if version = Some(...) and the ~/.wasmer/checkouts/.../{version} exists, the package is already installed // if version = Some(...) and the ~/.wasmer/checkouts/.../{version} exists, the package is already installed
UseLocalAlreadyInstalled { UseLocalAlreadyInstalled {
@@ -707,15 +379,17 @@ pub enum GetIfPackageHasNewVersionResult {
#[test] #[test]
fn test_get_if_package_has_new_version() { fn test_get_if_package_has_new_version() {
const TEST_NAME: &str = "test_get_if_package_has_new_version";
let fake_registry = "https://h0.com"; let fake_registry = "https://h0.com";
let fake_name = "namespace0/project1"; let fake_name = "namespace0/project1";
let fake_version = "1.0.0"; let fake_version = "1.0.0";
let package_path = get_package_local_dir("h0.com", fake_name, fake_version).unwrap(); let package_path = get_package_local_dir(TEST_NAME, "h0.com", fake_name, fake_version).unwrap();
let _ = std::fs::remove_file(&package_path.join("wapm.toml")); let _ = std::fs::remove_file(&package_path.join("wapm.toml"));
let _ = std::fs::remove_file(&package_path.join("wapm.toml")); let _ = std::fs::remove_file(&package_path.join("wapm.toml"));
let r1 = get_if_package_has_new_version( let r1 = get_if_package_has_new_version(
TEST_NAME,
fake_registry, fake_registry,
"namespace0/project1", "namespace0/project1",
Some(fake_version.to_string()), Some(fake_version.to_string()),
@@ -732,11 +406,12 @@ fn test_get_if_package_has_new_version() {
} }
); );
let package_path = get_package_local_dir("h0.com", fake_name, fake_version).unwrap(); let package_path = get_package_local_dir(TEST_NAME, "h0.com", fake_name, fake_version).unwrap();
std::fs::create_dir_all(&package_path).unwrap(); std::fs::create_dir_all(&package_path).unwrap();
std::fs::write(&package_path.join("wapm.toml"), b"").unwrap(); std::fs::write(&package_path.join("wapm.toml"), b"").unwrap();
let r1 = get_if_package_has_new_version( let r1 = get_if_package_has_new_version(
TEST_NAME,
fake_registry, fake_registry,
"namespace0/project1", "namespace0/project1",
Some(fake_version.to_string()), Some(fake_version.to_string()),
@@ -759,6 +434,7 @@ fn test_get_if_package_has_new_version() {
/// ///
/// Also returns true if the package is not installed yet. /// Also returns true if the package is not installed yet.
pub fn get_if_package_has_new_version( pub fn get_if_package_has_new_version(
#[cfg(test)] test_name: &str,
registry_url: &str, registry_url: &str,
name: &str, name: &str,
version: Option<String>, version: Option<String>,
@@ -776,7 +452,12 @@ pub fn get_if_package_has_new_version(
.split_once('/') .split_once('/')
.ok_or_else(|| format!("missing namespace / name for {name:?}"))?; .ok_or_else(|| format!("missing namespace / name for {name:?}"))?;
let package_dir = get_global_install_dir(&host).map(|path| path.join(namespace).join(name)); #[cfg(not(test))]
let global_install_dir = get_global_install_dir(&host);
#[cfg(test)]
let global_install_dir = get_global_install_dir(test_name, &host);
let package_dir = global_install_dir.map(|path| path.join(namespace).join(name));
let package_dir = match package_dir { let package_dir = match package_dir {
Some(s) => s, Some(s) => s,
@@ -934,16 +615,35 @@ pub fn query_package_from_registry(
}) })
} }
pub fn get_wasmer_root_dir() -> Option<PathBuf> { pub fn get_wasmer_root_dir(#[cfg(test)] test_name: &str) -> Option<PathBuf> {
PartialWapmConfig::get_folder().ok() #[cfg(test)]
{
PartialWapmConfig::get_folder(test_name).ok()
}
#[cfg(not(test))]
{
PartialWapmConfig::get_folder().ok()
}
} }
pub fn get_checkouts_dir() -> Option<PathBuf> {
Some(get_wasmer_root_dir()?.join("checkouts")) pub fn get_checkouts_dir(#[cfg(test)] test_name: &str) -> Option<PathBuf> {
#[cfg(test)]
let root_dir = get_wasmer_root_dir(test_name)?;
#[cfg(not(test))]
let root_dir = get_wasmer_root_dir()?;
Some(root_dir.join("checkouts"))
} }
/// Returs the path to the directory where all packages on this computer are being stored /// Returs the path to the directory where all packages on this computer are being stored
pub fn get_global_install_dir(registry_host: &str) -> Option<PathBuf> { pub fn get_global_install_dir(
Some(get_checkouts_dir()?.join(registry_host)) #[cfg(test)] test_name: &str,
registry_host: &str,
) -> Option<PathBuf> {
#[cfg(test)]
let root_dir = get_checkouts_dir(test_name)?;
#[cfg(not(test))]
let root_dir = get_checkouts_dir()?;
Some(root_dir.join(registry_host))
} }
/// Convenience function that will unpack .tar.gz files and .tar.bz /// Convenience function that will unpack .tar.gz files and .tar.bz
@@ -1060,6 +760,7 @@ where
/// Given a triple of [registry, name, version], downloads and installs the /// Given a triple of [registry, name, version], downloads and installs the
/// .tar.gz if it doesn't yet exist, returns the (package dir, entrypoint .wasm file path) /// .tar.gz if it doesn't yet exist, returns the (package dir, entrypoint .wasm file path)
pub fn install_package( pub fn install_package(
#[cfg(test)] test_name: &str,
registry: Option<&str>, registry: Option<&str>,
name: &str, name: &str,
version: Option<&str>, version: Option<&str>,
@@ -1071,7 +772,16 @@ pub fn install_package(
None => { None => {
let registries = match registry { let registries = match registry {
Some(s) => vec![s.to_string()], Some(s) => vec![s.to_string()],
None => get_all_available_registries()?, None => {
#[cfg(test)]
{
get_all_available_registries(test_name)?
}
#[cfg(not(test))]
{
get_all_available_registries()?
}
}
}; };
let mut url_of_package = None; let mut url_of_package = None;
@@ -1090,12 +800,21 @@ pub fn install_package(
for r in registries.iter() { for r in registries.iter() {
if !force_install { if !force_install {
#[cfg(not(test))]
let package_has_new_version = get_if_package_has_new_version( let package_has_new_version = get_if_package_has_new_version(
r, r,
name, name,
version.map(|s| s.to_string()), version.map(|s| s.to_string()),
Duration::from_secs(60 * 5), Duration::from_secs(60 * 5),
)?; )?;
#[cfg(test)]
let package_has_new_version = get_if_package_has_new_version(
test_name,
r,
name,
version.map(|s| s.to_string()),
Duration::from_secs(60 * 5),
)?;
if let GetIfPackageHasNewVersionResult::UseLocalAlreadyInstalled { if let GetIfPackageHasNewVersionResult::UseLocalAlreadyInstalled {
registry_host, registry_host,
namespace, namespace,
@@ -1146,6 +865,14 @@ pub fn install_package(
.ok_or_else(|| format!("invalid url: {}", package_info.registry))? .ok_or_else(|| format!("invalid url: {}", package_info.registry))?
.to_string(); .to_string();
#[cfg(test)]
let dir = get_package_local_dir(
test_name,
&host,
&package_info.package,
&package_info.version,
)?;
#[cfg(not(test))]
let dir = get_package_local_dir(&host, &package_info.package, &package_info.version)?; let dir = get_package_local_dir(&host, &package_info.package, &package_info.version)?;
let version = package_info.version; let version = package_info.version;
@@ -1170,7 +897,7 @@ pub fn test_if_registry_present(registry: &str) -> Result<bool, String> {
use graphql_client::GraphQLQuery; use graphql_client::GraphQLQuery;
let q = TestIfRegistryPresent::build_query(test_if_registry_present::Variables {}); let q = TestIfRegistryPresent::build_query(test_if_registry_present::Variables {});
let _ = crate::graphql::execute_query_modifier_inner_check_json( crate::graphql::execute_query_modifier_inner_check_json(
registry, registry,
"", "",
&q, &q,
@@ -1182,8 +909,12 @@ pub fn test_if_registry_present(registry: &str) -> Result<bool, String> {
Ok(true) Ok(true)
} }
pub fn get_all_available_registries() -> Result<Vec<String>, String> { pub fn get_all_available_registries(#[cfg(test)] test_name: &str) -> Result<Vec<String>, String> {
#[cfg(test)]
let config = PartialWapmConfig::from_file(test_name)?;
#[cfg(not(test))]
let config = PartialWapmConfig::from_file()?; let config = PartialWapmConfig::from_file()?;
let mut registries = Vec::new(); let mut registries = Vec::new();
match config.registry { match config.registry {
Registries::Single(s) => { Registries::Single(s) => {
@@ -1203,6 +934,8 @@ pub fn get_all_available_registries() -> Result<Vec<String>, String> {
#[cfg(not(target_env = "musl"))] #[cfg(not(target_env = "musl"))]
#[test] #[test]
fn test_install_package() { fn test_install_package() {
const TEST_NAME: &str = "test_install_package";
println!("test install package..."); println!("test install package...");
let registry = "https://registry.wapm.io/graphql"; let registry = "https://registry.wapm.io/graphql";
if !test_if_registry_present(registry).unwrap_or(false) { if !test_if_registry_present(registry).unwrap_or(false) {
@@ -1226,21 +959,28 @@ fn test_install_package() {
"https://registry-cdn.wapm.io/packages/wasmer/wabt/wabt-1.0.29.tar.gz".to_string() "https://registry-cdn.wapm.io/packages/wasmer/wabt/wabt-1.0.29.tar.gz".to_string()
); );
let (package, _) = let (package, _) = install_package(
install_package(Some(registry), "wasmer/wabt", Some("1.0.29"), None, true).unwrap(); TEST_NAME,
Some(registry),
"wasmer/wabt",
Some("1.0.29"),
None,
true,
)
.unwrap();
println!("package installed: {package:#?}"); println!("package installed: {package:#?}");
assert_eq!( assert_eq!(
package.get_path().unwrap(), package.get_path(TEST_NAME).unwrap(),
get_global_install_dir("registry.wapm.io") get_global_install_dir(TEST_NAME, "registry.wapm.io")
.unwrap() .unwrap()
.join("wasmer") .join("wasmer")
.join("wabt") .join("wabt")
.join("1.0.29") .join("1.0.29")
); );
let all_installed_packages = get_all_local_packages(Some(registry)); let all_installed_packages = get_all_local_packages(TEST_NAME, Some(registry));
println!("all_installed_packages: {all_installed_packages:#?}"); println!("all_installed_packages: {all_installed_packages:#?}");
@@ -1251,7 +991,7 @@ fn test_install_package() {
println!("is_installed: {is_installed:#?}"); println!("is_installed: {is_installed:#?}");
if !is_installed { if !is_installed {
let panic_str = get_all_local_packages(Some(registry)) let panic_str = get_all_local_packages(TEST_NAME, Some(registry))
.iter() .iter()
.map(|p| format!("{} {} {}", p.registry, p.name, p.version)) .map(|p| format!("{} {} {}", p.registry, p.name, p.version))
.collect::<Vec<_>>() .collect::<Vec<_>>()
@@ -1261,3 +1001,90 @@ fn test_install_package() {
println!("ok, done"); println!("ok, done");
} }
/// A library that exposes bindings to a WAPM package.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Bindings {
/// A unique ID specifying this set of bindings.
pub id: String,
/// The URL which can be used to download the files that were generated
/// (typically as a `*.tar.gz` file).
pub url: String,
/// The programming language these bindings are written in.
pub language: graphql::get_bindings_query::ProgrammingLanguage,
/// The generator used to generate these bindings.
pub generator: BindingsGenerator,
}
/// The generator used to create [`Bindings`].
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BindingsGenerator {
/// A unique ID specifying this generator.
pub id: String,
/// The generator package's name (e.g. `wasmer/wasmer-pack`).
pub package_name: String,
/// The exact package version.
pub version: String,
/// The name of the command that was used for generating bindings.
pub command: String,
}
impl Display for BindingsGenerator {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let BindingsGenerator {
package_name,
version,
command,
..
} = self;
write!(f, "{package_name}@{version}:{command}")?;
Ok(())
}
}
/// List all bindings associated with a particular package.
///
/// If a version number isn't provided, this will default to the most recently
/// published version.
pub fn list_bindings(
registry: &str,
name: &str,
version: Option<&str>,
) -> Result<Vec<Bindings>, anyhow::Error> {
use crate::graphql::{
get_bindings_query::{ResponseData, Variables},
GetBindingsQuery,
};
use graphql_client::GraphQLQuery;
let variables = Variables {
name: name.to_string(),
version: version.map(String::from),
};
let q = GetBindingsQuery::build_query(variables);
let response: ResponseData = crate::graphql::execute_query(registry, "", &q)?;
let package_version = response.package_version.context("Package not found")?;
let mut bindings_packages = Vec::new();
for b in package_version.bindings.into_iter().flatten() {
let pkg = Bindings {
id: b.id,
url: b.url,
language: b.language,
generator: BindingsGenerator {
id: b.generator.package_version.id,
package_name: b.generator.package_version.package.name,
version: b.generator.package_version.version,
command: b.generator.command_name,
},
};
bindings_packages.push(pkg);
}
Ok(bindings_packages)
}

36
lib/registry/src/login.rs Normal file
View File

@@ -0,0 +1,36 @@
use crate::config::{format_graphql, UpdateRegistry};
use crate::PartialWapmConfig;
/// Login to a registry and save the token associated with it.
///
/// Also sets the registry as the currently active registry to provide a better UX.
pub fn login_and_save_token(
#[cfg(test)] test_name: &str,
registry: &str,
token: &str,
) -> Result<(), anyhow::Error> {
let registry = format_graphql(registry);
#[cfg(test)]
let mut config = PartialWapmConfig::from_file(test_name).map_err(|e| anyhow::anyhow!("{e}"))?;
#[cfg(not(test))]
let mut config = PartialWapmConfig::from_file().map_err(|e| anyhow::anyhow!("{e}"))?;
config.registry.set_current_registry(&registry);
config.registry.set_login_token_for_registry(
&config.registry.get_current_registry(),
token,
UpdateRegistry::Update,
);
#[cfg(test)]
let path =
PartialWapmConfig::get_file_location(test_name).map_err(|e| anyhow::anyhow!("{e}"))?;
#[cfg(not(test))]
let path = PartialWapmConfig::get_file_location().map_err(|e| anyhow::anyhow!("{e}"))?;
config.save(&path)?;
let username = crate::utils::get_username_registry_token(&registry, token);
if let Some(s) = username.ok().and_then(|o| o) {
println!("Login for WAPM user {:?} saved", s);
} else {
println!("Login for WAPM user saved");
}
Ok(())
}

27
lib/registry/src/utils.rs Normal file
View File

@@ -0,0 +1,27 @@
use crate::{graphql::execute_query, PartialWapmConfig};
use graphql_client::GraphQLQuery;
#[derive(GraphQLQuery)]
#[graphql(
schema_path = "graphql/schema.graphql",
query_path = "graphql/queries/whoami.graphql",
response_derives = "Debug"
)]
struct WhoAmIQuery;
pub fn get_username(#[cfg(test)] test_name: &str) -> anyhow::Result<Option<String>> {
#[cfg(test)]
let config = PartialWapmConfig::from_file(test_name).map_err(|e| anyhow::anyhow!("{e}"))?;
#[cfg(not(test))]
let config = PartialWapmConfig::from_file().map_err(|e| anyhow::anyhow!("{e}"))?;
let registry = &config.registry.get_current_registry();
let q = WhoAmIQuery::build_query(who_am_i_query::Variables {});
let response: who_am_i_query::ResponseData = execute_query(registry, "", &q)?;
Ok(response.viewer.map(|viewer| viewer.username))
}
pub fn get_username_registry_token(registry: &str, token: &str) -> anyhow::Result<Option<String>> {
let q = WhoAmIQuery::build_query(who_am_i_query::Variables {});
let response: who_am_i_query::ResponseData = execute_query(registry, token, &q)?;
Ok(response.viewer.map(|viewer| viewer.username))
}

View File

@@ -23,7 +23,7 @@ where
pub memory: Arc<MemFileSystem>, pub memory: Arc<MemFileSystem>,
} }
impl<'a, T> WebcFileSystem<T> impl<T> WebcFileSystem<T>
where where
T: std::fmt::Debug + Send + Sync + 'static, T: std::fmt::Debug + Send + Sync + 'static,
T: Deref<Target = WebC<'static>>, T: Deref<Target = WebC<'static>>,
@@ -54,7 +54,7 @@ where
pub memory: Arc<MemFileSystem>, pub memory: Arc<MemFileSystem>,
} }
impl<'a, T> FileOpener for WebCFileOpener<T> impl<T> FileOpener for WebCFileOpener<T>
where where
T: std::fmt::Debug + Send + Sync + 'static, T: std::fmt::Debug + Send + Sync + 'static,
T: Deref<Target = WebC<'static>>, T: Deref<Target = WebC<'static>>,

View File

@@ -261,8 +261,8 @@ impl<T> MaybeInstanceOwned<T> {
/// Returns underlying pointer to the VM data. /// Returns underlying pointer to the VM data.
pub fn as_ptr(&self) -> NonNull<T> { pub fn as_ptr(&self) -> NonNull<T> {
match self { match self {
MaybeInstanceOwned::Host(p) => unsafe { NonNull::new_unchecked(p.get()) }, Self::Host(p) => unsafe { NonNull::new_unchecked(p.get()) },
MaybeInstanceOwned::Instance(p) => *p, Self::Instance(p) => *p,
} }
} }
} }
@@ -273,12 +273,12 @@ where
{ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
MaybeInstanceOwned::Host(p) => { Self::Host(p) => {
write!(f, "host(")?; write!(f, "host(")?;
p.as_ref().fmt(f)?; p.as_ref().fmt(f)?;
write!(f, ")") write!(f, ")")
} }
MaybeInstanceOwned::Instance(p) => { Self::Instance(p) => {
write!(f, "instance(")?; write!(f, "instance(")?;
unsafe { p.as_ref().fmt(f)? }; unsafe { p.as_ref().fmt(f)? };
write!(f, ")") write!(f, ")")

View File

@@ -829,14 +829,14 @@ enum UnwindReason {
impl UnwindReason { impl UnwindReason {
fn into_trap(self) -> Trap { fn into_trap(self) -> Trap {
match self { match self {
UnwindReason::UserTrap(data) => Trap::User(data), Self::UserTrap(data) => Trap::User(data),
UnwindReason::LibTrap(trap) => trap, Self::LibTrap(trap) => trap,
UnwindReason::WasmTrap { Self::WasmTrap {
backtrace, backtrace,
pc, pc,
signal_trap, signal_trap,
} => Trap::wasm(pc, backtrace, signal_trap), } => Trap::wasm(pc, backtrace, signal_trap),
UnwindReason::Panic(panic) => std::panic::resume_unwind(panic), Self::Panic(panic) => std::panic::resume_unwind(panic),
} }
} }
} }

View File

@@ -1,3 +1,6 @@
#![doc(html_favicon_url = "https://wasmer.io/images/icons/favicon-32x32.png")]
#![doc(html_logo_url = "https://github.com/wasmerio.png?size=200")]
pub mod types; pub mod types;
pub mod wasi; pub mod wasi;

View File

@@ -1,6 +1,4 @@
#![deny(unused_mut)] #![deny(unused_mut)]
#![doc(html_favicon_url = "https://wasmer.io/images/icons/favicon-32x32.png")]
#![doc(html_logo_url = "https://github.com/wasmerio.png?size=200")]
#![allow(non_camel_case_types, clippy::identity_op)] #![allow(non_camel_case_types, clippy::identity_op)]
//! Wasmer's WASI types implementation. //! Wasmer's WASI types implementation.

View File

@@ -1 +1 @@
1.61 1.63

View File

@@ -2,7 +2,7 @@ use std::sync::Arc;
use wasmer::{CompilerConfig, Features, ModuleMiddleware, Store}; use wasmer::{CompilerConfig, Features, ModuleMiddleware, Store};
use wasmer_compiler::Engine; use wasmer_compiler::Engine;
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub enum Compiler { pub enum Compiler {
LLVM, LLVM,
Cranelift, Cranelift,

View File

@@ -34,8 +34,7 @@ fn test_trap_return(config: crate::Config) -> Result<()> {
let e = run_func let e = run_func
.call(&mut store, &[]) .call(&mut store, &[])
.err() .expect_err("error calling function");
.expect("error calling function");
assert_eq!(e.message(), "test 123"); assert_eq!(e.message(), "test 123");
@@ -62,8 +61,7 @@ fn test_trap_trace(config: crate::Config) -> Result<()> {
let e = run_func let e = run_func
.call(&mut store, &[]) .call(&mut store, &[])
.err() .expect_err("error calling function");
.expect("error calling function");
let trace = e.trace(); let trace = e.trace();
assert_eq!(trace.len(), 2); assert_eq!(trace.len(), 2);
@@ -113,8 +111,7 @@ fn test_trap_trace_cb(config: crate::Config) -> Result<()> {
let e = run_func let e = run_func
.call(&mut store, &[]) .call(&mut store, &[])
.err() .expect_err("error calling function");
.expect("error calling function");
let trace = e.trace(); let trace = e.trace();
println!("Trace {:?}", trace); println!("Trace {:?}", trace);
@@ -148,8 +145,7 @@ fn test_trap_stack_overflow(config: crate::Config) -> Result<()> {
let e = run_func let e = run_func
.call(&mut store, &[]) .call(&mut store, &[])
.err() .expect_err("error calling function");
.expect("error calling function");
// We specifically don't check the stack trace here: stack traces after // We specifically don't check the stack trace here: stack traces after
// stack overflows are not generally possible due to unreliable unwinding // stack overflows are not generally possible due to unreliable unwinding
@@ -181,8 +177,7 @@ fn trap_display_pretty(config: crate::Config) -> Result<()> {
let e = run_func let e = run_func
.call(&mut store, &[]) .call(&mut store, &[])
.err() .expect_err("error calling function");
.expect("error calling function");
assert_eq!( assert_eq!(
e.to_string(), e.to_string(),
"\ "\
@@ -236,8 +231,7 @@ fn trap_display_multi_module(config: crate::Config) -> Result<()> {
let e = bar2 let e = bar2
.call(&mut store, &[]) .call(&mut store, &[])
.err() .expect_err("error calling function");
.expect("error calling function");
assert_eq!( assert_eq!(
e.to_string(), e.to_string(),
"\ "\
@@ -433,9 +427,7 @@ fn call_signature_mismatch(config: crate::Config) -> Result<()> {
"#; "#;
let module = Module::new(&store, &binary)?; let module = Module::new(&store, &binary)?;
let err = Instance::new(&mut store, &module, &imports! {}) let err = Instance::new(&mut store, &module, &imports! {}).expect_err("expected error");
.err()
.expect("expected error");
assert_eq!( assert_eq!(
format!("{}", err), format!("{}", err),
"\ "\
@@ -461,9 +453,7 @@ fn start_trap_pretty(config: crate::Config) -> Result<()> {
"#; "#;
let module = Module::new(&store, wat)?; let module = Module::new(&store, wat)?;
let err = Instance::new(&mut store, &module, &imports! {}) let err = Instance::new(&mut store, &module, &imports! {}).expect_err("expected error");
.err()
.expect("expected error");
assert_eq!( assert_eq!(
format!("{}", err), format!("{}", err),

View File

@@ -1,3 +1,5 @@
#![allow(clippy::unnecessary_operation)] // We use x1 multiplies for clarity
use anyhow::Result; use anyhow::Result;
use std::convert::Infallible; use std::convert::Infallible;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};

View File

@@ -0,0 +1,30 @@
use anyhow::bail;
use std::path::PathBuf;
use std::process::Command;
use wasmer_integration_tests_cli::{get_repo_root_path, get_wasmer_path, ASSET_PATH, C_ASSET_PATH};
#[test]
fn login_works() -> anyhow::Result<()> {
let wapm_dev_token = std::env::var("WAPM_DEV_TOKEN").expect("WAPM_DEV_TOKEN env var not set");
let output = Command::new(get_wasmer_path())
.arg("login")
.arg("--registry")
.arg("wapm.dev")
.arg(wapm_dev_token)
.output()?;
if !output.status.success() {
bail!(
"wasmer login failed with: stdout: {}\n\nstderr: {}",
std::str::from_utf8(&output.stdout)
.expect("stdout is not utf8! need to handle arbitrary bytes"),
std::str::from_utf8(&output.stderr)
.expect("stderr is not utf8! need to handle arbitrary bytes")
);
}
let stdout_output = std::str::from_utf8(&output.stdout).unwrap();
assert_eq!(stdout_output, "Login for WAPM user \"ciuser\" saved\n");
Ok(())
}