-
Notifications
You must be signed in to change notification settings - Fork 436
Expand file tree
/
Copy pathdependency.py
More file actions
210 lines (165 loc) · 5.7 KB
/
Copy pathdependency.py
File metadata and controls
210 lines (165 loc) · 5.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
import yaml
import shutil
import os
try:
from tool_manager_gui.version import get_version, compare_versions, max_version
except ImportError:
from version import get_version, compare_versions, max_version
# ---------- LOAD TOOLS ----------
def load_tools():
base_dir = os.path.dirname(__file__)
tools_path = os.path.join(base_dir, "tools.yml")
with open(tools_path, encoding="utf-8") as f:
data = yaml.safe_load(f) or {}
return data.get("tools", {})
# ---------- CHECK HELPERS ----------
def check_executable(names):
if isinstance(names, str):
names = [names]
return any(shutil.which(name) for name in names)
def check_directory(path):
return os.path.exists(path)
def is_installed(info):
ttype = (info or {}).get("type")
if ttype == "executable":
return check_executable((info or {}).get("check"))
if ttype == "directory":
return check_directory((info or {}).get("path"))
return False
def get_installed_version(info):
"""
Best-effort: only meaningful for executable tools.
Returns version string or None.
"""
if (info or {}).get("type") != "executable":
return None
if not check_executable((info or {}).get("check")):
return None
cmd = (info or {}).get("version_cmd")
return get_version(cmd)
def get_latest_target_version(info):
"""
Defines what "latest" means for update checks.
Priority:
- recommended_version
- highest item in versions list
- min_version (as a fallback target)
"""
if not isinstance(info, dict):
return None
rec = info.get("recommended_version")
if isinstance(rec, str) and rec.strip():
return rec.strip()
versions = info.get("versions")
if isinstance(versions, list):
mv = max_version(versions)
if mv:
return mv
min_v = info.get("min_version")
if isinstance(min_v, str) and min_v.strip():
return min_v.strip()
return None
# ---------- TABLE VIEW (list / check) ----------
def check_dependencies():
tools = load_tools()
results = []
for tool, info in tools.items():
# Defensive: ignore malformed tool entries in tools.yml (e.g. nested "tools:" key)
if not isinstance(info, dict):
continue
ttype = info.get("type")
status = "not installed"
version = "-"
if ttype == "executable":
found = check_executable(info.get("check"))
if found:
status = "installed"
if "version_cmd" in info:
version = get_version(info["version_cmd"]) or "-"
elif ttype == "directory":
found = check_directory(info.get("path"))
if found:
status = "installed"
results.append((tool.lower(), status, version))
return results
def print_dependency_table(results):
print(f"{'Tool':<12} {'Status':<14} Version")
print("-" * 38)
for tool, status, version in results:
print(f"{tool:<12} {status:<14} {version}")
# ---------- DOCTOR COMMAND ----------
def run_doctor():
print("🔍 System Diagnostics\n")
tools = load_tools()
system_ready = True
for tool, info in tools.items():
tool_name = tool.lower()
if info.get("type") != "executable":
continue
found = check_executable(info.get("check"))
if not found:
print(f"✖ {tool_name} missing")
system_ready = False
continue
# Tools without version rules are still required, just not version-gated.
if (
"min_version" not in info
and "recommended_version" not in info
):
print(f"✔ {tool_name} found")
continue
installed_version = None
if "version_cmd" in info:
installed_version = get_version(info["version_cmd"])
if installed_version and "min_version" in info:
cmp = compare_versions(installed_version, info["min_version"])
if cmp == -1:
print(
f"⚠ {tool_name} version outdated "
f"({installed_version} < {info['min_version']})"
)
system_ready = False
continue
if installed_version and "recommended_version" in info:
cmp = compare_versions(installed_version, info["recommended_version"])
if cmp == -1:
print(
f"ℹ {tool_name} update recommended "
f"(v{installed_version} < {info['recommended_version']})"
)
continue
if installed_version:
print(f"✔ {tool_name} found (v{installed_version})")
else:
print(f"✔ {tool_name} found")
print("\nStatus:", end=" ")
if system_ready:
print("✅ System ready")
else:
print("❌ System not ready")
#-----------------Update---------------
def needs_update(tool_name, info):
"""
Returns True only if:
- tool is executable
- tool is installed
- AND version rules are defined
- AND installed version is outdated
"""
# Only executables can be updated
if info.get("type") != "executable":
return False
# 🔑 KEY RULE: no known target → no update
target = get_latest_target_version(info)
if not target:
return False
# Tool must be installed
if not check_executable(info.get("check")):
return False
# Detect version
installed_version = None
if "version_cmd" in info:
installed_version = get_version(info["version_cmd"])
if not installed_version:
return False
return compare_versions(installed_version, target) == -1