Skip to content

Commit 99d58e3

Browse files
authored
refactor: hoist guts of run-soliplex-cli-in-throwawy-container into 'stack' (#10)
... from 'soliplex_config'.
1 parent 27f0b56 commit 99d58e3

8 files changed

Lines changed: 545 additions & 185 deletions

File tree

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,14 @@ The core does pure filesystem work: no Docker, no running backend. The
1515
resolve and validate the stack root, infer its package, and ensure
1616
`installation.yaml`'s `room_paths` loads the room (editing line-based, so
1717
comments and layout are preserved).
18+
- **`stack`** — shared plumbing to run `soliplex-cli` against a stack in a
19+
throwaway `docker compose run --rm` container (validate the stack, build the
20+
argv, capture or stream output), optionally binding an alternative
21+
installation tree to dry-run against. Needs Docker.
1822
- **`soliplex_config`** — query a *running* stack's resolved installation
1923
config via `soliplex-cli config` in a one-off backend container (`show` /
2024
`get` / `rooms` / `room`); installs the `soliplex-config` console script.
21-
Needs Docker.
25+
Builds on `stack`.
2226

2327
```python
2428
from soliplex_plumber import rooms

docs/index.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,14 @@ installer -- so the stack-wiring rules live in one place.
1919
`installation.yaml`'s `room_paths` loads the room (editing line-based, so
2020
comments and layout are preserved). See the
2121
[API reference](reference/api.md).
22+
- **`stack`** -- shared plumbing to run `soliplex-cli` against a stack in a
23+
throwaway `docker compose run --rm` container (validate the stack, build the
24+
argv, capture or stream output), optionally binding an alternative
25+
installation tree to dry-run against. Needs Docker.
2226
- **`soliplex_config`** -- query a *running* stack's resolved installation
2327
config via `soliplex-cli config` in a one-off backend container (`show` /
2428
`get` / `rooms` / `room`); installs the `soliplex-config` console script.
25-
Needs Docker.
29+
Builds on `stack`.
2630

2731
There is no re-exporting package `__init__`; client code imports the submodule
2832
and uses its members by dotted name:

docs/reference/api.md

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -72,21 +72,45 @@ non-default parent is added).
7272
| `ADDED` / `UNCHANGED` / `COVERED` | the `installation.TargetAction` members, re-exported |
7373
| `ROOMS_PARENT_ENTRY` | the `./rooms` default-discovery container |
7474

75+
## `stack` — run `soliplex-cli` against a stack in a throwaway container
76+
77+
The shared plumbing for talking to a *running* stack. `soliplex-cli` ships only
78+
inside the backend image, so this spins up a one-off `docker compose run --rm`
79+
container pointed at a stack directory and runs the requested command — the
80+
caller need not be *inside* a configured/running stack. It needs **Docker** on
81+
`PATH`. `soliplex_config` builds on it, and the `soliplex-cli` skill uses it to
82+
run arbitrary subcommands.
83+
84+
Every soliplex-cli command takes the in-container installation path as its
85+
leaf-command positional, so `cli_args` is the subcommand (and options) *without*
86+
that path: `run_cli` appends `installation`. By default the container uses the
87+
stack's own bind mount; pass `host_environment` to bind that host tree onto
88+
`installation` instead — pointing the one-off container at an alternative
89+
installation (e.g. to dry-run changes). A consumer's CLI wires the options that
90+
feed these calls via `add_arguments`.
91+
92+
| Member | Purpose |
93+
| --- | --- |
94+
| `require_docker()` | raise `DockerMissing` unless the Docker CLI is on `PATH` |
95+
| `resolve_project(project_dir)` | resolve a stack root requiring a `docker-compose.yml`; raises `ComposeNotFound` |
96+
| `cli_command(project, cli_args, *, service=…, cli=…, installation=…, host_environment=None, columns=…)` | build the `docker compose run … <cli> <*cli_args> <installation>` argv; only adds `-v <host_environment>:<installation>` when `host_environment` is given |
97+
| `run_cli(project, cli_args, *, capture=True, check=True, …)` | `require_docker()` then run the command; `capture` returns output for parsing, else streams it; returns a `CompletedProcess` |
98+
| `add_arguments(parser)` | add the `--project-dir` / `--service` / `--cli` / `--installation` / `--host-environment` options a consumer feeds to `resolve_project` / `run_cli` |
99+
| `DEFAULT_SERVICE` / `DEFAULT_CLI` / `DEFAULT_INSTALLATION` / `DEFAULT_HOST_ENVIRONMENT` / `WIDE_COLUMNS` | the container defaults |
100+
| `StackError` | base class for the user-facing errors (printed without a traceback) |
101+
| `DockerMissing` / `ComposeNotFound` | the specific failure modes |
102+
75103
## `soliplex_config` — query a running stack's resolved installation config
76104

77-
The one module that does **not** do pure filesystem work: it runs
78-
`soliplex-cli config <installation>` inside a one-off backend container
79-
(`docker compose run --rm`) and parses the resolved-config YAML. It therefore
80-
needs **Docker** on `PATH`. It installs the **`soliplex-config`** console
81-
script (`run` wraps `main` with the user-facing error handling) and backs a
82-
thin `soliplex-cli config` shim; the host-mapping helpers honor the resolved
83-
`room_paths`, mapping each back through the backend's
105+
Builds on `stack`: runs `soliplex-cli config <installation>` (via
106+
`stack.run_cli`) and parses the resolved-config YAML. It installs the
107+
**`soliplex-config`** console script (`run` wraps `main` with the user-facing
108+
error handling) and backs a thin `soliplex-cli config` shim; the host-mapping
109+
helpers honor the resolved `room_paths`, mapping each back through the backend's
84110
`<host-environment> → <installation>` bind mount.
85111

86112
| Member | Purpose |
87113
| --- | --- |
88-
| `resolve_project(project_dir)` | resolve a stack root requiring a `docker-compose.yml`; raises `ComposeNotFound` |
89-
| `run_config(project, service, cli, installation)` | run `soliplex-cli config` in a one-off backend container, returning its stdout |
90114
| `parse_config(stdout)` | parse the YAML body (banner comments and all) into a dict (`{}` if not a mapping) |
91115
| `navigate(config, key)` | resolve a dotted `key` (mapping names / sequence indices) into the config; raises `KeyNotFound` |
92116
| `render_value(value, fmt)` | render a value `plain` (scalar bare, list-of-scalars one per line, else YAML) or `yaml` |
@@ -96,6 +120,6 @@ thin `soliplex-cli config` shim; the host-mapping helpers honor the resolved
96120
| `resolve_rooms(project, service, cli, installation, host_environment)` | the loaded rooms' `{room_id, name, description}` mappings + the unmapped container paths |
97121
| `do_show` / `do_get` / `do_rooms` / `do_room` | the subcommand handlers (each takes the parsed `argparse.Namespace`) |
98122
| `build_parser()` / `parse_args(argv)` / `main(argv)` | the `show`/`get`/`rooms`/`room` CLI; `main` returns the process exit code |
99-
| `run()` | the `soliplex-config` console-script entry point — `main(sys.argv[1:])` with the user-facing errors below printed (no traceback) as exit code 2 |
100-
| `SoliplexConfigError` | base class for the user-facing errors below |
101-
| `DockerMissing` / `ComposeNotFound` / `NoRoomPaths` / `KeyNotFound` / `RoomNotFound` | the specific failure modes |
123+
| `run()` | the `soliplex-config` console-script entry point — `main(sys.argv[1:])` with `stack.StackError` / `CalledProcessError` printed (no traceback) as exit code 2 |
124+
| `SoliplexConfigError(stack.StackError)` | base class for the config-specific errors below |
125+
| `NoRoomPaths` / `KeyNotFound` / `RoomNotFound` | the specific failure modes |

0 commit comments

Comments
 (0)