You've already forked platform-info
mirror of
https://github.com/uutils/platform-info.git
synced 2026-06-10 15:48:45 -07:00
Add WASI platform support (#106)
This commit is contained in:
@@ -56,6 +56,11 @@ jobs:
|
|||||||
docs/src/**/*.md
|
docs/src/**/*.md
|
||||||
src/**/*.md
|
src/**/*.md
|
||||||
- run: cargo clippy --all-targets -- -D warnings
|
- run: cargo clippy --all-targets -- -D warnings
|
||||||
|
- name: Clippy (WASI)
|
||||||
|
if: matrix.os == 'ubuntu-latest'
|
||||||
|
run: |
|
||||||
|
rustup target add wasm32-wasip1
|
||||||
|
cargo clippy --target wasm32-wasip1 -- -D warnings
|
||||||
|
|
||||||
style_spellcheck:
|
style_spellcheck:
|
||||||
name: Style/spellcheck
|
name: Style/spellcheck
|
||||||
@@ -108,6 +113,28 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
RUST_BACKTRACE: '1'
|
RUST_BACKTRACE: '1'
|
||||||
|
|
||||||
|
test_wasi:
|
||||||
|
name: Build/Test (WASI)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
with:
|
||||||
|
targets: wasm32-wasip1
|
||||||
|
- uses: Swatinem/rust-cache@v2
|
||||||
|
- uses: mozilla-actions/sccache-action@v0.0.9
|
||||||
|
- name: Install wasmtime
|
||||||
|
run: |
|
||||||
|
curl https://wasmtime.dev/install.sh -sSf | bash
|
||||||
|
echo "$HOME/.wasmtime/bin" >> $GITHUB_PATH
|
||||||
|
- name: Build for WASI
|
||||||
|
run: cargo build --target wasm32-wasip1
|
||||||
|
- name: Test with wasmtime
|
||||||
|
env:
|
||||||
|
CARGO_TARGET_WASM32_WASIP1_RUNNER: wasmtime
|
||||||
|
# WASI does not support threads, so tests must run sequentially
|
||||||
|
run: cargo test --target wasm32-wasip1 -- --test-threads 1
|
||||||
|
|
||||||
coverage:
|
coverage:
|
||||||
name: Code Coverage
|
name: Code Coverage
|
||||||
runs-on: ${{ matrix.job.os }}
|
runs-on: ${{ matrix.job.os }}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
# platform-info
|
# platform-info
|
||||||
|
|
||||||
<!-- spell-checker:ignore (API) nodename osname sysname (rust) println -->
|
<!-- spell-checker:ignore (API) nodename osname sysname (rust) println -->
|
||||||
|
<!-- spell-checker:ignore (wasm) wasip wasmtime -->
|
||||||
|
|
||||||
[](https://crates.io/crates/platform-info)
|
[](https://crates.io/crates/platform-info)
|
||||||
[](LICENSE)
|
[](LICENSE)
|
||||||
@@ -48,6 +49,34 @@ GNU/Linux
|
|||||||
|
|
||||||
> Using `cargo run --example ex` will build and execute this [example code](examples/ex.rs).
|
> Using `cargo run --example ex` will build and execute this [example code](examples/ex.rs).
|
||||||
|
|
||||||
|
### WASI
|
||||||
|
|
||||||
|
To cross-compile and run the example under [WASI](https://wasi.dev/), first install
|
||||||
|
[wasmtime](https://wasmtime.dev/):
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl https://wasmtime.dev/install.sh -sSf | bash
|
||||||
|
```
|
||||||
|
|
||||||
|
Then build and run:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cargo build --target wasm32-wasip1 --example ex
|
||||||
|
wasmtime target/wasm32-wasip1/debug/examples/ex.wasm
|
||||||
|
```
|
||||||
|
|
||||||
|
This should display:
|
||||||
|
|
||||||
|
```text
|
||||||
|
wasi
|
||||||
|
localhost
|
||||||
|
0.0.0
|
||||||
|
0.0.0
|
||||||
|
wasm32
|
||||||
|
wasm32
|
||||||
|
WASI
|
||||||
|
```
|
||||||
|
|
||||||
Other examples can be found in the [examples](examples) directory.
|
Other examples can be found in the [examples](examples) directory.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|||||||
+7
-2
@@ -99,19 +99,24 @@ const HOST_OS_NAME: &str = if cfg!(all(
|
|||||||
"solaris"
|
"solaris"
|
||||||
} else if cfg!(target_os = "cygwin") {
|
} else if cfg!(target_os = "cygwin") {
|
||||||
"Cygwin"
|
"Cygwin"
|
||||||
|
} else if cfg!(target_os = "wasi") {
|
||||||
|
"WASI"
|
||||||
} else {
|
} else {
|
||||||
"unknown"
|
"unknown"
|
||||||
};
|
};
|
||||||
|
|
||||||
//=== platform-specific module code
|
//=== platform-specific module code
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(all(unix, not(target_os = "wasi")))]
|
||||||
#[path = "platform/unix.rs"]
|
#[path = "platform/unix.rs"]
|
||||||
mod target;
|
mod target;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
#[path = "platform/windows.rs"]
|
#[path = "platform/windows.rs"]
|
||||||
mod target;
|
mod target;
|
||||||
#[cfg(not(any(unix, windows)))]
|
#[cfg(target_os = "wasi")]
|
||||||
|
#[path = "platform/wasi.rs"]
|
||||||
|
mod target;
|
||||||
|
#[cfg(not(any(unix, windows, target_os = "wasi")))]
|
||||||
#[path = "platform/unknown.rs"]
|
#[path = "platform/unknown.rs"]
|
||||||
mod target;
|
mod target;
|
||||||
|
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ impl Debug for UTSName {
|
|||||||
.field("release", &oss_from_cstr(&self.0.release))
|
.field("release", &oss_from_cstr(&self.0.release))
|
||||||
.field("version", &oss_from_cstr(&self.0.version))
|
.field("version", &oss_from_cstr(&self.0.version))
|
||||||
.field("machine", &oss_from_cstr(&self.0.machine));
|
.field("machine", &oss_from_cstr(&self.0.machine));
|
||||||
// The domainname field is not part of the POSIX standard but a GNU extension. Therefor
|
// The domainname field is not part of the POSIX standard but a GNU extension. Therefore
|
||||||
// BSD-like platforms and solaris/illumos are missing the domainname field.
|
// BSD-like platforms and solaris/illumos are missing the domainname field.
|
||||||
#[cfg(not(any(
|
#[cfg(not(any(
|
||||||
target_os = "aix",
|
target_os = "aix",
|
||||||
@@ -161,7 +161,7 @@ impl PartialEq for UTSName {
|
|||||||
other.0.version,
|
other.0.version,
|
||||||
other.0.machine,
|
other.0.machine,
|
||||||
);
|
);
|
||||||
// The domainname field is not part of the POSIX standard but a GNU extension. Therefor
|
// The domainname field is not part of the POSIX standard but a GNU extension. Therefore
|
||||||
// BSD-like platforms and solaris/illumos are missing the domainname field.
|
// BSD-like platforms and solaris/illumos are missing the domainname field.
|
||||||
#[cfg(not(any(
|
#[cfg(not(any(
|
||||||
target_os = "aix",
|
target_os = "aix",
|
||||||
|
|||||||
@@ -0,0 +1,140 @@
|
|||||||
|
// This file is part of the platform-info package.
|
||||||
|
//
|
||||||
|
// For the full copyright and license information, please view the LICENSE file
|
||||||
|
// that was distributed with this source code.
|
||||||
|
|
||||||
|
// spell-checker:ignore (API) nodename osname sysname gethostname
|
||||||
|
// spell-checker:ignore (runtimes) wasmtime wasmer wazero
|
||||||
|
|
||||||
|
#![warn(unused_results)] // enable warnings for unused results
|
||||||
|
|
||||||
|
use std::ffi::{OsStr, OsString};
|
||||||
|
|
||||||
|
use crate::{PlatformInfoAPI, PlatformInfoError, UNameAPI};
|
||||||
|
|
||||||
|
/// Platform information for WASI (WebAssembly System Interface).
|
||||||
|
///
|
||||||
|
/// WASI does not provide a `uname()` syscall, so we return values
|
||||||
|
/// that describe the WebAssembly platform.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct PlatformInfo {
|
||||||
|
sysname: OsString,
|
||||||
|
nodename: OsString,
|
||||||
|
release: OsString,
|
||||||
|
version: OsString,
|
||||||
|
machine: OsString,
|
||||||
|
processor: OsString,
|
||||||
|
osname: OsString,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Try to detect the hostname from environment variables.
|
||||||
|
///
|
||||||
|
/// WASI (neither preview 1 nor preview 2) provides a `gethostname` syscall or
|
||||||
|
/// equivalent WIT interface. The `wasi-sockets` proposal lists hostname as a
|
||||||
|
/// future goal. Until then, the best we can do is check environment variables
|
||||||
|
/// that the host runtime may pass (e.g. `wasmtime --env HOSTNAME=$(hostname)`).
|
||||||
|
fn detect_nodename() -> OsString {
|
||||||
|
for var in &["HOSTNAME", "COMPUTERNAME"] {
|
||||||
|
if let Ok(val) = std::env::var(var) {
|
||||||
|
if !val.is_empty() {
|
||||||
|
return OsString::from(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OsString::from("localhost")
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PlatformInfoAPI for PlatformInfo {
|
||||||
|
/// Create a new `PlatformInfo` for WASI.
|
||||||
|
///
|
||||||
|
/// WASI does not provide a `uname()` syscall, and no WASI runtime (wasmtime,
|
||||||
|
/// wasmer, WasmEdge, wazero) exposes its identity or version to guest modules.
|
||||||
|
/// There is no standard or convention for runtime self-identification.
|
||||||
|
///
|
||||||
|
/// We follow the same approach as wasi-libc's `uname()` implementation, which
|
||||||
|
/// returns hardcoded values: `sysname="wasi"`, `release="0.0.0"`,
|
||||||
|
/// `version="0.0.0"`, `machine="wasm32"`.
|
||||||
|
///
|
||||||
|
/// ref: <https://github.com/WebAssembly/wasi-libc/blob/main/libc-top-half/musl/src/misc/uname.c>
|
||||||
|
fn new() -> Result<Self, PlatformInfoError> {
|
||||||
|
Ok(Self {
|
||||||
|
sysname: OsString::from("wasi"),
|
||||||
|
nodename: detect_nodename(),
|
||||||
|
release: OsString::from("0.0.0"),
|
||||||
|
version: OsString::from("0.0.0"),
|
||||||
|
machine: OsString::from(std::env::consts::ARCH),
|
||||||
|
processor: OsString::from(crate::lib_impl::map_processor(std::env::consts::ARCH)),
|
||||||
|
osname: OsString::from(crate::lib_impl::HOST_OS_NAME),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UNameAPI for PlatformInfo {
|
||||||
|
fn sysname(&self) -> &OsStr {
|
||||||
|
&self.sysname
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nodename(&self) -> &OsStr {
|
||||||
|
&self.nodename
|
||||||
|
}
|
||||||
|
|
||||||
|
fn release(&self) -> &OsStr {
|
||||||
|
&self.release
|
||||||
|
}
|
||||||
|
|
||||||
|
fn version(&self) -> &OsStr {
|
||||||
|
&self.version
|
||||||
|
}
|
||||||
|
|
||||||
|
fn machine(&self) -> &OsStr {
|
||||||
|
&self.machine
|
||||||
|
}
|
||||||
|
|
||||||
|
fn processor(&self) -> &OsStr {
|
||||||
|
&self.processor
|
||||||
|
}
|
||||||
|
|
||||||
|
fn osname(&self) -> &OsStr {
|
||||||
|
&self.osname
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_wasi() {
|
||||||
|
let info = PlatformInfo::new().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(info.sysname().to_string_lossy(), "wasi");
|
||||||
|
// nodename comes from env or defaults to "localhost"
|
||||||
|
assert!(!info.nodename().to_string_lossy().is_empty());
|
||||||
|
assert_eq!(info.release().to_string_lossy(), "0.0.0");
|
||||||
|
assert_eq!(info.version().to_string_lossy(), "0.0.0");
|
||||||
|
assert_eq!(info.machine().to_string_lossy(), std::env::consts::ARCH);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_wasi_nodename_env() {
|
||||||
|
let orig = std::env::var("HOSTNAME").ok();
|
||||||
|
|
||||||
|
std::env::set_var("HOSTNAME", "my-wasi-host");
|
||||||
|
let info = PlatformInfo::new().unwrap();
|
||||||
|
assert_eq!(info.nodename().to_string_lossy(), "my-wasi-host");
|
||||||
|
|
||||||
|
std::env::remove_var("HOSTNAME");
|
||||||
|
std::env::remove_var("COMPUTERNAME");
|
||||||
|
let info = PlatformInfo::new().unwrap();
|
||||||
|
assert_eq!(info.nodename().to_string_lossy(), "localhost");
|
||||||
|
|
||||||
|
// Restore
|
||||||
|
match orig {
|
||||||
|
Some(v) => std::env::set_var("HOSTNAME", v),
|
||||||
|
None => std::env::remove_var("HOSTNAME"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn structure_clone() {
|
||||||
|
let info = PlatformInfo::new().unwrap();
|
||||||
|
println!("{:?}", info);
|
||||||
|
let info_copy = info.clone();
|
||||||
|
assert_eq!(info_copy, info);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user