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:
parent
983857bd5b
commit
076ca348d7
2 changed files with 46 additions and 12 deletions
|
|
@ -147,26 +147,45 @@ 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()
|
||||
for pkg in packages:
|
||||
# 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", "-s", pkg,
|
||||
"dpkg-query", "-W", "-f", "${Package} ${Status}\n", *sorted(packages),
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.PIPE,
|
||||
env=_safe_env(),
|
||||
)
|
||||
try:
|
||||
stdout, _ = await asyncio.wait_for(proc.communicate(), timeout=5)
|
||||
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:
|
||||
installed.add(pkg)
|
||||
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,
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.PIPE,
|
||||
env=_safe_env(),
|
||||
)
|
||||
try:
|
||||
stdout, _ = await asyncio.wait_for(proc.communicate(), timeout=5)
|
||||
except asyncio.TimeoutError:
|
||||
continue
|
||||
if proc.returncode == 0:
|
||||
output = stdout.decode()
|
||||
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))
|
||||
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ install_deps() {
|
|||
xdotool \
|
||||
imagemagick \
|
||||
x11-utils \
|
||||
libxcb-cursor0 \
|
||||
> /dev/null 2>&1
|
||||
ok "System dependencies installed."
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue