YugJ commited on
Commit
820b976
·
verified ·
1 Parent(s): e684a7a

Upload system_info.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. system_info.py +359 -0
system_info.py ADDED
@@ -0,0 +1,359 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import platform
3
+ import shutil
4
+ import subprocess
5
+
6
+ # ------------------------- helpers -------------------------
7
+
8
+
9
+ def _run(cmd, timeout=3):
10
+ """Run a command safely. Returns stdout text or ''.
11
+ Accepts either a string (shell) or list (no shell)."""
12
+ try:
13
+ if isinstance(cmd, str):
14
+ return subprocess.check_output(
15
+ cmd, shell=True, text=True, stderr=subprocess.DEVNULL, timeout=timeout
16
+ ).strip()
17
+ else:
18
+ return subprocess.check_output(
19
+ cmd, shell=False, text=True, stderr=subprocess.DEVNULL, timeout=timeout
20
+ ).strip()
21
+ except Exception:
22
+ return ""
23
+
24
+
25
+ def _first_line(s: str) -> str:
26
+ s = (s or "").strip()
27
+ return s.splitlines()[0].strip() if s else ""
28
+
29
+
30
+ def _which(name: str) -> str:
31
+ return shutil.which(name) or ""
32
+
33
+
34
+ def _bool_from_output(s: str) -> bool:
35
+ return s.strip() in {"1", "true", "True", "YES", "Yes", "yes"}
36
+
37
+
38
+ # ------------------------- OS & env -------------------------
39
+
40
+
41
+ def _os_block():
42
+ sysname = platform.system() # 'Windows', 'Darwin', 'Linux'
43
+ machine = platform.machine() or ""
44
+ release = platform.release() or ""
45
+ version = platform.version() or ""
46
+ kernel = release if sysname == "Windows" else (_run(["uname", "-r"]) or release)
47
+
48
+ distro = {"name": "", "version": ""}
49
+ if sysname == "Linux":
50
+ # Best-effort parse of /etc/os-release
51
+ try:
52
+ with open("/etc/os-release", "r") as f:
53
+ data = {}
54
+ for line in f:
55
+ if "=" in line:
56
+ k, v = line.rstrip().split("=", 1)
57
+ data[k] = v.strip('"')
58
+ distro["name"] = data.get("PRETTY_NAME") or data.get("NAME", "")
59
+ distro["version"] = data.get("VERSION_ID") or data.get("VERSION", "")
60
+ except Exception:
61
+ pass
62
+
63
+ # WSL / Rosetta detection (harmless if not present)
64
+ wsl = False
65
+ if sysname != "Windows":
66
+ try:
67
+ with open("/proc/version", "r") as f:
68
+ v = f.read().lower()
69
+ wsl = ("microsoft" in v) or ("wsl" in v)
70
+ except Exception:
71
+ wsl = False
72
+
73
+ rosetta = False
74
+ if sysname == "Darwin":
75
+ rosetta = _bool_from_output(_run(["sysctl", "-in", "sysctl.proc_translated"]))
76
+
77
+ # Target triple (best effort)
78
+ target = ""
79
+ for cc in ("clang", "gcc"):
80
+ if _which(cc):
81
+ out = _run([cc, "-dumpmachine"])
82
+ if out:
83
+ target = _first_line(out)
84
+ break
85
+
86
+ return {
87
+ "system": sysname,
88
+ "arch": machine,
89
+ "release": release,
90
+ "version": version,
91
+ "kernel": kernel,
92
+ "distro": distro if sysname == "Linux" else None,
93
+ "wsl": wsl,
94
+ "rosetta2_translated": rosetta,
95
+ "target_triple": target,
96
+ }
97
+
98
+
99
+ # ------------------------- package managers -------------------------
100
+
101
+
102
+ def _package_managers():
103
+ sysname = platform.system()
104
+ pms = []
105
+ if sysname == "Windows":
106
+ for pm in ("winget", "choco", "scoop"):
107
+ if _which(pm):
108
+ pms.append(pm)
109
+ elif sysname == "Darwin":
110
+ if _run(["xcode-select", "-p"]):
111
+ pms.append("xcode-select (CLT)")
112
+ for pm in ("brew", "port"):
113
+ if _which(pm):
114
+ pms.append(pm)
115
+ else:
116
+ for pm in ("apt", "dnf", "yum", "pacman", "zypper", "apk", "emerge"):
117
+ if _which(pm):
118
+ pms.append(pm)
119
+ return pms
120
+
121
+
122
+ # ------------------------- CPU (minimal) -------------------------
123
+
124
+
125
+ def _cpu_block():
126
+ sysname = platform.system()
127
+ brand = ""
128
+ # A simple brand/model read per OS; ignore failures
129
+ if sysname == "Linux":
130
+ brand = _run("grep -m1 'model name' /proc/cpuinfo | cut -d: -f2").strip()
131
+ elif sysname == "Darwin":
132
+ brand = _run(["sysctl", "-n", "machdep.cpu.brand_string"])
133
+ elif sysname == "Windows":
134
+ brand = _run('powershell -NoProfile -Command "(Get-CimInstance Win32_Processor).Name"')
135
+ if not brand:
136
+ brand = _run("wmic cpu get Name /value").replace("Name=", "").strip()
137
+
138
+ # Logical cores always available; physical is best-effort
139
+ cores_logical = os.cpu_count() or 0
140
+ cores_physical = 0
141
+ if sysname == "Darwin":
142
+ cores_physical = int(_run(["sysctl", "-n", "hw.physicalcpu"]) or "0")
143
+ elif sysname == "Windows":
144
+ cores_physical = int(
145
+ _run('powershell -NoProfile -Command "(Get-CimInstance Win32_Processor).NumberOfCores"')
146
+ or "0"
147
+ )
148
+ elif sysname == "Linux":
149
+ # This is a quick approximation; fine for our use (parallel -j suggestions)
150
+ try:
151
+ # Count unique "core id" per physical id
152
+ mapping = _run("LC_ALL=C lscpu -p=CORE,SOCKET | grep -v '^#'").splitlines()
153
+ unique = set(tuple(line.split(",")) for line in mapping if "," in line)
154
+ cores_physical = len(unique) or 0
155
+ except Exception:
156
+ cores_physical = 0
157
+
158
+ # A tiny SIMD hint set (best-effort, optional)
159
+ simd = []
160
+ if sysname == "Linux":
161
+ flags = _run("grep -m1 'flags' /proc/cpuinfo | cut -d: -f2")
162
+ if flags:
163
+ fset = set(flags.upper().split())
164
+ for x in ("AVX512F", "AVX2", "AVX", "FMA", "SSE4_2", "NEON", "SVE"):
165
+ if x in fset:
166
+ simd.append(x)
167
+ elif sysname == "Darwin":
168
+ feats = (
169
+ (
170
+ _run(["sysctl", "-n", "machdep.cpu.features"])
171
+ + " "
172
+ + _run(["sysctl", "-n", "machdep.cpu.leaf7_features"])
173
+ )
174
+ .upper()
175
+ .split()
176
+ )
177
+ for x in ("AVX512F", "AVX2", "AVX", "FMA", "SSE4_2", "NEON", "SVE"):
178
+ if x in feats:
179
+ simd.append(x)
180
+ # On Windows, skip flags — brand typically suffices for MSVC /arch choice.
181
+
182
+ return {
183
+ "brand": brand.strip(),
184
+ "cores_logical": cores_logical,
185
+ "cores_physical": cores_physical,
186
+ "simd": sorted(set(simd)),
187
+ }
188
+
189
+
190
+ # ------------------------- toolchain presence -------------------------
191
+
192
+
193
+ def _toolchain_block():
194
+ def ver_line(exe, args=("--version",)):
195
+ p = _which(exe)
196
+ if not p:
197
+ return ""
198
+ out = _run([p, *args])
199
+ return _first_line(out)
200
+
201
+ gcc = ver_line("gcc")
202
+ gpp = ver_line("g++")
203
+ clang = ver_line("clang")
204
+
205
+ # MSVC cl (only available inside proper dev shell; handle gracefully)
206
+ msvc_cl = ""
207
+ cl_path = _which("cl")
208
+ if cl_path:
209
+ msvc_cl = _first_line(_run("cl 2>&1"))
210
+
211
+ # Build tools (presence + short version line)
212
+ cmake = ver_line("cmake")
213
+ ninja = _first_line(_run([_which("ninja"), "--version"])) if _which("ninja") else ""
214
+ make = ver_line("make")
215
+
216
+ # Linker (we only care if lld is available)
217
+ lld = ver_line("ld.lld")
218
+ return {
219
+ "compilers": {"gcc": gcc, "g++": gpp, "clang": clang, "msvc_cl": msvc_cl},
220
+ "build_tools": {"cmake": cmake, "ninja": ninja, "make": make},
221
+ "linkers": {"ld_lld": lld},
222
+ }
223
+
224
+
225
+ # ------------------------- public API -------------------------
226
+
227
+
228
+ def retrieve_system_info():
229
+ """
230
+ Returns a compact dict with enough info for an LLM to:
231
+ - Pick an install path (winget/choco/scoop, Homebrew/Xcode CLT, apt/dnf/...),
232
+ - Choose a compiler family (MSVC/clang/gcc),
233
+ - Suggest safe optimization flags (e.g., -O3/-march=native or MSVC /O2),
234
+ - Decide on a build system (cmake+ninja) and parallel -j value.
235
+ """
236
+ return {
237
+ "os": _os_block(),
238
+ "package_managers": _package_managers(),
239
+ "cpu": _cpu_block(),
240
+ "toolchain": _toolchain_block(),
241
+ }
242
+
243
+
244
+ def rust_toolchain_info():
245
+ """
246
+ Return a dict with Rust-related settings:
247
+ - presence and paths for rustc / cargo / rustup / rust-analyzer
248
+ - versions
249
+ - active/default toolchain (if rustup is present)
250
+ - installed targets
251
+ - common env vars (CARGO_HOME, RUSTUP_HOME, RUSTFLAGS, CARGO_BUILD_TARGET)
252
+ - simple execution examples
253
+ Works on Windows, macOS, and Linux. Uses the existing helpers: _run, _which, _first_line.
254
+ """
255
+ info = {
256
+ "installed": False,
257
+ "rustc": {"path": "", "version": "", "host_triple": "", "release": "", "commit_hash": ""},
258
+ "cargo": {"path": "", "version": ""},
259
+ "rustup": {
260
+ "path": "",
261
+ "version": "",
262
+ "active_toolchain": "",
263
+ "default_toolchain": "",
264
+ "toolchains": [],
265
+ "targets_installed": [],
266
+ },
267
+ "rust_analyzer": {"path": ""},
268
+ "env": {
269
+ "CARGO_HOME": os.environ.get("CARGO_HOME", ""),
270
+ "RUSTUP_HOME": os.environ.get("RUSTUP_HOME", ""),
271
+ "RUSTFLAGS": os.environ.get("RUSTFLAGS", ""),
272
+ "CARGO_BUILD_TARGET": os.environ.get("CARGO_BUILD_TARGET", ""),
273
+ },
274
+ "execution_examples": [],
275
+ }
276
+
277
+ # Paths
278
+ rustc_path = _which("rustc")
279
+ cargo_path = _which("cargo")
280
+ rustup_path = _which("rustup")
281
+ ra_path = _which("rust-analyzer")
282
+
283
+ info["rustc"]["path"] = rustc_path or ""
284
+ info["cargo"]["path"] = cargo_path or ""
285
+ info["rustup"]["path"] = rustup_path or ""
286
+ info["rust_analyzer"]["path"] = ra_path or ""
287
+
288
+ # Versions & verbose details
289
+ if rustc_path:
290
+ ver_line = _first_line(_run([rustc_path, "--version"]))
291
+ info["rustc"]["version"] = ver_line
292
+ verbose = _run([rustc_path, "--version", "--verbose"])
293
+ host = release = commit = ""
294
+ for line in verbose.splitlines():
295
+ if line.startswith("host:"):
296
+ host = line.split(":", 1)[1].strip()
297
+ elif line.startswith("release:"):
298
+ release = line.split(":", 1)[1].strip()
299
+ elif line.startswith("commit-hash:"):
300
+ commit = line.split(":", 1)[1].strip()
301
+ info["rustc"]["host_triple"] = host
302
+ info["rustc"]["release"] = release
303
+ info["rustc"]["commit_hash"] = commit
304
+
305
+ if cargo_path:
306
+ info["cargo"]["version"] = _first_line(_run([cargo_path, "--version"]))
307
+
308
+ if rustup_path:
309
+ info["rustup"]["version"] = _first_line(_run([rustup_path, "--version"]))
310
+ # Active toolchain
311
+ active = _first_line(_run([rustup_path, "show", "active-toolchain"]))
312
+ info["rustup"]["active_toolchain"] = active
313
+
314
+ # Default toolchain (best effort)
315
+ # Try parsing `rustup toolchain list` and pick the line with "(default)"
316
+ tlist = _run([rustup_path, "toolchain", "list"]).splitlines()
317
+ info["rustup"]["toolchains"] = [t.strip() for t in tlist if t.strip()]
318
+ default_tc = ""
319
+ for line in tlist:
320
+ if "(default)" in line:
321
+ default_tc = line.strip()
322
+ break
323
+ if not default_tc:
324
+ # Fallback: sometimes `rustup show` includes "default toolchain: ..."
325
+ for line in _run([rustup_path, "show"]).splitlines():
326
+ if "default toolchain:" in line:
327
+ default_tc = line.split(":", 1)[1].strip()
328
+ break
329
+ info["rustup"]["default_toolchain"] = default_tc
330
+
331
+ # Installed targets
332
+ targets = _run([rustup_path, "target", "list", "--installed"]).split()
333
+ info["rustup"]["targets_installed"] = targets
334
+
335
+ # Execution examples (only include what will work on this system)
336
+ exec_examples = []
337
+ if cargo_path:
338
+ exec_examples.append(f'"{cargo_path}" build')
339
+ exec_examples.append(f'"{cargo_path}" run')
340
+ exec_examples.append(f'"{cargo_path}" test')
341
+ if rustc_path:
342
+ exec_examples.append(f'"{rustc_path}" hello.rs -o hello')
343
+ info["execution_examples"] = exec_examples
344
+
345
+ # Installed?
346
+ info["installed"] = bool(rustc_path or cargo_path or rustup_path)
347
+
348
+ # Fill in default homes if env vars are empty but typical locations exist
349
+ def _maybe_default_home(env_val, default_basename):
350
+ if env_val:
351
+ return env_val
352
+ home = os.path.expanduser("~") or ""
353
+ candidate = os.path.join(home, default_basename) if home else ""
354
+ return candidate if candidate and os.path.isdir(candidate) else ""
355
+
356
+ info["env"]["CARGO_HOME"] = _maybe_default_home(info["env"]["CARGO_HOME"], ".cargo")
357
+ info["env"]["RUSTUP_HOME"] = _maybe_default_home(info["env"]["RUSTUP_HOME"], ".rustup")
358
+
359
+ return info