-
Notifications
You must be signed in to change notification settings - Fork 1.5k
feat(wasip3): implement wasi:cli
#11257
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
rvolosatovs
merged 14 commits into
bytecodealliance:main
from
rvolosatovs:feat/wasip3-cli
Jul 18, 2025
Merged
Changes from 13 commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
5eb62bb
feat(wasi): introduce common CLI context
rvolosatovs b3d0f06
chore(wasi): implement traits for boxed values
rvolosatovs cd2bb96
chore(wasi): implement `Default` for common WASI builder
rvolosatovs bd58d70
feat(wasip3): implement `wasi:cli`
rvolosatovs 248313a
refactor: require streams to be `Send`
rvolosatovs 44626a5
refactor: avoid typing `WasiCli` in task
rvolosatovs 70274b0
refactor: remove `Unpin` bound from stream I/O
rvolosatovs 0d1dc77
refactor: remove `ResourceView`
rvolosatovs 7cc19b1
chore: update `serve` to new WASI `isatty` API
rvolosatovs bbb4f9d
chore: adapt to stream API changes
rvolosatovs 3775d98
refactor: avoid `**` syntax
rvolosatovs 46c2003
refactor(wasip3): remove `Impl` wrappers
rvolosatovs b226577
refactor(wasip3): use shorthand closure syntax
rvolosatovs 2588476
chore: account for different env on different targets
rvolosatovs File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| use test_programs::p3::wasi::cli::{ | ||
| environment, stderr, stdin, stdout, terminal_stderr, terminal_stdin, terminal_stdout, | ||
| }; | ||
| use test_programs::p3::wit_stream; | ||
| use wit_bindgen::StreamResult; | ||
|
|
||
| struct Component; | ||
|
|
||
| test_programs::p3::export!(Component); | ||
|
|
||
| impl test_programs::p3::exports::wasi::cli::run::Guest for Component { | ||
| async fn run() -> Result<(), ()> { | ||
| assert_eq!(environment::get_arguments(), ["p3_cli.component", "."]); | ||
| assert_eq!(environment::get_environment().len(), 1); | ||
| assert_eq!(environment::initial_cwd(), None); | ||
|
|
||
| assert!(terminal_stdin::get_terminal_stdin().is_none()); | ||
| assert!(terminal_stdout::get_terminal_stdout().is_none()); | ||
| assert!(terminal_stderr::get_terminal_stderr().is_none()); | ||
|
|
||
| let mut stdin = stdin::get_stdin(); | ||
| assert!(stdin.next().await.is_none()); | ||
|
|
||
| let (mut stdout_tx, stdout_rx) = wit_stream::new(); | ||
| stdout::set_stdout(stdout_rx); | ||
| let (res, buf) = stdout_tx.write(b"hello stdout\n".into()).await; | ||
| assert_eq!(res, StreamResult::Complete(13)); | ||
| assert_eq!(buf.into_vec(), []); | ||
|
|
||
| let (mut stderr_tx, stderr_rx) = wit_stream::new(); | ||
| stderr::set_stderr(stderr_rx); | ||
| let (res, buf) = stderr_tx.write(b"hello stderr\n".into()).await; | ||
| assert_eq!(res, StreamResult::Complete(13)); | ||
| assert_eq!(buf.into_vec(), []); | ||
|
|
||
| Ok(()) | ||
| } | ||
| } | ||
|
|
||
| fn main() {} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| use std::rc::Rc; | ||
| use std::sync::Arc; | ||
|
|
||
| #[derive(Default)] | ||
| pub struct WasiCliCtx<I, O> { | ||
| pub environment: Vec<(String, String)>, | ||
| pub arguments: Vec<String>, | ||
| pub initial_cwd: Option<String>, | ||
| pub stdin: I, | ||
| pub stdout: O, | ||
| pub stderr: O, | ||
| } | ||
|
|
||
| pub trait IsTerminal { | ||
| /// Returns whether this stream is backed by a TTY. | ||
| fn is_terminal(&self) -> bool; | ||
| } | ||
|
|
||
| impl<T: ?Sized + IsTerminal> IsTerminal for &T { | ||
| fn is_terminal(&self) -> bool { | ||
| T::is_terminal(self) | ||
| } | ||
| } | ||
|
|
||
| impl<T: ?Sized + IsTerminal> IsTerminal for &mut T { | ||
| fn is_terminal(&self) -> bool { | ||
| T::is_terminal(self) | ||
| } | ||
| } | ||
|
|
||
| impl<T: ?Sized + IsTerminal> IsTerminal for Box<T> { | ||
| fn is_terminal(&self) -> bool { | ||
| T::is_terminal(self) | ||
| } | ||
| } | ||
|
|
||
| impl<T: ?Sized + IsTerminal> IsTerminal for Rc<T> { | ||
| fn is_terminal(&self) -> bool { | ||
| T::is_terminal(self) | ||
| } | ||
| } | ||
|
|
||
| impl<T: ?Sized + IsTerminal> IsTerminal for Arc<T> { | ||
| fn is_terminal(&self) -> bool { | ||
| T::is_terminal(self) | ||
| } | ||
| } | ||
|
|
||
| impl IsTerminal for tokio::io::Empty { | ||
| fn is_terminal(&self) -> bool { | ||
| false | ||
| } | ||
| } | ||
|
|
||
| impl IsTerminal for std::io::Empty { | ||
| fn is_terminal(&self) -> bool { | ||
| false | ||
| } | ||
| } | ||
|
|
||
| impl IsTerminal for tokio::io::Stdin { | ||
| fn is_terminal(&self) -> bool { | ||
| std::io::stdin().is_terminal() | ||
| } | ||
| } | ||
|
|
||
| impl IsTerminal for std::io::Stdin { | ||
| fn is_terminal(&self) -> bool { | ||
| std::io::IsTerminal::is_terminal(self) | ||
| } | ||
| } | ||
|
|
||
| impl IsTerminal for tokio::io::Stdout { | ||
| fn is_terminal(&self) -> bool { | ||
| std::io::stdout().is_terminal() | ||
| } | ||
| } | ||
|
|
||
| impl IsTerminal for std::io::Stdout { | ||
| fn is_terminal(&self) -> bool { | ||
| std::io::IsTerminal::is_terminal(self) | ||
| } | ||
| } | ||
|
|
||
| impl IsTerminal for tokio::io::Stderr { | ||
| fn is_terminal(&self) -> bool { | ||
| std::io::stderr().is_terminal() | ||
| } | ||
| } | ||
|
|
||
| impl IsTerminal for std::io::Stderr { | ||
| fn is_terminal(&self) -> bool { | ||
| std::io::IsTerminal::is_terminal(self) | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be possible to use
std::io::IsTerminalinstead?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My guess is "no" given the litany of implementations we have, but in such a case could documentation be added that this is basically a mirror of what's in libstd? Also is it worth trying to add a blanket
impl<T: std::IsTerminal> wasi::IsTermainal for Timpl?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We cannot use the
std::io::IsTerminal, because it's sealed: https://github.com/rust-lang/rust/blob/f8f6997469237299c1d60814c7b9828602a1f8e4/library/std/src/io/stdio.rs#L1197Unfortunately, largely because of that, blanket implementations for
Talso do not appear to be possible.For example:
tokio::io::Stderrcannot implementstd::io::IsTerminal, because it's sealed and we cannot implementwasmtime_wasi::cli::IsTerminalfor it if we provide a blanket implementation forstd::io::IsTerminal