Files

142 lines
4.3 KiB
JavaScript

import { requestServerShutdown } from './cli-http.js';
import { discoverRunningInstances } from './cli-lifecycle.js';
import {
readInstanceOptions,
removePidFile,
stopInstanceProcess,
} from './cli-process.js';
import {
intro as clackIntro,
outro as clackOutro,
isJsonMode,
isQuietMode,
shouldRenderHumanOutput,
createSpinner,
printJson,
logStatus,
} from '../cli-output.js';
function createUpdateCommand({ importFromFilePath, packageManagerPath, serveCommand }) {
return async function updateCommand(options = {}) {
const showOutput = shouldRenderHumanOutput(options);
const updateSpin = createSpinner(options);
const {
checkForUpdates,
executeUpdate,
detectPackageManager,
getCurrentVersion,
} = await importFromFilePath(packageManagerPath);
const runningInstances = await discoverRunningInstances();
const currentVersion = getCurrentVersion();
if (showOutput) {
clackIntro('OpenChamber Update');
}
if (showOutput && !updateSpin) {
logStatus('info', `current version: ${currentVersion}`);
}
updateSpin?.start('Checking for updates...');
const updateInfo = await checkForUpdates();
if (updateInfo.error) {
updateSpin?.error('Update check failed');
if (showOutput) {
clackOutro('update failed');
}
throw new Error(updateInfo.error);
}
if (!updateInfo.available) {
if (isJsonMode(options)) {
printJson({
currentVersion,
latestVersion: updateInfo.version || currentVersion,
updated: false,
});
return;
}
if (showOutput && !updateSpin) {
logStatus('success', 'you are running the latest version');
}
updateSpin?.stop('Already up to date');
if (showOutput) {
clackOutro('no update needed');
} else if (isQuietMode(options)) {
process.stdout.write(`up-to-date ${currentVersion}\n`);
}
return;
}
if (showOutput && !updateSpin) {
logStatus('info', `updating ${updateInfo.currentVersion || currentVersion} -> ${updateInfo.version || 'latest'}`);
}
updateSpin?.message(`Updating to ${updateInfo.version || 'latest'}...`);
if (runningInstances.length > 0) {
updateSpin?.message(`Stopping ${runningInstances.length} running instance(s)...`);
for (const instance of runningInstances) {
try {
const requested = await requestServerShutdown(instance.port, instance.host);
await stopInstanceProcess(instance.pid, {
shutdownWaitMs: requested ? 5000 : 0,
gracefulTimeoutMs: 2500,
forceTimeoutMs: 3000,
});
removePidFile(instance.pidFilePath);
} catch {
}
}
}
const pm = detectPackageManager();
const result = executeUpdate(pm, { silent: isJsonMode(options) || isQuietMode(options) });
if (!result.success) {
updateSpin?.error('Update failed');
if (showOutput) {
clackOutro('update failed');
}
throw new Error(`Update failed with exit code ${result.exitCode}`);
}
if (runningInstances.length > 0) {
updateSpin?.message(`Restarting ${runningInstances.length} instance(s)...`);
for (const instance of runningInstances) {
const storedOptions = readInstanceOptions(instance.instanceFilePath) || { port: instance.port };
await serveCommand({
port: storedOptions.port || instance.port,
host: storedOptions.host,
explicitPort: true,
uiPassword: storedOptions.uiPassword,
suppressStartupSummary: true,
suppressUiPasswordWarning: true,
quiet: true,
});
}
}
if (showOutput && !updateSpin) {
logStatus('success', `updated to ${updateInfo.version || 'latest'}`);
}
updateSpin?.stop(`Updated to ${updateInfo.version || 'latest'}`);
if (isJsonMode(options)) {
printJson({
currentVersion,
latestVersion: updateInfo.version || 'latest',
updated: true,
restartedCount: runningInstances.length,
});
return;
}
if (showOutput) {
clackOutro('update complete');
} else if (isQuietMode(options)) {
process.stdout.write(`updated ${updateInfo.version || 'latest'}\n`);
}
};
}
export { createUpdateCommand };