mirror of
https://github.com/got-feedBack/feedBack-desktop.git
synced 2026-08-11 11:19:24 +00:00
204 lines
11 KiB
Markdown
204 lines
11 KiB
Markdown
# Build system architecture
|
|
|
|
How Slopsmith Desktop is built — the flow of scripts, config, and
|
|
packaging across local dev and CI.
|
|
|
|
## Philosophy
|
|
|
|
1. **npm scripts are the API.** Every build step is callable via
|
|
`npm run <name>`. CI, local dev, and the DevContainer all use the
|
|
same entry points.
|
|
2. **Shell scripts implement.** Complex bundling lives in
|
|
`scripts/bundle-*.sh`; npm just invokes them.
|
|
3. **Configuration is centralized.** Tool versions + external pins
|
|
live in `.build-config.json`; per-OS system deps in `.packages/`.
|
|
4. **Reproducibility is pinned, not floating.** External dependencies
|
|
(FluidR3/GeneralUser soundfonts, fluidsynth Windows zip) are tied to
|
|
specific commits or SHA256s; CI and local see the same bytes.
|
|
|
|
## High-level flow
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ Build environments │
|
|
│ │
|
|
│ GitHub Actions DevContainer (Docker) Developer CLI │
|
|
│ │ │ │ │
|
|
│ └─────────────────────┼───────────────────────┘ │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ ┌─────────────────────┐ │
|
|
│ │ npm scripts │ │
|
|
│ │ (package.json) │ ← single-source entry │
|
|
│ └─────────────────────┘ │
|
|
│ │ │
|
|
│ ┌──────────────────┼──────────────────┐ │
|
|
│ ▼ ▼ ▼ │
|
|
│ ┌────────────┐ ┌──────────────┐ ┌────────────┐ │
|
|
│ │build:native│ │ bundle │ │ build:ts │ │
|
|
│ │ │ │ │ │ │ │
|
|
│ │• build:audio│ │• bundle: │ │ (tsc) │ │
|
|
│ │ │ │ slopsmith │ │ │ │
|
|
│ └────────────┘ │• bundle: │ └────────────┘ │
|
|
│ │ python │ │
|
|
│ │• bundle: │ │
|
|
│ │ binaries │ │
|
|
│ │• bundle: │ │
|
|
│ │ soundfont │ │
|
|
│ └──────────────┘ │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ ┌─────────────────────┐ │
|
|
│ │ electron-builder │ │
|
|
│ │ (dist:linux etc.) │ │
|
|
│ └─────────────────────┘ │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ Configuration files │
|
|
│ │
|
|
│ .build-config.json .packages/ │
|
|
│ ├── versions ├── apt.txt (Ubuntu/Debian) │
|
|
│ │ ├── node ├── brew.txt (macOS) │
|
|
│ │ ├── python ├── choco.txt (Windows) │
|
|
│ │ ├── electron └── README.md │
|
|
│ │ ├── cmake │
|
|
│ │ └── ubuntu │
|
|
│ └── external │
|
|
│ ├── fluidsynth_windows (version + URL) │
|
|
│ └── soundfont_general_user (URL + SHA256) │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
## Detailed flow for `npm run dist:linux`
|
|
|
|
```
|
|
npm run dist:linux
|
|
└── npm run dist -- --linux
|
|
└── npm run bundle && npm run build:ts && electron-builder --linux
|
|
└── bundle
|
|
├── bundle-slopsmith.sh — server.py + lib + static + plugins
|
|
├── bundle-python.sh — portable Python 3.12 runtime + pip + app deps
|
|
├── bundle-binaries.sh — ffmpeg + vgmstream-cli + fluidsynth + its .so chain
|
|
└── bundle-soundfont.sh — GeneralUser-GS.sf2 (SHA256-verified)
|
|
└── build:ts
|
|
└── tsc
|
|
└── electron-builder
|
|
└── AppImage + .deb
|
|
```
|
|
|
|
For `build:native` (run separately, not part of `dist`):
|
|
|
|
```
|
|
npm run build:native
|
|
└── build:audio — cmake-js builds the JUCE C++ native addon
|
|
```
|
|
|
|
## Scripts directory
|
|
|
|
```
|
|
scripts/
|
|
├── bundle.sh — top-level Linux delegator (→ bundle-*.sh)
|
|
├── bundle-slopsmith.sh — copy server + plugins
|
|
├── bundle-python.sh — portable Python runtime (Linux)
|
|
├── bundle-binaries.sh — ffmpeg + vgmstream + fluidsynth + libs (Linux)
|
|
├── bundle-soundfont.sh — GeneralUser-GS.sf2 download + verify (cross-platform)
|
|
├── build-linux-release.sh — Docker wrapper for reproducible Linux AppImage
|
|
├── parse-build-config.py — JSON value extractor
|
|
└── setup-dev.sh — local prerequisite checker
|
|
```
|
|
|
|
### Why modular
|
|
|
|
- **Composability**: debug or re-run a single step (`npm run bundle:python`)
|
|
- **Readability**: each script does one thing and has a single reason to change
|
|
- **CI/local parity**: CI calls the same scripts where platform-independent; platform-specific inline bash stays in `build.yml` for macOS/Windows (dylibbundler, zip downloads) only because those tools don't fit the Linux shell-script model
|
|
|
|
### Platform scope per script
|
|
|
|
| Script | Linux | macOS | Windows |
|
|
|---|---|---|---|
|
|
| `bundle.sh` | yes | n/a | n/a |
|
|
| `bundle-slopsmith.sh` | yes | yes (untested) | yes (untested) |
|
|
| `bundle-python.sh` | yes | no (CI inline) | no (CI inline) |
|
|
| `bundle-binaries.sh` | yes | no (CI uses dylibbundler inline) | no (CI downloads zips) |
|
|
| `bundle-soundfont.sh` | yes | yes | yes |
|
|
|
|
## Configuration
|
|
|
|
### `.build-config.json`
|
|
|
|
Tool versions pinned once, read by the CI workflow (via `node -p`) and
|
|
by the DevContainer (via `parse-build-config.py`). External pins
|
|
(soundfont SHA256, fluidsynth Windows zip URL) live under `external.*`.
|
|
|
|
Update tool versions in one place; every consumer picks them up.
|
|
|
|
### `.packages/`
|
|
|
|
Platform system-dep lists. One package per line; `#` comments and
|
|
blank lines are filtered by consumers. See `.packages/README.md` for
|
|
manual install snippets.
|
|
|
|
### Electron version
|
|
|
|
One source of truth: `devDependencies.electron` in `package.json`.
|
|
`build:audio` derives `--runtime-version` via
|
|
`node -p "require('electron/package.json').version"` so cmake-js
|
|
rebuilds the native addon against the currently-installed Electron.
|
|
|
|
## CI vs local parity
|
|
|
|
| Aspect | GitHub Actions | DevContainer |
|
|
|---|---|---|
|
|
| Entry | `npm run dist:linux` (via checkout + setup-* + install) | `npm run dist:linux` (inside container) |
|
|
| Node / Python | From `.build-config.json` | From `.build-config.json` |
|
|
| System deps | `.packages/apt.txt` | `.packages/apt.txt` |
|
|
| Slopsmith source | Cloned fresh to `$RUNNER_TEMP` | Bind-mounted from `../slopsmith` |
|
|
| Python bundle | `scripts/bundle-python.sh` | `scripts/bundle-python.sh` |
|
|
| Binary bundle | Inline bash (ffmpeg / vgmstream / fluidsynth lib chain) | `scripts/bundle-binaries.sh` (invoked by `npm run bundle`) |
|
|
| Soundfont bundle | `scripts/bundle-soundfont.sh` | `scripts/bundle-soundfont.sh` |
|
|
| Smoke test | `fluidsynth --version` + `ffmpeg -version` + `vgmstream-cli --help` | (run manually) |
|
|
|
|
## Adding a new build step
|
|
|
|
1. Create a script in `scripts/` (e.g. `bundle-foo.sh`)
|
|
2. Register an npm script in `package.json` (e.g. `"bundle:foo": "bash scripts/bundle-foo.sh"`)
|
|
3. Wire into the appropriate chain (`bundle`, `build:native`, etc.)
|
|
4. Test locally: `npm run bundle:foo`
|
|
5. Open a PR — CI consumes the same npm scripts
|
|
|
|
## Troubleshooting
|
|
|
|
### Run individual steps
|
|
|
|
```bash
|
|
npm run bundle:python # rebuild just the Python runtime
|
|
npm run bundle:binaries # rebuild just the binary chain
|
|
npm run bundle:soundfont # re-verify the soundfont
|
|
```
|
|
|
|
### Read the current config
|
|
|
|
```bash
|
|
python3 scripts/parse-build-config.py .build-config.json
|
|
python3 scripts/parse-build-config.py .build-config.json .versions.electron
|
|
```
|
|
|
|
### Local vs CI divergence
|
|
|
|
If local and CI builds differ:
|
|
|
|
1. `.build-config.json` — pinned versions identical?
|
|
2. `.packages/apt.txt` — are you running in the DevContainer?
|
|
3. The CI workflow inline-bundles some things differently on
|
|
macOS/Windows (dylibbundler, zip downloads). Local linux dev won't
|
|
reproduce those.
|
|
|
|
## See also
|
|
|
|
- [`../.build-config.json`](../.build-config.json)
|
|
- [`../.packages/`](../.packages/)
|
|
- [`../.devcontainer/`](../.devcontainer/)
|
|
- [`../.github/workflows/build.yml`](../.github/workflows/build.yml)
|