better compose detection

This commit is contained in:
phact 2025-11-05 14:27:56 -05:00
parent 284d0dfbbc
commit 992a08fda6
2 changed files with 115 additions and 16 deletions

View file

@ -121,15 +121,18 @@ class ContainerManager:
return Path(filename)
def is_available(self) -> bool:
"""Check if container runtime is available."""
return self.runtime_info.runtime_type != RuntimeType.NONE
"""Check if container runtime with compose is available."""
return (self.runtime_info.runtime_type != RuntimeType.NONE and
len(self.runtime_info.compose_command) > 0)
def get_runtime_info(self) -> RuntimeInfo:
"""Get container runtime information."""
return self.runtime_info
def get_installation_help(self) -> str:
"""Get installation instructions if runtime is not available."""
"""Get installation instructions based on what's missing."""
if self.runtime_info.has_runtime_without_compose:
return self.platform_detector.get_compose_installation_instructions()
return self.platform_detector.get_installation_instructions()
async def _run_compose_command(
@ -644,6 +647,9 @@ class ContainerManager:
if line.strip():
yield False, line, False
# Show runtime detection info
runtime_cmd_str = " ".join(self.runtime_info.compose_command)
yield False, f"Using compose command: {runtime_cmd_str}", False
yield False, f"Final compose file: {compose_file.absolute()}", False
if not compose_file.exists():
yield False, f"ERROR: Compose file not found at {compose_file.absolute()}", False

View file

@ -21,6 +21,7 @@ class RuntimeInfo:
compose_command: list[str]
runtime_command: list[str]
version: Optional[str] = None
has_runtime_without_compose: bool = False # True if docker/podman exists but compose missing
class PlatformDetector:
@ -49,7 +50,8 @@ class PlatformDetector:
docker_version = self._get_docker_version()
if docker_version and podman_version in docker_version:
# This is podman masquerading as docker
if self._check_command(["docker", "compose", "--help"]):
if self._check_command(["docker", "compose", "--help"]) and \
self._check_command(["docker", "compose", "version"]):
return RuntimeInfo(
RuntimeType.PODMAN,
["docker", "compose"],
@ -65,7 +67,8 @@ class PlatformDetector:
)
# Check for native podman compose
if self._check_command(["podman", "compose", "--help"]):
if self._check_command(["podman", "compose", "--help"]) and \
self._check_command(["podman", "compose", "version"]):
return RuntimeInfo(
RuntimeType.PODMAN,
["podman", "compose"],
@ -73,8 +76,10 @@ class PlatformDetector:
podman_version,
)
# Check for actual docker
if self._check_command(["docker", "compose", "--help"]):
# Check for actual docker - try docker compose (new) first, then docker-compose (old)
# Check both --help and version to ensure compose subcommand actually works
if self._check_command(["docker", "compose", "--help"]) and \
self._check_command(["docker", "compose", "version"]):
version = self._get_docker_version()
return RuntimeInfo(
RuntimeType.DOCKER, ["docker", "compose"], ["docker"], version
@ -85,6 +90,27 @@ class PlatformDetector:
RuntimeType.DOCKER_COMPOSE, ["docker-compose"], ["docker"], version
)
# Check if we have docker/podman runtime but no working compose
docker_version = self._get_docker_version()
if docker_version:
return RuntimeInfo(
RuntimeType.DOCKER,
[],
["docker"],
docker_version,
has_runtime_without_compose=True
)
podman_version = self._get_podman_version()
if podman_version:
return RuntimeInfo(
RuntimeType.PODMAN,
[],
["podman"],
podman_version,
has_runtime_without_compose=True
)
return RuntimeInfo(RuntimeType.NONE, [], [])
def detect_gpu_available(self) -> bool:
@ -114,7 +140,15 @@ class PlatformDetector:
def _check_command(self, cmd: list[str]) -> bool:
try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
return result.returncode == 0
# Check both return code and that stderr doesn't contain "unknown" error
# This helps catch cases where docker exists but compose subcommand doesn't
if result.returncode != 0:
return False
# Check both stdout and stderr for error indicators
combined = (result.stdout + result.stderr).lower()
if "unknown" in combined and ("command" in combined or "flag" in combined or "shorthand" in combined):
return False
return True
except (subprocess.TimeoutExpired, FileNotFoundError):
return False
@ -192,6 +226,64 @@ To set up WSL:
Learn more: https://docs.microsoft.com/en-us/windows/wsl/install
"""
def get_compose_installation_instructions(self) -> str:
"""Get instructions for installing compose when runtime exists but compose is missing."""
if self.platform_system == "Darwin":
return """
Container runtime detected but Docker Compose is missing.
Recommended - Install Docker Desktop for Mac:
Docker Desktop includes both Docker Engine and Docker Compose.
https://docs.docker.com/desktop/install/mac-install/
Or install docker-compose separately:
brew install docker-compose
For Podman:
brew install podman-compose
"""
elif self.platform_system == "Linux":
return """
Container runtime detected but Docker Compose is missing.
Install Docker Compose plugin:
# For Ubuntu/Debian:
sudo apt-get update
sudo apt-get install docker-compose-plugin
# For RHEL/Fedora:
sudo dnf install docker-compose-plugin
Or install standalone docker-compose:
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
For Podman:
# Ubuntu/Debian: sudo apt install podman-compose
# RHEL/Fedora: sudo dnf install podman-compose
"""
elif self.platform_system == "Windows":
return """
Container runtime detected but Docker Compose is missing.
Please install Docker Compose in WSL:
In WSL terminal, install Docker Compose plugin:
sudo apt-get update
sudo apt-get install docker-compose-plugin
Or for Podman:
sudo apt install podman-compose
"""
else:
return """
Container runtime detected but Docker Compose is missing.
Please install Docker Compose:
- Docker Compose: https://docs.docker.com/compose/install/
- Or Podman Compose: https://github.com/containers/podman-compose
"""
def get_installation_instructions(self) -> str:
if self.platform_system == "Darwin":
return """
@ -219,17 +311,18 @@ Or Podman:
"""
elif self.platform_system == "Windows":
return """
No container runtime found. Please install one:
No container runtime found. Please install one using WSL:
Docker Desktop for Windows:
https://docs.docker.com/desktop/install/windows-install/
Or Podman Desktop:
https://podman-desktop.io/downloads
For better performance, consider using WSL:
Run: wsl --install
https://docs.microsoft.com/en-us/windows/wsl/install
Docker:
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
Or Podman:
# Ubuntu/Debian: sudo apt install podman
# RHEL/Fedora: sudo dnf install podman
"""
else:
return """