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
|
||||
src/**/*.md
|
||||
- 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:
|
||||
name: Style/spellcheck
|
||||
@@ -108,6 +113,28 @@ jobs:
|
||||
env:
|
||||
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:
|
||||
name: Code Coverage
|
||||
runs-on: ${{ matrix.job.os }}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# platform-info
|
||||
|
||||
<!-- spell-checker:ignore (API) nodename osname sysname (rust) println -->
|
||||
<!-- spell-checker:ignore (wasm) wasip wasmtime -->
|
||||
|
||||
[](https://crates.io/crates/platform-info)
|
||||
[](LICENSE)
|
||||
@@ -48,6 +49,34 @@ GNU/Linux
|
||||
|
||||
> 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.
|
||||
|
||||
## License
|
||||
|
||||
+7
-2
@@ -99,19 +99,24 @@ const HOST_OS_NAME: &str = if cfg!(all(
|
||||
"solaris"
|
||||
} else if cfg!(target_os = "cygwin") {
|
||||
"Cygwin"
|
||||
} else if cfg!(target_os = "wasi") {
|
||||
"WASI"
|
||||
} else {
|
||||
"unknown"
|
||||
};
|
||||
|
||||
//=== platform-specific module code
|
||||
|
||||
#[cfg(unix)]
|
||||
#[cfg(all(unix, not(target_os = "wasi")))]
|
||||
#[path = "platform/unix.rs"]
|
||||
mod target;
|
||||
#[cfg(windows)]
|
||||
#[path = "platform/windows.rs"]
|
||||
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"]
|
||||
mod target;
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ impl Debug for UTSName {
|
||||
.field("release", &oss_from_cstr(&self.0.release))
|
||||
.field("version", &oss_from_cstr(&self.0.version))
|
||||
.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.
|
||||
#[cfg(not(any(
|
||||
target_os = "aix",
|
||||
@@ -161,7 +161,7 @@ impl PartialEq for UTSName {
|
||||
other.0.version,
|
||||
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.
|
||||
#[cfg(not(any(
|
||||
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