mirror of
https://github.com/davidkaya/aryx.git
synced 2026-07-24 13:38:43 +02:00
feat: add packaging and validation coverage
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
import { access, cp, mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
|
||||
import { constants } from 'node:fs';
|
||||
import { dirname, join, resolve } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const productName = 'Kopaya';
|
||||
const sidecarRuntime = 'win-x64';
|
||||
const outputDirectoryName = 'win-unpacked';
|
||||
|
||||
const scriptDirectory = dirname(fileURLToPath(import.meta.url));
|
||||
const repositoryRoot = resolve(scriptDirectory, '..');
|
||||
const electronDistributionDirectory = join(repositoryRoot, 'node_modules', 'electron', 'dist');
|
||||
const rendererBuildDirectory = join(repositoryRoot, 'dist');
|
||||
const electronBuildDirectory = join(repositoryRoot, 'dist-electron');
|
||||
const publishedSidecarDirectory = join(repositoryRoot, 'dist-sidecar', sidecarRuntime);
|
||||
const outputDirectory = join(repositoryRoot, 'release', outputDirectoryName);
|
||||
const outputResourcesDirectory = join(outputDirectory, 'resources');
|
||||
const packagedAppDirectory = join(outputResourcesDirectory, 'app');
|
||||
|
||||
async function ensurePathExists(path, label) {
|
||||
try {
|
||||
await access(path, constants.F_OK);
|
||||
} catch {
|
||||
throw new Error(`${label} was not found at ${path}.`);
|
||||
}
|
||||
}
|
||||
|
||||
async function readJson(path) {
|
||||
return JSON.parse(await readFile(path, 'utf8'));
|
||||
}
|
||||
|
||||
async function collectRuntimeDependencies() {
|
||||
const rootPackageJson = await readJson(join(repositoryRoot, 'package.json'));
|
||||
const dependencies = new Set(Object.keys(rootPackageJson.dependencies ?? {}));
|
||||
const queue = [...dependencies];
|
||||
|
||||
while (queue.length > 0) {
|
||||
const dependencyName = queue.shift();
|
||||
const dependencyPackageJson = await readJson(
|
||||
join(repositoryRoot, 'node_modules', ...dependencyName.split('/'), 'package.json'),
|
||||
);
|
||||
|
||||
for (const transitiveDependency of Object.keys({
|
||||
...(dependencyPackageJson.dependencies ?? {}),
|
||||
...(dependencyPackageJson.optionalDependencies ?? {}),
|
||||
})) {
|
||||
if (!dependencies.has(transitiveDependency)) {
|
||||
dependencies.add(transitiveDependency);
|
||||
queue.push(transitiveDependency);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [...dependencies].sort();
|
||||
}
|
||||
|
||||
async function copyRuntimeDependencies(dependencyNames) {
|
||||
const packagedNodeModulesDirectory = join(packagedAppDirectory, 'node_modules');
|
||||
await mkdir(packagedNodeModulesDirectory, { recursive: true });
|
||||
|
||||
for (const dependencyName of dependencyNames) {
|
||||
const dependencyPathParts = dependencyName.split('/');
|
||||
const sourceDirectory = join(repositoryRoot, 'node_modules', ...dependencyPathParts);
|
||||
const targetDirectory = join(packagedNodeModulesDirectory, ...dependencyPathParts);
|
||||
await mkdir(dirname(targetDirectory), { recursive: true });
|
||||
await cp(sourceDirectory, targetDirectory, { recursive: true });
|
||||
}
|
||||
}
|
||||
|
||||
async function writePackagedManifest() {
|
||||
const sourcePackageJson = await readJson(join(repositoryRoot, 'package.json'));
|
||||
const packagedManifest = {
|
||||
name: sourcePackageJson.name,
|
||||
productName,
|
||||
version: sourcePackageJson.version,
|
||||
description: sourcePackageJson.description,
|
||||
main: sourcePackageJson.main,
|
||||
author: sourcePackageJson.author,
|
||||
license: sourcePackageJson.license,
|
||||
};
|
||||
|
||||
await writeFile(join(packagedAppDirectory, 'package.json'), `${JSON.stringify(packagedManifest, null, 2)}\n`);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
if (process.platform !== 'win32') {
|
||||
throw new Error('This packaging script currently targets Windows only.');
|
||||
}
|
||||
|
||||
await Promise.all([
|
||||
ensurePathExists(electronDistributionDirectory, 'Electron runtime'),
|
||||
ensurePathExists(rendererBuildDirectory, 'Renderer build output'),
|
||||
ensurePathExists(electronBuildDirectory, 'Electron build output'),
|
||||
ensurePathExists(publishedSidecarDirectory, 'Published sidecar output'),
|
||||
]);
|
||||
|
||||
const runtimeDependencies = await collectRuntimeDependencies();
|
||||
|
||||
await rm(outputDirectory, { recursive: true, force: true });
|
||||
await mkdir(outputDirectory, { recursive: true });
|
||||
await cp(electronDistributionDirectory, outputDirectory, { recursive: true });
|
||||
await rename(join(outputDirectory, 'electron.exe'), join(outputDirectory, `${productName}.exe`));
|
||||
|
||||
await mkdir(packagedAppDirectory, { recursive: true });
|
||||
await Promise.all([
|
||||
writePackagedManifest(),
|
||||
cp(rendererBuildDirectory, join(packagedAppDirectory, 'dist'), { recursive: true }),
|
||||
cp(electronBuildDirectory, join(packagedAppDirectory, 'dist-electron'), { recursive: true }),
|
||||
cp(publishedSidecarDirectory, join(outputResourcesDirectory, 'sidecar'), { recursive: true }),
|
||||
]);
|
||||
await copyRuntimeDependencies(runtimeDependencies);
|
||||
|
||||
console.log(`Packaged ${productName} to ${outputDirectory}`);
|
||||
console.log(`Bundled ${runtimeDependencies.length} runtime dependencies and the self-contained .NET sidecar.`);
|
||||
}
|
||||
|
||||
await main();
|
||||
Reference in New Issue
Block a user