package dependencies import ( "fmt" "os" "os/exec" "regexp" "runtime" "strings" "github.com/blang/semver" "github.com/juju/errors" "git.home.m-and-m.ovh/mderasse/boot/helpers" log "github.com/sirupsen/logrus" ) // minimum minor required for the app to work const minimumGolangVersion = "1.18.4" // installation directory for fresh install. // will be prefixed by $HOME const defaultGolangInstallDir = "/local/go" var regexGolangVersion = regexp.MustCompile(`^go version go(\d+\.\d+\.\d+)`) type Golang struct{} // regroup all golang dependencies function // GetName func (g Golang) GetName() string { return "Golang" } // GetMinimumVersion func (g Golang) GetMinimumVersion() string { return minimumGolangVersion } // IsInstalled func (g Golang) IsInstalled() (bool, error) { _, err := g.GetBinaryPath() if err != nil && !errors.Is(err, exec.ErrNotFound) { return false, errors.Trace(err) } else if err != nil && errors.Is(err, exec.ErrNotFound) { return false, nil } return true, nil } // GetBinaryPath func (g Golang) GetBinaryPath() (string, error) { log.Debug("looking for golang binary") path, err := exec.LookPath("go") if err != nil { return "", errors.Trace(err) } log.Debug("found golang binary in", path) return path, nil } // GetVersion return the major, minor and patch version of Golang func (g Golang) GetVersion() (string, error) { isInstalled, err := g.IsInstalled() if err != nil { return "", errors.Trace(err) } if !isInstalled { return "", errors.NotFoundf("golang is not installed on the system") } golangPath, err := g.GetBinaryPath() if err != nil { return "", errors.Trace(err) } log.Debug("executing go version command") cmd := exec.Command(golangPath, "version") stdout, err := cmd.Output() if err != nil { return "", errors.Trace(err) } cleanOut := strings.TrimSpace(string(stdout)) log.Debugf("go version returned %s", cleanOut) parseOutput := regexGolangVersion.FindStringSubmatch(cleanOut) if len(parseOutput) != 2 { return "", errors.NotSupportedf("failed to parse golang version output: %s", cleanOut) } return parseOutput[1], nil } // IsVersionSupported func (g Golang) IsVersionSupported() (bool, error) { version, err := g.GetVersion() if err != nil { return false, errors.Trace(err) } installedVersion, err := semver.Make(version) if err != nil { return false, errors.Trace(err) } requiredVersion, _ := semver.Make(minimumGolangVersion) if err != nil { return false, errors.Trace(err) } if installedVersion.LT(*&requiredVersion) { return false, nil } return true, nil } // DescribeInstall func (g Golang) DescribeInstall(path string) string { description := fmt.Sprintf("rm -rf %s/* ", path) description = fmt.Sprintf("%s\ncurl %s | tar --strip-components=1 -C %s -zxf -", description, getDownloadUrl(), path) return description } // Install func (g Golang) Install(path string) error { err := helpers.RemoveDirectoryContent(path) if err != nil { log.Warnf("fail to delete content of directory %s", path) } downloadUrl := getDownloadUrl() content, err := downloadFile(downloadUrl) if err != nil { log.Warnf("fail to download file from %s", downloadUrl) return errors.Trace(err) } gzipReader, err := unGzip(content) if err != nil { log.Warnf("fail to un-gzip downloaded file from %s, error:", downloadUrl) return errors.Trace(err) } // XXX: unTar should take a subdir err = unTar(gzipReader, "go/", path) if err != nil { log.Warnf("fail to un-tar downloaded file from %s", downloadUrl) return errors.Trace(err) } return nil } // GetInstallDirectory will try to find the current golang directory. If it doesn't exist or if it's in a // not userspace directory, it will provide the "default" // It doesn't mean that the directory is "writable" func (g Golang) GetInstallDirectory() (string, error) { homeDir, err := os.UserHomeDir() if err != nil { return "", errors.Trace(err) } isInstalled, err := g.IsInstalled() if err != nil { return "", errors.Trace(err) } // concat default install dir with home and we have our path if !isInstalled { return fmt.Sprintf("%s/%s", homeDir, defaultGolangInstallDir), nil } // now let's play and find the current install path golangPath, err := g.GetBinaryPath() if err != nil { return "", errors.Trace(err) } log.Debug("executing go env GOROOT command") cmd := exec.Command(golangPath, "env", "GOROOT") stdout, err := cmd.Output() if err != nil { return "", errors.Trace(err) } cleanOut := strings.TrimSpace(string(stdout)) if !strings.Contains(cleanOut, homeDir) { return fmt.Sprintf("%s/%s", homeDir, defaultGolangInstallDir), nil } return cleanOut, nil } func getDownloadUrl() string { return fmt.Sprintf("https://dl.google.com/go/go%s.%s-%s.tar.gz", minimumGolangVersion, runtime.GOOS, runtime.GOARCH) }