-
Notifications
You must be signed in to change notification settings - Fork 12
Doc: Add how-to for designing interface layout #877
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
Draft
akcano
wants to merge
1
commit into
main
Choose a base branch
from
plugs-and-slots-3
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
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
221 changes: 221 additions & 0 deletions
221
docs/how-to/customize-workshops/design-interface-layout.rst
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,221 @@ | ||
| .. _how_design_interface_layout: | ||
|
|
||
| .. meta:: | ||
| :description: Shape a workshop's interface topology with explicit connection | ||
| entries in the workshop definition: survey what auto-connects, | ||
| wire a consumer to a specific provider, graft a missing plug, | ||
| or rewire a running workshop with workshop connect. | ||
|
|
||
| How to design the interface layout of a workshop | ||
| ================================================ | ||
|
|
||
| .. @tests in tests/docs-how-to/design-interface-layout/task.yaml | ||
|
|
||
| .. @artefact interface connection | ||
| .. @artefact workshop definition | ||
|
|
||
| You can shape the topology of a workshop | ||
| by writing explicit plug-to-slot connections in the workshop definition. | ||
| Use explicit connections | ||
| when several SDKs in the workshop expose or consume the same interface | ||
| and you want to be specific about which provider satisfies which consumer, | ||
| when auto-connection lands a plug on a slot you did not intend, | ||
| or when a consumer SDK ships no plug for a capability you want it to use. | ||
| You need a workshop definition under :file:`.workshop/` | ||
| that lists at least two SDKs, one with a slot and one with a matching plug. | ||
|
|
||
| This is a different problem from same-interface plug conflicts, | ||
| where two plugs would compete over the same target. | ||
| For that case, see :ref:`how_resolve_plug_conflicts`, | ||
| which uses an inline :samp:`bind:` attribute to delegate one plug to another. | ||
|
|
||
|
|
||
| Survey the plugs and slots in scope | ||
| ----------------------------------- | ||
|
|
||
| Launch the workshop once to see what |ws_markup| connects on its own. | ||
| The examples here use three in-project SDKs | ||
| that live under :file:`.workshop/` next to the definition: | ||
| :samp:`provider-a` and :samp:`provider-b` | ||
| each expose a mount slot named :samp:`data`, | ||
| and :samp:`consumer` declares a mount plug named :samp:`feed`. | ||
|
|
||
| .. code-block:: console | ||
|
|
||
| $ workshop launch dev | ||
| $ workshop connections dev | ||
|
|
||
| INTERFACE PLUG SLOT NOTES | ||
| mount - dev/provider-a:data - | ||
| mount - dev/provider-b:data - | ||
| mount dev/consumer:feed dev/system:mount - | ||
|
|
||
|
|
||
| The output lists every plug and slot in the workshop, | ||
| the slot each plug is connected to (if any), | ||
| and any notes on the connection. | ||
| :samp:`consumer:feed` landed on the system SDK's default mount slot, | ||
| not on either regular provider, | ||
| because mount plugs auto-connect to system SDK slots by default. | ||
| The :samp:`provider-a:data` and :samp:`provider-b:data` slots | ||
| stay listed but unconnected: | ||
| regular SDK mount slots are not reached by auto-connection by default, | ||
| even when a matching plug is in scope. | ||
| The result is a working workshop, but probably not the one you intended. | ||
| A regular SDK slot is wired | ||
| either by a top-level :samp:`connections:` entry in the definition | ||
| or manually with :command:`workshop connect`. | ||
|
|
||
|
|
||
| Wire a consumer to a specific provider | ||
| -------------------------------------- | ||
|
|
||
| Add a top-level :samp:`connections:` list to the workshop definition, | ||
| pairing the plug with the slot you want it to use: | ||
|
|
||
| .. code-block:: yaml | ||
| :caption: .workshop/dev.yaml | ||
| :emphasize-lines: 8-10 | ||
|
|
||
| name: dev | ||
| base: ubuntu@22.04 | ||
| sdks: | ||
| - name: project-provider-a | ||
| - name: project-provider-b | ||
| - name: project-consumer | ||
|
|
||
| connections: | ||
| - plug: consumer:feed | ||
| slot: provider-b:data | ||
|
|
||
|
|
||
| Each entry uses the :samp:`<SDK-NAME>:<NAME>` form on both sides. | ||
| In-project SDKs take the :samp:`project-` prefix | ||
| in the :samp:`sdks:` list only; | ||
| :samp:`connections:` entries and CLI output use the bare name. | ||
| After :command:`workshop refresh`, | ||
| |ws_markup| applies the listed pairing | ||
| regardless of what other slots could have matched it: | ||
|
|
||
| .. code-block:: console | ||
|
|
||
| $ workshop refresh dev | ||
| $ workshop connections dev | ||
|
|
||
| INTERFACE PLUG SLOT NOTES | ||
| mount - dev/provider-a:data - | ||
| mount dev/consumer:feed dev/provider-b:data - | ||
|
|
||
|
|
||
| This decision is persistent; | ||
| re-launching the workshop or recreating it | ||
| applies the same pairing every time. | ||
| To inspect the resolved mount details, run :command:`workshop info dev`, | ||
| which lists each connected mount plug | ||
| along with the source path the slot exposed | ||
| and the target path inside the workshop. | ||
|
|
||
|
|
||
| Graft a missing plug onto a consumer SDK | ||
| ---------------------------------------- | ||
|
|
||
| Suppose a consumer SDK ships no plug for the capability you want it to use. | ||
| The workshop definition can add one: | ||
| declare the plug under the SDK's entry in :samp:`sdks`, | ||
| then connect it as before. | ||
| This example pairs :samp:`provider-sdk`, | ||
| which exposes a mount slot named :samp:`bin`, | ||
| with :samp:`consumer-sdk`, which ships no matching plug: | ||
|
|
||
| .. code-block:: yaml | ||
| :caption: .workshop/dev.yaml | ||
| :emphasize-lines: 5-9, 11-13 | ||
|
|
||
| name: dev | ||
| base: ubuntu@22.04 | ||
| sdks: | ||
| - name: project-provider-sdk | ||
| - name: project-consumer-sdk | ||
| plugs: | ||
| tools: | ||
| interface: mount | ||
| workshop-target: /home/workshop/.local/share/tools | ||
|
|
||
| connections: | ||
| - plug: consumer-sdk:tools | ||
| slot: provider-sdk:bin | ||
|
|
||
|
|
||
| This grafts a new plug onto :samp:`consumer-sdk` | ||
| without modifying the SDK itself. | ||
| The publisher does not need to ship every plug | ||
| their users might want; | ||
| the workshop author can add the missing piece locally. | ||
|
|
||
|
|
||
| Rewire a running workshop with workshop connect | ||
| ----------------------------------------------- | ||
|
|
||
| For a one-off change, :command:`workshop connect` rewires a running workshop | ||
| without editing the workshop definition. | ||
| Pass the plug and the target slot explicitly: | ||
|
|
||
| .. code-block:: console | ||
|
|
||
| $ workshop disconnect dev/consumer:feed | ||
| $ workshop connect dev/consumer:feed dev/provider-a:data | ||
| $ workshop connections dev | ||
|
|
||
| INTERFACE PLUG SLOT NOTES | ||
| mount - dev/provider-b:data - | ||
| mount dev/consumer:feed dev/provider-a:data manual | ||
|
|
||
|
|
||
| The :samp:`manual` note in the :samp:`NOTES` column flags that the connection | ||
| came from a CLI invocation rather than the workshop definition | ||
| or the auto-connection mechanism. | ||
|
|
||
| The workshop definition on disk is unchanged, | ||
| and the runtime marks are not reconciled with it: | ||
| the next :command:`workshop refresh` that applies updates | ||
| drops connections made with :command:`workshop connect`, | ||
| while plugs disconnected with :command:`workshop disconnect` | ||
| stay disconnected, | ||
| unless the disconnection was made with :option:`!--forget`. | ||
| In the example above, | ||
| a refresh thus leaves :samp:`consumer:feed` unconnected: | ||
| the manual connection to :samp:`provider-a:data` is dropped, | ||
| and the definition's pairing with :samp:`provider-b:data` is not restored | ||
| because the plug was manually disconnected from it. | ||
| Running :command:`workshop remove` discards all runtime marks, | ||
| so a subsequent :command:`workshop launch` starts from the definition. | ||
|
|
||
| For a topology that survives refreshes | ||
| and travels with the project, | ||
| edit the workshop definition instead. | ||
|
|
||
|
|
||
| See also | ||
| -------- | ||
|
|
||
| Explanation: | ||
|
|
||
| - :ref:`exp_in_project_sdk` | ||
| - :ref:`exp_interface_concepts` | ||
| - :ref:`exp_plug_bindings` | ||
| - :ref:`exp_plugs_slots` | ||
|
|
||
|
|
||
| How-to guides: | ||
|
|
||
| - :ref:`how_resolve_plug_conflicts` | ||
|
|
||
|
|
||
| Reference: | ||
|
|
||
| - :ref:`ref_workshop_connect` | ||
| - :ref:`ref_workshop_connections` | ||
| - :ref:`ref_workshop_definition` | ||
| - :ref:`ref_workshop_disconnect` | ||
| - :ref:`ref_workshop_info` | ||
| - :ref:`ref_workshop_refresh` | ||
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
14 changes: 14 additions & 0 deletions
14
tests/docs-how-to/design-interface-layout/.workshop/consumer/sdk.yaml
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,14 @@ | ||
| name: consumer | ||
| base: ubuntu@22.04 | ||
| summary: Synthesized consumer for the ambiguity test | ||
| description: | | ||
| Declares a mount plug named "feed". With provider-a and provider-b both | ||
| present, autowiring is ambiguous and the workshop definition must specify | ||
| which slot to use. | ||
|
|
||
| sdkcraft-started-at: "2026-05-14T00:00:00.000000+00:00" | ||
|
|
||
| plugs: | ||
| feed: | ||
| interface: mount | ||
| workshop-target: /home/workshop/feed |
13 changes: 13 additions & 0 deletions
13
tests/docs-how-to/design-interface-layout/.workshop/graft.yaml
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,13 @@ | ||
| name: graft | ||
| base: ubuntu@22.04 | ||
| sdks: | ||
| - name: project-provider-a | ||
| - name: project-plainconsumer | ||
| plugs: | ||
| feed: | ||
| interface: mount | ||
| workshop-target: /home/workshop/feed | ||
|
|
||
| connections: | ||
| - plug: plainconsumer:feed | ||
| slot: provider-a:data |
8 changes: 8 additions & 0 deletions
8
tests/docs-how-to/design-interface-layout/.workshop/plainconsumer/sdk.yaml
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,8 @@ | ||
| name: plainconsumer | ||
| base: ubuntu@22.04 | ||
| summary: Synthesized consumer that ships no plug, for the graft scenario | ||
| description: | | ||
| Ships no mount plug. The graft workshop declares a "feed" plug inline under | ||
| this SDK's sdks entry to demonstrate grafting a plug the SDK did not ship. | ||
|
|
||
| sdkcraft-started-at: "2026-05-14T00:00:00.000000+00:00" |
4 changes: 4 additions & 0 deletions
4
tests/docs-how-to/design-interface-layout/.workshop/provider-a/hooks/setup-base
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,4 @@ | ||
| #!/bin/bash | ||
| install -d -m 0755 -o 1000 -g 1000 /home/workshop/provider-a-data | ||
| echo "from-a" >/home/workshop/provider-a-data/marker | ||
| chown 1000:1000 /home/workshop/provider-a-data/marker |
13 changes: 13 additions & 0 deletions
13
tests/docs-how-to/design-interface-layout/.workshop/provider-a/sdk.yaml
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,13 @@ | ||
| name: provider-a | ||
| base: ubuntu@22.04 | ||
| summary: First synthesized provider for the ambiguity test | ||
| description: | | ||
| Exposes a mount slot named "data". Combined with provider-b in the same | ||
| workshop, this creates ambiguous autowiring for the consumer's "feed" plug. | ||
|
|
||
| sdkcraft-started-at: "2026-05-14T00:00:00.000000+00:00" | ||
|
|
||
| slots: | ||
| data: | ||
| interface: mount | ||
| workshop-source: /home/workshop/provider-a-data |
4 changes: 4 additions & 0 deletions
4
tests/docs-how-to/design-interface-layout/.workshop/provider-b/hooks/setup-base
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,4 @@ | ||
| #!/bin/bash | ||
| install -d -m 0755 -o 1000 -g 1000 /home/workshop/provider-b-data | ||
| echo "from-b" >/home/workshop/provider-b-data/marker | ||
| chown 1000:1000 /home/workshop/provider-b-data/marker |
13 changes: 13 additions & 0 deletions
13
tests/docs-how-to/design-interface-layout/.workshop/provider-b/sdk.yaml
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,13 @@ | ||
| name: provider-b | ||
| base: ubuntu@22.04 | ||
| summary: Second synthesized provider for the ambiguity test | ||
| description: | | ||
| Exposes a mount slot named "data" with the same interface as provider-a, | ||
| creating the ambiguous autowiring scenario the how-to teaches you to resolve. | ||
|
|
||
| sdkcraft-started-at: "2026-05-14T00:00:00.000000+00:00" | ||
|
|
||
| slots: | ||
| data: | ||
| interface: mount | ||
| workshop-source: /home/workshop/provider-b-data |
10 changes: 10 additions & 0 deletions
10
tests/docs-how-to/design-interface-layout/dev.connected.yaml
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,10 @@ | ||
| name: dev | ||
| base: ubuntu@22.04 | ||
| sdks: | ||
| - name: project-provider-a | ||
| - name: project-provider-b | ||
| - name: project-consumer | ||
|
|
||
| connections: | ||
| - plug: consumer:feed | ||
| slot: provider-b:data |
10 changes: 10 additions & 0 deletions
10
tests/docs-how-to/design-interface-layout/dev.reordered.yaml
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,10 @@ | ||
| name: dev | ||
| base: ubuntu@22.04 | ||
| sdks: | ||
| - name: project-provider-b | ||
| - name: project-provider-a | ||
| - name: project-consumer | ||
|
|
||
| connections: | ||
| - plug: consumer:feed | ||
| slot: provider-b:data |
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,6 @@ | ||
| name: dev | ||
| base: ubuntu@22.04 | ||
| sdks: | ||
| - name: project-provider-a | ||
| - name: project-provider-b | ||
| - name: project-consumer |
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,37 @@ | ||
| summary: Test 'How to design the interface layout of a workshop' to ensure it's operational | ||
| restore: | | ||
| . "$TESTSLIB"/utils.sh | ||
| workshop_exec remove dev graft || true | ||
| execute: | | ||
| . "$TESTSLIB"/utils.sh | ||
| chown -R ubuntu:ubuntu . | ||
|
|
||
| echo "Stage 1: launch without connections; mount plugs do not auto-connect to regular SDK slots, so consumer:feed falls back to system:mount." | ||
| cp dev.yaml .workshop/dev.yaml | ||
| workshop_exec launch dev | ||
| workshop_exec connections dev | MATCH '^mount.+dev/consumer:feed.+dev/system:mount' | ||
|
|
||
| echo "Stage 2: add a connections entry pointing the plug at provider-b; refresh; verify the chosen slot connects and the marker is from-b." | ||
| cp dev.connected.yaml .workshop/dev.yaml | ||
| workshop_exec refresh dev | ||
| workshop_exec connections dev | MATCH '^mount.+dev/consumer:feed.+dev/provider-b:data' | ||
| workshop_exec exec dev -- cat /home/workshop/feed/marker | MATCH '^from-b$' | ||
|
|
||
| echo "Stage 3: disconnect then connect to provider-a at runtime; the runtime change is visible (manual) but the on-disk definition is unchanged." | ||
| EXPECTED_YAML_HASH=$(sha256sum .workshop/dev.yaml | cut -d' ' -f1) | ||
| workshop_exec disconnect dev/consumer:feed | ||
| workshop_exec connect dev/consumer:feed dev/provider-a:data | ||
| workshop_exec connections dev | MATCH '^mount.+dev/consumer:feed.+dev/provider-a:data.+manual' | ||
| workshop_exec exec dev -- cat /home/workshop/feed/marker | MATCH '^from-a$' | ||
| ACTUAL_YAML_HASH=$(sha256sum .workshop/dev.yaml | cut -d' ' -f1) | ||
| test "$EXPECTED_YAML_HASH" = "$ACTUAL_YAML_HASH" | ||
|
|
||
| echo "Stage 4: a refresh that applies updates drops the manual connection and keeps the manually disconnected pairing disconnected, so the plug ends up unconnected." | ||
| cp dev.reordered.yaml .workshop/dev.yaml | ||
| workshop_exec refresh dev | ||
| workshop_exec connections dev | MATCH '^mount +dev/consumer:feed +- +-' | ||
|
|
||
| echo "Stage 5: graft a plug onto an SDK that ships none; launch the graft workshop; the grafted plug connects to provider-a and reads from-a." | ||
| workshop_exec launch graft | ||
| workshop_exec connections graft | MATCH '^mount.+graft/plainconsumer:feed.+graft/provider-a:data' | ||
| workshop_exec exec graft -- cat /home/workshop/feed/marker | MATCH '^from-a$' |
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.
I think this how-to should not go as is. Let's merge the other outstanding PRs and discuss this. Mainly, the issues are duplication (e.g. wiring) and going against the pattern in the workshop's how-to where we cover interface related topics from the specific interface perspective, e.g. forward a port, add a mount (both, address adding a missing plug to an SDK; there will be another section on how to add a secret which would use the same mechanics as these two and so on). Some topics from here should become such how-to sections. E.g. share content between two SDKs to demonstrate the
connectionssections.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.
OK, converting this to draft, then.