Fix package detection using dpkg-query, add apt-get update before install, add libxcb-cursor0 dep

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
roberts 2026-03-14 23:51:53 -05:00
parent 983857bd5b
commit 076ca348d7
2 changed files with 46 additions and 12 deletions

View file

@ -147,10 +147,30 @@ def _parse_apt_packages(install_sh_content: str) -> set[str]:
async def _get_installed_packages(packages: set[str]) -> set[str]:
"""Check which packages from the set are already installed via dpkg."""
"""Check which packages from the set are already installed via dpkg-query."""
if not packages:
return set()
installed = set()
# Use dpkg-query for batch check — more reliable than dpkg -s
# Note: dpkg-query returns non-zero if ANY package is unknown, but still
# outputs status for known packages on stdout.
try:
proc = await asyncio.create_subprocess_exec(
"dpkg-query", "-W", "-f", "${Package} ${Status}\n", *sorted(packages),
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
env=_safe_env(),
)
stdout, _ = await asyncio.wait_for(proc.communicate(), timeout=10)
# returncode may be non-zero if some packages are unknown — that's fine
for line in stdout.decode().strip().splitlines():
# Format: "packagename install ok installed"
if "install ok installed" in line:
pkg_name = line.split()[0]
installed.add(pkg_name)
except (asyncio.TimeoutError, Exception) as e:
log.debug("dpkg-query failed, falling back to individual checks: %s", e)
# Fallback: check each package individually
for pkg in packages:
proc = await asyncio.create_subprocess_exec(
"dpkg", "-s", pkg,
@ -163,9 +183,8 @@ async def _get_installed_packages(packages: set[str]) -> set[str]:
except asyncio.TimeoutError:
continue
if proc.returncode == 0:
# Verify it's actually installed (Status: install ok installed)
output = stdout.decode()
if "Status:" in output and "installed" in output:
if "install ok installed" in output:
installed.add(pkg)
return installed
@ -262,6 +281,20 @@ async def install_deps(req: InstallDepsRequest, _user: str = Depends(get_current
raise HTTPException(400, f"Invalid package name: {pkg}")
apt_bin = shutil.which("apt-get") or "/usr/bin/apt-get"
# Update package lists first
log.info("Running apt-get update before install")
update_proc = await asyncio.create_subprocess_exec(
apt_bin, "update", "-qq",
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
env=_safe_env(),
)
try:
await asyncio.wait_for(update_proc.communicate(), timeout=120)
except asyncio.TimeoutError:
pass # Non-fatal, proceed with install anyway
cmd = [apt_bin, "install", "-y"] + req.packages
log.info("Installing system packages: %s", " ".join(req.packages))

View file

@ -52,6 +52,7 @@ install_deps() {
xdotool \
imagemagick \
x11-utils \
libxcb-cursor0 \
> /dev/null 2>&1
ok "System dependencies installed."
}