mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-07-27 04:49:49 -07:00
feat(sync-ui): sync window self-spawns the app, dropping the local launcher/bun requirement
resolveSyncLauncherCommand now returns process.execPath + --sync-cli (with the app path prepended in dev runs) instead of hunting for bun and the bundled launcher script. Same NDJSON child protocol, so the sync window, checks, and auto-sync scheduler are unchanged.
This commit is contained in:
+5
-1
@@ -2257,7 +2257,11 @@ const syncUiRuntime = createSyncUiRuntime({
|
||||
const configured = getResolvedConfig().immersionTracking?.dbPath?.trim();
|
||||
return configured || DEFAULT_IMMERSION_DB_PATH;
|
||||
},
|
||||
resolveLauncherCommand: () => resolveSyncLauncherCommand(),
|
||||
resolveLauncherCommand: () =>
|
||||
resolveSyncLauncherCommand({
|
||||
execPath: process.execPath,
|
||||
appPath: app.isPackaged ? null : app.getAppPath(),
|
||||
}),
|
||||
runLauncher: runSyncLauncher,
|
||||
getWindow: () => appState.syncUiWindow,
|
||||
pickSnapshotFile: async () => {
|
||||
|
||||
@@ -120,28 +120,18 @@ test('runSyncLauncher surfaces spawn errors', async () => {
|
||||
assert.match(result.error ?? '', /ENOENT/);
|
||||
});
|
||||
|
||||
test('resolveSyncLauncherCommand prefers the bundled launcher over PATH', async () => {
|
||||
test('resolveSyncLauncherCommand self-spawns the app in --sync-cli mode', async () => {
|
||||
const { resolveSyncLauncherCommand } = await import('./sync-launcher-client');
|
||||
const bundled = resolveSyncLauncherCommand({
|
||||
findCommand: (name: string) =>
|
||||
name === 'bun' ? '/usr/bin/bun' : name === 'subminer' ? '/home/u/.local/bin/subminer' : null,
|
||||
resolveResourcePath: () => '/opt/app/resources/launcher/subminer',
|
||||
existsSync: () => true,
|
||||
const packaged = resolveSyncLauncherCommand({
|
||||
execPath: '/opt/SubMiner/subminer-app',
|
||||
appPath: null,
|
||||
});
|
||||
assert.deepEqual(bundled.command, ['/usr/bin/bun', '/opt/app/resources/launcher/subminer']);
|
||||
assert.deepEqual(packaged.command, ['/opt/SubMiner/subminer-app', '--sync-cli']);
|
||||
assert.equal(packaged.error, null);
|
||||
|
||||
const fallback = resolveSyncLauncherCommand({
|
||||
findCommand: (name: string) => (name === 'subminer' ? '/home/u/.local/bin/subminer' : null),
|
||||
resolveResourcePath: () => '/missing',
|
||||
existsSync: () => false,
|
||||
const dev = resolveSyncLauncherCommand({
|
||||
execPath: '/usr/bin/electron',
|
||||
appPath: '/home/u/SubMiner',
|
||||
});
|
||||
assert.deepEqual(fallback.command, ['/home/u/.local/bin/subminer']);
|
||||
|
||||
const none = resolveSyncLauncherCommand({
|
||||
findCommand: () => null,
|
||||
resolveResourcePath: () => '/missing',
|
||||
existsSync: () => false,
|
||||
});
|
||||
assert.equal(none.command, null);
|
||||
assert.match(none.error ?? '', /launcher/i);
|
||||
assert.deepEqual(dev.command, ['/usr/bin/electron', '/home/u/SubMiner', '--sync-cli']);
|
||||
});
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import { spawn as nodeSpawn } from 'node:child_process';
|
||||
import fs from 'node:fs';
|
||||
import { parseSyncProgressLine, type SyncProgressEvent } from '../../shared/sync/sync-events';
|
||||
import { findCommand } from './command-line-launcher-deps';
|
||||
import { resolveLauncherResourcePath } from './command-line-launcher';
|
||||
import { SYNC_CLI_FLAG } from '../../core/services/stats-sync/cli-args';
|
||||
|
||||
export interface SyncLauncherChildLike {
|
||||
stdout: { on(event: 'data', listener: (chunk: Buffer | string) => void): unknown } | null;
|
||||
@@ -29,33 +27,21 @@ export interface SyncLauncherResolution {
|
||||
error: string | null;
|
||||
}
|
||||
|
||||
// The launcher is a bun script. Prefer the bundled launcher resource (it
|
||||
// always matches this app version's sync protocol) and only fall back to a
|
||||
// PATH-installed `subminer`, which may be older.
|
||||
// Sync runs in a child copy of this app in headless --sync-cli mode: same
|
||||
// engine and NDJSON protocol as `subminer sync --json`, with no dependency on
|
||||
// bun or an installed command-line launcher. In dev runs process.execPath is
|
||||
// a bare electron binary, so the app path is passed as its entry argument.
|
||||
export function resolveSyncLauncherCommand(
|
||||
deps: {
|
||||
findCommand?: typeof findCommand;
|
||||
resolveResourcePath?: () => string;
|
||||
existsSync?: (candidate: string) => boolean;
|
||||
execPath?: string;
|
||||
appPath?: string | null;
|
||||
} = {},
|
||||
): SyncLauncherResolution {
|
||||
const find = deps.findCommand ?? findCommand;
|
||||
const exists = deps.existsSync ?? fs.existsSync;
|
||||
const resourcePath = deps.resolveResourcePath
|
||||
? deps.resolveResourcePath()
|
||||
: resolveLauncherResourcePath({});
|
||||
const bunPath = find('bun', {});
|
||||
if (bunPath && resourcePath && exists(resourcePath)) {
|
||||
return { command: [bunPath, resourcePath], error: null };
|
||||
}
|
||||
|
||||
const installed = find('subminer', {});
|
||||
if (installed) return { command: [installed], error: null };
|
||||
|
||||
const execPath = deps.execPath ?? process.execPath;
|
||||
const appPath = deps.appPath ?? null;
|
||||
return {
|
||||
command: null,
|
||||
error:
|
||||
'Could not find the subminer launcher. Install the command-line launcher from SubMiner setup (or install bun).',
|
||||
command: appPath ? [execPath, appPath, SYNC_CLI_FLAG] : [execPath, SYNC_CLI_FLAG],
|
||||
error: null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -66,7 +52,15 @@ export function runSyncLauncher(options: {
|
||||
onStderr?: (text: string) => void;
|
||||
spawn?: SyncLauncherSpawn;
|
||||
}): SyncLauncherRunHandle {
|
||||
const spawn = options.spawn ?? ((command, args) => nodeSpawn(command, args, { stdio: 'pipe' }));
|
||||
const spawn =
|
||||
options.spawn ??
|
||||
((command, args) => {
|
||||
// The child must boot as a full Electron app (its entry handles
|
||||
// --sync-cli); a leaked ELECTRON_RUN_AS_NODE would turn it into node.
|
||||
const env = { ...process.env };
|
||||
delete env.ELECTRON_RUN_AS_NODE;
|
||||
return nodeSpawn(command, args, { stdio: 'pipe', env });
|
||||
});
|
||||
const [executable, ...prefixArgs] = options.command;
|
||||
const child = spawn(executable!, [...prefixArgs, ...options.args]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user