chore: monorepo scripts (dev, build, db, etc)
This commit is contained in:
parent
74551f2023
commit
7685a6dea7
8 changed files with 221 additions and 33 deletions
38
AGENTS.md
38
AGENTS.md
|
|
@ -6,21 +6,43 @@ Guidance for AI coding agents working in this repository.
|
|||
|
||||
Classic Minesweeper as a vanilla web game — no framework, no TypeScript (JSDoc + `// @ts-check` only). Deployed at [mnswpr.com](https://mnswpr.com) (Netlify) and published to npm as `@ayo-run/mnswpr`. The game engine has **zero runtime dependencies**; only the website adds Firebase.
|
||||
|
||||
**`mnswpr` is the main test app.** It's the reference app for the monorepo and the default target for local runs — `.claude/launch.json` launches it (`dev` on :5173, `preview` on :4173), and it's what you should build/run/preview when verifying changes to the shared packages or tooling.
|
||||
|
||||
## Commands
|
||||
|
||||
Workspace-wide commands run from the root; per-app commands target the app by name with pnpm's `-F` filter (apps are named `<name>` — there are no mnswpr-specific root scripts).
|
||||
|
||||
```bash
|
||||
pnpm i # install (pnpm is required — this is a pnpm workspace)
|
||||
pnpm dev # run the website dev server (vite apps/mnswpr) — most common
|
||||
pnpm build # build the website -> apps/mnswpr/dist
|
||||
pnpm build:lib # build the publishable library -> packages/mnswpr/dist
|
||||
pnpm lint # eslint . (JS + CSS); runs automatically on pre-commit
|
||||
pnpm lint:fix # eslint --fix
|
||||
pnpm build:preview # build the app and serve the production preview
|
||||
pnpm test # run the Vitest suite once (jsdom)
|
||||
pnpm test:watch # run Vitest in watch mode
|
||||
pnpm lint # eslint . (JS + CSS); runs automatically on pre-commit
|
||||
pnpm lint:fix # eslint --fix
|
||||
pnpm build:lib # build the publishable library -> packages/mnswpr/dist
|
||||
|
||||
pnpm -F mnswpr run dev # Firestore emulator + auto-seed + dev server (emulators:exec) — most common; needs JDK 21+
|
||||
pnpm -F mnswpr run dev:no-db # plain vite, no emulator (UI-only work / no JDK)
|
||||
pnpm -F mnswpr run build # build the website -> apps/mnswpr/dist
|
||||
pnpm -F mnswpr run build:preview # build the app and serve the production preview
|
||||
```
|
||||
|
||||
Tests are co-located with the package they exercise (`packages/utils/test/`, `packages/mnswpr/test/`) and run under **Vitest** with a jsdom environment (root config in `vitest.config.js`). They cover the shared utils and drive the engine through real DOM events (mount `#app`, dispatch mouse events, assert on cell/grid attributes). For anything visual or input-timing related, also verify by running `pnpm dev` and playing.
|
||||
### Infra (local CLI only — no web dashboards)
|
||||
|
||||
All infra runs through local CLIs. Each app **owns its infra scripts** in its own `package.json` under generic, tech-agnostic names (`deploy:db`, not `deploy:firestore`) — run them by targeting the app with pnpm's `-F` filter (no root wrapper scripts):
|
||||
|
||||
```bash
|
||||
pnpm -F mnswpr run db:start # local DB emulator (mnswpr -> Firestore), standalone
|
||||
pnpm -F mnswpr run db:seed # seed the running local emulator
|
||||
pnpm -F mnswpr run db:stop # kill a stray/orphaned Firestore emulator holding :8080
|
||||
pnpm -F mnswpr run deploy:db # deploy DB rules/indexes (-> firebase deploy --only firestore)
|
||||
pnpm -F mnswpr run deploy:site # build + deploy hosting (-> netlify deploy --prod)
|
||||
```
|
||||
|
||||
Each app defines the same generic script names backed by whatever stack it uses (e.g. Postgres, a different host), so `pnpm -F <name> run deploy:db` is uniform across apps. `deploy:site` requires a one-time `npx netlify-cli login && npx netlify-cli link` per app.
|
||||
|
||||
The Firestore emulator needs **Java** (it's a JVM program). `pnpm install` runs a root `postinstall` (`scripts/ensure-java.mjs`) that installs a user-local Temurin JRE 21 into `~/.local` without `sudo` when `java` is missing — idempotent, non-fatal, and auto-skipped on `CI` / `SKIP_JRE_SETUP` / unsupported platforms.
|
||||
|
||||
Tests are co-located with the package they exercise (`packages/utils/test/`, `packages/mnswpr/test/`) and run under **Vitest** with a jsdom environment (root config in `vitest.config.js`). They cover the shared utils and drive the engine through real DOM events (mount `#app`, dispatch mouse events, assert on cell/grid attributes). For anything visual or input-timing related, also verify by running `pnpm -F mnswpr run dev` and playing.
|
||||
|
||||
Node version: `.nvmrc` pins `lts/*`.
|
||||
|
||||
|
|
@ -28,7 +50,7 @@ Node version: `.nvmrc` pins `lts/*`.
|
|||
|
||||
This is the **Cozy Games** monorepo. Workspaces are declared in `pnpm-workspace.yaml` as `apps/*`, `packages/*`, and `sites/*`. `utils/` is now a real workspace package (`@cozy-games/utils`), imported by name — no more `../utils` relative paths.
|
||||
|
||||
- **`apps/mnswpr/`** — `@ayo-run/mnswpr`'s host, the mnswpr.com website. Consumes the engine and leaderboard via `workspace:*` (`import mnswpr from '@ayo-run/mnswpr/mnswpr.js'`) and wires them together in `apps/mnswpr/main.js`. Owns its Firebase config (`firebase.json`, `firestore.rules`, `.firebaserc`) and app-specific scripts (`apps/mnswpr/scripts/`). A future app (e.g. sudoku) gets its own `apps/<name>/`.
|
||||
- **`apps/mnswpr/`** — package `mnswpr`, `@ayo-run/mnswpr`'s host, the mnswpr.com website. Consumes the engine and leaderboard via `workspace:*` (`import mnswpr from '@ayo-run/mnswpr/mnswpr.js'`) and wires them together in `apps/mnswpr/main.js`. Owns its Firebase config (`firebase.json`, `firestore.rules`, `.firebaserc`) and app-specific scripts (`apps/mnswpr/scripts/`). A future app (e.g. sudoku) gets its own `apps/<name>/` and its `package.json` `name` is just the app name (`<name>`, unscoped) so it's addressable directly by name (`pnpm -F <name> run <script>`).
|
||||
- **`packages/mnswpr/`** — `@ayo-run/mnswpr`, the standalone, framework-free game engine published to npm. `packages/mnswpr/mnswpr.js` is the whole engine; `levels.js` defines the four difficulty presets. Depends only on `@cozy-games/utils`.
|
||||
- **`packages/leaderboard/`** — `@cozy-games/leaderboard`, a backend-agnostic, time-windowed leaderboard (adapter-injected storage).
|
||||
- **`packages/utils/`** — `@cozy-games/utils`, shared services with no dependencies, re-exported from `index.js`: `StorageService`, `TimerService` (`pretty()` time formatting used by both engine and leaderboard), `LoggerService`, `LoadingService`, and date-bucket helpers.
|
||||
|
|
|
|||
33
README.md
33
README.md
|
|
@ -23,15 +23,44 @@ Each app owns its own backend config (e.g. mnswpr's Firestore rules live in
|
|||
|
||||
This is a [pnpm](https://pnpm.io) workspace (pnpm is required).
|
||||
|
||||
Workspace-wide commands run from the root:
|
||||
|
||||
```bash
|
||||
pnpm i # install
|
||||
pnpm dev # run the mnswpr app (Vite dev server)
|
||||
pnpm test # run all package tests (vitest)
|
||||
pnpm lint # eslint
|
||||
pnpm build # build the mnswpr app -> apps/mnswpr/dist
|
||||
pnpm build:lib # build the engine package -> packages/mnswpr/dist
|
||||
```
|
||||
|
||||
### Per-app local development
|
||||
|
||||
Apps aren't run from the root — target the app by name with pnpm's `-F` filter. Apps are
|
||||
named `<name>` (e.g. `mnswpr`), so every app runs the same way:
|
||||
|
||||
```bash
|
||||
pnpm -F mnswpr run dev # start that app's Vite dev server
|
||||
pnpm -F mnswpr run build # build just that app -> apps/mnswpr/dist
|
||||
pnpm -F mnswpr run preview # preview its production build
|
||||
```
|
||||
|
||||
## Infra (per-app, via local CLI)
|
||||
|
||||
Infra runs through local CLIs, never web dashboards. Each app owns its infra scripts
|
||||
under generic names (`deploy:db`, `deploy:site`, `db:start`, `db:seed`) — run them by
|
||||
targeting the app with pnpm's `-F` filter:
|
||||
|
||||
```bash
|
||||
pnpm -F mnswpr run db:start # start the local DB emulator (Firestore) — needs Java, see app README
|
||||
pnpm -F mnswpr run db:seed # seed the running emulator with dev data
|
||||
pnpm -F mnswpr run db:stop # kill a stray emulator left holding :8080
|
||||
pnpm -F mnswpr run deploy:db # deploy DB rules/indexes (firebase deploy --only firestore)
|
||||
pnpm -F mnswpr run deploy:site # build + deploy hosting (netlify deploy --prod)
|
||||
```
|
||||
|
||||
Apps are named `<name>`, so a future app uses the same command shape
|
||||
(`pnpm -F <name> run deploy:db`), backed by whatever stack that app uses.
|
||||
`deploy:site` needs a one-time `npx netlify-cli login && npx netlify-cli link` per app.
|
||||
|
||||
See [apps/mnswpr/README.md](apps/mnswpr/README.md) for the game itself, and each package's
|
||||
README for library usage.
|
||||
|
||||
|
|
|
|||
|
|
@ -52,15 +52,15 @@ Technology Stack: HTML, JS, and CSS; [Google Firebase](https://firebase.google.c
|
|||
|
||||
To start development, you need [`node`](https://nodejs.org/en/download). I highly recommend [`pnpm`](https://pnpm.io/installation) to be used as well. Once you know you have this, you can do the following:
|
||||
1. Install dependencies: `pnpm i`
|
||||
2. Start the dev server: `pnpm run dev`
|
||||
2. Start the dev server: `pnpm -F mnswpr run dev`
|
||||
|
||||
The rest of the everyday commands:
|
||||
|
||||
```bash
|
||||
pnpm test # run the Vitest suite
|
||||
pnpm test # run the Vitest suite (workspace-wide)
|
||||
pnpm lint # ESLint (JS + CSS)
|
||||
pnpm lint:fix # ESLint with autofix
|
||||
pnpm build # build the website
|
||||
pnpm -F mnswpr run build # build the website
|
||||
pnpm build:lib # build the publishable library
|
||||
```
|
||||
|
||||
|
|
@ -68,15 +68,49 @@ pnpm build:lib # build the publishable library
|
|||
|
||||
The leader board is backed by [Google Firestore](https://firebase.google.com). For local development the app talks to the **Firestore emulator** by default — fully local, no cloud, no deploy. The flag `VITE_FIRESTORE_EMULATOR=1` is already set in `app/.env.development`.
|
||||
|
||||
You need a **JDK 21+** installed (the emulator runs on Java; `firebase-tools` itself is fetched on demand via `npx`). Then, in two terminals:
|
||||
`dev` is the whole loop in one command — it wraps Vite in `firebase emulators:exec`, so the Firestore emulator (on :8080, + UI) comes up, gets **seeded with sample scores automatically**, and the app dev server starts against it; everything shuts down when you stop it. (Each `dev` starts a fresh in-memory emulator, so the auto-seed writes exactly one clean set every time — no accumulation.) `firebase-tools` itself is fetched on demand via `npx`, so the only prerequisite is **Java** — the Firestore emulator is a Java program (`java -jar cloud-firestore-emulator-*.jar`), and firebase-tools does not bundle a JRE.
|
||||
|
||||
**Usually automatic.** `pnpm install` runs a root `postinstall` ([`scripts/ensure-java.mjs`](../../scripts/ensure-java.mjs)) that installs a user-local Temurin JRE 21 into `~/.local` (no `sudo`) when `java` isn't already on your PATH. It's idempotent and never fails the install, and it skips when `CI` or `SKIP_JRE_SETUP=1` is set, or on unsupported platforms.
|
||||
|
||||
If that skipped and you need Java (or prefer a system-wide install), do it manually — **install a JRE (Java 11+; 21 recommended):**
|
||||
|
||||
```bash
|
||||
pnpm emulators # terminal 1 — start the Firestore emulator on :8080 (+ UI)
|
||||
pnpm seed:emulator # terminal 2, once — fill it with sample scores
|
||||
pnpm dev # terminal 2 — run the app against the emulator
|
||||
# Debian / Ubuntu / Pop!_OS
|
||||
sudo apt update && sudo apt install -y openjdk-21-jre-headless
|
||||
|
||||
# Fedora
|
||||
sudo dnf install -y java-21-openjdk-headless
|
||||
|
||||
# macOS (Homebrew)
|
||||
brew install openjdk@21
|
||||
|
||||
java -version # verify: should print "openjdk 21.x" (or 11+)
|
||||
```
|
||||
|
||||
If the emulator isn't running, the board simply shows *"unavailable"* (a refused connection). To skip the emulator — for quick UI-only work, or if you don't have a JDK — set `VITE_FIRESTORE_EMULATOR=` (empty) in a local, gitignored `app/.env.local`; the app then uses the cloud `mw-test` namespace instead.
|
||||
No `sudo`? Install a JRE into your home directory instead (no root needed):
|
||||
|
||||
```bash
|
||||
curl -fsSL -o /tmp/jre21.tgz "https://api.adoptium.net/v3/binary/latest/21/ga/linux/x64/jre/hotspot/normal/eclipse"
|
||||
mkdir -p ~/.local/lib && tar xzf /tmp/jre21.tgz -C ~/.local/lib
|
||||
ln -sf ~/.local/lib/jdk-21*-jre/bin/java ~/.local/bin/java # ~/.local/bin is already on PATH
|
||||
java -version
|
||||
```
|
||||
|
||||
Without Java, `dev` and `db:start` fail with `Could not spawn 'java -version'`. Install it to a permanent location — a JRE unpacked under `/tmp` disappears when the OS cleans temp files. Then just:
|
||||
|
||||
```bash
|
||||
pnpm -F mnswpr run dev # emulator (:8080 + UI) + auto-seed + app dev server — one command
|
||||
```
|
||||
|
||||
That's the everyday loop. The other DB scripts are for when you want to run pieces separately:
|
||||
|
||||
```bash
|
||||
pnpm -F mnswpr run db:start # emulator only (stays up across app restarts); pair with dev:no-db
|
||||
pnpm -F mnswpr run db:seed # seed a separately-running emulator (what dev does for you)
|
||||
pnpm -F mnswpr run db:stop # kill a stray/orphaned emulator holding :8080
|
||||
```
|
||||
|
||||
To skip the emulator entirely — for quick UI-only work, or if you don't have a JDK — run `pnpm -F mnswpr run dev:no-db` (plain Vite) and set `VITE_FIRESTORE_EMULATOR=` (empty) in a local, gitignored `app/.env.local`; the app then uses the cloud `mw-test` namespace instead.
|
||||
|
||||
See [`docs/firebase-leaderboards.md`](./docs/firebase-leaderboards.md) for the full data model, security rules, environments, and deployment.
|
||||
|
||||
|
|
|
|||
|
|
@ -138,11 +138,11 @@ locally (so you validate them before deploying). The flag
|
|||
Everyday dev loop:
|
||||
|
||||
```bash
|
||||
pnpm emulators # terminal 1: Firestore emulator (+ Emulator UI) on :8080
|
||||
pnpm seed:emulator # terminal 2, once: fill it with sample scores
|
||||
pnpm dev # terminal 2: app runs against the local emulator
|
||||
pnpm -F mnswpr run dev # emulator (+ UI) on :8080, auto-seeded with sample scores, + app dev server
|
||||
```
|
||||
|
||||
`dev` seeds the fresh emulator for you (via `emulators:exec "node scripts/seed-dev-scores.js; vite"`). Use the standalone `db:start` / `db:seed` scripts only when running the emulator separately from the app.
|
||||
|
||||
Wiring: `app/main.js` passes `{ emulator: { host, port } }` to `FirebaseAdapter`,
|
||||
which calls `connectFirestoreEmulator`. If the emulator isn't running the board
|
||||
just shows "unavailable" (a refused connection) — start it, or opt out.
|
||||
|
|
|
|||
|
|
@ -1,13 +1,21 @@
|
|||
{
|
||||
"name": "app",
|
||||
"name": "mnswpr",
|
||||
"version": "0.0.1",
|
||||
"description": "the mnswpr.com web app",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"dev": "npx -y firebase-tools emulators:exec --only firestore --ui \"node scripts/seed-dev-scores.js; vite\"",
|
||||
"dev:no-db": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"build:preview": "npm run build && npm run preview"
|
||||
"build:preview": "npm run build && npm run preview",
|
||||
"deploy:db": "npx -y firebase-tools deploy --only firestore",
|
||||
"deploy:site": "npm run build && npx -y netlify-cli deploy --prod --dir=dist",
|
||||
"db:start": "npx -y firebase-tools emulators:start --only firestore",
|
||||
"db:seed": "FIRESTORE_EMULATOR_HOST=127.0.0.1:8080 node scripts/seed-dev-scores.js",
|
||||
"db:stop": "pkill -f '[c]loud-firestore-emulator'; pkill -f '[f]irebase.* emulators:'; true"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ayo-run/mnswpr": "workspace:*",
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ export default defineConfig([
|
|||
}
|
||||
},
|
||||
{
|
||||
files: ['**/scripts/**/*.js'],
|
||||
files: ['**/scripts/**/*.{js,mjs,cjs}'],
|
||||
languageOptions: {
|
||||
globals: globals.node
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,16 +12,12 @@
|
|||
"homepage": "https://mnswpr.com",
|
||||
"scripts": {
|
||||
"test": "vitest run",
|
||||
"dev": "pnpm -F mnswpr dev",
|
||||
"test:watch": "vitest",
|
||||
"dev": "vite apps/mnswpr",
|
||||
"start": "vite apps/mnswpr",
|
||||
"emulators": "cd apps/mnswpr && npx -y firebase-tools emulators:start --only firestore",
|
||||
"seed:emulator": "cd apps/mnswpr && FIRESTORE_EMULATOR_HOST=127.0.0.1:8080 node scripts/seed-dev-scores.js",
|
||||
"build": "vite build apps/mnswpr",
|
||||
"build:lib": "vite build packages/mnswpr",
|
||||
"publish:lib": "node scripts/publish-lib.js",
|
||||
"release": "pnpm build:lib && pnpm -F @ayo-run/mnswpr run release && pnpm publish:lib",
|
||||
"build:preview": "pnpm -F app run build:preview",
|
||||
"postinstall": "node scripts/ensure-java.mjs",
|
||||
"prepare": "husky",
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "eslint . --fix"
|
||||
|
|
|
|||
99
scripts/ensure-java.mjs
Normal file
99
scripts/ensure-java.mjs
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/**
|
||||
* Post-install convenience: make a Java runtime available for the Firebase
|
||||
* Firestore emulator (used by `pnpm -F mnswpr dev` / `db:start`). The emulator is
|
||||
* a Java program and firebase-tools does not bundle a JRE.
|
||||
*
|
||||
* Installs a Temurin JRE 21 into the user's home (~/.local) WITHOUT sudo and
|
||||
* symlinks `java` into ~/.local/bin (already on most PATHs). Properties:
|
||||
* - idempotent: does nothing if `java` is already on PATH
|
||||
* - non-fatal: never fails `pnpm install` — on any problem it warns, exits 0
|
||||
* - opt-out: set SKIP_JRE_SETUP=1 (also auto-skips when CI is set)
|
||||
* Only Linux/macOS on x64/arm64 are auto-handled; anything else prints manual
|
||||
* instructions (see apps/mnswpr/README.md).
|
||||
*/
|
||||
import { spawnSync } from 'node:child_process'
|
||||
import { existsSync, mkdirSync, readdirSync, rmSync, symlinkSync, writeFileSync } from 'node:fs'
|
||||
import { homedir, tmpdir, platform, arch } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
|
||||
const log = msg => console.log(`[ensure-java] ${msg}`)
|
||||
const warn = msg => console.warn(`[ensure-java] ${msg}`)
|
||||
|
||||
// This is a convenience, never a blocker — always exit 0.
|
||||
try {
|
||||
await main()
|
||||
} catch (err) {
|
||||
warn(`skipped (${err?.message || err}).`)
|
||||
warn('The Firestore emulator needs Java 11+ — install it manually, see apps/mnswpr/README.md.')
|
||||
}
|
||||
process.exit(0)
|
||||
|
||||
async function main() {
|
||||
if (process.env.SKIP_JRE_SETUP) return log('SKIP_JRE_SETUP set — skipping.')
|
||||
if (process.env.CI) return log('CI detected — skipping JRE setup.')
|
||||
if (hasJava('java')) return log('Java already on PATH — nothing to do.')
|
||||
|
||||
const adoptOs = { linux: 'linux', darwin: 'mac' }[platform()]
|
||||
const adoptArch = { x64: 'x64', arm64: 'aarch64' }[arch()]
|
||||
if (!adoptOs || !adoptArch) {
|
||||
warn(`no auto-install for ${platform()}/${arch()} — install a JRE 21 manually (apps/mnswpr/README.md).`)
|
||||
return
|
||||
}
|
||||
if (!hasTool('tar')) {
|
||||
warn('`tar` not found — cannot unpack the JRE. Install Java manually (apps/mnswpr/README.md).')
|
||||
return
|
||||
}
|
||||
|
||||
const prefix = process.env.JAVA_SETUP_PREFIX || join(homedir(), '.local')
|
||||
const libDir = join(prefix, 'lib')
|
||||
const binDir = join(prefix, 'bin')
|
||||
mkdirSync(libDir, { recursive: true })
|
||||
mkdirSync(binDir, { recursive: true })
|
||||
|
||||
const url = `https://api.adoptium.net/v3/binary/latest/21/ga/${adoptOs}/${adoptArch}/jre/hotspot/normal/eclipse`
|
||||
log(`no Java found — downloading Temurin JRE 21 (${adoptOs}/${adoptArch})…`)
|
||||
const res = await fetch(url, { redirect: 'follow' })
|
||||
if (!res.ok) throw new Error(`download failed: HTTP ${res.status}`)
|
||||
const tgz = join(tmpdir(), `temurin-jre-21-${adoptOs}-${adoptArch}.tar.gz`)
|
||||
writeFileSync(tgz, Buffer.from(await res.arrayBuffer()))
|
||||
|
||||
const before = new Set(readdirSync(libDir))
|
||||
const untar = spawnSync('tar', ['xzf', tgz, '-C', libDir], { stdio: 'inherit' })
|
||||
rmSync(tgz, { force: true })
|
||||
if (untar.status !== 0) throw new Error('tar extraction failed')
|
||||
|
||||
// the top-level dir the tarball created (e.g. jdk-21.0.11+10-jre); on re-runs
|
||||
// it already exists, so fall back to the newest matching dir.
|
||||
const jreDir = readdirSync(libDir).find(d => !before.has(d) && /jdk.*jre/i.test(d))
|
||||
|| readdirSync(libDir).filter(d => /jdk.*jre/i.test(d)).sort().pop()
|
||||
if (!jreDir) throw new Error('could not locate the unpacked JRE directory')
|
||||
|
||||
// java is at bin/java (linux) or Contents/Home/bin/java (macOS)
|
||||
const javaBin = [
|
||||
join(libDir, jreDir, 'bin', 'java'),
|
||||
join(libDir, jreDir, 'Contents', 'Home', 'bin', 'java')
|
||||
].find(existsSync)
|
||||
if (!javaBin) throw new Error('java binary not found in the unpacked JRE')
|
||||
|
||||
for (const tool of ['java', 'keytool']) {
|
||||
const src = javaBin.replace(/java$/, tool)
|
||||
const dst = join(binDir, tool)
|
||||
if (existsSync(src)) { rmSync(dst, { force: true }); symlinkSync(src, dst) }
|
||||
}
|
||||
if (!hasJava(join(binDir, 'java'))) throw new Error('the installed java did not run')
|
||||
|
||||
log(`installed JRE 21 → ${join(libDir, jreDir)}`)
|
||||
log(`linked java → ${join(binDir, 'java')}`)
|
||||
if (!(process.env.PATH || '').split(':').includes(binDir)) {
|
||||
warn(`${binDir} is not on your PATH — add it (e.g. in ~/.profile) so \`java\` is found.`)
|
||||
}
|
||||
}
|
||||
|
||||
function hasJava(bin) {
|
||||
const r = spawnSync(bin, ['-version'], { stdio: 'ignore' })
|
||||
return !r.error && r.status === 0
|
||||
}
|
||||
function hasTool(name) {
|
||||
const r = spawnSync(name, ['--version'], { stdio: 'ignore' })
|
||||
return !r.error
|
||||
}
|
||||
Loading…
Reference in a new issue