v / cmd / tools
Raw file | 291 loc (275 sloc) | 6.76 KB | Latest commit hash 017ace6ea
1import os
2import time
3import term
4import v.util.version
5import runtime
6
7struct App {
8mut:
9 report_lines []string
10 cached_cpuinfo map[string]string
11}
12
13fn (mut a App) println(s string) {
14 a.report_lines << s
15}
16
17fn (mut a App) collect_info() {
18 a.line('V full version', version.full_v_version(true))
19 //
20 mut os_kind := os.user_os()
21 mut arch_details := []string{}
22 arch_details << '${runtime.nr_cpus()} cpus'
23 if runtime.is_32bit() {
24 arch_details << '32bit'
25 }
26 if runtime.is_64bit() {
27 arch_details << '64bit'
28 }
29 if runtime.is_big_endian() {
30 arch_details << 'big endian'
31 }
32 if runtime.is_little_endian() {
33 arch_details << 'little endian'
34 }
35 if os_kind == 'macos' {
36 arch_details << a.cmd(command: 'sysctl -n machdep.cpu.brand_string')
37 }
38 if os_kind == 'linux' {
39 mut cpu_details := ''
40 if cpu_details == '' {
41 cpu_details = a.cpu_info('model name')
42 }
43 if cpu_details == '' {
44 cpu_details = a.cpu_info('hardware')
45 }
46 if cpu_details == '' {
47 cpu_details = os.uname().machine
48 }
49 arch_details << cpu_details
50 }
51 if os_kind == 'windows' {
52 arch_details << a.cmd(
53 command: 'wmic cpu get name /format:table'
54 line: 1
55 )
56 }
57 //
58 mut os_details := ''
59 wsl_check := a.cmd(command: 'cat /proc/sys/kernel/osrelease')
60 if os_kind == 'linux' {
61 os_details = a.get_linux_os_name()
62 if a.cpu_info('flags').contains('hypervisor') {
63 if wsl_check.contains('microsoft') {
64 // WSL 2 is a Managed VM and Full Linux Kernel
65 // See https://docs.microsoft.com/en-us/windows/wsl/compare-versions
66 os_details += ' (WSL 2)'
67 } else {
68 os_details += ' (VM)'
69 }
70 }
71 // WSL 1 is NOT a Managed VM and Full Linux Kernel
72 // See https://docs.microsoft.com/en-us/windows/wsl/compare-versions
73 if wsl_check.contains('Microsoft') {
74 os_details += ' (WSL)'
75 }
76 // From https://unix.stackexchange.com/a/14346
77 awk_cmd := '[ "$(awk \'\$5=="/" {print \$1}\' </proc/1/mountinfo)" != "$(awk \'\$5=="/" {print \$1}\' </proc/$$/mountinfo)" ] ; echo \$?'
78 if a.cmd(command: awk_cmd) == '0' {
79 os_details += ' (chroot)'
80 }
81 } else if os_kind == 'macos' {
82 mut details := []string{}
83 details << a.cmd(command: 'sw_vers -productName')
84 details << a.cmd(command: 'sw_vers -productVersion')
85 details << a.cmd(command: 'sw_vers -buildVersion')
86 os_details = details.join(', ')
87 } else if os_kind == 'windows' {
88 wmic_info := a.cmd(
89 command: 'wmic os get * /format:value'
90 line: -1
91 )
92 p := a.parse(wmic_info, '=')
93 caption, build_number, os_arch := p['caption'], p['buildnumber'], p['osarchitecture']
94 os_details = '${caption} v${build_number} ${os_arch}'
95 } else {
96 ouname := os.uname()
97 os_details = '${ouname.release}, ${ouname.version}'
98 }
99 a.line('OS', '${os_kind}, ${os_details}')
100 a.line('Processor', arch_details.join(', '))
101 a.println('')
102 getwd := os.getwd()
103 vmodules := os.vmodules_dir()
104 vtmp_dir := os.vtmp_dir()
105 vexe := os.getenv('VEXE')
106 vroot := os.dir(vexe)
107 os.chdir(vroot) or {}
108 a.line('getwd', getwd)
109 a.line('vexe', vexe)
110 a.line('vexe mtime', time.unix(os.file_last_mod_unix(vexe)).str())
111 a.println('')
112 a.line2('vroot', diagnose_dir(vroot), vroot)
113 a.line2('VMODULES', diagnose_dir(vmodules), vmodules)
114 a.line2('VTMP', diagnose_dir(vtmp_dir), vtmp_dir)
115 vflags := os.getenv('VFLAGS')
116 a.println('')
117 if vflags != '' {
118 a.line('env VFLAGS', '"${vflags}"')
119 a.println('')
120 }
121 a.line('Git version', a.cmd(command: 'git --version'))
122 a.line('Git vroot status', a.git_info())
123 a.line('.git/config present', os.is_file('.git/config').str())
124 a.println('')
125 //
126 a.line('CC version', a.cmd(command: 'cc --version'))
127 a.report_tcc_version('thirdparty/tcc')
128}
129
130struct CmdConfig {
131 line int
132 command string
133}
134
135fn (mut a App) cmd(c CmdConfig) string {
136 x := os.execute(c.command)
137 if x.exit_code < 0 {
138 return 'N/A'
139 }
140 if x.exit_code == 0 {
141 if c.line < 0 {
142 return x.output
143 }
144 output := x.output.split_into_lines()
145 if output.len > 0 && output.len > c.line {
146 return output[c.line]
147 }
148 }
149 return 'Error: ${x.output}'
150}
151
152fn (mut a App) line(label string, value string) {
153 a.println('${label}: ${term.colorize(term.bold, value)}')
154}
155
156fn (mut a App) line2(label string, value string, value2 string) {
157 a.println('${label}: ${term.colorize(term.bold, value)}, value: ${term.colorize(term.bold,
158 value2)}')
159}
160
161fn (app &App) parse(config string, sep string) map[string]string {
162 mut m := map[string]string{}
163 lines := config.split_into_lines()
164 for line in lines {
165 sline := line.trim_space()
166 if sline.len == 0 || sline[0] == `#` {
167 continue
168 }
169 x := sline.split(sep)
170 if x.len < 2 {
171 continue
172 }
173 m[x[0].trim_space().to_lower()] = x[1].trim_space().trim('"')
174 }
175 return m
176}
177
178fn (mut a App) get_linux_os_name() string {
179 mut os_details := ''
180 linux_os_methods := ['os-release', 'lsb_release', 'kernel', 'uname']
181 for m in linux_os_methods {
182 match m {
183 'os-release' {
184 if !os.is_file('/etc/os-release') {
185 continue
186 }
187 lines := os.read_file('/etc/os-release') or { continue }
188 vals := a.parse(lines, '=')
189 if vals['PRETTY_NAME'] == '' {
190 continue
191 }
192 os_details = vals['PRETTY_NAME']
193 break
194 }
195 'lsb_release' {
196 exists := a.cmd(command: 'type lsb_release')
197 if exists.starts_with('Error') {
198 continue
199 }
200 os_details = a.cmd(command: 'lsb_release -d -s')
201 break
202 }
203 'kernel' {
204 if !os.is_file('/proc/version') {
205 continue
206 }
207 os_details = a.cmd(command: 'cat /proc/version')
208 break
209 }
210 'uname' {
211 ouname := os.uname()
212 os_details = '${ouname.release}, ${ouname.version}'
213 break
214 }
215 else {}
216 }
217 }
218 return os_details
219}
220
221fn (mut a App) cpu_info(key string) string {
222 if a.cached_cpuinfo.len > 0 {
223 return a.cached_cpuinfo[key]
224 }
225 info := os.execute('cat /proc/cpuinfo')
226 if info.exit_code != 0 {
227 return '`cat /proc/cpuinfo` could not run'
228 }
229 a.cached_cpuinfo = a.parse(info.output, ':')
230 return a.cached_cpuinfo[key]
231}
232
233fn (mut a App) git_info() string {
234 mut out := a.cmd(command: 'git -C . describe --abbrev=8 --dirty --always --tags').trim_space()
235 os.execute('git -C . remote add V_REPO https://github.com/vlang/v') // ignore failure (i.e. remote exists)
236 os.execute('git -C . fetch V_REPO')
237 commit_count := a.cmd(command: 'git rev-list @{0}...V_REPO/master --right-only --count').int()
238 if commit_count > 0 {
239 out += ' (${commit_count} commit(s) behind V master)'
240 }
241 return out
242}
243
244fn (mut a App) report_tcc_version(tccfolder string) {
245 if !os.is_file(os.join_path(tccfolder, '.git', 'config')) {
246 a.line(tccfolder, 'N/A')
247 return
248 }
249 tcc_branch_name := a.cmd(
250 command: 'git -C ${os.quoted_path(tccfolder)} rev-parse --abbrev-ref HEAD'
251 )
252 tcc_commit := a.cmd(
253 command: 'git -C ${os.quoted_path(tccfolder)} describe --abbrev=8 --dirty --always --tags'
254 )
255 a.line('${tccfolder} status', '${tcc_branch_name} ${tcc_commit}')
256}
257
258fn (mut a App) report_info() {
259 for x in a.report_lines {
260 println(x)
261 }
262}
263
264fn is_writable_dir(path string) bool {
265 os.ensure_folder_is_writable(path) or { return false }
266 return true
267}
268
269fn diagnose_dir(path string) string {
270 mut diagnostics := []string{}
271 if !is_writable_dir(path) {
272 diagnostics << 'NOT writable'
273 }
274 if path.contains(' ') {
275 diagnostics << 'contains spaces'
276 }
277 path_non_ascii_runes := path.runes().filter(it > 255)
278 if path_non_ascii_runes.len > 0 {
279 diagnostics << 'contains these non ASCII characters: ${path_non_ascii_runes}'
280 }
281 if diagnostics.len == 0 {
282 diagnostics << 'OK'
283 }
284 return diagnostics.join(', ')
285}
286
287fn main() {
288 mut app := App{}
289 app.collect_info()
290 app.report_info()
291}