172 lines
6.9 KiB
Markdown
172 lines
6.9 KiB
Markdown
# Export / Compile
|
|
|
|
Soleprint's source tree is not what runs. `build.py` compiles the framework plus
|
|
a room's configuration into a self-contained instance under `gen/<room>/`, and
|
|
that directory is what a container boots, what `deploy.sh` rsyncs, and what the
|
|
cluster manifests point at.
|
|
|
|
Everything below is a `make` target, and every target is one script in `ctrl/`.
|
|
The logic lives in the scripts, never in the Makefile.
|
|
|
|
```bash
|
|
make build # cfg/standalone -> gen/standalone
|
|
make start # run it
|
|
```
|
|
|
|
## The targets
|
|
|
|
| Command | Runs | Does |
|
|
| --- | --- | --- |
|
|
| `make build [<room>\|all\|models]` | `ctrl/build.sh` | compile a room into `gen/` |
|
|
| `make dist [NAME\|FILE]` | `ctrl/dist.sh` | compile the plexus UIs to single files — nothing built first |
|
|
| `make docs [serve\|graphs]` | `ctrl/docs.sh` | serve the docs, or re-render the diagrams |
|
|
| `make start [<room>] [-d]` | `ctrl/start.sh` | run a built room's compose stack |
|
|
| `make stop [<room>]` | `ctrl/stop.sh` | stop it |
|
|
| `make cluster [up\|down\|status]` | `ctrl/cluster.sh` | the shared kind cluster |
|
|
| `make component [list\|publish\|sync\|watch\|diff]` | `ctrl/spr.py` | publish a distributable component |
|
|
| `make deploy` | `ctrl/deploy.sh` | rsync `gen/standalone` to the server and restart |
|
|
|
|
Bare words pass straight through, so `make build myroom` becomes
|
|
`ctrl/build.sh myroom`. Anything starting with a dash would be eaten by make
|
|
itself, so those go through `ARGS`:
|
|
|
|
```bash
|
|
make deploy ARGS="--build"
|
|
make component ARGS="publish soleprint-ui /tmp/out --dist"
|
|
```
|
|
|
|
## What a build does
|
|
|
|
`python build.py --cfg <room>` runs these in order:
|
|
|
|
1. **Clean** `gen/<room>/`. A build is not incremental — a stale file left
|
|
behind is worse than a slow build.
|
|
2. **Copy the framework.** `main.py`, `run.py`, `index.html`, `Dockerfile`,
|
|
`requirements.txt`, `dataloader/`, `common/`, and the three systems
|
|
(`artery/`, `atlas/`, `station/`).
|
|
3. **Merge the room** (`copy_cfg`). `cfg/<room>/config.json` lands in `cfg/`,
|
|
`data/*.json` in `data/`, and anything under `cfg/<room>/soleprint/artery|atlas|station/`
|
|
is merged *over* the framework copy — which is how a room adds its own vein,
|
|
shunt, tool or generator without forking the tree.
|
|
4. **Compose cabinets.** The dependency containers the room declared in
|
|
`data/cabinets.json` are merged into its `docker-compose.yml`. See
|
|
[Cabinets](#station-cabinets).
|
|
5. **Generate models.** modelgen reads the room's `config.json` and writes
|
|
`models/pydantic/__init__.py`.
|
|
6. **Render k8s** (optional). When the room's config enables it,
|
|
`soleprint/ctrl/k8s/` writes manifests and lifecycle scripts.
|
|
|
|
## What comes out
|
|
|
|
A standalone room is a flat instance:
|
|
|
|
```
|
|
gen/standalone/
|
|
run.py main.py Dockerfile docker-compose.yml
|
|
artery/ atlas/ station/ common/
|
|
cfg/config.json
|
|
data/*.json
|
|
models/pydantic/
|
|
```
|
|
|
|
A **managed** room — one that wraps an existing application — is three folders
|
|
instead, because soleprint sits beside the app rather than containing it:
|
|
|
|
```
|
|
gen/<room>/
|
|
<app>/ the application's repos, plus its ctrl scripts
|
|
link/ bridge code between the two
|
|
soleprint/ the instance, exactly as above
|
|
```
|
|
|
|
`build.py` picks between them on whether the room's `config.json` has a
|
|
`managed` block. `gen/` is gitignored in full: it is an artifact, and the way to
|
|
change it is to change `cfg/<room>/` and rebuild.
|
|
|
|
## Distributing components
|
|
|
|
Rooms are compiled; *components* are published. `registry.json` lists what can
|
|
be shipped out of this repo on its own:
|
|
|
|
```bash
|
|
make component # list
|
|
make component ARGS="publish soleprint-ui /tmp/out --dist"
|
|
make component ARGS="watch soleprint-ui ../unt/ui/framework"
|
|
```
|
|
|
|
`--dist` copies only the built bundle — `dist/**` plus `package.json`,
|
|
`README.md` and `LICENSE` — rather than the source. It refuses to publish an
|
|
empty `dist/`, because a component whose bundle was never built is the failure
|
|
that shows up later as a container that starts and renders nothing:
|
|
|
|
```
|
|
no build at soleprint/common/ui
|
|
build it first: cd soleprint/common/ui && pnpm build
|
|
```
|
|
|
|
Each publish leaves a `.spr` stamp in the destination recording name, version,
|
|
type, source and mode, so a copy can say where it came from.
|
|
|
|
### Slices: only what a consumer uses
|
|
|
|
`publish` hands over the whole component. A **slice** hands over the part one
|
|
consumer actually uses, as readable source, computed rather than picked:
|
|
|
|
```bash
|
|
make ui # list: every export and part, and what it pulls in
|
|
make ui scan ../mpr/ui/detection-app # what an app uses; its framework copy against spr
|
|
./ctrl/ui.sh slice path/to/ui.toml # write the slices a run file lists
|
|
./ctrl/ui.sh check path/to/ui.toml # the same, writing nothing — exit 1 if stale
|
|
```
|
|
|
|
A run file names the consumer, where the slice goes, and whether it is read from
|
|
the consumer's own imports (`scan`) or named (`use`). `target = "vue"` takes files
|
|
from `common/ui/src` — `Panel` alone is one file and `vue`; `TimeSeriesRenderer`
|
|
brings uplot and nothing else does. `target = "plain"` takes parts from
|
|
`common/theme/parts` as one `ui.css` and one `ui.js`. See
|
|
`soleprint/common/slice/ui.example.toml`.
|
|
|
|
Two deliveries:
|
|
|
|
| `delivery` | for | what changes |
|
|
| --- | --- | --- |
|
|
| `dependency` | your own projects | nothing: spr's names stay, and a `.spr` stamp says where the copy came from |
|
|
| `vendored` | a repository that is not spr's | names go through a mapping profile, headers are stripped, no stamp is written, a scrub fails on any spr word, and `notice` must be stated |
|
|
|
|
Every run writes a manifest beside its run file recording the hash of each file
|
|
it wrote. That is what makes drift visible both ways: when spr moves on, `check`
|
|
says the slice is stale; when someone edits the copy, the next run names the file
|
|
and refuses to overwrite it without `--force` — so an improvement made in a
|
|
consumer can be brought back instead of lost.
|
|
|
|
## Deploying
|
|
|
|
```bash
|
|
make deploy ARGS="--build" # rebuild, sync, restart
|
|
make deploy ARGS="--sync-only" # sync, leave it running
|
|
```
|
|
|
|
`deploy.sh` rsyncs `gen/standalone/` and runs `docker compose up -d --build` on
|
|
the far side. `.env` is excluded, so server secrets stay on the server.
|
|
|
|
## Running without building
|
|
|
|
`python run.py` from `soleprint/` serves every subsystem on one port (12000 by
|
|
default) straight from the source tree. It is for developing the framework
|
|
itself; a room's `cfg/config.json` does not exist there, so the landing pages
|
|
fall back to their defaults. Rooms use docker.
|
|
|
|
## Diagrams
|
|
|
|
The `.dot` sources under `docs/graphs/` carry structure; the palette lives in
|
|
`docs/graphs/themes/*.gvpr` and is applied at render time, so one source renders
|
|
in every theme.
|
|
|
|
```bash
|
|
make docs graphs # every graph, every theme
|
|
make docs graphs lucid # one theme
|
|
```
|
|
|
|
`<name>.svg` is the dark default the docs link to; other themes write
|
|
`<name>.<theme>.svg`. See [Themes](#themes).
|