mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-09 06:08:29 +00:00
Merge branch 'master' into fix-create-exe-windows
This commit is contained in:
2
.github/workflows/benchmark.yaml
vendored
2
.github/workflows/benchmark.yaml
vendored
@@ -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
|
||||||
|
|||||||
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -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
|
||||||
|
|||||||
2
.github/workflows/cloudcompiler.yaml
vendored
2
.github/workflows/cloudcompiler.yaml
vendored
@@ -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
|
||||||
|
|||||||
2
.github/workflows/coverage.yaml
vendored
2
.github/workflows/coverage.yaml
vendored
@@ -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
|
||||||
|
|||||||
2
.github/workflows/documentation.yaml
vendored
2
.github/workflows/documentation.yaml
vendored
@@ -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: |
|
||||||
|
|||||||
2
.github/workflows/lint.yaml
vendored
2
.github/workflows/lint.yaml
vendored
@@ -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: |
|
||||||
|
|||||||
2
.github/workflows/test-js.yaml
vendored
2
.github/workflows/test-js.yaml
vendored
@@ -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
|
||||||
|
|||||||
26
.github/workflows/test-sys.yaml
vendored
26
.github/workflows/test-sys.yaml
vendored
@@ -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: |
|
||||||
|
|||||||
26
CHANGELOG.md
26
CHANGELOG.md
@@ -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
52
Cargo.lock
generated
@@ -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"
|
||||||
|
|||||||
3
Makefile
3
Makefile
@@ -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
|
||||||
|
|||||||
@@ -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};
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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};
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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" ] }
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|
||||||
|
|||||||
@@ -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
181
lib/cli/src/commands/add.rs
Normal 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(®istry)?;
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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")
|
||||||
|
|||||||
@@ -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(())
|
||||||
}
|
}
|
||||||
|
|||||||
51
lib/cli/src/commands/login.rs
Normal file
51
lib/cli/src/commands/login.rs
Normal 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}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
22
lib/registry/graphql/queries/get_bindings.graphql
Normal file
22
lib/registry/graphql/queries/get_bindings.graphql
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
5
lib/registry/graphql/queries/whoami.graphql
Normal file
5
lib/registry/graphql/queries/whoami.graphql
Normal 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
325
lib/registry/src/config.rs
Normal 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(®istries.get_current_registry()),
|
||||||
|
None
|
||||||
|
);
|
||||||
|
registries.set_current_registry("https://registry.wapm.io");
|
||||||
|
assert_eq!(
|
||||||
|
registries.get_login_token_for_registry(®istries.get_current_registry()),
|
||||||
|
Some("token1".to_string())
|
||||||
|
);
|
||||||
|
registries.clear_current_registry_token();
|
||||||
|
assert_eq!(
|
||||||
|
registries.get_login_token_for_registry(®istries.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(®istry)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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(®istry) {
|
||||||
|
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
267
lib/registry/src/graphql.rs
Normal 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)
|
||||||
|
}
|
||||||
@@ -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
36
lib/registry/src/login.rs
Normal 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(®istry);
|
||||||
|
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(®istry, 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
27
lib/registry/src/utils.rs
Normal 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))
|
||||||
|
}
|
||||||
@@ -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>>,
|
||||||
|
|||||||
@@ -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, ")")
|
||||||
|
|||||||
@@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
1.61
|
1.63
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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};
|
||||||
|
|||||||
30
tests/integration/cli/tests/login.rs
Normal file
30
tests/integration/cli/tests/login.rs
Normal 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(())
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user