mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
Added fallback variable to track valid candidates that don't match appName. Now returns immediately on exact match, otherwise continues searching and falls back to any valid executable. Applied fix consistently across Windows, Darwin, and Linux branches including .app directories and .AppImage files.
140 lines
5.0 KiB
JavaScript
140 lines
5.0 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Find the packaged Electron executable built by Electron Forge.
|
|
* This script locates the executable in the out/ directory structure.
|
|
*/
|
|
|
|
import { readdirSync, statSync, existsSync, readFileSync } from 'fs';
|
|
import { isAbsolute, join, resolve } from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = resolve(__filename, '..');
|
|
|
|
const platform = process.platform;
|
|
const repoRoot = resolve(__dirname, '..');
|
|
const packageJson = JSON.parse(readFileSync(join(repoRoot, 'package.json'), 'utf-8'));
|
|
const appName = (packageJson.build?.productName || packageJson.name || '5chan').toLowerCase();
|
|
|
|
const resolveOutDir = (dir) => (isAbsolute(dir) ? dir : join(repoRoot, dir));
|
|
|
|
const envOutDir = process.env.ELECTRON_FORGE_OUT_DIR;
|
|
|
|
const candidateRoots = [
|
|
envOutDir ? resolveOutDir(envOutDir) : null,
|
|
join(repoRoot, 'out'),
|
|
join(repoRoot, 'out', 'make'),
|
|
join(repoRoot, '..', 'out'),
|
|
join(repoRoot, '..', '..', 'out'),
|
|
join(repoRoot, 'electron', 'out'),
|
|
].filter(Boolean);
|
|
|
|
// Skip directories that contain helper binaries/app code, not the main executable
|
|
// 'resources' contains the app bundle with IPFS binaries in bin/ - don't recurse there
|
|
const skipDirs = new Set(['node_modules', '.git', 'bin', 'app', 'resources']);
|
|
|
|
function findExecutable(dir, platform) {
|
|
const entries = readdirSync(dir, { withFileTypes: true });
|
|
let fallback = null; // Track a valid candidate that doesn't match appName
|
|
|
|
for (const entry of entries) {
|
|
const fullPath = join(dir, entry.name);
|
|
|
|
if (entry.isDirectory()) {
|
|
if (skipDirs.has(entry.name)) continue;
|
|
|
|
if (platform === 'darwin' && entry.name.endsWith('.app')) {
|
|
const appPath = fullPath;
|
|
const exePath = join(appPath, 'Contents', 'MacOS', entry.name.replace('.app', ''));
|
|
if (existsSync(exePath)) {
|
|
const lowerAppName = entry.name.toLowerCase();
|
|
if (lowerAppName.includes(appName)) {
|
|
return exePath; // Exact match, return immediately
|
|
}
|
|
fallback = fallback || exePath; // Store as fallback, continue searching
|
|
}
|
|
}
|
|
|
|
const result = findExecutable(fullPath, platform);
|
|
if (result) {
|
|
const resultName = result.split('/').pop().toLowerCase();
|
|
if (resultName.includes(appName)) {
|
|
return result; // Exact match from recursion
|
|
}
|
|
fallback = fallback || result; // Store as fallback
|
|
}
|
|
} else if (entry.isFile()) {
|
|
// Check if it's an executable
|
|
if (platform === 'win32') {
|
|
const lowerName = entry.name.toLowerCase();
|
|
if (lowerName.endsWith('.exe') && !lowerName.includes('electron') && !lowerName.includes('crashpad')) {
|
|
if (lowerName.includes(appName)) {
|
|
return fullPath; // Exact match, return immediately
|
|
}
|
|
fallback = fallback || fullPath; // Store as fallback, continue searching
|
|
}
|
|
} else if (platform === 'darwin') {
|
|
const stat = statSync(fullPath);
|
|
if (stat.isFile() && stat.mode & parseInt('111', 8)) {
|
|
const lowerName = entry.name.toLowerCase();
|
|
if (!lowerName.includes('helper') && !lowerName.includes('crashpad')) {
|
|
if (lowerName.includes(appName)) {
|
|
return fullPath; // Exact match, return immediately
|
|
}
|
|
fallback = fallback || fullPath; // Store as fallback, continue searching
|
|
}
|
|
}
|
|
} else if (platform === 'linux') {
|
|
// Linux executables (AppImage or unpacked)
|
|
if (entry.name.endsWith('.AppImage')) {
|
|
const lowerName = entry.name.toLowerCase();
|
|
if (lowerName.includes(appName)) {
|
|
return fullPath; // Exact match, return immediately
|
|
}
|
|
fallback = fallback || fullPath; // Store as fallback, continue searching
|
|
}
|
|
// Check for executable files (not .so libraries)
|
|
const stat = statSync(fullPath);
|
|
if (stat.isFile() && stat.mode & parseInt('111', 8) && !entry.name.includes('.so')) {
|
|
// Skip helper binaries
|
|
const lowerName = entry.name.toLowerCase();
|
|
if (!lowerName.includes('chrome') && !lowerName.includes('crashpad')) {
|
|
if (lowerName.includes(appName)) {
|
|
return fullPath; // Exact match, return immediately
|
|
}
|
|
fallback = fallback || fullPath; // Store as fallback, continue searching
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return fallback; // Return fallback candidate if no exact appName match found
|
|
}
|
|
|
|
let executable = null;
|
|
const checkedDirs = [];
|
|
|
|
for (const root of candidateRoots) {
|
|
if (!existsSync(root)) {
|
|
checkedDirs.push(`${root} (missing)`);
|
|
continue;
|
|
}
|
|
|
|
const result = findExecutable(root, platform);
|
|
checkedDirs.push(root);
|
|
if (result) {
|
|
executable = result;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!executable) {
|
|
console.error('Error: Could not find packaged executable.');
|
|
console.error('Platform:', platform);
|
|
console.error('Checked directories:', checkedDirs.join(', '));
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log(executable);
|