add a 'check go version' command to RPC (#2542)

This commit is contained in:
Mike Sawka 2025-11-10 22:46:56 -08:00 committed by GitHub
parent 7955bf6279
commit 3a08c5518d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 153 additions and 41 deletions

View file

@ -42,6 +42,11 @@ class RpcApiType {
return client.wshRpcCall("captureblockscreenshot", data, opts);
}
// command "checkgoversion" [call]
CheckGoVersionCommand(client: WshClient, opts?: RpcOpts): Promise<CommandCheckGoVersionRtnData> {
return client.wshRpcCall("checkgoversion", null, opts);
}
// command "connconnect" [call]
ConnConnectCommand(client: WshClient, data: ConnRequest, opts?: RpcOpts): Promise<void> {
return client.wshRpcCall("connconnect", data, opts);

View file

@ -173,6 +173,14 @@ declare global {
blockid: string;
};
// wshrpc.CommandCheckGoVersionRtnData
type CommandCheckGoVersionRtnData = {
gostatus: string;
gopath: string;
goversion: string;
errorstring?: string;
};
// wshrpc.CommandControllerAppendOutputData
type CommandControllerAppendOutputData = {
blockid: string;

View file

@ -59,6 +59,12 @@ func CaptureBlockScreenshotCommand(w *wshutil.WshRpc, data wshrpc.CommandCapture
return resp, err
}
// command "checkgoversion", wshserver.CheckGoVersionCommand
func CheckGoVersionCommand(w *wshutil.WshRpc, opts *wshrpc.RpcOpts) (*wshrpc.CommandCheckGoVersionRtnData, error) {
resp, err := sendRpcRequestCallHelper[*wshrpc.CommandCheckGoVersionRtnData](w, "checkgoversion", nil, opts)
return resp, err
}
// command "connconnect", wshserver.ConnConnectCommand
func ConnConnectCommand(w *wshutil.WshRpc, data wshrpc.ConnRequest, opts *wshrpc.RpcOpts) error {
_, err := sendRpcRequestCallHelper[any](w, "connconnect", data, opts)

View file

@ -167,6 +167,7 @@ const (
Command_StartBuilder = "startbuilder"
Command_GetBuilderStatus = "getbuilderstatus"
Command_GetBuilderOutput = "getbuilderoutput"
Command_CheckGoVersion = "checkgoversion"
// electron
Command_ElectronEncrypt = "electronencrypt"
@ -335,6 +336,7 @@ type WshRpcInterface interface {
StartBuilderCommand(ctx context.Context, data CommandStartBuilderData) error
GetBuilderStatusCommand(ctx context.Context, builderId string) (*BuilderStatusData, error)
GetBuilderOutputCommand(ctx context.Context, builderId string) ([]string, error)
CheckGoVersionCommand(ctx context.Context) (*CommandCheckGoVersionRtnData, error)
// proc
VDomRenderCommand(ctx context.Context, data vdom.VDomFrontendUpdate) chan RespOrErrorUnion[*vdom.VDomBackendUpdate]
@ -1018,6 +1020,13 @@ type BuilderStatusData struct {
Version int `json:"version"`
}
type CommandCheckGoVersionRtnData struct {
GoStatus string `json:"gostatus"`
GoPath string `json:"gopath"`
GoVersion string `json:"goversion"`
ErrorString string `json:"errorstring,omitempty"`
}
type CommandElectronEncryptData struct {
PlainText string `json:"plaintext"`
}

View file

@ -57,6 +57,7 @@ import (
"github.com/wavetermdev/waveterm/pkg/wsl"
"github.com/wavetermdev/waveterm/pkg/wslconn"
"github.com/wavetermdev/waveterm/pkg/wstore"
"github.com/wavetermdev/waveterm/tsunami/build"
)
var InvalidWslDistroNames = []string{"docker-desktop", "docker-desktop-data"}
@ -1073,6 +1074,21 @@ func (ws *WshServer) GetBuilderOutputCommand(ctx context.Context, builderId stri
return bc.GetOutput(), nil
}
func (ws *WshServer) CheckGoVersionCommand(ctx context.Context) (*wshrpc.CommandCheckGoVersionRtnData, error) {
watcher := wconfig.GetWatcher()
fullConfig := watcher.GetFullConfig()
goPath := fullConfig.Settings.TsunamiGoPath
result := build.CheckGoVersion(goPath)
return &wshrpc.CommandCheckGoVersionRtnData{
GoStatus: result.GoStatus,
GoPath: result.GoPath,
GoVersion: result.GoVersion,
ErrorString: result.ErrorString,
}, nil
}
func (ws *WshServer) RecordTEventCommand(ctx context.Context, data telemetrydata.TEvent) error {
err := telemetry.RecordTEvent(ctx, &data)
if err != nil {

View file

@ -119,6 +119,13 @@ func (opts BuildOpts) getNodePath() string {
return "node"
}
type GoVersionCheckResult struct {
GoStatus string
GoPath string
GoVersion string
ErrorString string
}
func FindGoExecutable() (string, error) {
// First try the standard PATH lookup
if goPath, err := exec.LookPath("go"); err == nil {
@ -156,6 +163,88 @@ func FindGoExecutable() (string, error) {
return "", fmt.Errorf("go command not found in PATH or common installation locations")
}
func CheckGoVersion(customGoPath string) GoVersionCheckResult {
var goPath string
var err error
if customGoPath != "" {
goPath = customGoPath
} else {
goPath, err = FindGoExecutable()
if err != nil {
return GoVersionCheckResult{
GoStatus: "notfound",
GoPath: "",
GoVersion: "",
ErrorString: "",
}
}
}
cmd := exec.Command(goPath, "version")
output, err := cmd.Output()
if err != nil {
return GoVersionCheckResult{
GoStatus: "error",
GoPath: goPath,
GoVersion: "",
ErrorString: fmt.Sprintf("failed to run 'go version': %v", err),
}
}
versionStr := strings.TrimSpace(string(output))
versionRegex := regexp.MustCompile(`go(1\.\d+)`)
matches := versionRegex.FindStringSubmatch(versionStr)
if len(matches) < 2 {
return GoVersionCheckResult{
GoStatus: "error",
GoPath: goPath,
GoVersion: versionStr,
ErrorString: fmt.Sprintf("unable to parse go version from: %s", versionStr),
}
}
goVersion := matches[1]
minorRegex := regexp.MustCompile(`1\.(\d+)`)
minorMatches := minorRegex.FindStringSubmatch(goVersion)
if len(minorMatches) < 2 {
return GoVersionCheckResult{
GoStatus: "error",
GoPath: goPath,
GoVersion: versionStr,
ErrorString: fmt.Sprintf("unable to parse minor version from: %s", goVersion),
}
}
minor, err := strconv.Atoi(minorMatches[1])
if err != nil {
return GoVersionCheckResult{
GoStatus: "error",
GoPath: goPath,
GoVersion: versionStr,
ErrorString: fmt.Sprintf("failed to parse minor version: %v", err),
}
}
if minor < MinSupportedGoMinorVersion {
return GoVersionCheckResult{
GoStatus: "badversion",
GoPath: goPath,
GoVersion: versionStr,
ErrorString: "",
}
}
return GoVersionCheckResult{
GoStatus: "ok",
GoPath: goPath,
GoVersion: versionStr,
ErrorString: "",
}
}
func verifyEnvironment(verbose bool, opts BuildOpts) (*BuildEnv, error) {
oc := opts.OutputCapture
@ -170,57 +259,36 @@ func verifyEnvironment(verbose bool, opts BuildOpts) (*BuildEnv, error) {
}
}
var goPath string
var err error
result := CheckGoVersion(opts.GoPath)
if opts.GoPath != "" {
goPath = opts.GoPath
switch result.GoStatus {
case "notfound":
return nil, fmt.Errorf("go command not found")
case "badversion":
return nil, fmt.Errorf("go version 1.%d or higher required, found: %s", MinSupportedGoMinorVersion, result.GoVersion)
case "error":
return nil, fmt.Errorf("%s", result.ErrorString)
case "ok":
if verbose {
oc.Printf("Using custom go path: %s", opts.GoPath)
}
} else {
goPath, err = FindGoExecutable()
if err != nil {
return nil, fmt.Errorf("go command not found: %w", err)
}
if verbose {
oc.Printf("Using go path: %s", goPath)
if opts.GoPath != "" {
oc.Printf("Using custom go path: %s", result.GoPath)
} else {
oc.Printf("Using go path: %s", result.GoPath)
}
oc.Printf("Found %s", result.GoVersion)
}
default:
return nil, fmt.Errorf("unexpected go status: %s", result.GoStatus)
}
// Run go version command
cmd := exec.Command(goPath, "version")
output, err := cmd.Output()
if err != nil {
return nil, fmt.Errorf("failed to run 'go version': %w", err)
}
// Parse go version output and check for 1.22+
versionStr := strings.TrimSpace(string(output))
if verbose {
oc.Printf("Found %s", versionStr)
}
// Extract version like "go1.22.0" from output
versionRegex := regexp.MustCompile(`go(1\.\d+)`)
matches := versionRegex.FindStringSubmatch(versionStr)
matches := versionRegex.FindStringSubmatch(result.GoVersion)
if len(matches) < 2 {
return nil, fmt.Errorf("unable to parse go version from: %s", versionStr)
return nil, fmt.Errorf("unable to parse go version from: %s", result.GoVersion)
}
goVersion := matches[1]
// Check if version is 1.22+
minorRegex := regexp.MustCompile(`1\.(\d+)`)
minorMatches := minorRegex.FindStringSubmatch(goVersion)
if len(minorMatches) < 2 {
return nil, fmt.Errorf("unable to parse minor version from: %s", goVersion)
}
minor, err := strconv.Atoi(minorMatches[1])
if err != nil || minor < MinSupportedGoMinorVersion {
return nil, fmt.Errorf("go version 1.%d or higher required, found: %s", MinSupportedGoMinorVersion, versionStr)
}
var err error
// Check if node is available
if opts.NodePath != "" {