Exocore / exocore-web /server /services /templateService.ts
ChoruYt's picture
Upload 216 files
a7f51f5 verified
Raw
History Blame Contribute Delete
3.68 kB
import fs from 'fs';
import fsp from 'fs/promises';
import path from 'path';
import { exec } from 'child_process';
export interface TemplateJson {
name: string;
description: string;
language: string;
runtime: string;
run: string;
port: number;
install: boolean;
}
export interface InstallResult {
status: 'installing' | 'done' | 'error';
logs: string[];
}
const TEMPLATES_DIR = path.join(process.cwd(), 'templates');
const PROJECTS_DIR = path.join(process.cwd(), 'projects');
export function getTemplateList(): { id: string; meta: TemplateJson }[] {
if (!fs.existsSync(TEMPLATES_DIR)) return [];
const entries = fs.readdirSync(TEMPLATES_DIR, { withFileTypes: true });
return entries
.filter((e) => e.isDirectory())
.map((e) => {
const metaPath = path.join(TEMPLATES_DIR, e.name, 'template.json');
if (!fs.existsSync(metaPath)) return null;
try {
const meta = JSON.parse(fs.readFileSync(metaPath, 'utf-8')) as TemplateJson;
return { id: e.name, meta };
} catch {
return null;
}
})
.filter((t): t is { id: string; meta: TemplateJson } => t !== null);
}
export async function copyTemplateToProject(
templateId: string,
projectId: string,
): Promise<void> {
const sanitized = templateId.replace(/[^a-zA-Z0-9_-]/g, '');
const templatePath = path.join(TEMPLATES_DIR, sanitized);
const projectPath = path.join(PROJECTS_DIR, projectId);
if (!fs.existsSync(templatePath)) {
throw new Error(`Template "${sanitized}" not found`);
}
await fsp.mkdir(projectPath, { recursive: true });
const copyDir = async (src: string, dest: string): Promise<void> => {
const entries = await fsp.readdir(src, { withFileTypes: true });
for (const entry of entries) {
if (entry.name === 'template.json') continue;
const srcPath = path.join(src, entry.name);
const destPath = path.join(dest, entry.name);
if (entry.isDirectory()) {
await fsp.mkdir(destPath, { recursive: true });
await copyDir(srcPath, destPath);
} else {
await fsp.copyFile(srcPath, destPath);
}
}
};
await copyDir(templatePath, projectPath);
}
export function runInstallScript(
projectId: string,
onLog: (line: string) => void,
): Promise<void> {
return new Promise((resolve, reject) => {
const projectPath = path.join(PROJECTS_DIR, projectId);
const installScript = path.join(projectPath, 'install.sh');
if (!fs.existsSync(installScript)) {
onLog('[Exocore] No install script found — skipping.\n');
resolve();
return;
}
const child = exec(
`bash install.sh`,
{
cwd: projectPath,
env: { ...process.env, FORCE_COLOR: '1' },
timeout: 300_000,
},
);
child.stdout?.on('data', (d: Buffer) => onLog(d.toString()));
child.stderr?.on('data', (d: Buffer) => onLog(d.toString()));
child.on('error', (err) => {
onLog(`[Exocore] Install error: ${err.message}\n`);
reject(err);
});
child.on('close', (code) => {
if (code === 0 || code === null) {
onLog('[Exocore] Installation complete!\n');
} else {
onLog(`[Exocore] Install script exited with code ${code} — project was still created.\n`);
}
resolve();
});
});
}