|
4 | 4 | from __future__ import annotations |
5 | 5 |
|
6 | 6 | import importlib |
7 | | -import os |
| 7 | +import shutil |
8 | 8 | import sys |
9 | 9 | import typing |
10 | 10 | from importlib.metadata import version |
11 | 11 | from pathlib import Path |
12 | 12 |
|
13 | 13 | import git |
14 | 14 | import gitdb.exc |
| 15 | +from docker import errors as docker_errors |
| 16 | +from docker import from_env as docker_from_env |
15 | 17 |
|
16 | 18 | import colrev.env.environment_manager |
17 | 19 | import colrev.env.utils |
@@ -86,12 +88,37 @@ def _set_versions(self) -> None: |
86 | 88 | self.colrev_version = f'version {version("colrev")}' |
87 | 89 | sys_v = sys.version |
88 | 90 | self.python_version = f'version {sys_v[: sys_v.find(" ")]}' |
89 | | - stream = os.popen("git --version") |
90 | | - self.git_version = stream.read().replace("git ", "").replace("\n", "") |
91 | | - stream = os.popen("docker --version") |
92 | | - self.docker_version = stream.read().replace("Docker ", "").replace("\n", "") |
93 | | - if self.docker_version == "": # pragma: no cover |
94 | | - self.docker_version = "Not installed" |
| 91 | + self.git_version = self._get_git_version() |
| 92 | + self.docker_version = self._get_docker_version() |
| 93 | + |
| 94 | + def _get_git_version(self) -> str: |
| 95 | + git_executable = shutil.which("git") |
| 96 | + if git_executable is None: |
| 97 | + return "Not installed" |
| 98 | + |
| 99 | + try: |
| 100 | + # Use the resolved absolute executable path to avoid partial-path execution. |
| 101 | + git.refresh(path=git_executable) |
| 102 | + version_info = git.cmd.Git().version_info |
| 103 | + return "version " + ".".join(map(str, version_info)) |
| 104 | + except (git.exc.GitError, TypeError, ValueError): |
| 105 | + return "Not installed" |
| 106 | + |
| 107 | + def _get_docker_version(self) -> str: |
| 108 | + # This validates Docker daemon availability/version through the Docker SDK, |
| 109 | + # not just whether the docker CLI binary exists on PATH. |
| 110 | + client = None |
| 111 | + try: |
| 112 | + client = docker_from_env() |
| 113 | + docker_version = client.version().get("Version", "") |
| 114 | + if docker_version == "": # pragma: no cover |
| 115 | + return "Not installed" |
| 116 | + return f"version {docker_version}" |
| 117 | + except docker_errors.DockerException: |
| 118 | + return "Not installed" |
| 119 | + finally: |
| 120 | + if client is not None: |
| 121 | + client.close() |
95 | 122 |
|
96 | 123 | def _set_script_information(self, script_name: str) -> None: |
97 | 124 | self.ext_script_name = "" |
|
0 commit comments