feat(dependencies): Add postinstall process and swagger dependency

This commit is contained in:
Matthieu 'JP' DERASSE
2022-07-15 22:16:59 +00:00
parent f04f5513ab
commit 7c9cc568ab
8 changed files with 430 additions and 22 deletions

View File

@ -66,7 +66,7 @@ func (g Golang) GetBinaryPath() (string, error) {
return path, nil
}
// GetVersion return the major, minor and patch version of Golang
// GetVersion
func (g Golang) GetVersion() (string, error) {
isInstalled, err := g.IsInstalled()
@ -78,14 +78,14 @@ func (g Golang) GetVersion() (string, error) {
return "", errors.NotFoundf("golang is not installed on the system")
}
golangPath, err := g.GetBinaryPath()
binaryPath, err := g.GetBinaryPath()
if err != nil {
return "", errors.Trace(err)
}
log.Debug("executing go version command")
cmd := exec.Command(golangPath, "version")
cmd := exec.Command(binaryPath, "version")
stdout, err := cmd.Output()
if err != nil {
return "", errors.Trace(err)
@ -105,6 +105,14 @@ func (g Golang) GetVersion() (string, error) {
// 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)
@ -130,9 +138,13 @@ func (g Golang) IsVersionSupported() (bool, error) {
// 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
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
@ -143,7 +155,7 @@ func (g Golang) Install(path string) error {
log.Warnf("fail to delete content of directory %s", path)
}
downloadUrl := getDownloadUrl()
downloadUrl := g.getDownloadUrl()
content, err := downloadFile(downloadUrl)
if err != nil {
log.Warnf("fail to download file from %s", downloadUrl)
@ -166,6 +178,95 @@ func (g Golang) Install(path string) error {
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 {
lineBashRc := []string{
"# Golang - Added by goguik",
}
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(
fmt.Sprintf("%s.bashrc", homeDir),
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(fmt.Sprintf("%sgo", homeDir))
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"
@ -183,18 +284,18 @@ func (g Golang) GetInstallDirectory() (string, error) {
// concat default install dir with home and we have our path
if !isInstalled {
return fmt.Sprintf("%s/%s", homeDir, defaultGolangInstallDir), nil
return fmt.Sprintf("%s%s", homeDir, defaultGolangInstallDir), nil
}
// now let's play and find the current install path
golangPath, err := g.GetBinaryPath()
binaryPath, err := g.GetBinaryPath()
if err != nil {
return "", errors.Trace(err)
}
log.Debug("executing go env GOROOT command")
cmd := exec.Command(golangPath, "env", "GOROOT")
cmd := exec.Command(binaryPath, "env", "GOROOT")
stdout, err := cmd.Output()
if err != nil {
return "", errors.Trace(err)
@ -202,13 +303,13 @@ func (g Golang) GetInstallDirectory() (string, error) {
cleanOut := strings.TrimSpace(string(stdout))
if !strings.Contains(cleanOut, homeDir) {
return fmt.Sprintf("%s/%s", homeDir, defaultGolangInstallDir), nil
return fmt.Sprintf("%s%s", homeDir, defaultGolangInstallDir), nil
}
return cleanOut, nil
}
func getDownloadUrl() string {
func (g Golang) getDownloadUrl() string {
return fmt.Sprintf("https://dl.google.com/go/go%s.%s-%s.tar.gz", minimumGolangVersion, runtime.GOOS, runtime.GOARCH)
}

View File

@ -3,12 +3,14 @@ package dependencies
// Dependency
type Dependency interface {
DescribeInstall(path string) string
DescribePostInstall(path string) string
GetBinaryPath() (string, error)
GetInstallDirectory() (string, error)
GetName() string
GetMinimumVersion() string
GetVersion() (string, error)
Install(path string) error
PostInstall(path string) error
IsInstalled() (bool, error)
IsVersionSupported() (bool, error)
}

View File

@ -0,0 +1,276 @@
package dependencies
import (
"fmt"
"io/ioutil"
"os"
"os/exec"
"regexp"
"runtime"
"strings"
"github.com/blang/semver"
"github.com/juju/errors"
log "github.com/sirupsen/logrus"
)
// minimum minor required for the app to work
const minimumSwaggerVersion = "0.29.0"
// installation directory for fresh install.
// will be prefixed by $HOME
const defaultSwaggerInstallDir = "/bin"
var regexSwaggerVersion = regexp.MustCompile(`^version: v(\d+\.\d+\.\d+)`)
type Swagger struct{}
// regroup all swagger dependencies function
// GetName
func (s Swagger) GetName() string {
return "Go Swagger"
}
// GetMinimumVersion
func (s Swagger) GetMinimumVersion() string {
return minimumSwaggerVersion
}
// IsInstalled
func (s Swagger) IsInstalled() (bool, error) {
_, err := s.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 (s Swagger) GetBinaryPath() (string, error) {
log.Debug("looking for swagger binary")
path, err := exec.LookPath("swagger")
if err != nil {
return "", errors.Trace(err)
}
log.Debug("found swagger binary in", path)
return path, nil
}
// GetVersion
func (s Swagger) GetVersion() (string, error) {
isInstalled, err := s.IsInstalled()
if err != nil {
return "", errors.Trace(err)
}
if !isInstalled {
return "", errors.NotFoundf("swagger is not installed on the system")
}
binaryPath, err := s.GetBinaryPath()
if err != nil {
return "", errors.Trace(err)
}
log.Debug("executing swagger 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("swagger version returned %s", cleanOut)
parseOutput := regexSwaggerVersion.FindStringSubmatch(cleanOut)
if len(parseOutput) != 2 {
return "", errors.NotSupportedf("failed to parse swagger version output: %s", cleanOut)
}
return parseOutput[1], nil
}
// IsVersionSupported
func (s Swagger) IsVersionSupported() (bool, error) {
isInstalled, err := s.IsInstalled()
if err != nil {
return false, errors.Trace(err)
}
if !isInstalled {
return false, nil
}
version, err := s.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(minimumSwaggerVersion)
if err != nil {
return false, errors.Trace(err)
}
if installedVersion.LT(*&requiredVersion) {
return false, nil
}
return true, nil
}
// DescribeInstall
func (s Swagger) DescribeInstall(path string) string {
commands := []string{
"The following commands will be executed",
fmt.Sprintf("rm -rf %s/swagger ", path),
fmt.Sprintf("wget %s -O %s/swagger", s.getDownloadUrl(), path),
fmt.Sprintf("chmod 644 %s/swagger", path),
}
return strings.Join(commands, "\n")
}
// Install
func (s Swagger) Install(path string) error {
downloadUrl := s.getDownloadUrl()
content, err := downloadFile(downloadUrl)
if err != nil {
log.Warnf("fail to download file from %s", downloadUrl)
return errors.Trace(err)
}
fh, err := os.OpenFile(
fmt.Sprintf("%s/swagger", path),
os.O_RDWR|os.O_CREATE|os.O_TRUNC,
0744,
)
if err != nil {
return errors.Trace(err)
}
defer fh.Close()
bContent, err := ioutil.ReadAll(content)
if err != nil {
return errors.Trace(err)
}
_, err = fh.Write(bContent)
if err != nil {
return errors.Trace(err)
}
return nil
}
// DescribePostInstall
func (s Swagger) DescribePostInstall(path string) string {
return `For your environment to work correctly, we will add if needed the following environment variable to your .bashrc:
PATH=\"$HOME/bin:$PATH\"
You will have to reopen a new terminal to apply the changes or execute the following command:
source $HOME/.bashrc
`
}
// PostInstall
func (s Swagger) PostInstall(path string) error {
lineBashRc := []string{
"# Swagger - Added by goguik",
}
// checking if swagger binary is found after installation
// if not it's probably not in the path
isInstalled, err := s.IsInstalled()
if err != nil {
return errors.Trace(err)
}
if !isInstalled {
lineBashRc = append(lineBashRc, "PATH=\"$HOME/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(
fmt.Sprintf("%s.bashrc", homeDir),
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)
}
}
return nil
}
// GetInstallDirectory will try to find the current swagger 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 (s Swagger) GetInstallDirectory() (string, error) {
homeDir, err := os.UserHomeDir()
if err != nil {
return "", errors.Trace(err)
}
isInstalled, err := s.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, defaultSwaggerInstallDir), nil
}
// now let's play and find the current install path
binaryPath, err := s.GetBinaryPath()
if err != nil {
return "", errors.Trace(err)
}
return strings.TrimSuffix(binaryPath, "/swagger"), nil
}
func (s Swagger) getDownloadUrl() string {
return fmt.Sprintf("https://github.com/go-swagger/go-swagger/releases/download/v%s/swagger_%s_%s", minimumSwaggerVersion, runtime.GOOS, runtime.GOARCH)
}

View File

@ -70,7 +70,7 @@ func unTar(reader io.Reader, subdir string, dest string) error {
if subdir != "" && strings.HasPrefix(filename, subdir) {
filename = strings.Replace(filename, subdir, "", 1)
filename = strings.TrimPrefix(filename, subdir)
if filename == "" {
continue