mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-16 12:10:45 +00:00
fix: harden macOS gateway updates
This commit is contained in:
@@ -152,6 +152,75 @@ export function shouldUseLegacyProcessRestartAfterUpdate(params: {
|
||||
return !isPackageManagerUpdateMode(params.updateMode);
|
||||
}
|
||||
|
||||
type PrePackageServiceStop = {
|
||||
stopped: boolean;
|
||||
serviceEnv?: NodeJS.ProcessEnv;
|
||||
};
|
||||
|
||||
async function maybeStopManagedServiceBeforePackageUpdate(params: {
|
||||
shouldRestart: boolean;
|
||||
jsonMode: boolean;
|
||||
}): Promise<PrePackageServiceStop> {
|
||||
let service: ReturnType<typeof resolveGatewayService>;
|
||||
let serviceState: Awaited<ReturnType<typeof readGatewayServiceState>>;
|
||||
try {
|
||||
service = resolveGatewayService();
|
||||
serviceState = await readGatewayServiceState(service, { env: process.env });
|
||||
} catch {
|
||||
return { stopped: false };
|
||||
}
|
||||
|
||||
if (!serviceState.installed) {
|
||||
return { stopped: false };
|
||||
}
|
||||
|
||||
if (!params.shouldRestart) {
|
||||
if (!params.jsonMode && serviceState.running) {
|
||||
defaultRuntime.log(
|
||||
theme.warn(
|
||||
"--no-restart is set while the managed gateway service is running; the package update will not stop or restart that process.",
|
||||
),
|
||||
);
|
||||
}
|
||||
return { stopped: false, serviceEnv: serviceState.env };
|
||||
}
|
||||
|
||||
if (!serviceState.running) {
|
||||
return { stopped: false, serviceEnv: serviceState.env };
|
||||
}
|
||||
|
||||
if (!params.jsonMode) {
|
||||
defaultRuntime.log(theme.muted("Stopping managed gateway service before package update..."));
|
||||
}
|
||||
await service.stop({ env: serviceState.env, stdout: process.stdout });
|
||||
return { stopped: true, serviceEnv: serviceState.env };
|
||||
}
|
||||
|
||||
async function maybeRestartServiceAfterFailedPackageUpdate(params: {
|
||||
prePackageServiceStop: PrePackageServiceStop | undefined;
|
||||
jsonMode: boolean;
|
||||
}): Promise<void> {
|
||||
if (!params.prePackageServiceStop?.stopped || !params.prePackageServiceStop.serviceEnv) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await resolveGatewayService().restart({
|
||||
env: params.prePackageServiceStop.serviceEnv,
|
||||
stdout: process.stdout,
|
||||
});
|
||||
if (!params.jsonMode) {
|
||||
defaultRuntime.log(theme.muted("Restarted managed gateway service after failed update."));
|
||||
}
|
||||
} catch (err) {
|
||||
const message = `Failed to restart managed gateway service after failed update: ${String(err)}`;
|
||||
if (params.jsonMode) {
|
||||
defaultRuntime.error(message);
|
||||
} else {
|
||||
defaultRuntime.log(theme.warn(message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isRunningInsideGatewayService(
|
||||
env: Record<string, string | undefined> = process.env,
|
||||
): boolean {
|
||||
@@ -1386,31 +1455,56 @@ export async function updateCommand(opts: UpdateCommandOptions): Promise<void> {
|
||||
const { progress, stop } = createUpdateProgress(showProgress);
|
||||
const startedAt = Date.now();
|
||||
|
||||
const result =
|
||||
updateInstallKind === "package"
|
||||
? await runPackageInstallUpdate({
|
||||
root,
|
||||
installKind,
|
||||
tag,
|
||||
timeoutMs: updateStepTimeoutMs,
|
||||
startedAt,
|
||||
progress,
|
||||
jsonMode: Boolean(opts.json),
|
||||
})
|
||||
: await runGitUpdate({
|
||||
root,
|
||||
switchToGit,
|
||||
installKind,
|
||||
timeoutMs,
|
||||
startedAt,
|
||||
progress,
|
||||
channel,
|
||||
tag,
|
||||
showProgress,
|
||||
opts,
|
||||
stop,
|
||||
devTargetRef,
|
||||
});
|
||||
let prePackageServiceStop: PrePackageServiceStop | undefined;
|
||||
if (updateInstallKind === "package") {
|
||||
try {
|
||||
prePackageServiceStop = await maybeStopManagedServiceBeforePackageUpdate({
|
||||
shouldRestart,
|
||||
jsonMode: Boolean(opts.json),
|
||||
});
|
||||
} catch (err) {
|
||||
stop();
|
||||
defaultRuntime.error(`Failed to stop managed gateway service before update: ${String(err)}`);
|
||||
defaultRuntime.exit(1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let result: UpdateRunResult;
|
||||
try {
|
||||
result =
|
||||
updateInstallKind === "package"
|
||||
? await runPackageInstallUpdate({
|
||||
root,
|
||||
installKind,
|
||||
tag,
|
||||
timeoutMs: updateStepTimeoutMs,
|
||||
startedAt,
|
||||
progress,
|
||||
jsonMode: Boolean(opts.json),
|
||||
})
|
||||
: await runGitUpdate({
|
||||
root,
|
||||
switchToGit,
|
||||
installKind,
|
||||
timeoutMs,
|
||||
startedAt,
|
||||
progress,
|
||||
channel,
|
||||
tag,
|
||||
showProgress,
|
||||
opts,
|
||||
stop,
|
||||
devTargetRef,
|
||||
});
|
||||
} catch (err) {
|
||||
stop();
|
||||
await maybeRestartServiceAfterFailedPackageUpdate({
|
||||
prePackageServiceStop,
|
||||
jsonMode: Boolean(opts.json),
|
||||
});
|
||||
throw err;
|
||||
}
|
||||
|
||||
stop();
|
||||
if (!opts.json || result.status !== "ok") {
|
||||
@@ -1418,11 +1512,19 @@ export async function updateCommand(opts: UpdateCommandOptions): Promise<void> {
|
||||
}
|
||||
|
||||
if (result.status === "error") {
|
||||
await maybeRestartServiceAfterFailedPackageUpdate({
|
||||
prePackageServiceStop,
|
||||
jsonMode: Boolean(opts.json),
|
||||
});
|
||||
defaultRuntime.exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.status === "skipped") {
|
||||
await maybeRestartServiceAfterFailedPackageUpdate({
|
||||
prePackageServiceStop,
|
||||
jsonMode: Boolean(opts.json),
|
||||
});
|
||||
if (result.reason === "dirty") {
|
||||
defaultRuntime.error(theme.error("Update blocked: local files are edited in this checkout."));
|
||||
defaultRuntime.log(
|
||||
@@ -1524,6 +1626,10 @@ export async function updateCommand(opts: UpdateCommandOptions): Promise<void> {
|
||||
} else {
|
||||
defaultRuntime.error(theme.error("Update failed during plugin post-update sync."));
|
||||
}
|
||||
await maybeRestartServiceAfterFailedPackageUpdate({
|
||||
prePackageServiceStop,
|
||||
jsonMode: Boolean(opts.json),
|
||||
});
|
||||
defaultRuntime.exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user