-
Notifications
You must be signed in to change notification settings - Fork 98
CLI Embedding Proposal #80
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,115 @@ | ||
| # Typed Main | ||
|
|
||
| A high-level goal of the component model is the ability to run a single component portably on various hosts. One such embedding is a classic Unix-style Command-Line Interface (CLI) accepting positional/named arguments. | ||
|
|
||
| This document describes how a component can be generically interpreted by a component-enabled CLI to allow components to be directly instantiated and invoked from the command line in an idiomatic manner, corresponding to use case #2 of [invoking component exports](https://github.com/WebAssembly/component-model/blob/main/design/high-level/UseCases.md#invoking-component-exports-from-the-host). It also defines annotations which can be used to extend the default interpretation of a component to specify CLI-specific features (e.g. short flag names). | ||
|
|
||
| The component type is specified here in terms of a [`*.wit`](https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md) interface and annotations as [Structured Annotations](https://github.com/WebAssembly/component-model/issues/58). | ||
|
|
||
| ## Arguments | ||
| * Value imports are can be supplied as positional arguments in the order they are defined | ||
| * Value imports can be supplied as long-form named arguments with their defined name | ||
| * The ordering of named arguments with respect to each other and positional arguments is not constrained | ||
| * If a named argument is present, parsing of positional argument skips over it to the next position | ||
|
|
||
| ```rust | ||
| input: string | ||
| pattern: string | ||
| replace: string | ||
| ``` | ||
|
Comment on lines
+15
to
+19
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Once @fibonacci1729 posts a sketch |
||
|
|
||
| ### Usage | ||
| ``` | ||
| $ replace "some-thing" "-" "_" | ||
| $ replace --input "some-thing" --pattern "-" --replace "_" | ||
| $ replace --pattern "-" --replace "_" "some-thing" | ||
| ``` | ||
|
|
||
| ## File Preopen Arguments | ||
| * If the type of a value import is a WASI file, the host reads the corresponding argument as a path and preopens it. | ||
| * The preopen must occur even for file paths which do not exist (as long as their parent does), so that output file paths can be supported. | ||
|
|
||
| ```rust | ||
| import { file } from ... | ||
|
|
||
| input: file | ||
| output: file | ||
| ``` | ||
|
|
||
| ### Usage | ||
| ```bash | ||
| $ copy ./input.txt --output ./output.txt | ||
| ``` | ||
|
|
||
| ## Optional Arguments | ||
| * Value imports with type `option<T>` are optional arguments | ||
| * If an optional argument is not provided, the value import takes value `none` | ||
| * All arguments defined after an optional argument must be optional | ||
|
|
||
| ```rust | ||
| import { file } from ... | ||
|
|
||
| input: file | ||
| output: option<file> | ||
| ``` | ||
|
|
||
| ### Usage | ||
| ```bash | ||
| $ foo ./input.txt ./output.txt | ||
| $ foo ./input.txt | ||
| ``` | ||
|
|
||
| ## Flags | ||
| * Value imports with type `bool` inferred to be flags. | ||
| * Flags have value `true` if present and `false` if absent. | ||
| * By default, flags are "long" | ||
| * Equivalent to annotation `@flag(long)` | ||
| * Specified in long form with no associated value e.g. `--foobar` | ||
| * Name is inferred to be the value import name | ||
| * Name can be explicitly set `@flag(long = "foobar")` | ||
| * Does not support grouping | ||
| * Flags can annotated as "short" | ||
| * Using annotation `@flag(short)` | ||
| * Specified in short form with no associated value e.g.`-f` | ||
| * Name is inferred to be first character of value import name | ||
| * Name can be explicitly set `@flag(short = "f")` | ||
| * Supports grouping `-a -b -c` = `-abc` | ||
| * Flag can be short and long `@flag(short, long)`, value `true` if either are present | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems to me like the long name should always be accepted (since it's explicitly part of the component interface as an import) and that the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm leaning towards this answer to always export long but it would be great to hear other opinions. I almost always want a long-named flag when I have a short and it's difficult to come up with reasons for why that would be a problem. On the other hand, the way we would have to back out of this implementation once we standardize it is awkward in case we really do find a use-case where providing a long-named flag is not desired. A contrived example would be for a drop-in replacement of an existing CLI that only wants to accept inputs they have tests for (aka short-names), then we would need to support something like
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, that's a good case to think about. My expectation here is that, for a large number of reasons, this automatic CLI Embedding won't be able to emulate the variety of CLI syntaxes in use for tools today, so we shouldn't worry too much about these exact-emulation scenarios. On the flip side, thinking about this issue afresh, it seems like the "adding CLI annotations should always be backwards-compatible" principle mentioned below is a useful one to preserve. |
||
|
|
||
| ```rust | ||
| @flag(short) | ||
| help: bool | ||
|
|
||
| verbose: bool | ||
|
|
||
| @flag(short = "x", long) | ||
| execute: bool | ||
| ``` | ||
|
|
||
| ### Usage | ||
| ```bash | ||
| $ foo -h | ||
| $ foo --verbose | ||
| $ foo -x | ||
| $ foo --execute -x --verbose | ||
| ``` | ||
|
|
||
| ## Short Named Arguments | ||
| * By default named arguments are "long" (inferred as `@arg(pos, named, long)`). | ||
| * By annotating them with with the `short` parameter, they can be used in short form e.g. `-i` | ||
| * Name inference and manual assignment works the same as flags | ||
|
|
||
| ```rust | ||
| import { file } from ... | ||
|
|
||
| input: file | ||
|
|
||
| @arg(named, short, long) | ||
| output: option<file> | ||
| ``` | ||
|
|
||
| ### Usage | ||
| ```bash | ||
| $ foo ./input.txt --output ./output.txt | ||
| $ foo ./input.txt -o ./output.txt | ||
| ``` | ||
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.