@@ -123,6 +123,45 @@ def _version_is_podman(version: Any) -> bool:
123123 return "podman" in str (version .get ("Name" , "" )).lower ()
124124
125125
126+ def _default_podman_socket_candidates () -> list [Path ]:
127+ """Return common Podman Docker-compatible API socket paths."""
128+ candidates : list [Path ] = []
129+
130+ xdg_runtime_dir = os .environ .get ("XDG_RUNTIME_DIR" , "" ).strip ()
131+ if xdg_runtime_dir :
132+ candidates .append (Path (xdg_runtime_dir ) / "podman" / "podman.sock" )
133+
134+ getuid = getattr (os , "getuid" , None )
135+ if callable (getuid ):
136+ candidates .append (Path ("/run/user" ) / str (getuid ()) / "podman" / "podman.sock" )
137+
138+ candidates .append (Path ("/run/podman/podman.sock" ))
139+
140+ seen : set [str ] = set ()
141+ unique : list [Path ] = []
142+ for candidate in candidates :
143+ key = str (candidate )
144+ if key in seen :
145+ continue
146+ seen .add (key )
147+ unique .append (candidate )
148+ return unique
149+
150+
151+ def _format_podman_socket_hint () -> str :
152+ candidates = ", " .join (f"unix://{ path } " for path in _default_podman_socket_candidates ())
153+ if shutil .which ("podman" ):
154+ return (
155+ " Podman appears to be installed, but VibePod could not connect to its "
156+ "Docker-compatible socket. Start the Podman socket or set DOCKER_HOST "
157+ f"to one of: { candidates } ."
158+ )
159+ return (
160+ " Install/start Docker, or install Podman and expose its Docker-compatible socket "
161+ f"with DOCKER_HOST (for example: { candidates } )."
162+ )
163+
164+
126165def _parse_image_name (image : str ) -> tuple [str , str | None ]:
127166 """Parse a full image string into repository and tag/digest."""
128167 if "@" in image :
@@ -141,13 +180,33 @@ class DockerManager:
141180 def __init__ (self ) -> None :
142181 if docker is None :
143182 raise DockerClientError ("Docker SDK not installed" )
183+
184+ self ._rootless_podman : bool | None = None
144185 try :
145186 self .client = docker .from_env ()
146187 self .client .ping ()
147188 except DockerException as exc :
148- raise DockerClientError (f"Docker is not available: { exc } " ) from exc
149-
150- self ._rootless_podman : bool | None = None
189+ podman_errors : list [str ] = []
190+ docker_client = getattr (docker , "DockerClient" , None )
191+ if callable (docker_client ):
192+ for socket_path in _default_podman_socket_candidates ():
193+ if not socket_path .exists ():
194+ continue
195+ base_url = f"unix://{ socket_path } "
196+ try :
197+ client = docker_client (base_url = base_url , version = "auto" )
198+ client .ping ()
199+ except DockerException as podman_exc :
200+ podman_errors .append (f"{ base_url } : { podman_exc } " )
201+ continue
202+ self .client = client
203+ return
204+
205+ message = f"Docker is not available: { exc } "
206+ if podman_errors :
207+ message += " Podman socket attempts failed: " + "; " .join (podman_errors ) + "."
208+ message += _format_podman_socket_hint ()
209+ raise DockerClientError (message ) from exc
151210
152211 def is_rootless_podman (self ) -> bool :
153212 """Return True for a rootless Podman engine exposed through the Docker API."""
0 commit comments