-
Notifications
You must be signed in to change notification settings - Fork 190
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
👔 up: sysutil - add new OSVersionInfo for parse Windows version info
- Loading branch information
Showing
2 changed files
with
165 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
package sysutil | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/gookit/goutil/errorx" | ||
"github.com/gookit/goutil/strutil" | ||
) | ||
|
||
// OSVersionInfo 结构体用于存储操作系统版本信息 | ||
// | ||
// NOTE: Windows 10 和 Windows 11 在主版本号和次版本号上是相同的,因此需要通过构建号(win11: DwBuildNumber>=22000)来进一步区分 | ||
type OSVersionInfo struct { | ||
// 主版本号 | ||
MajorVersion uint16 | ||
// 次版本号 | ||
MinorVersion uint16 | ||
// 构建号 | ||
BuildNumber uint32 | ||
// 修订号 | ||
RevisionNumber uint32 | ||
} | ||
|
||
// FetchOsVersion Get Windows system version information | ||
// | ||
// 还可用使用dll获取: | ||
// | ||
// 通过 GetVersion, GetVersionEx 函数获取的信息不准确. win11获取到 6.2.9200, 实际是 10.0.22631 | ||
func FetchOsVersion() (*OSVersionInfo, error) { | ||
// Windows cmd 执行 ver 命令 | ||
out, err := ShellExec("ver", "cmd") | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return parseOsVersionString(out) | ||
} | ||
|
||
// IsLtWindows7 判断是否小于 Windows 7 | ||
func (ov *OSVersionInfo) IsLtWindows7() bool { | ||
return ov.MajorVersion < 6 || (ov.MajorVersion == 6 && ov.MinorVersion < 1) | ||
} | ||
|
||
// IsWindows7 判断是否为 Windows 7 | ||
func (ov *OSVersionInfo) IsWindows7() bool { | ||
return ov.MajorVersion == 6 && ov.MinorVersion == 1 | ||
} | ||
|
||
// IsWindows8 判断是否为 Windows 8 | ||
func (ov *OSVersionInfo) IsWindows8() bool { | ||
return ov.MajorVersion == 6 && ov.MinorVersion == 2 | ||
} | ||
|
||
// IsWindows10 判断是否为 Windows 10 | ||
func (ov *OSVersionInfo) IsWindows10() bool { | ||
return ov.MajorVersion == 10 && ov.MinorVersion == 0 && ov.BuildNumber < 22000 | ||
} | ||
|
||
// IsWindows11 判断是否为 Windows 11 | ||
func (ov *OSVersionInfo) IsWindows11() bool { | ||
return ov.MajorVersion == 10 && ov.MinorVersion == 0 && ov.BuildNumber >= 22000 | ||
} | ||
|
||
// Name 获取 Windows 通用的版本名称. eg: xp, win7, win8, win10, win11, unknown | ||
func (ov *OSVersionInfo) Name() string { | ||
switch ov.MajorVersion { | ||
case 10: | ||
if ov.BuildNumber < 22000 { | ||
return "win10" | ||
} else { | ||
return "win11" | ||
} | ||
case 6: | ||
switch ov.MinorVersion { | ||
case 0: | ||
return "vista" | ||
case 1: | ||
return "win7" | ||
case 2: | ||
return "win8" | ||
case 3: | ||
return "win8.1" | ||
} | ||
case 5: | ||
switch ov.MinorVersion { | ||
case 1: | ||
return "xp" | ||
case 2: | ||
return "ws2003" // win server 2003 | ||
} | ||
} | ||
return "unknown" | ||
} | ||
|
||
// String format | ||
func (ov *OSVersionInfo) String() string { | ||
return fmt.Sprintf("%d.%d.%d", ov.MajorVersion, ov.MinorVersion, ov.BuildNumber) | ||
} | ||
|
||
func parseOsVersionString(out string) (*OSVersionInfo, error) { | ||
// out eg: Microsoft Windows [Version 10.0.22631.4391] => 10.0.22631.4391 | ||
// 部分系统会输出中文 eg: Microsoft Windows [版本 10.0.22631.4391] | ||
out = strings.TrimSpace(out) | ||
ns := strings.SplitN(out, "[", 2) | ||
if len(ns) < 2 { | ||
return nil, errorx.Rawf("cannot parse version info: %s", out) | ||
} | ||
|
||
ns = strutil.SplitByWhitespace(strings.Trim(ns[1], "]")) | ||
if len(ns) < 2 { | ||
return nil, errorx.Rawf("cannot parse version info2: %s", out) | ||
} | ||
|
||
var err error | ||
var ovi OSVersionInfo | ||
// get like: 10.0.22631.4391 or 10.0.22631 | ||
verStr := ns[1] | ||
|
||
if strings.Count(verStr, ".") >= 3 { | ||
_, err = fmt.Sscanf(verStr, "%d.%d.%d.%d", &ovi.MajorVersion, &ovi.MinorVersion, &ovi.BuildNumber, &ovi.RevisionNumber) | ||
} else { | ||
_, err = fmt.Sscanf(verStr, "%d.%d.%d", &ovi.MajorVersion, &ovi.MinorVersion, &ovi.BuildNumber) | ||
} | ||
|
||
if err != nil { | ||
return nil, errorx.Rawf("parse version info %q error: %v", verStr, err) | ||
} | ||
return &ovi, nil | ||
} | ||
|
||
// 全局变量 | ||
var stdOv, stdErr = FetchOsVersion() | ||
|
||
// OsVersion Get operating system version information | ||
func OsVersion() *OSVersionInfo { | ||
return stdOv | ||
} | ||
|
||
// OvParseError error on parse os version info | ||
func OvParseError() error { | ||
return stdErr | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
//go:build windows | ||
// +build windows | ||
|
||
package sysutil_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/gookit/goutil/dump" | ||
"github.com/gookit/goutil/sysutil" | ||
"github.com/gookit/goutil/testutil/assert" | ||
) | ||
|
||
func TestFetchOsVersion(t *testing.T) { | ||
ov, err := sysutil.FetchOsVersion() | ||
assert.NoErr(t, err) | ||
assert.NotEmpty(t, ov) | ||
assert.NotEmpty(t, ov.String()) | ||
|
||
dump.P(ov.Name(), ov) | ||
assert.NotEmpty(t, sysutil.OsVersion()) | ||
} |