Skip to content

Commit

Permalink
stop kebab-casing and validate component names (#1294)
Browse files Browse the repository at this point in the history
* stop kebab-casing and validate component names

* tests

* validate  for wasm-compose

* don't validate , change name to composition-root

* new tests in

* lose import map cow and shorten compostition root name
  • Loading branch information
macovedj authored Nov 30, 2023
1 parent fe363f0 commit 30c7a09
Show file tree
Hide file tree
Showing 30 changed files with 186 additions and 43 deletions.
48 changes: 24 additions & 24 deletions crates/wasm-compose/CONFIG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ To specify the configuration file to use, pass the `--config` option to

The configuration file has the following top-level fields:

* `search-paths` : `list<string>` (optional) - a list of paths to search for
dependencies.
* `skip-validation` : `bool` (optional) - a boolean indicating whether to skip
validation of the resulting composed component.
* `dependencies` : `map<string, dependency>` (optional) - a map specifying the
explicit locations of transitive dependencies.
* `instantiations` : `map<string, instantiation>` (optional) - a map specifying
the explicit instantiations of transitive dependencies.
* `definitions` : `list<string>` (optional) - a list of paths to _definition_
components.
- `search-paths` : `list<string>` (optional) - a list of paths to search for
dependencies.
- `skip-validation` : `bool` (optional) - a boolean indicating whether to skip
validation of the resulting composed component.
- `dependencies` : `map<string, dependency>` (optional) - a map specifying the
explicit locations of transitive dependencies.
- `instantiations` : `map<string, instantiation>` (optional) - a map specifying
the explicit instantiations of transitive dependencies.
- `definitions` : `list<string>` (optional) - a list of paths to _definition_
components.

## Dependencies

Expand All @@ -25,10 +25,10 @@ dependency, rather than searching the configured search paths.

A dependency has the following fields:

* `path` : `string` - the path to the WebAssembly component file; the path is
- `path` : `string` - the path to the WebAssembly component file; the path is
relative to the configuration file.

* `import` : `string` (optional) - the name to use for importing the component.
- `import` : `string` (optional) - the name to use for importing the component.
If not present, the component at the given path will be defined directly in
the composed component.

Expand All @@ -49,11 +49,11 @@ dependencies:
In the above example, two dependencies are defined in the configuration:
* `a` - the contents of `a.wasm` will be defined directly in the composed
component.
* `b` - a component of the same type as `b.wasm` will be imported in the
composed component with name `b`; the original file will not be embedded in the
composed component.
- `a` - the contents of `a.wasm` will be defined directly in the composed
component.
- `b` - a component of the same type as `b.wasm` will be imported in the
composed component with name `b`; the original file will not be embedded in the
composed component.

_Note: importing components from a composed component is not currently
supported in [Wasmtime](https://github.com/bytecodealliance/wasmtime)._
Expand All @@ -68,19 +68,19 @@ instantiated, even allowing a dependency to be instantiated multiple times.

An instantiation has the following fields:

* `dependency` : `string` (optional) - the name of the dependency to
- `dependency` : `string` (optional) - the name of the dependency to
instantiate.

If unspecified, the instantiation will be for a dependency of the same name
as the instantiation itself.

* `arguments` : `map<string, argument>` (optional) - a mapping of argument
- `arguments` : `map<string, argument>` (optional) - a mapping of argument
names to arguments.

Argument names match the names of the imports of the dependency being
instantiated.

Note that the instantiation name `$input` is special and signifies how the input
Note that the instantiation name `root` is special and signifies how the input
component is to be instantiated.

### Instantiation arguments
Expand All @@ -90,9 +90,9 @@ to the instantiation of a dependency.

An argument has the following fields:

* `instance` : `string` - the name of the instance to pass as the argument.
- `instance` : `string` - the name of the instance to pass as the argument.

* `export` : `string` (optional) - the name of the exported instance on
- `export` : `string` (optional) - the name of the exported instance on
`instance` to use as the argument.

If not present, the instance specified by `instance` will be passed directly.
Expand All @@ -106,7 +106,7 @@ A slightly complex example of configuring instantiations:

```yaml
instantiations:
$input:
root:
arguments:
a: b
b:
Expand All @@ -118,7 +118,7 @@ instantiations:
dependency: f
```

In the above example, the `$input` instantiation (i.e. the root instantiation)
In the above example, the `root` instantiation (i.e. the root instantiation)
has explicitly specified that the argument named `a` is to be provided instance
`b`.

Expand Down
2 changes: 1 addition & 1 deletion crates/wasm-compose/example/server/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ search-paths:
- ../service/target/wasm32-wasi/release

instantiations:
$input:
root:
arguments:
example:service/handler@0.1.0:
instance: svc
Expand Down
2 changes: 1 addition & 1 deletion crates/wasm-compose/src/composer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use wasmparser::{
};

/// The root component name used in configuration.
pub const ROOT_COMPONENT_NAME: &str = "$input";
pub const ROOT_COMPONENT_NAME: &str = "root";

/// A reference to an instance import on a component.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
Expand Down
5 changes: 2 additions & 3 deletions crates/wasm-compose/src/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use crate::graph::{
type_desc, CompositionGraph, EncodeOptions, ExportIndex, ImportIndex, InstanceId,
};
use anyhow::{anyhow, bail, Result};
use heck::ToKebabCase;
use indexmap::{IndexMap, IndexSet};
use petgraph::EdgeDirection;
use smallvec::SmallVec;
Expand Down Expand Up @@ -1038,7 +1037,7 @@ enum ImportMapEntry<'a> {
/// Represents the import map built during the encoding
/// of a composition graph.
#[derive(Default)]
struct ImportMap<'a>(IndexMap<Cow<'a, str>, ImportMapEntry<'a>>);
struct ImportMap<'a>(IndexMap<&'a str, ImportMapEntry<'a>>);

impl<'a> ImportMap<'a> {
fn new(import_components: bool, graph: &'a CompositionGraph) -> Result<Self> {
Expand All @@ -1062,7 +1061,7 @@ impl<'a> ImportMap<'a> {
assert!(self
.0
.insert(
entry.component.name.to_kebab_case().into(),
&entry.component.name,
ImportMapEntry::Component(&entry.component),
)
.is_none());
Expand Down
14 changes: 9 additions & 5 deletions crates/wasm-compose/src/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use std::{
sync::atomic::{AtomicUsize, Ordering},
};
use wasmparser::{
names::ComponentName,
types::{
ComponentAnyTypeId, ComponentEntityType, ComponentInstanceTypeId, Remap, Remapping,
ResourceId, SubtypeCx, Types, TypesRef,
Expand Down Expand Up @@ -48,12 +49,11 @@ pub struct Component<'a> {

impl<'a> Component<'a> {
/// Constructs a new component from reading the given file.
pub fn from_file(name: impl Into<String>, path: impl AsRef<Path>) -> Result<Self> {
pub fn from_file(name: &str, path: impl AsRef<Path>) -> Result<Self> {
let path = path.as_ref();
log::info!("parsing WebAssembly component file `{}`", path.display());

let component = Self::parse(
name.into(),
ComponentName::new(name, 0)?.to_string(),
Some(path.to_owned()),
wat::parse_file(path)
.with_context(|| {
Expand Down Expand Up @@ -83,8 +83,12 @@ impl<'a> Component<'a> {
}

log::info!("parsing WebAssembly component from bytes");
let component =
Self::parse(name.into(), None, bytes).context("failed to parse component")?;
let component = Self::parse(
ComponentName::new(&name.into(), 0)?.to_string(),
None,
bytes,
)
.context("failed to parse component")?;

log::debug!("WebAssembly component parsed:\n{component:#?}",);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
(export (;1;) "m2" (func (type 1)))
)
)
(import "input" (component (;0;) (type 0)))
(import "root" (component (;0;) (type 0)))
(type (;1;)
(component
(type (;0;)
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
cannot import instance with name `a` for an instantiation argument of component `b` because it conflicts with an imported instantiation argument of component `$input`
cannot import instance with name `a` for an instantiation argument of component `b` because it conflicts with an imported instantiation argument of component `root`
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
instantiations:
$input:
root:
arguments:
example:service/logging@0.1.0:
instance: logger
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
failed to connect instance `$input` to definition component `tests/compositions/def-mismatch/definitions.wat`
failed to connect instance `root` to definition component `tests/compositions/def-mismatch/definitions.wat`

Caused by:
source instance export `foo` is not compatible with target instance import `foo`
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
instantiations:
$input:
root:
arguments:
a:
instance: a
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
instantiations:
$input:
root:
arguments:
a:
instance: a
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
instantiations:
$input:
root:
arguments:
b: a1
a1:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
instantiations:
$input:
root:
arguments:
invalid: a
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
(component
(import "b" (instance (export "a" (func))))
(alias export 0 "a" (func))
(export "a" (func 0))
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
instantiations:
root:
arguments:
locked-dep=<foo:add@1.0.>: a1
a1:
dependency: a
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
failed to parse component `tests/compositions/locked-dep-invalid-semver/root.wat`

Caused by:
import name `locked-dep=<foo:add@1.0.>` is not a valid extern name
`1.0.` is not a valid semver: unexpected end of input while parsing patch version number (at offset 0x1b)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(component
(import "locked-dep=<foo:add@1.0.>" (instance (export "a" (func))))
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
(component
(import "b" (instance (export "a" (func))))
(alias export 0 "a" (func))
(export "a" (func 0))
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
(component
(type (;0;)
(instance
(type (;0;) (func))
(export (;0;) "a" (func (type 0)))
)
)
(import "b" (instance (;0;) (type 0)))
(component (;0;)
(type (;0;)
(instance
(type (;0;) (func))
(export (;0;) "a" (func (type 0)))
)
)
(import "locked-dep=<foo:add@1.0.0>" (instance (;0;) (type 0)))
)
(component (;1;)
(type (;0;)
(instance
(type (;0;) (func))
(export (;0;) "a" (func (type 0)))
)
)
(import "b" (instance (;0;) (type 0)))
(alias export 0 "a" (func (;0;)))
(export (;1;) "a" (func 0))
)
(instance (;1;) (instantiate 1
(with "b" (instance 0))
)
)
(instance (;2;) (instantiate 0
(with "locked-dep=<foo:add@1.0.0>" (instance 1))
)
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
instantiations:
root:
arguments:
locked-dep=<foo:add@1.0.0>: a1
a1:
dependency: a
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(component
(import "locked-dep=<foo:add@1.0.0>" (instance (export "a" (func))))
)
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
instantiations:
$input:
root:
arguments:
a:
instance: a
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
(component
(import "b" (instance (export "a" (func))))
(alias export 0 "a" (func))
(export "a" (func 0))
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
instantiations:
root:
arguments:
unlocked-dep=<foo:add@{>=1.0.}>: a1
a1:
dependency: a
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
failed to parse component `tests/compositions/unlocked-dep-invalid-semver/root.wat`

Caused by:
import name `unlocked-dep=<foo:add@{>=1.0.}>` is not a valid extern name
`1.0.` is not a valid semver: unexpected end of input while parsing patch version number (at offset 0x1b)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
(component
(import "unlocked-dep=<foo:add@{>=1.0.}>" (instance (export "a" (func))))
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
(component
(import "b" (instance (export "a" (func))))
(alias export 0 "a" (func))
(export "a" (func 0))
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
(component
(type (;0;)
(instance
(type (;0;) (func))
(export (;0;) "a" (func (type 0)))
)
)
(import "b" (instance (;0;) (type 0)))
(component (;0;)
(type (;0;)
(instance
(type (;0;) (func))
(export (;0;) "a" (func (type 0)))
)
)
(import "unlocked-dep=<foo:add@{>=1.0.0}>" (instance (;0;) (type 0)))
)
(component (;1;)
(type (;0;)
(instance
(type (;0;) (func))
(export (;0;) "a" (func (type 0)))
)
)
(import "b" (instance (;0;) (type 0)))
(alias export 0 "a" (func (;0;)))
(export (;1;) "a" (func 0))
)
(instance (;1;) (instantiate 1
(with "b" (instance 0))
)
)
(instance (;2;) (instantiate 0
(with "unlocked-dep=<foo:add@{>=1.0.0}>" (instance 1))
)
)
)
Loading

0 comments on commit 30c7a09

Please sign in to comment.