mirror of
https://github.com/agent0ai/agent-zero.git
synced 2026-10-14 22:07:00 +00:00
fix(office): retire legacy Collabora during self-update
Stop and remove the old a0_office_collabora supervisor program during Docker self-update preparation, before stale Collabora runtime paths are deleted. Add a narrow repo-side retirement hook so older bootstrap managers can clean the checked-out runtime without reinstalling desktop packages during health checks. Harden XFCE desktop startup with explicit XDG config/data directories so upgraded Desktop sessions avoid the failsafe-session path after the Collabora-to-LibreOffice transition.
This commit is contained in:
parent
818bda0385
commit
02838f7698
3 changed files with 138 additions and 24 deletions
|
|
@ -1201,6 +1201,8 @@ export HOME="${HOME:-%s}"
|
||||||
export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
|
export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
|
||||||
export XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
|
export XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
|
||||||
export XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}"
|
export XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}"
|
||||||
|
export XDG_CONFIG_DIRS="/etc/xdg${XDG_CONFIG_DIRS:+:$XDG_CONFIG_DIRS}"
|
||||||
|
export XDG_DATA_DIRS="/usr/local/share:/usr/share${XDG_DATA_DIRS:+:$XDG_DATA_DIRS}"
|
||||||
export XDG_CURRENT_DESKTOP="${XDG_CURRENT_DESKTOP:-XFCE}"
|
export XDG_CURRENT_DESKTOP="${XDG_CURRENT_DESKTOP:-XFCE}"
|
||||||
mkdir -p "$HOME/Desktop" "$XDG_CONFIG_HOME" "$XDG_DATA_HOME" "$XDG_CACHE_HOME"
|
mkdir -p "$HOME/Desktop" "$XDG_CONFIG_HOME" "$XDG_DATA_HOME" "$XDG_CACHE_HOME"
|
||||||
if command -v xfconf-query >/dev/null 2>&1; then
|
if command -v xfconf-query >/dev/null 2>&1; then
|
||||||
|
|
@ -1261,6 +1263,8 @@ fi
|
||||||
'export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"',
|
'export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"',
|
||||||
'export XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"',
|
'export XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"',
|
||||||
'export XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}"',
|
'export XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}"',
|
||||||
|
'export XDG_CONFIG_DIRS="/etc/xdg${XDG_CONFIG_DIRS:+:$XDG_CONFIG_DIRS}"',
|
||||||
|
'export XDG_DATA_DIRS="/usr/local/share:/usr/share${XDG_DATA_DIRS:+:$XDG_DATA_DIRS}"',
|
||||||
'export XDG_CURRENT_DESKTOP="${XDG_CURRENT_DESKTOP:-XFCE}"',
|
'export XDG_CURRENT_DESKTOP="${XDG_CURRENT_DESKTOP:-XFCE}"',
|
||||||
(
|
(
|
||||||
"exec dbus-launch --exit-with-session sh -c "
|
"exec dbus-launch --exit-with-session sh -c "
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
@ -99,22 +100,12 @@ def cleanup_stale_runtime_state(force: bool = False) -> dict[str, Any]:
|
||||||
cleanup_needed = force or not CLEANUP_MARKER.exists() or bool(retired_web_paths or retired_web_packages)
|
cleanup_needed = force or not CLEANUP_MARKER.exists() or bool(retired_web_paths or retired_web_packages)
|
||||||
|
|
||||||
if cleanup_needed:
|
if cleanup_needed:
|
||||||
_kill_old_processes(errors)
|
_cleanup_retired_web_runtime(
|
||||||
|
removed,
|
||||||
for path in [
|
errors,
|
||||||
RETIRED_WEB_APT_SOURCE_FILE,
|
retired_web_packages=retired_web_packages,
|
||||||
RETIRED_WEB_APT_KEYRING_FILE,
|
purge_packages=True,
|
||||||
RETIRED_WEB_SUPERVISOR_FILE,
|
)
|
||||||
*RETIRED_WEB_RUNTIME_DIRS,
|
|
||||||
]:
|
|
||||||
try:
|
|
||||||
if _remove_path(path):
|
|
||||||
removed.append(str(path))
|
|
||||||
except Exception as exc:
|
|
||||||
errors.append(f"{path}: {exc}")
|
|
||||||
|
|
||||||
_retire_supervisor_program(errors)
|
|
||||||
_purge_packages(removed, errors, installed_packages=retired_web_packages)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
CLEANUP_MARKER.parent.mkdir(parents=True, exist_ok=True)
|
CLEANUP_MARKER.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
@ -144,6 +135,45 @@ def cleanup_stale_runtime_state(force: bool = False) -> dict[str, Any]:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def retire_collabora_web_runtime(force: bool = False) -> dict[str, Any]:
|
||||||
|
"""Retire the legacy Collabora web runtime without preparing LibreOffice.
|
||||||
|
|
||||||
|
This is intentionally narrower than cleanup_stale_runtime_state(). Older
|
||||||
|
Docker self-update managers run the checked-out repo's prepare.py before the
|
||||||
|
updated UI starts, so prepare.py can call this fast hook to remove the stale
|
||||||
|
supervisor program left by v1.10 without blocking health checks on desktop
|
||||||
|
package installation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
removed: list[str] = []
|
||||||
|
errors: list[str] = []
|
||||||
|
retired_web_paths = [
|
||||||
|
path
|
||||||
|
for path in [
|
||||||
|
RETIRED_WEB_APT_SOURCE_FILE,
|
||||||
|
RETIRED_WEB_APT_KEYRING_FILE,
|
||||||
|
RETIRED_WEB_SUPERVISOR_FILE,
|
||||||
|
*RETIRED_WEB_RUNTIME_DIRS,
|
||||||
|
]
|
||||||
|
if path.exists() or path.is_symlink()
|
||||||
|
]
|
||||||
|
|
||||||
|
if force or retired_web_paths:
|
||||||
|
_cleanup_retired_web_runtime(
|
||||||
|
removed,
|
||||||
|
errors,
|
||||||
|
retired_web_packages=[],
|
||||||
|
purge_packages=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"ok": not errors,
|
||||||
|
"skipped": not force and not retired_web_paths,
|
||||||
|
"removed": removed,
|
||||||
|
"errors": errors,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def _migrate_legacy_document_state(
|
def _migrate_legacy_document_state(
|
||||||
migrated: list[str],
|
migrated: list[str],
|
||||||
warnings: list[str],
|
warnings: list[str],
|
||||||
|
|
@ -218,11 +248,41 @@ def _remove_path(path: Path) -> bool:
|
||||||
path.unlink(missing_ok=True)
|
path.unlink(missing_ok=True)
|
||||||
return True
|
return True
|
||||||
if path.exists():
|
if path.exists():
|
||||||
shutil.rmtree(path)
|
try:
|
||||||
|
shutil.rmtree(path)
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _cleanup_retired_web_runtime(
|
||||||
|
removed: list[str],
|
||||||
|
errors: list[str],
|
||||||
|
*,
|
||||||
|
retired_web_packages: list[str],
|
||||||
|
purge_packages: bool,
|
||||||
|
) -> None:
|
||||||
|
_stop_supervisor_program(errors)
|
||||||
|
_kill_old_processes(errors)
|
||||||
|
|
||||||
|
for path in [
|
||||||
|
RETIRED_WEB_APT_SOURCE_FILE,
|
||||||
|
RETIRED_WEB_APT_KEYRING_FILE,
|
||||||
|
RETIRED_WEB_SUPERVISOR_FILE,
|
||||||
|
*RETIRED_WEB_RUNTIME_DIRS,
|
||||||
|
]:
|
||||||
|
try:
|
||||||
|
if _remove_path(path):
|
||||||
|
removed.append(str(path))
|
||||||
|
except Exception as exc:
|
||||||
|
errors.append(f"{path}: {exc}")
|
||||||
|
|
||||||
|
_retire_supervisor_program(errors)
|
||||||
|
if purge_packages:
|
||||||
|
_purge_packages(removed, errors, installed_packages=retired_web_packages)
|
||||||
|
|
||||||
|
|
||||||
def _kill_old_processes(errors: list[str]) -> None:
|
def _kill_old_processes(errors: list[str]) -> None:
|
||||||
if not shutil.which("pkill"):
|
if not shutil.which("pkill"):
|
||||||
return
|
return
|
||||||
|
|
@ -237,6 +297,28 @@ def _kill_old_processes(errors: list[str]) -> None:
|
||||||
errors.append((result.stderr or result.stdout or "pkill coolwsd failed").strip())
|
errors.append((result.stderr or result.stdout or "pkill coolwsd failed").strip())
|
||||||
|
|
||||||
|
|
||||||
|
def _stop_supervisor_program(errors: list[str]) -> None:
|
||||||
|
if not shutil.which("supervisorctl"):
|
||||||
|
return
|
||||||
|
status = _supervisorctl("status", RETIRED_WEB_SUPERVISOR_PROGRAM)
|
||||||
|
status_output = _supervisor_output(status)
|
||||||
|
if status.returncode != 0:
|
||||||
|
if _supervisor_absent(status_output) or _supervisor_stopped(status_output):
|
||||||
|
return
|
||||||
|
errors.append(status_output or f"supervisorctl status {RETIRED_WEB_SUPERVISOR_PROGRAM} failed")
|
||||||
|
return
|
||||||
|
|
||||||
|
if _supervisor_stopped(status_output):
|
||||||
|
return
|
||||||
|
|
||||||
|
stopped = _supervisorctl("stop", RETIRED_WEB_SUPERVISOR_PROGRAM)
|
||||||
|
stopped_output = _supervisor_output(stopped)
|
||||||
|
if stopped.returncode != 0 and not (
|
||||||
|
_supervisor_absent(stopped_output) or _supervisor_stopped(stopped_output)
|
||||||
|
):
|
||||||
|
errors.append(stopped_output or f"supervisorctl stop {RETIRED_WEB_SUPERVISOR_PROGRAM} failed")
|
||||||
|
|
||||||
|
|
||||||
def _retire_supervisor_program(errors: list[str]) -> None:
|
def _retire_supervisor_program(errors: list[str]) -> None:
|
||||||
if not shutil.which("supervisorctl"):
|
if not shutil.which("supervisorctl"):
|
||||||
return
|
return
|
||||||
|
|
@ -245,14 +327,18 @@ def _retire_supervisor_program(errors: list[str]) -> None:
|
||||||
if status.returncode != 0:
|
if status.returncode != 0:
|
||||||
if _supervisor_absent(status_output):
|
if _supervisor_absent(status_output):
|
||||||
return
|
return
|
||||||
errors.append(status_output or f"supervisorctl status {RETIRED_WEB_SUPERVISOR_PROGRAM} failed")
|
if not _supervisor_stopped(status_output):
|
||||||
return
|
errors.append(status_output or f"supervisorctl status {RETIRED_WEB_SUPERVISOR_PROGRAM} failed")
|
||||||
|
return
|
||||||
|
|
||||||
stopped = _supervisorctl("stop", RETIRED_WEB_SUPERVISOR_PROGRAM)
|
if not _supervisor_stopped(status_output):
|
||||||
stopped_output = _supervisor_output(stopped)
|
stopped = _supervisorctl("stop", RETIRED_WEB_SUPERVISOR_PROGRAM)
|
||||||
if stopped.returncode != 0 and not _supervisor_absent(stopped_output):
|
stopped_output = _supervisor_output(stopped)
|
||||||
errors.append(stopped_output or f"supervisorctl stop {RETIRED_WEB_SUPERVISOR_PROGRAM} failed")
|
if stopped.returncode != 0 and not (
|
||||||
return
|
_supervisor_absent(stopped_output) or _supervisor_stopped(stopped_output)
|
||||||
|
):
|
||||||
|
errors.append(stopped_output or f"supervisorctl stop {RETIRED_WEB_SUPERVISOR_PROGRAM} failed")
|
||||||
|
return
|
||||||
|
|
||||||
removed = _supervisorctl("remove", RETIRED_WEB_SUPERVISOR_PROGRAM)
|
removed = _supervisorctl("remove", RETIRED_WEB_SUPERVISOR_PROGRAM)
|
||||||
removed_output = _supervisor_output(removed)
|
removed_output = _supervisor_output(removed)
|
||||||
|
|
@ -293,6 +379,10 @@ def _supervisor_absent(output: str) -> bool:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _supervisor_stopped(output: str) -> bool:
|
||||||
|
return bool(re.search(rf"(^|\s){re.escape(RETIRED_WEB_SUPERVISOR_PROGRAM)}\s+STOPPED\b", output))
|
||||||
|
|
||||||
|
|
||||||
def _installed_packages(packages: tuple[str, ...]) -> list[str]:
|
def _installed_packages(packages: tuple[str, ...]) -> list[str]:
|
||||||
if not shutil.which("dpkg-query"):
|
if not shutil.which("dpkg-query"):
|
||||||
return []
|
return []
|
||||||
|
|
|
||||||
20
prepare.py
20
prepare.py
|
|
@ -1,13 +1,33 @@
|
||||||
from helpers import dotenv, runtime, settings
|
from helpers import dotenv, runtime, settings
|
||||||
import string
|
import string
|
||||||
import random
|
import random
|
||||||
|
import sys
|
||||||
from helpers.print_style import PrintStyle
|
from helpers.print_style import PrintStyle
|
||||||
|
|
||||||
|
|
||||||
|
def _retire_legacy_collabora_runtime() -> None:
|
||||||
|
if not any(arg.lower() == "--dockerized=true" for arg in sys.argv):
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
from plugins._office import hooks as office_hooks
|
||||||
|
|
||||||
|
result = office_hooks.retire_collabora_web_runtime(force=True)
|
||||||
|
except Exception as exc:
|
||||||
|
PrintStyle.warning("Legacy Collabora runtime cleanup failed:", exc)
|
||||||
|
return
|
||||||
|
|
||||||
|
if result.get("errors"):
|
||||||
|
PrintStyle.warning("Legacy Collabora runtime cleanup reported errors:", result["errors"])
|
||||||
|
elif result.get("removed"):
|
||||||
|
PrintStyle.info("Legacy Collabora runtime retired:", result)
|
||||||
|
|
||||||
|
|
||||||
PrintStyle.standard("Preparing environment...")
|
PrintStyle.standard("Preparing environment...")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
|
_retire_legacy_collabora_runtime()
|
||||||
runtime.initialize()
|
runtime.initialize()
|
||||||
|
|
||||||
# generate random root password if not set (for SSH)
|
# generate random root password if not set (for SSH)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue