mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-19 15:06:20 +00:00
Merge pull request #229 from simoleo89/feat/installer-configurable-renderer-dir
feat(installer): make the renderer folder configurable
This commit is contained in:
+82
-9
@@ -2,15 +2,21 @@
|
|||||||
import { spawn } from 'node:child_process';
|
import { spawn } from 'node:child_process';
|
||||||
import { copyFile, readFile, writeFile } from 'node:fs/promises';
|
import { copyFile, readFile, writeFile } from 'node:fs/promises';
|
||||||
import { existsSync } from 'node:fs';
|
import { existsSync } from 'node:fs';
|
||||||
import { dirname, join, resolve } from 'node:path';
|
import { basename, dirname, isAbsolute, join, resolve } from 'node:path';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
import { platform } from 'node:os';
|
import { platform } from 'node:os';
|
||||||
import * as readline from 'node:readline/promises';
|
import * as readline from 'node:readline/promises';
|
||||||
import { stdin as input, stdout as output } from 'node:process';
|
import { stdin as input, stdout as output } from 'node:process';
|
||||||
|
|
||||||
const ROOT = dirname(fileURLToPath(import.meta.url));
|
const ROOT = dirname(fileURLToPath(import.meta.url));
|
||||||
const RENDERER_REPO_URL = 'https://github.com/duckietm/Nitro_Render_V3.git';
|
const DEFAULT_RENDERER_REPO_URL = 'https://github.com/duckietm/Nitro_Render_V3.git';
|
||||||
const RENDERER_DIR = resolve(ROOT, '..', 'Nitro_Render_V3');
|
// Sibling folder names the client's vite.config / tsconfig already know how to resolve.
|
||||||
|
// Auto-detection walks these in order; a fresh clone defaults to the first one.
|
||||||
|
const RENDERER_DIR_CANDIDATES = ['Nitro_Render_V3', 'renderer'];
|
||||||
|
const DEFAULT_RENDERER_DIR_NAME = RENDERER_DIR_CANDIDATES[0];
|
||||||
|
// Resolved in main() from --renderer-repo / --renderer-dir / NITRO_RENDERER_DIR / auto-detection.
|
||||||
|
let RENDERER_REPO_URL = DEFAULT_RENDERER_REPO_URL;
|
||||||
|
let RENDERER_DIR = resolve(ROOT, '..', DEFAULT_RENDERER_DIR_NAME);
|
||||||
const CONFIG_DIR = join(ROOT, 'public', 'configuration');
|
const CONFIG_DIR = join(ROOT, 'public', 'configuration');
|
||||||
const NITRO_BUILD_FILE = join(ROOT, '.nitro-build.json');
|
const NITRO_BUILD_FILE = join(ROOT, '.nitro-build.json');
|
||||||
const IS_WINDOWS = platform() === 'win32';
|
const IS_WINDOWS = platform() === 'win32';
|
||||||
@@ -57,7 +63,7 @@ const CONFIG_FILES = [
|
|||||||
|
|
||||||
const STEPS = [
|
const STEPS = [
|
||||||
'Check prerequisites',
|
'Check prerequisites',
|
||||||
'Clone Nitro_Render_V3',
|
'Resolve / clone renderer',
|
||||||
'Setup renderer (yarn install + yarn link)',
|
'Setup renderer (yarn install + yarn link)',
|
||||||
'Setup client (yarn install + yarn link)',
|
'Setup client (yarn install + yarn link)',
|
||||||
'Copy config files',
|
'Copy config files',
|
||||||
@@ -161,6 +167,8 @@ function parseArgs() {
|
|||||||
skipLink: false,
|
skipLink: false,
|
||||||
help: false,
|
help: false,
|
||||||
jsonMode: null,
|
jsonMode: null,
|
||||||
|
rendererDir: null,
|
||||||
|
rendererRepo: null,
|
||||||
urlOverrides: {}
|
urlOverrides: {}
|
||||||
};
|
};
|
||||||
const builtinFlags = new Set([
|
const builtinFlags = new Set([
|
||||||
@@ -193,6 +201,16 @@ function parseArgs() {
|
|||||||
opts.jsonMode = value;
|
opts.jsonMode = value;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (flagName === 'renderer-dir') {
|
||||||
|
if (value.length === 0) { warn('Empty --renderer-dir ignored'); continue; }
|
||||||
|
opts.rendererDir = value;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (flagName === 'renderer-repo') {
|
||||||
|
if (value.length === 0) { warn('Empty --renderer-repo ignored'); continue; }
|
||||||
|
opts.rendererRepo = value;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
const key = FLAG_TO_KEY[flagName];
|
const key = FLAG_TO_KEY[flagName];
|
||||||
if (key) {
|
if (key) {
|
||||||
opts.urlOverrides[key] = value;
|
opts.urlOverrides[key] = value;
|
||||||
@@ -216,8 +234,11 @@ function printUsage() {
|
|||||||
'Workflow flags:',
|
'Workflow flags:',
|
||||||
' --non-interactive, --skip-prompts Keep default URLs unless overridden by --<key>=<value>',
|
' --non-interactive, --skip-prompts Keep default URLs unless overridden by --<key>=<value>',
|
||||||
' --json-mode=<json5|legacy|auto> Choose the JSON parsing mode without prompting',
|
' --json-mode=<json5|legacy|auto> Choose the JSON parsing mode without prompting',
|
||||||
|
' --renderer-dir=<path> Renderer folder (absolute, or relative to the parent dir).',
|
||||||
|
' Default: auto-detect ' + RENDERER_DIR_CANDIDATES.join(' / ') + ', else "' + DEFAULT_RENDERER_DIR_NAME + '". Env: NITRO_RENDERER_DIR',
|
||||||
|
' --renderer-repo=<url> Git URL to clone the renderer from (default: duckietm Nitro_Render_V3)',
|
||||||
' --skip-build Skip the final yarn build',
|
' --skip-build Skip the final yarn build',
|
||||||
' --skip-clone Skip cloning Nitro_Render_V3',
|
' --skip-clone Skip cloning the renderer',
|
||||||
' --skip-link Skip yarn link calls (useful when re-running)',
|
' --skip-link Skip yarn link calls (useful when re-running)',
|
||||||
' --help, -h Show this help and exit',
|
' --help, -h Show this help and exit',
|
||||||
'',
|
'',
|
||||||
@@ -226,7 +247,7 @@ function printUsage() {
|
|||||||
'',
|
'',
|
||||||
'Steps performed:',
|
'Steps performed:',
|
||||||
' 1. Check Node >= ' + MIN_NODE_MAJOR + ', yarn, git',
|
' 1. Check Node >= ' + MIN_NODE_MAJOR + ', yarn, git',
|
||||||
' 2. Clone Nitro_Render_V3 to ../Nitro_Render_V3',
|
' 2. Resolve the renderer dir (--renderer-dir / NITRO_RENDERER_DIR / interactive prompt / auto-detect ' + RENDERER_DIR_CANDIDATES.join(' or ') + '), cloning to ../' + DEFAULT_RENDERER_DIR_NAME + ' if absent',
|
||||||
' 3. yarn install + yarn link in the renderer',
|
' 3. yarn install + yarn link in the renderer',
|
||||||
' 4. yarn install + yarn link "@nitrots/nitro-renderer" in this project',
|
' 4. yarn install + yarn link "@nitrots/nitro-renderer" in this project',
|
||||||
' 5. Copy public/configuration/*.example -> *.json (keeps existing files)',
|
' 5. Copy public/configuration/*.example -> *.json (keeps existing files)',
|
||||||
@@ -262,16 +283,66 @@ async function checkPrereqs() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resolve which sibling folder is the renderer SDK, honouring (in priority order):
|
||||||
|
// 1. --renderer-dir=<path> 2. NITRO_RENDERER_DIR env (both skip the prompt)
|
||||||
|
// 3. interactive prompt — the operator chooses (default = a detected folder, else ./Nitro_Render_V3)
|
||||||
|
// 4. --non-interactive: first existing folder among RENDERER_DIR_CANDIDATES, else ./Nitro_Render_V3
|
||||||
|
// A chosen/explicit path may be absolute or relative to the parent of the client.
|
||||||
|
async function resolveRendererDir(opts) {
|
||||||
|
const parent = resolve(ROOT, '..');
|
||||||
|
const toAbs = p => (isAbsolute(p) ? resolve(p) : resolve(parent, p));
|
||||||
|
|
||||||
|
if (opts.rendererDir) {
|
||||||
|
const dir = toAbs(opts.rendererDir);
|
||||||
|
info('Renderer dir from --renderer-dir: ' + dir);
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
if (process.env.NITRO_RENDERER_DIR) {
|
||||||
|
const dir = toAbs(process.env.NITRO_RENDERER_DIR);
|
||||||
|
info('Renderer dir from NITRO_RENDERER_DIR: ' + dir);
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
let detected = null;
|
||||||
|
for (const name of RENDERER_DIR_CANDIDATES) {
|
||||||
|
const candidate = resolve(parent, name);
|
||||||
|
if (existsSync(candidate)) { detected = candidate; break; }
|
||||||
|
}
|
||||||
|
const suggested = detected || resolve(parent, DEFAULT_RENDERER_DIR_NAME);
|
||||||
|
|
||||||
|
if (!opts.interactive) {
|
||||||
|
info(detected ? 'Using detected renderer: ' + detected : 'Renderer will be cloned to: ' + suggested);
|
||||||
|
return suggested;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (detected) info('Found an existing renderer at ' + detected + ' (press Enter to reuse it).');
|
||||||
|
info('Choose where the renderer SDK lives — a folder name (relative to ' + parent + ') or an absolute path.');
|
||||||
|
const rl = readline.createInterface({ input, output });
|
||||||
|
activeReadline = rl;
|
||||||
|
try {
|
||||||
|
const answer = (await rl.question(' Renderer folder [' + suggested + ']: ')).trim();
|
||||||
|
return answer.length === 0 ? suggested : toAbs(answer);
|
||||||
|
} finally {
|
||||||
|
activeReadline = null;
|
||||||
|
rl.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function cloneRenderer(opts) {
|
async function cloneRenderer(opts) {
|
||||||
if (opts.skipClone) { info('--skip-clone: not cloning Nitro_Render_V3'); summary.rendererSkipped = true; return; }
|
RENDERER_DIR = await resolveRendererDir(opts);
|
||||||
|
ok('Renderer dir: ' + RENDERER_DIR);
|
||||||
|
if (!RENDERER_DIR_CANDIDATES.includes(basename(RENDERER_DIR))) {
|
||||||
|
warn('Custom renderer folder "' + basename(RENDERER_DIR) + '": vite.config resolves it via path alias, but ui/tsconfig.json only lists [' + RENDERER_DIR_CANDIDATES.join(', ') + ']. Add this path under "paths" there so tsc/IDE type-resolution works.');
|
||||||
|
}
|
||||||
|
if (opts.skipClone) { info('--skip-clone: not cloning the renderer'); summary.rendererSkipped = true; return; }
|
||||||
if (existsSync(RENDERER_DIR)) {
|
if (existsSync(RENDERER_DIR)) {
|
||||||
warn('Nitro_Render_V3 already exists at ' + RENDERER_DIR + ' - skipping clone (yarn install/link will still run).');
|
warn('Renderer already present at ' + RENDERER_DIR + ' - skipping clone (yarn install/link will still run).');
|
||||||
summary.rendererSkipped = true;
|
summary.rendererSkipped = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await runShell('git clone ' + RENDERER_REPO_URL + ' "' + RENDERER_DIR + '"', dirname(RENDERER_DIR));
|
await runShell('git clone ' + RENDERER_REPO_URL + ' "' + RENDERER_DIR + '"', dirname(RENDERER_DIR));
|
||||||
summary.rendererCloned = true;
|
summary.rendererCloned = true;
|
||||||
ok('Cloned Nitro_Render_V3 to ' + RENDERER_DIR);
|
ok('Cloned renderer to ' + RENDERER_DIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setupRenderer(opts) {
|
async function setupRenderer(opts) {
|
||||||
@@ -522,6 +593,8 @@ async function main() {
|
|||||||
const opts = parseArgs();
|
const opts = parseArgs();
|
||||||
if (opts.help) { printUsage(); process.exit(0); }
|
if (opts.help) { printUsage(); process.exit(0); }
|
||||||
|
|
||||||
|
RENDERER_REPO_URL = opts.rendererRepo || DEFAULT_RENDERER_REPO_URL;
|
||||||
|
|
||||||
console.log(c.bold + 'Nitro-V3 installer' + c.reset + ' (' + (IS_WINDOWS ? 'Windows' : platform()) + ')');
|
console.log(c.bold + 'Nitro-V3 installer' + c.reset + ' (' + (IS_WINDOWS ? 'Windows' : platform()) + ')');
|
||||||
console.log('Project root: ' + ROOT);
|
console.log('Project root: ' + ROOT);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user