Skip to content

Commit d8fb118

Browse files
committed
refactor(installer): split install scripts into build sources
1 parent d20dead commit d8fb118

14 files changed

Lines changed: 2794 additions & 0 deletions

build.js

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#!/usr/bin/env node
2+
/**
3+
* ClawGod build script.
4+
*
5+
* Reads src/ files and install script templates, then produces final
6+
* install.sh and install.ps1 with heredoc content embedded.
7+
*
8+
* src/ layout:
9+
* generic/ - shared by both platforms
10+
* unix/ - install.sh only
11+
* windows/ - install.ps1 only
12+
* template/ - install.sh and install.ps1 templates
13+
*
14+
* Platform dirs override generic/ for same-named files.
15+
*/
16+
17+
const { readFileSync, writeFileSync, existsSync } = require('fs');
18+
const { join } = require('path');
19+
20+
const root = __dirname;
21+
const src = join(root, 'src');
22+
23+
// ─── Placeholder → source file mapping ───────────────────────────────
24+
25+
const PLACEHOLDER_MAP = {
26+
'extract-natives.mjs': 'extractor.js',
27+
'post-process.mjs': 'post-processor.js',
28+
'repatch.mjs': 'repatcher.js',
29+
'cli.cjs': 'wrapper.js',
30+
'patch.mjs': 'patcher.js',
31+
'features.json': 'features.json',
32+
'npm-fetch.mjs': 'npm-fetch.js',
33+
};
34+
35+
// Build a content map for a specific platform.
36+
// Lookup order: {platform}/ → generic/
37+
function buildContentMap(platform) {
38+
const map = {};
39+
for (const [placeholder, filename] of Object.entries(PLACEHOLDER_MAP)) {
40+
let found = null;
41+
for (const dir of [platform, 'generic']) {
42+
const p = join(src, dir, filename);
43+
if (existsSync(p)) { found = p; break; }
44+
}
45+
if (!found) {
46+
// Some files only exist in one platform's template (e.g. npm-fetch.mjs
47+
// is PS1-only). Skip silently — if the template doesn't use the
48+
// placeholder, no harm done.
49+
continue;
50+
}
51+
map[placeholder] = readFileSync(found, 'utf8');
52+
}
53+
return map;
54+
}
55+
56+
// ─── Template rendering ──────────────────────────────────────────────
57+
58+
function renderTemplate(templatePath, contentMap) {
59+
let template = readFileSync(templatePath, 'utf8');
60+
61+
for (const [name, content] of Object.entries(contentMap)) {
62+
const placeholder = `{{CONTENT:${name}}}`;
63+
const replacement = content.endsWith('\n') ? content.slice(0, -1) : content;
64+
// Function-form replace: avoids $$/$&/$1 special pattern interpretation.
65+
template = template.replaceAll(placeholder, () => replacement);
66+
}
67+
68+
const unresolved = template.match(/{{CONTENT:[^}]+}}/g);
69+
if (unresolved) {
70+
throw new Error(`Unresolved placeholders in ${templatePath}: ${[...new Set(unresolved)].join(', ')}`);
71+
}
72+
73+
return template;
74+
}
75+
76+
// ─── Build ───────────────────────────────────────────────────────────
77+
78+
function build() {
79+
const shTemplate = join(src, 'template', 'install.sh');
80+
const ps1Template = join(src, 'template', 'install.ps1');
81+
82+
if (!existsSync(shTemplate)) {
83+
console.error('Template not found:', shTemplate);
84+
process.exit(1);
85+
}
86+
if (!existsSync(ps1Template)) {
87+
console.error('Template not found:', ps1Template);
88+
process.exit(1);
89+
}
90+
91+
const shMap = buildContentMap('unix');
92+
const ps1Map = buildContentMap('windows');
93+
94+
const shContent = renderTemplate(shTemplate, shMap);
95+
const ps1Content = renderTemplate(ps1Template, ps1Map);
96+
97+
writeFileSync(join(root, 'install.sh'), shContent, 'utf8');
98+
writeFileSync(join(root, 'install.ps1'), ps1Content, 'utf8');
99+
100+
console.log(`Built: install.sh (${(shContent.length / 1024).toFixed(0)} KB)`);
101+
console.log(`Built: install.ps1 (${(ps1Content.length / 1024).toFixed(0)} KB)`);
102+
}
103+
104+
build();

0 commit comments

Comments
 (0)