mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-04 09:09:28 +08:00
275 lines
7.2 KiB
Go
275 lines
7.2 KiB
Go
package doctor
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"regexp"
|
|
"runtime"
|
|
"runtime/debug"
|
|
"slices"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/wailsapp/wails/v3/internal/term"
|
|
|
|
"github.com/wailsapp/wails/v3/internal/buildinfo"
|
|
|
|
"github.com/go-git/go-git/v5"
|
|
"github.com/jaypipes/ghw"
|
|
"github.com/pterm/pterm"
|
|
"github.com/samber/lo"
|
|
"github.com/wailsapp/wails/v3/internal/operatingsystem"
|
|
"github.com/wailsapp/wails/v3/internal/version"
|
|
)
|
|
|
|
func Run() (err error) {
|
|
|
|
get, err := buildinfo.Get()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_ = get
|
|
|
|
term.Header("Wails Doctor")
|
|
|
|
spinner, _ := pterm.DefaultSpinner.WithRemoveWhenDone().Start("Scanning system - Please wait (this may take a long time)...")
|
|
|
|
defer func() {
|
|
if err != nil {
|
|
spinner.Fail()
|
|
}
|
|
}()
|
|
|
|
/** Build **/
|
|
|
|
// BuildSettings contains the build settings for the application
|
|
var BuildSettings map[string]string
|
|
|
|
// BuildInfo contains the build info for the application
|
|
var BuildInfo *debug.BuildInfo
|
|
|
|
var ok bool
|
|
BuildInfo, ok = debug.ReadBuildInfo()
|
|
if !ok {
|
|
return fmt.Errorf("could not read build info from binary")
|
|
}
|
|
BuildSettings = lo.Associate(BuildInfo.Settings, func(setting debug.BuildSetting) (string, string) {
|
|
return setting.Key, setting.Value
|
|
})
|
|
|
|
/** Operating System **/
|
|
|
|
// Get system info
|
|
info, err := operatingsystem.Info()
|
|
if err != nil {
|
|
term.Error("Failed to get system information")
|
|
return err
|
|
}
|
|
|
|
/** Wails **/
|
|
|
|
wailsPackage, _ := lo.Find(BuildInfo.Deps, func(dep *debug.Module) bool {
|
|
return dep.Path == "github.com/wailsapp/wails/v3"
|
|
})
|
|
|
|
wailsVersion := strings.TrimSpace(version.String())
|
|
if wailsPackage != nil && wailsPackage.Replace != nil {
|
|
wailsVersion = "(local) => " + filepath.ToSlash(wailsPackage.Replace.Path)
|
|
// Get the latest commit hash
|
|
repo, err := git.PlainOpen(filepath.Join(wailsPackage.Replace.Path, ".."))
|
|
if err == nil {
|
|
head, err := repo.Head()
|
|
if err == nil {
|
|
wailsVersion += " (" + head.Hash().String()[:8] + ")"
|
|
}
|
|
}
|
|
}
|
|
|
|
platformExtras, ok := getInfo()
|
|
|
|
dependencies := make(map[string]string)
|
|
checkPlatformDependencies(dependencies, &ok)
|
|
|
|
spinner.Success()
|
|
|
|
/** Output **/
|
|
|
|
term.Section("System")
|
|
|
|
systemTabledata := pterm.TableData{
|
|
{pterm.Sprint("Name"), info.Name},
|
|
{pterm.Sprint("Version"), info.Version},
|
|
{pterm.Sprint("ID"), info.ID},
|
|
{pterm.Sprint("Branding"), info.Branding},
|
|
|
|
{pterm.Sprint("Platform"), runtime.GOOS},
|
|
{pterm.Sprint("Architecture"), runtime.GOARCH},
|
|
}
|
|
|
|
mapKeys := lo.Keys(platformExtras)
|
|
slices.Sort(mapKeys)
|
|
for _, key := range mapKeys {
|
|
systemTabledata = append(systemTabledata, []string{key, platformExtras[key]})
|
|
}
|
|
|
|
// Probe CPU
|
|
cpus, _ := ghw.CPU()
|
|
if cpus != nil {
|
|
prefix := "CPU"
|
|
for idx, cpu := range cpus.Processors {
|
|
if len(cpus.Processors) > 1 {
|
|
prefix = "CPU " + strconv.Itoa(idx+1)
|
|
}
|
|
systemTabledata = append(systemTabledata, []string{prefix, cpu.Model})
|
|
}
|
|
} else {
|
|
systemTabledata = append(systemTabledata, []string{"CPU", "Unknown"})
|
|
}
|
|
|
|
// Probe GPU
|
|
gpu, _ := ghw.GPU(ghw.WithDisableWarnings())
|
|
if gpu != nil {
|
|
for idx, card := range gpu.GraphicsCards {
|
|
details := "Unknown"
|
|
prefix := "GPU " + strconv.Itoa(idx+1)
|
|
if card.DeviceInfo != nil {
|
|
details = fmt.Sprintf("%s (%s) - Driver: %s ", card.DeviceInfo.Product.Name, card.DeviceInfo.Vendor.Name, card.DeviceInfo.Driver)
|
|
}
|
|
systemTabledata = append(systemTabledata, []string{prefix, details})
|
|
}
|
|
} else {
|
|
if runtime.GOOS == "darwin" {
|
|
var numCoresValue string
|
|
cmd := exec.Command("sh", "-c", "ioreg -l | grep gpu-core-count")
|
|
output, err := cmd.Output()
|
|
if err == nil {
|
|
// Look for an `=` sign, optional spaces and then an integer
|
|
re := regexp.MustCompile(`= *(\d+)`)
|
|
matches := re.FindAllStringSubmatch(string(output), -1)
|
|
numCoresValue = "Unknown"
|
|
if len(matches) > 0 {
|
|
numCoresValue = matches[0][1]
|
|
}
|
|
|
|
}
|
|
|
|
// Run `system_profiler SPDisplaysDataType | grep Metal`
|
|
var metalSupport string
|
|
cmd = exec.Command("sh", "-c", "system_profiler SPDisplaysDataType | grep Metal")
|
|
output, err = cmd.Output()
|
|
if err == nil {
|
|
metalSupport = ", " + strings.TrimSpace(string(output))
|
|
}
|
|
systemTabledata = append(systemTabledata, []string{"GPU", numCoresValue + " cores" + metalSupport})
|
|
|
|
} else {
|
|
systemTabledata = append(systemTabledata, []string{"GPU", "Unknown"})
|
|
}
|
|
}
|
|
|
|
memory, _ := ghw.Memory()
|
|
var memoryText = "Unknown"
|
|
if memory != nil {
|
|
memoryText = strconv.Itoa(int(memory.TotalPhysicalBytes/1024/1024/1024)) + "GB"
|
|
} else {
|
|
if runtime.GOOS == "darwin" {
|
|
cmd := exec.Command("sh", "-c", "system_profiler SPHardwareDataType | grep 'Memory'")
|
|
output, err := cmd.Output()
|
|
if err == nil {
|
|
output = bytes.Replace(output, []byte("Memory: "), []byte(""), 1)
|
|
memoryText = strings.TrimSpace(string(output))
|
|
}
|
|
}
|
|
}
|
|
systemTabledata = append(systemTabledata, []string{"Memory", memoryText})
|
|
|
|
err = pterm.DefaultTable.WithBoxed().WithData(systemTabledata).Render()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Build Environment
|
|
|
|
term.Section("Build Environment")
|
|
|
|
tableData := pterm.TableData{
|
|
{"Wails CLI", wailsVersion},
|
|
{"Go Version", runtime.Version()},
|
|
}
|
|
|
|
if buildInfo, _ := debug.ReadBuildInfo(); buildInfo != nil {
|
|
buildSettingToName := map[string]string{
|
|
"vcs.revision": "Revision",
|
|
"vcs.modified": "Modified",
|
|
}
|
|
for _, buildSetting := range buildInfo.Settings {
|
|
name := buildSettingToName[buildSetting.Key]
|
|
if name == "" {
|
|
continue
|
|
}
|
|
tableData = append(tableData, []string{name, buildSetting.Value})
|
|
}
|
|
}
|
|
|
|
mapKeys = lo.Keys(BuildSettings)
|
|
slices.Sort(mapKeys)
|
|
for _, key := range mapKeys {
|
|
tableData = append(tableData, []string{key, BuildSettings[key]})
|
|
}
|
|
|
|
err = pterm.DefaultTable.WithBoxed(true).WithData(tableData).Render()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Dependencies
|
|
term.Section("Dependencies")
|
|
dependenciesBox := pterm.DefaultBox.WithTitleBottomCenter().WithTitle(pterm.Gray("*") + " - Optional Dependency")
|
|
dependencyTableData := pterm.TableData{}
|
|
if len(dependencies) == 0 {
|
|
pterm.Info.Println("No dependencies found")
|
|
} else {
|
|
var optionals pterm.TableData
|
|
mapKeys = lo.Keys(dependencies)
|
|
for _, key := range mapKeys {
|
|
if strings.HasPrefix(dependencies[key], "*") {
|
|
optionals = append(optionals, []string{key, dependencies[key]})
|
|
} else {
|
|
dependencyTableData = append(dependencyTableData, []string{key, dependencies[key]})
|
|
}
|
|
}
|
|
dependencyTableData = append(dependencyTableData, optionals...)
|
|
dependenciesTableString, _ := pterm.DefaultTable.WithData(dependencyTableData).Srender()
|
|
dependenciesBox.Println(dependenciesTableString)
|
|
}
|
|
|
|
// Run diagnostics after system info
|
|
term.Section("Checking for issues")
|
|
|
|
diagnosticResults := RunDiagnostics()
|
|
if len(diagnosticResults) == 0 {
|
|
pterm.Success.Println("No issues found")
|
|
} else {
|
|
pterm.Warning.Println("Found potential issues:")
|
|
for _, result := range diagnosticResults {
|
|
pterm.Printf("• %s: %s\n", result.TestName, result.ErrorMsg)
|
|
url := result.HelpURL
|
|
if strings.HasPrefix(url, "/") {
|
|
url = "https://v3.wails.io" + url
|
|
}
|
|
pterm.Printf(" For more information: %s\n", term.Hyperlink(url, url))
|
|
}
|
|
}
|
|
|
|
term.Section("Diagnosis")
|
|
if !ok {
|
|
term.Warning("There are some items above that need addressing!")
|
|
} else {
|
|
term.Success("Your system is ready for Wails development!")
|
|
}
|
|
|
|
return nil
|
|
}
|