346 lines
7.4 KiB
Go
346 lines
7.4 KiB
Go
package dependencies
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"regexp"
|
|
"runtime"
|
|
"strings"
|
|
|
|
"github.com/blang/semver"
|
|
"github.com/juju/errors"
|
|
|
|
"git.home.m-and-m.ovh/mderasse/gouick/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
|
|
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")
|
|
}
|
|
|
|
binaryPath, err := g.GetBinaryPath()
|
|
if err != nil {
|
|
return "", errors.Trace(err)
|
|
}
|
|
|
|
log.Debug("executing go version command")
|
|
|
|
cmd := exec.Command(binaryPath, "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) {
|
|
|
|
isInstalled, err := g.IsInstalled()
|
|
if err != nil {
|
|
return false, errors.Trace(err)
|
|
}
|
|
if !isInstalled {
|
|
return false, nil
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
// CanBeInstalled
|
|
func (g Golang) CanBeInstalled() bool {
|
|
return true
|
|
}
|
|
|
|
// DescribeInstall
|
|
func (g Golang) DescribeInstall(path string) string {
|
|
|
|
commands := []string{
|
|
"The following commands will be executed",
|
|
fmt.Sprintf("rm -rf %s/* ", path),
|
|
fmt.Sprintf("curl %s | tar --strip-components=1 -C %s -zxf -", g.getDownloadUrl(), path),
|
|
}
|
|
|
|
return strings.Join(commands, "\n")
|
|
}
|
|
|
|
// 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 := g.getDownloadUrl()
|
|
content, err := downloadFile(downloadUrl)
|
|
if err != nil {
|
|
log.Warnf("fail to download file from %s", downloadUrl)
|
|
return errors.Trace(err)
|
|
}
|
|
|
|
// zip on windows, tar gz on other platform
|
|
if runtime.GOOS == "windows" {
|
|
|
|
log.Debug("Working on zip, Unzip")
|
|
|
|
err = unZip(content, "go/", path)
|
|
if err != nil {
|
|
log.Warnf("fail to un-zip downloaded file from %s", downloadUrl)
|
|
return errors.Trace(err)
|
|
}
|
|
|
|
} else {
|
|
|
|
log.Debug("Working on tar gz, UnGzip & unTar")
|
|
|
|
gzipReader, err := unGzip(content)
|
|
if err != nil {
|
|
log.Warnf("fail to un-gzip downloaded file from %s, error:", downloadUrl)
|
|
return errors.Trace(err)
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
// DescribePostInstall
|
|
func (g Golang) DescribePostInstall(path string) string {
|
|
|
|
descriptions := []string{
|
|
`For your environment to work correctly, we will add if needed the following environment variable to your .bashrc:
|
|
|
|
export GOPATH=\"$HOME/go\"`,
|
|
fmt.Sprintf(" export GOROOT=\"%s\"", path),
|
|
` "PATH=\"$GOROOT/bin:$GOPATH/bin:$PATH\"
|
|
|
|
You will have to reopen a new terminal to apply the changes or execute the following command:
|
|
|
|
source $HOME/.bashrc
|
|
|
|
`,
|
|
}
|
|
|
|
return strings.Join(descriptions, "\n")
|
|
}
|
|
|
|
// PostInstall
|
|
func (g Golang) PostInstall(path string) error {
|
|
|
|
if runtime.GOOS == "windows" {
|
|
log.Warnf("Unable to environement variable on windows. Please add it by yourself")
|
|
return nil
|
|
}
|
|
|
|
lineBashRc := []string{
|
|
"# Golang - Added by gouick",
|
|
}
|
|
|
|
gopath := os.Getenv("GOPATH")
|
|
createGoPath := false
|
|
if gopath == "" {
|
|
lineBashRc = append(lineBashRc, "export GOPATH=\"$HOME/go\"")
|
|
createGoPath = true
|
|
}
|
|
|
|
goroot := os.Getenv("GOROOT")
|
|
if goroot == "" {
|
|
lineBashRc = append(lineBashRc, fmt.Sprintf("export GOROOT=\"%s\"", path))
|
|
}
|
|
|
|
// checking if go binary is found after installation
|
|
// if not it's probably not in the path
|
|
isInstalled, err := g.IsInstalled()
|
|
if err != nil {
|
|
return errors.Trace(err)
|
|
}
|
|
|
|
if !isInstalled {
|
|
lineBashRc = append(lineBashRc, "PATH=\"$GOROOT/bin:$GOPATH/bin:$PATH\"")
|
|
}
|
|
|
|
homeDir, err := os.UserHomeDir()
|
|
if err != nil {
|
|
return errors.Trace(err)
|
|
}
|
|
|
|
if len(lineBashRc) > 1 {
|
|
log.Debug("Adding env variable to .bashrc")
|
|
|
|
fh, err := os.OpenFile(
|
|
filepath.Join(homeDir, ".bashrc"),
|
|
os.O_APPEND|os.O_CREATE|os.O_WRONLY,
|
|
0644,
|
|
)
|
|
if err != nil {
|
|
return errors.Trace(err)
|
|
}
|
|
defer fh.Close()
|
|
|
|
_, err = fh.WriteString(
|
|
fmt.Sprintf("\n\n%s\n", strings.Join(lineBashRc, "\n")),
|
|
)
|
|
if err != nil {
|
|
return errors.Trace(err)
|
|
}
|
|
}
|
|
|
|
if createGoPath {
|
|
|
|
log.Debug("creating gopath directory")
|
|
|
|
err = helpers.CheckAndCreateDir(filepath.Join(homeDir, "go"))
|
|
if err != nil {
|
|
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 filepath.Join(homeDir, defaultGolangInstallDir), nil
|
|
}
|
|
|
|
// now let's play and find the current install path
|
|
binaryPath, err := g.GetBinaryPath()
|
|
if err != nil {
|
|
return "", errors.Trace(err)
|
|
}
|
|
|
|
log.Debug("executing go env GOROOT command")
|
|
|
|
cmd := exec.Command(binaryPath, "env", "GOROOT")
|
|
stdout, err := cmd.Output()
|
|
if err != nil {
|
|
return "", errors.Trace(err)
|
|
}
|
|
cleanOut := strings.TrimSpace(string(stdout))
|
|
|
|
if !strings.Contains(cleanOut, homeDir) {
|
|
return filepath.Join(homeDir, defaultGolangInstallDir), nil
|
|
}
|
|
|
|
return cleanOut, nil
|
|
}
|
|
|
|
func (g Golang) getDownloadUrl() string {
|
|
|
|
if runtime.GOOS == "windows" {
|
|
return fmt.Sprintf("https://dl.google.com/go/go%s.%s-%s.zip", minimumGolangVersion, runtime.GOOS, runtime.GOARCH)
|
|
} else {
|
|
return fmt.Sprintf("https://dl.google.com/go/go%s.%s-%s.tar.gz", minimumGolangVersion, runtime.GOOS, runtime.GOARCH)
|
|
}
|
|
}
|