Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 920fcd6a1a | |||
| bd8a7da379 |
+94
-11
@@ -1,7 +1,9 @@
|
|||||||
# Runs on pull requests: unit tests plus a compile check.
|
# Runs on pull requests: unit tests plus a compile check.
|
||||||
# Split into separate jobs (Odin, API, Infra) so they can run concurrently,
|
# Split into separate jobs (Odin, API, Infra) so they can run concurrently,
|
||||||
# and gated by changed paths so each only runs when its code changes.
|
# and gated by changed paths so each only runs when its code changes.
|
||||||
# Infra always runs regardless of what changed.
|
# Infra always runs (unit tests + vet) regardless of what changed; its Pulumi
|
||||||
|
# preview (posted as a PR comment) runs when the infra, gui, or api code
|
||||||
|
# changed, since any of those can change what gets deployed.
|
||||||
|
|
||||||
name: CI
|
name: CI
|
||||||
|
|
||||||
@@ -28,18 +30,31 @@ jobs:
|
|||||||
outputs:
|
outputs:
|
||||||
odin: ${{ steps.filter.outputs.odin }}
|
odin: ${{ steps.filter.outputs.odin }}
|
||||||
api: ${{ steps.filter.outputs.api }}
|
api: ${{ steps.filter.outputs.api }}
|
||||||
|
infra: ${{ steps.filter.outputs.infra }}
|
||||||
|
preview: ${{ steps.decide.outputs.run }}
|
||||||
steps:
|
steps:
|
||||||
- uses: dorny/paths-filter@v4
|
- uses: dorny/paths-filter@v4
|
||||||
id: filter
|
id: filter
|
||||||
with:
|
with:
|
||||||
filters: |
|
filters: |
|
||||||
odin:
|
odin:
|
||||||
- 'src/**'
|
- 'gui/**'
|
||||||
- 'lib/**'
|
|
||||||
- 'scripts/**'
|
- 'scripts/**'
|
||||||
- 'odinfmt.json'
|
|
||||||
api:
|
api:
|
||||||
- 'api/**'
|
- 'api/**'
|
||||||
|
infra:
|
||||||
|
- 'infra/**'
|
||||||
|
|
||||||
|
- name: Decide whether to run the infra preview
|
||||||
|
id: decide
|
||||||
|
run: |
|
||||||
|
if [ "${{ steps.filter.outputs.infra }}" = "true" ] || \
|
||||||
|
[ "${{ steps.filter.outputs.odin }}" = "true" ] || \
|
||||||
|
[ "${{ steps.filter.outputs.api }}" = "true" ]; then
|
||||||
|
echo "run=true" >> "$GITHUB_OUTPUT"
|
||||||
|
else
|
||||||
|
echo "run=false" >> "$GITHUB_OUTPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
odin:
|
odin:
|
||||||
name: Odin unit tests and build
|
name: Odin unit tests and build
|
||||||
@@ -65,14 +80,10 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Run Odin unit tests
|
- name: Run Odin unit tests
|
||||||
run: |
|
run: make -C gui test
|
||||||
mkdir -p lib/local
|
|
||||||
odin test src -collection:lib=lib/local
|
|
||||||
|
|
||||||
- name: Verify build
|
- name: Verify build
|
||||||
run: |
|
run: make -C gui build
|
||||||
mkdir -p bin
|
|
||||||
odin build src -collection:lib=lib/local -o:speed -out:bin/desi_explorer
|
|
||||||
|
|
||||||
api:
|
api:
|
||||||
name: API unit tests and lint
|
name: API unit tests and lint
|
||||||
@@ -103,8 +114,13 @@ jobs:
|
|||||||
cargo fmt --all --check
|
cargo fmt --all --check
|
||||||
|
|
||||||
infra:
|
infra:
|
||||||
name: Infra unit tests and vet
|
name: Infra unit tests, vet, and preview
|
||||||
|
needs: changes
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
issues: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
@@ -124,3 +140,70 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd infra
|
cd infra
|
||||||
go vet ./...
|
go vet ./...
|
||||||
|
|
||||||
|
# Pulumi CLI. State uses the local file backend (infra/Pulumi.yaml ->
|
||||||
|
# file://~/.pulumi), so no Pulumi Cloud token is needed. Preview diffs
|
||||||
|
# the current source against the last-known stack state; on an ephemeral
|
||||||
|
# runner the self-hosted environment must persist ~/.pulumi to get a
|
||||||
|
# meaningful diff (otherwise preview shows the pending creates).
|
||||||
|
- name: Install Pulumi
|
||||||
|
if: ${{ needs.changes.outputs.preview == 'true' }}
|
||||||
|
run: |
|
||||||
|
curl -fsSL https://get.pulumi.com | sh
|
||||||
|
echo "$HOME/.pulumi/bin" >> "$GITHUB_PATH"
|
||||||
|
|
||||||
|
# The runner must reach the on-prem k3s cluster for preview to diff
|
||||||
|
# against live state. For a self-hosted runner this is the ambient
|
||||||
|
# kubeconfig; otherwise populate it from the KUBECONFIG secret here.
|
||||||
|
- name: Configure kubeconfig
|
||||||
|
if: ${{ needs.changes.outputs.preview == 'true' }}
|
||||||
|
run: |
|
||||||
|
mkdir -p "$HOME/.kube"
|
||||||
|
if [ -n "$KUBECONFIG_B64" ]; then
|
||||||
|
printf '%s' "$KUBECONFIG_B64" | base64 -d > "$HOME/.kube/config"
|
||||||
|
fi
|
||||||
|
env:
|
||||||
|
KUBECONFIG_B64: ${{ secrets.KUBECONFIG }}
|
||||||
|
|
||||||
|
- name: Pulumi preview
|
||||||
|
if: ${{ needs.changes.outputs.preview == 'true' }}
|
||||||
|
working-directory: infra
|
||||||
|
env:
|
||||||
|
PULUMI_SKIP_UPDATE_CHECK: 'true'
|
||||||
|
run: |
|
||||||
|
go mod download
|
||||||
|
pulumi preview --diff 2>&1 | tee /tmp/pulumi-preview.txt || true
|
||||||
|
|
||||||
|
- name: Comment preview on PR
|
||||||
|
if: ${{ needs.changes.outputs.preview == 'true' }}
|
||||||
|
env:
|
||||||
|
GITEA_API: ${{ gitea.api_url }}
|
||||||
|
REPO: ${{ gitea.repository }}
|
||||||
|
TOKEN: ${{ github.token }}
|
||||||
|
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||||
|
run: |
|
||||||
|
python3 - <<'PY'
|
||||||
|
import json, os, urllib.request
|
||||||
|
|
||||||
|
with open('/tmp/pulumi-preview.txt') as f:
|
||||||
|
preview = f.read().strip() or '(no changes)'
|
||||||
|
|
||||||
|
body = "### Pulumi preview\n\n```\n" + preview + "\n```"
|
||||||
|
payload = json.dumps({"body": body}).encode()
|
||||||
|
|
||||||
|
url = (
|
||||||
|
f"{os.environ['GITEA_API']}/repos/{os.environ['REPO']}"
|
||||||
|
f"/issues/{os.environ['PR_NUMBER']}/comments"
|
||||||
|
)
|
||||||
|
req = urllib.request.Request(
|
||||||
|
url,
|
||||||
|
data=payload,
|
||||||
|
method='POST',
|
||||||
|
headers={
|
||||||
|
'Authorization': f"token {os.environ['TOKEN']}",
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
urllib.request.urlopen(req)
|
||||||
|
print('Posted Pulumi preview comment')
|
||||||
|
PY
|
||||||
|
|||||||
@@ -53,10 +53,8 @@ jobs:
|
|||||||
base: ${{ steps.prev.outputs.prev }}
|
base: ${{ steps.prev.outputs.prev }}
|
||||||
filters: |
|
filters: |
|
||||||
odin:
|
odin:
|
||||||
- 'src/**'
|
- 'gui/**'
|
||||||
- 'lib/**'
|
|
||||||
- 'scripts/**'
|
- 'scripts/**'
|
||||||
- 'odinfmt.json'
|
|
||||||
api:
|
api:
|
||||||
- 'api/**'
|
- 'api/**'
|
||||||
infra:
|
infra:
|
||||||
@@ -84,7 +82,7 @@ jobs:
|
|||||||
- name: Build WebAssembly
|
- name: Build WebAssembly
|
||||||
run: |
|
run: |
|
||||||
source /tmp/emsdk/emsdk_env.sh
|
source /tmp/emsdk/emsdk_env.sh
|
||||||
scripts/build_web.sh
|
gui/scripts/build_web.sh
|
||||||
|
|
||||||
- name: Package
|
- name: Package
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -49,8 +49,8 @@ jobs:
|
|||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
mkdir -p lib/local build/linux
|
mkdir -p build/linux
|
||||||
odin build src -o:speed -collection:lib=lib/local -out:build/linux/desi_explorer
|
odin build gui/src -o:speed -collection:lib=gui/lib/local -out:build/linux/desi_explorer
|
||||||
|
|
||||||
- name: Package
|
- name: Package
|
||||||
run: |
|
run: |
|
||||||
@@ -110,10 +110,10 @@ jobs:
|
|||||||
# next to desi_explorer.exe.
|
# next to desi_explorer.exe.
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
mkdir -p lib/local build/windows
|
mkdir -p build/windows
|
||||||
odin build src -target:windows_amd64 -build-mode:obj \
|
odin build gui/src -target:windows_amd64 -build-mode:obj \
|
||||||
-define:RAYLIB_SHARED=true -o:speed \
|
-define:RAYLIB_SHARED=true -o:speed \
|
||||||
-collection:lib=lib/local -out:build/windows/desi_explorer
|
-collection:lib=gui/lib/local -out:build/windows/desi_explorer
|
||||||
x86_64-w64-mingw32-gcc -O2 -o build/windows/desi_explorer.exe \
|
x86_64-w64-mingw32-gcc -O2 -o build/windows/desi_explorer.exe \
|
||||||
build/windows/desi_explorer.obj \
|
build/windows/desi_explorer.obj \
|
||||||
/tmp/odin-win/dist/vendor/raylib/windows/raylibdll.lib \
|
/tmp/odin-win/dist/vendor/raylib/windows/raylibdll.lib \
|
||||||
@@ -151,7 +151,7 @@ jobs:
|
|||||||
- name: Build WebAssembly
|
- name: Build WebAssembly
|
||||||
run: |
|
run: |
|
||||||
source /tmp/emsdk/emsdk_env.sh
|
source /tmp/emsdk/emsdk_env.sh
|
||||||
scripts/build_web.sh
|
gui/scripts/build_web.sh
|
||||||
|
|
||||||
- name: Package
|
- name: Package
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -2,27 +2,28 @@
|
|||||||
|
|
||||||
Odin + raylib interactive 3D universe map (DESI data), a Rust + axum API, with Go + Pulumi infra and Gitea Actions CI. A clean `odin build` + `cargo test` + `go test` is the verification step.
|
Odin + raylib interactive 3D universe map (DESI data), a Rust + axum API, with Go + Pulumi infra and Gitea Actions CI. A clean `odin build` + `cargo test` + `go test` is the verification step.
|
||||||
|
|
||||||
## Commands (root Makefile)
|
## Commands
|
||||||
- Run: `make run` (`odin run src`); Build: `make build` (`odin build src -collection:lib=lib/local -out:bin/desi_explorer`)
|
The root `Makefile` is a lean delegator: base commands (`run`, `build`, `test`, ...) forward into the per-project Makefiles in `gui/`, `api/`, and `infra/`. Project-specific commands are reached via `make -C <dir> <target>`.
|
||||||
- Web: `make build-web` (Emscripten/WASM -> build/web); Debug: `make build-debug`
|
- Run: `make run`; Build: `make build` (`-> bin/desi_explorer`); Web: `make build-web` (Emscripten/WASM -> `build/web`); Debug: `make build-debug`
|
||||||
- Test: `make test` (runs `odin test` for src/, `go test` for infra/, and `cargo test` for api/); Clean: `make clean`
|
- Test: `make test` (runs `odin test` in gui/, `cargo test` in api/, `go test` in infra/); Clean: `make clean`; Format: `make fmt`
|
||||||
- API: `make api-run` (`cargo run` in api/), `make api-test`, `make api-check` (`cargo fmt --check` + `clippy -D warnings`)
|
- API: `make api-run`, `make api-test`, `make api-check` (thin passthroughs to `make -C api <target>`)
|
||||||
- Setup: `make setup` (submodules + `go mod tidy` in infra/)
|
- Setup: `make setup` (submodules + `go mod tidy` in infra/)
|
||||||
- Infra: `make infra-preview`, `make infra-up`, `make infra-down`, `make infra-refresh` (Pulumi, `--cwd infra`)
|
- Infra: `make infra-preview`, `make infra-up`, `make infra-down`, `make infra-refresh` (passthroughs to `make -C infra <target>`)
|
||||||
- Renovate: `make renovate-validate` (npx renovate-config-validator)
|
- Renovate: `make renovate-validate` (npx renovate-config-validator)
|
||||||
- Format Odin with `odinfmt` (config `odinfmt.json`: tabs, width 80); format Rust with `cargo fmt`
|
- Format Odin with `odinfmt` (config `gui/odinfmt.json`: tabs, width 80); format Rust with `cargo fmt`
|
||||||
|
|
||||||
## Layout
|
## Layout
|
||||||
- `src/main.odin` — entrypoint; loop is `update()` → `draw()`; resizable window with an orbital `Camera3D`; point cloud generated procedurally in `make_universe`.
|
- `gui/` — the Odin + raylib renderer. `gui/src/main.odin` is the entrypoint (loop is `update()` → `draw()`; resizable window with an orbital `Camera3D`; point cloud generated procedurally in `make_universe`). `gui/lib/` holds third-party Odin deps (see below), `gui/www/` the Web GUI (WASM shell / static web assets), and `gui/scripts/` the build scripts. `gui/Makefile` owns the Odin targets.
|
||||||
- `lib/` — third-party Odin deps (submodules / vendored libs). raylib is **not** here: it ships vendored with Odin and is imported as `vendor:raylib`. `lib/local/` is the default `-collection:lib` target and is currently empty.
|
- `gui/lib/` — third-party Odin deps (submodules / vendored libs). raylib is **not** here: it ships vendored with Odin and is imported as `vendor:raylib`. `gui/lib/local/` is the default `-collection:lib` target and is currently empty.
|
||||||
- `api/` — Rust + axum backend API that will serve DESI catalog data. `src/lib.rs` exposes `routes`/`models`/`config`; `src/main.rs` is the server entrypoint (binds `API_BIND_ADDR`, default `0.0.0.0:8080`). Crate name is `desi-explorer-api` (lib `desi_explorer_api`); Rust version pinned in `api/rust-toolchain.toml`.
|
- `api/` — Rust + axum backend API that will serve DESI catalog data. `src/lib.rs` exposes `routes`/`models`/`config`; `src/main.rs` is the server entrypoint (binds `API_BIND_ADDR`, default `0.0.0.0:8080`). Crate name is `desi-explorer-api` (lib `desi_explorer_api`); Rust version pinned in `api/rust-toolchain.toml`. `api/Makefile` owns the Rust targets.
|
||||||
- `infra/` — Go + Pulumi (`runtime: go`) targeting the on-prem k3s cluster via the default kubeconfig, mirroring the `homelab` repo's pattern. Module name is `desi-explorer-infra`.
|
- `infra/` — Go + Pulumi (`runtime: go`) targeting the on-prem k3s cluster via the default kubeconfig, mirroring the `homelab` repo's pattern. Module name is `desi-explorer-infra`. `infra/Makefile` owns the Pulumi/Go targets.
|
||||||
- `.gitea/workflows/` — `ci.yml` (PR: install Odin, Rust, `odin test` + build, `cargo test` + clippy, `go test`) and `release.yml` (tag `v*`: build native + WASM + publish a Gitea release).
|
- `scripts/` — repo-level build helpers (Odin toolchain install).
|
||||||
|
- `.gitea/workflows/` — `ci.yml` (PR: `odin test` + build, `cargo test` + clippy, `go test` + vet; infra always runs tests/vet and posts a `pulumi preview --diff` as a PR comment when infra/gui/api changed) and `release.yml` (tag `v*`: build native + WASM + publish a Gitea release).
|
||||||
|
|
||||||
## Conventions
|
## Conventions
|
||||||
- Odin code lives in `src/`; external deps go in `lib/` and are wired via `-collection:lib=lib/local` (or a git submodule imported by relative path).
|
- Odin code lives in `gui/src/`; external deps go in `gui/lib/` and are wired via `-collection:lib=lib/local` (or a git submodule imported by relative path).
|
||||||
- Everything is plain `make` — no Taskfile — so CI (Gitea Actions) can call `make` directly.
|
- Everything is plain `make` — no Taskfile — so CI (Gitea Actions) can call `make` directly.
|
||||||
- Keep the renderer (src/), API (api/), and infra (infra/) logically separated; the root Makefile is the only place that ties them together.
|
- Keep the renderer (gui/), API (api/), and infra (infra/) logically separated; each owns its own Makefile, and the root Makefile is the only place that ties them together.
|
||||||
|
|
||||||
## Gotchas
|
## Gotchas
|
||||||
- Odin version is pinned in `.gitea/workflows/*.yml` (`ODIN_VERSION`) and defaults in `scripts/install_odin.sh`; bump both together when tracking a new release.
|
- Odin version is pinned in `.gitea/workflows/*.yml` (`ODIN_VERSION`) and defaults in `scripts/install_odin.sh`; bump both together when tracking a new release.
|
||||||
|
|||||||
@@ -1,94 +1,69 @@
|
|||||||
# DESI Explorer — root Makefile
|
# DESI Explorer — root Makefile
|
||||||
#
|
#
|
||||||
# Orchestrates the Odin renderer (src/) and the Go/Pulumi infrastructure
|
# Lean orchestrator: the "base" commands (`run`, `build`, `test`, ...) delegate
|
||||||
# (infra/). Intended to be called directly by Gitea Actions CI.
|
# into the per-project Makefiles in `gui/`, `api/`, and `infra/`. Project-
|
||||||
|
# specific commands live in those directories and are reached with
|
||||||
|
# `make -C <dir> <target>` (or the thin passthrough targets below).
|
||||||
|
|
||||||
ODIN ?= odin
|
GUI := gui
|
||||||
CARGO ?= cargo
|
API := api
|
||||||
BIN ?= bin
|
INFRA := infra
|
||||||
BINARY := $(BIN)/desi_explorer
|
|
||||||
ODIN_FLAGS := -collection:lib=lib/local
|
|
||||||
WASM_DEFINE := RAYLIB_WASM_LIB=env.o
|
|
||||||
|
|
||||||
.PHONY: help setup run build build-debug build-web test clean fmt \
|
.PHONY: help setup run build build-debug build-web test clean fmt \
|
||||||
api-run api-build api-test api-check api-fmt \
|
|
||||||
infra-preview infra-up infra-down infra-refresh infra-static \
|
|
||||||
renovate-validate
|
renovate-validate
|
||||||
|
|
||||||
help: ## List available targets
|
help: ## List available targets
|
||||||
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
|
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
|
||||||
awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-18s\033[0m %s\n", $$1, $$2}'
|
awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-18s\033[0m %s\n", $$1, $$2}'
|
||||||
|
@echo ""
|
||||||
|
@echo "Sub-project targets:"
|
||||||
|
@echo " \033[36mmake -C gui help\033[0m Odin renderer (run, build, build-web, test, fmt, ...)"
|
||||||
|
@echo " \033[36mmake -C api help\033[0m Rust API (run, build, test, check, fmt, ...)"
|
||||||
|
@echo " \033[36mmake -C infra help\033[0m Infra (preview, up, down, refresh, test, ...)"
|
||||||
|
|
||||||
## ---- Setup ---------------------------------------------------------------
|
## ---- Setup ---------------------------------------------------------------
|
||||||
|
|
||||||
setup: ## Pull submodules + tidy Go deps
|
setup: ## Pull submodules + tidy Go deps
|
||||||
@git submodule update --init --recursive
|
@git submodule update --init --recursive
|
||||||
@mkdir -p lib/local
|
@$(MAKE) -C $(INFRA) tidy
|
||||||
@cd infra && go mod tidy
|
|
||||||
|
|
||||||
## ---- Renderer (Odin) -----------------------------------------------------
|
## ---- Renderer (Odin) -----------------------------------------------------
|
||||||
|
|
||||||
run: ## Run the native app
|
run: ## Run the native app (gui/)
|
||||||
@mkdir -p lib/local
|
@$(MAKE) -C $(GUI) run
|
||||||
$(ODIN) run src $(ODIN_FLAGS)
|
|
||||||
|
|
||||||
build: ## Release build -> bin/desi_explorer
|
build: ## Release build -> bin/desi_explorer (gui/)
|
||||||
@mkdir -p lib/local $(BIN)
|
@$(MAKE) -C $(GUI) build
|
||||||
$(ODIN) build src $(ODIN_FLAGS) -o:speed -out:$(BINARY)
|
|
||||||
|
|
||||||
build-debug: ## Debug build -> bin/desi_explorer
|
build-debug: ## Debug build -> bin/desi_explorer (gui/)
|
||||||
@mkdir -p lib/local $(BIN)
|
@$(MAKE) -C $(GUI) build-debug
|
||||||
$(ODIN) build src $(ODIN_FLAGS) -o:none -debug -out:$(BINARY)
|
|
||||||
|
|
||||||
build-web: ## WebAssembly build -> build/web (needs emscripten)
|
build-web: ## WebAssembly build -> build/web (gui/, needs emscripten)
|
||||||
@scripts/build_web.sh
|
@$(MAKE) -C $(GUI) build-web
|
||||||
|
|
||||||
test: ## Run tests (Odin src/ + Go infra/ + Rust api/)
|
## ---- Aggregates ----------------------------------------------------------
|
||||||
@mkdir -p lib/local
|
|
||||||
$(ODIN) test src $(ODIN_FLAGS)
|
|
||||||
@cd infra && go test ./...
|
|
||||||
@cd api && $(CARGO) test
|
|
||||||
|
|
||||||
clean: ## Remove build artifacts
|
test: ## Test all projects (odin + cargo + go)
|
||||||
rm -rf $(BIN) build
|
@$(MAKE) -C $(GUI) test
|
||||||
@cd api && $(CARGO) clean
|
@$(MAKE) -C $(API) test
|
||||||
|
@$(MAKE) -C $(INFRA) test
|
||||||
|
|
||||||
fmt: ## Format Odin sources with odinfmt
|
clean: ## Remove build artifacts from all projects
|
||||||
odinfmt src
|
@$(MAKE) -C $(GUI) clean
|
||||||
|
@$(MAKE) -C $(API) clean
|
||||||
|
@$(MAKE) -C $(INFRA) clean
|
||||||
|
|
||||||
## ---- API (Rust + axum) ---------------------------------------------------
|
fmt: ## Format all projects (odin + rust)
|
||||||
|
@$(MAKE) -C $(GUI) fmt
|
||||||
|
@$(MAKE) -C $(API) fmt
|
||||||
|
|
||||||
api-run: ## Run the API server (dev)
|
## ---- Passthrough to sub-project Makefiles --------------------------------
|
||||||
@cd api && $(CARGO) run
|
|
||||||
|
|
||||||
api-build: ## Release build the API -> api/target/release/
|
api-%: ## Forward a target to the api/ Makefile
|
||||||
@cd api && $(CARGO) build --release
|
@$(MAKE) -C $(API) $*
|
||||||
|
|
||||||
api-test: ## Run API unit/integration tests
|
infra-%: ## Forward a target to the infra/ Makefile
|
||||||
@cd api && $(CARGO) test
|
@$(MAKE) -C $(INFRA) $*
|
||||||
|
|
||||||
api-check: ## Typecheck + format-check + lint the API
|
|
||||||
@cd api && $(CARGO) fmt --all --check && $(CARGO) clippy --all-targets -- -D warnings
|
|
||||||
|
|
||||||
api-fmt: ## Format Rust sources with rustfmt
|
|
||||||
@cd api && $(CARGO) fmt
|
|
||||||
|
|
||||||
## ---- Infrastructure (Go + Pulumi) ----------------------------------------
|
|
||||||
|
|
||||||
infra-preview: ## Preview infra changes against the cluster
|
|
||||||
@pulumi preview --cwd infra
|
|
||||||
|
|
||||||
infra-up: ## Deploy/update infra
|
|
||||||
@pulumi up --cwd infra
|
|
||||||
|
|
||||||
infra-down: ## Tear down the stack's resources
|
|
||||||
@pulumi destroy --cwd infra
|
|
||||||
|
|
||||||
infra-refresh: ## Refresh Pulumi state against the live cluster
|
|
||||||
@pulumi refresh --cwd infra
|
|
||||||
|
|
||||||
infra-static: ## Typecheck + vet the Go infra without Pulumi
|
|
||||||
@cd infra && go build -o /dev/null . && go vet ./...
|
|
||||||
|
|
||||||
## ---- Tooling -------------------------------------------------------------
|
## ---- Tooling -------------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -42,17 +42,20 @@ Early scaffolding. The application currently:
|
|||||||
## Repository Layout
|
## Repository Layout
|
||||||
|
|
||||||
```
|
```
|
||||||
src/ Odin source — the interactive 3D experience (entrypoint: src/main.odin)
|
gui/ Odin renderer — the interactive 3D experience (entrypoint: gui/src/main.odin)
|
||||||
lib/ Third-party Odin dependencies (submodules / vendored libs)
|
gui/lib/ Third-party Odin dependencies (submodules / vendored libs)
|
||||||
|
gui/www/ Web GUI — WASM shell / static web assets
|
||||||
|
gui/scripts/ Build scripts (WASM build helper)
|
||||||
api/ Rust backend API (axum) for serving DESI catalog data
|
api/ Rust backend API (axum) for serving DESI catalog data
|
||||||
infra/ Go + Pulumi infrastructure-as-code (deploys the experience to k8s)
|
infra/ Go + Pulumi infrastructure-as-code (deploys the experience to k8s)
|
||||||
scripts/ Build helpers (Odin install, WASM build)
|
scripts/ Repo-level build helpers (Odin install)
|
||||||
.gitea/ Gitea Actions CI/CD workflows
|
.gitea/ Gitea Actions CI/CD workflows
|
||||||
```
|
```
|
||||||
|
|
||||||
The renderer (`src/`), the API (`api/`), and the infrastructure (`infra/`) are
|
The renderer (`gui/`), the API (`api/`), and the infrastructure (`infra/`) are
|
||||||
kept in separate directories so their logic stays cleanly separated; all are
|
kept in separate directories so their logic stays cleanly separated. Each
|
||||||
orchestrated by the root `Makefile`.
|
project carries its own `Makefile`; the root `Makefile` delegates the base
|
||||||
|
commands (`run`, `build`, `test`, ...) into them.
|
||||||
|
|
||||||
## Building & Running
|
## Building & Running
|
||||||
|
|
||||||
@@ -62,21 +65,33 @@ vendor bindings. The web build additionally requires [Emscripten](https://emscri
|
|||||||
pinned via `api/rust-toolchain.toml`). The infrastructure requires
|
pinned via `api/rust-toolchain.toml`). The infrastructure requires
|
||||||
[Go](https://go.dev) and [Pulumi](https://www.pulumi.com).
|
[Go](https://go.dev) and [Pulumi](https://www.pulumi.com).
|
||||||
|
|
||||||
All project commands live in the root `Makefile` (`make help` lists them):
|
The root `Makefile` delegates everything to the per-project Makefiles
|
||||||
|
(`make help` lists the base targets):
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
make setup # pull submodules + tidy Go deps
|
make setup # pull submodules + tidy Go deps
|
||||||
make run # run the native app
|
make run # run the native app (gui/)
|
||||||
make build # -> bin/desi_explorer
|
make build # -> bin/desi_explorer (gui/)
|
||||||
make build-debug # debug native build
|
make build-debug # debug native build (gui/)
|
||||||
make build-web # -> build/web (wasm + html)
|
make build-web # -> build/web (wasm + html, gui/)
|
||||||
make test # odin test + go test + cargo test
|
make test # odin test + go test + cargo test
|
||||||
make clean # remove build artifacts
|
make clean # remove build artifacts from all projects
|
||||||
make api-run # run the Rust API server
|
make fmt # format all projects
|
||||||
make api-test # cargo test
|
|
||||||
make api-check # rustfmt check + clippy
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Project-specific targets live in their own `Makefile` and are reached with
|
||||||
|
`make -C <dir> <target>`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make -C gui help # Odin renderer (run, build, build-debug, build-web, test, fmt)
|
||||||
|
make -C api help # Rust API (run, build, test, check, fmt)
|
||||||
|
make -C infra help # Infra (preview, up, down, refresh, static, test)
|
||||||
|
```
|
||||||
|
|
||||||
|
The root also provides thin passthroughs: `make api-<target>` and
|
||||||
|
`make infra-<target>` forward to the corresponding sub-project (e.g.
|
||||||
|
`make api-check` -> `make -C api check`).
|
||||||
|
|
||||||
## Dependency Updates (Renovate)
|
## Dependency Updates (Renovate)
|
||||||
|
|
||||||
[Renovate](https://github.com/renovatebot/renovate) keeps dependencies up to
|
[Renovate](https://github.com/renovatebot/renovate) keeps dependencies up to
|
||||||
@@ -91,5 +106,5 @@ It manages four categories:
|
|||||||
|
|
||||||
- **Infra dependencies** — `infra/go.mod` (`gomod` manager); minor/patch updates grouped into a single PR.
|
- **Infra dependencies** — `infra/go.mod` (`gomod` manager); minor/patch updates grouped into a single PR.
|
||||||
- **API dependencies** — `api/Cargo.toml` (`cargo` manager); minor/patch updates grouped into a single PR.
|
- **API dependencies** — `api/Cargo.toml` (`cargo` manager); minor/patch updates grouped into a single PR.
|
||||||
- **Submodules** — `lib/` submodules via `.gitmodules` (`git-submodules` manager).
|
- **Submodules** — `gui/lib/` submodules via `.gitmodules` (`git-submodules` manager).
|
||||||
- **Workflow actions** — action versions in `.gitea/workflows/*.yml` (`github-actions` manager, which understands Gitea's `.gitea` layout).
|
- **Workflow actions** — action versions in `.gitea/workflows/*.yml` (`github-actions` manager, which understands Gitea's `.gitea` layout).
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# api/Makefile — the Rust + axum backend API.
|
||||||
|
#
|
||||||
|
# Driven directly with `make -C api <target>` (or via the root Makefile's
|
||||||
|
# `api-*` convenience targets).
|
||||||
|
|
||||||
|
CARGO ?= cargo
|
||||||
|
|
||||||
|
.PHONY: help run build test check fmt clean
|
||||||
|
|
||||||
|
help: ## List available targets
|
||||||
|
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
|
||||||
|
awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-18s\033[0m %s\n", $$1, $$2}'
|
||||||
|
|
||||||
|
run: ## Run the API server (dev)
|
||||||
|
$(CARGO) run
|
||||||
|
|
||||||
|
build: ## Release build -> target/release/
|
||||||
|
$(CARGO) build --release
|
||||||
|
|
||||||
|
test: ## Run unit/integration tests
|
||||||
|
$(CARGO) test
|
||||||
|
|
||||||
|
check: ## Format-check + lint (clippy -D warnings)
|
||||||
|
$(CARGO) fmt --all --check && $(CARGO) clippy --all-targets -- -D warnings
|
||||||
|
|
||||||
|
fmt: ## Format Rust sources with rustfmt
|
||||||
|
$(CARGO) fmt
|
||||||
|
|
||||||
|
clean: ## Remove Cargo build artifacts
|
||||||
|
$(CARGO) clean
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# gui/Makefile — the Odin + raylib renderer (the interactive 3D universe map).
|
||||||
|
#
|
||||||
|
# This is the Odin sub-project. It is normally invoked from the repo root via
|
||||||
|
# `make run`, `make build`, etc. (which delegate here through the root
|
||||||
|
# Makefile), but it can also be driven directly with `make -C gui <target>`.
|
||||||
|
#
|
||||||
|
# `lib/` (third-party Odin deps) lives under `gui/lib`; the `bin/` / `build/`
|
||||||
|
# output dirs live at the repo root and are referenced through `$(ROOT)`.
|
||||||
|
|
||||||
|
ODIN ?= odin
|
||||||
|
ROOT := ..
|
||||||
|
BIN := $(ROOT)/bin
|
||||||
|
BINARY := $(BIN)/desi_explorer
|
||||||
|
ODIN_FLAGS := -collection:lib=lib/local
|
||||||
|
WASM_DEFINE := RAYLIB_WASM_LIB=env.o
|
||||||
|
|
||||||
|
.PHONY: help run build build-debug build-web test clean fmt
|
||||||
|
|
||||||
|
help: ## List available targets
|
||||||
|
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
|
||||||
|
awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-18s\033[0m %s\n", $$1, $$2}'
|
||||||
|
|
||||||
|
run: ## Run the native app
|
||||||
|
@mkdir -p lib/local
|
||||||
|
$(ODIN) run src $(ODIN_FLAGS)
|
||||||
|
|
||||||
|
build: ## Release build -> bin/desi_explorer
|
||||||
|
@mkdir -p lib/local $(BIN)
|
||||||
|
$(ODIN) build src $(ODIN_FLAGS) -o:speed -out:$(BINARY)
|
||||||
|
|
||||||
|
build-debug: ## Debug build -> bin/desi_explorer
|
||||||
|
@mkdir -p lib/local $(BIN)
|
||||||
|
$(ODIN) build src $(ODIN_FLAGS) -o:none -debug -out:$(BINARY)
|
||||||
|
|
||||||
|
build-web: ## WebAssembly build -> build/web (needs emscripten)
|
||||||
|
@scripts/build_web.sh
|
||||||
|
|
||||||
|
test: ## Run Odin unit tests
|
||||||
|
@mkdir -p lib/local
|
||||||
|
$(ODIN) test src $(ODIN_FLAGS)
|
||||||
|
|
||||||
|
clean: ## Remove build artifacts
|
||||||
|
rm -rf $(BIN) build
|
||||||
|
|
||||||
|
fmt: ## Format Odin sources with odinfmt
|
||||||
|
odinfmt src
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
# Libraries
|
# Libraries
|
||||||
|
|
||||||
Third-party libraries for the DESI Explorer renderer live here, either as git
|
Third-party libraries for the DESI Explorer renderer live here, either as git
|
||||||
submodules or vendored directly and wired in via `-collection:lib=lib/local`.
|
submodules or vendored directly and wired in via `-collection:lib=lib/local`
|
||||||
|
(as resolved from the `gui/` directory).
|
||||||
|
|
||||||
- `raylib` is bundled with Odin and imported as `vendor:raylib` — it does **not**
|
- `raylib` is bundled with Odin and imported as `vendor:raylib` — it does **not**
|
||||||
live in this directory.
|
live in this directory.
|
||||||
@@ -1,30 +1,36 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Builds the WebAssembly ("web") build of DESI Explorer with Odin
|
# Builds the WebAssembly ("web") build of DESI Explorer with Odin
|
||||||
# (js_wasm32) + emscripten. Output: build/web/index.html (+ index.wasm, odin.js).
|
# (js_wasm32) + emscripten. Output: build/web/index.html (+ index.wasm,
|
||||||
|
# odin.js) at the repo root. Run via `make -C gui build-web`.
|
||||||
#
|
#
|
||||||
# Requires:
|
# Requires:
|
||||||
# - `odin` on PATH with the js_wasm32 target
|
# - `odin` on PATH with the js_wasm32 target
|
||||||
# - emcc / emscripten active in PATH
|
# - emcc / emscripten active in PATH
|
||||||
# Optional:
|
# Optional:
|
||||||
# - ODIN_ROOT (defaults to `odin root`)
|
# - ODIN_ROOT (defaults to `odin root`)
|
||||||
# - OUT_DIR (defaults to build/web)
|
# - OUT_DIR (defaults to <repo>/build/web)
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
OUT_DIR="${OUT_DIR:-build/web}"
|
# Resolve the gui/ project root so this script works regardless of CWD.
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
GUI_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||||
|
ROOT_DIR="$(cd "${GUI_DIR}/.." && pwd)"
|
||||||
|
|
||||||
|
OUT_DIR="${OUT_DIR:-${ROOT_DIR}/build/web}"
|
||||||
ODIN_ROOT="${ODIN_ROOT:-$(odin root)}"
|
ODIN_ROOT="${ODIN_ROOT:-$(odin root)}"
|
||||||
|
|
||||||
mkdir -p lib/local
|
mkdir -p "${GUI_DIR}/lib/local"
|
||||||
mkdir -p "$OUT_DIR"
|
mkdir -p "$OUT_DIR"
|
||||||
|
|
||||||
# The Odin compiler emits a wasm object; raylib's C code is linked later by
|
# The Odin compiler emits a wasm object; raylib's C code is linked later by
|
||||||
# emcc. `-define:RAYLIB_WASM_LIB=env.o` stops the compiler from trying to
|
# emcc. `-define:RAYLIB_WASM_LIB=env.o` stops the compiler from trying to
|
||||||
# link the raylib lib itself (emcc does that; it ends up in the final module).
|
# link the raylib lib itself (emcc does that; it ends up in the final module).
|
||||||
odin build src \
|
odin build "${GUI_DIR}/src" \
|
||||||
-target:js_wasm32 \
|
-target:js_wasm32 \
|
||||||
-build-mode:obj \
|
-build-mode:obj \
|
||||||
-define:RAYLIB_WASM_LIB=env.o \
|
-define:RAYLIB_WASM_LIB=env.o \
|
||||||
-o:speed \
|
-o:speed \
|
||||||
-collection:lib=lib/local \
|
-collection:lib="${GUI_DIR}/lib/local" \
|
||||||
-out:"${OUT_DIR}/game"
|
-out:"${OUT_DIR}/game"
|
||||||
|
|
||||||
# Odin's JS runtime glue; the generated module imports functions from it.
|
# Odin's JS runtime glue; the generated module imports functions from it.
|
||||||
@@ -36,7 +42,7 @@ emcc \
|
|||||||
-o "${OUT_DIR}/index.html" \
|
-o "${OUT_DIR}/index.html" \
|
||||||
"${OUT_DIR}/game.obj" \
|
"${OUT_DIR}/game.obj" \
|
||||||
"${ODIN_ROOT}/vendor/raylib/wasm/libraylib.web.a" \
|
"${ODIN_ROOT}/vendor/raylib/wasm/libraylib.web.a" \
|
||||||
--shell-file scripts/web/index_template.html \
|
--shell-file "${GUI_DIR}/www/index_template.html" \
|
||||||
-sEXPORTED_RUNTIME_METHODS="['HEAPF32']" \
|
-sEXPORTED_RUNTIME_METHODS="['HEAPF32']" \
|
||||||
-sUSE_GLFW=3 \
|
-sUSE_GLFW=3 \
|
||||||
-sWASM_BIGINT \
|
-sWASM_BIGINT \
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# infra/Makefile — Go + Pulumi infrastructure-as-code.
|
||||||
|
#
|
||||||
|
# Driven directly with `make -C infra <target>` (or via the root Makefile's
|
||||||
|
# `infra-*` convenience targets). Targets that interact with the live cluster
|
||||||
|
# run Pulumi against the stack defined in Pulumi.yaml.
|
||||||
|
|
||||||
|
.PHONY: help preview up down refresh static test clean tidy
|
||||||
|
|
||||||
|
help: ## List available targets
|
||||||
|
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
|
||||||
|
awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-18s\033[0m %s\n", $$1, $$2}'
|
||||||
|
|
||||||
|
preview: ## Preview infra changes against the cluster
|
||||||
|
pulumi preview
|
||||||
|
|
||||||
|
up: ## Deploy/update infra
|
||||||
|
pulumi up
|
||||||
|
|
||||||
|
down: ## Tear down the stack's resources
|
||||||
|
pulumi destroy
|
||||||
|
|
||||||
|
refresh: ## Refresh Pulumi state against the live cluster
|
||||||
|
pulumi refresh
|
||||||
|
|
||||||
|
static: ## Typecheck + vet without Pulumi
|
||||||
|
go build -o /dev/null . && go vet ./...
|
||||||
|
|
||||||
|
test: ## Run Go unit tests
|
||||||
|
go test ./...
|
||||||
|
|
||||||
|
clean: ## Remove local Go build artifact
|
||||||
|
rm -f desi-explorer-infra
|
||||||
|
|
||||||
|
tidy: ## Tidy Go modules
|
||||||
|
go mod tidy
|
||||||
Reference in New Issue
Block a user