2022-07-15 22:16:59 +00:00
|
|
|
package dependencies
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2022-08-03 11:17:15 +00:00
|
|
|
"io"
|
2022-07-15 22:16:59 +00:00
|
|
|
"os"
|
|
|
|
"os/exec"
|
2022-07-16 22:16:29 +00:00
|
|
|
"path/filepath"
|
2022-07-15 22:16:59 +00:00
|
|
|
"regexp"
|
|
|
|
"runtime"
|
|
|
|
"strings"
|
|
|
|
|
2022-08-09 15:53:40 +00:00
|
|
|
"git.home.m-and-m.ovh/mderasse/gouick/models"
|
2022-07-15 22:16:59 +00:00
|
|
|
"github.com/blang/semver"
|
|
|
|
"github.com/juju/errors"
|
|
|
|
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
)
|
|
|
|
|
2022-08-03 11:17:15 +00:00
|
|
|
// minimumGolangVersion is the minimum minor required for the app to work.
|
2022-11-21 17:22:17 +00:00
|
|
|
const minimumSwaggerVersion = "0.30.3"
|
2022-07-15 22:16:59 +00:00
|
|
|
|
|
|
|
// installation directory for fresh install.
|
2022-08-03 11:17:15 +00:00
|
|
|
// will be prefixed by $HOME.
|
2022-07-15 22:16:59 +00:00
|
|
|
const defaultSwaggerInstallDir = "/bin"
|
|
|
|
|
|
|
|
var regexSwaggerVersion = regexp.MustCompile(`^version: v(\d+\.\d+\.\d+)`)
|
|
|
|
|
2022-08-03 11:17:15 +00:00
|
|
|
// Swagger represent an empty struct respecting the DependencyInterface.
|
2022-07-15 22:16:59 +00:00
|
|
|
type Swagger struct{}
|
|
|
|
|
2022-08-03 11:17:15 +00:00
|
|
|
// regroup all swagger dependencies function.
|
2022-07-15 22:16:59 +00:00
|
|
|
|
2022-08-03 11:17:15 +00:00
|
|
|
// GetName return the name of the dependency using DependencyName enum.
|
|
|
|
func (s Swagger) GetName() models.DependencyName {
|
|
|
|
return models.DependencyName_GO_SWAGGER
|
2022-07-15 22:16:59 +00:00
|
|
|
}
|
|
|
|
|
2022-08-03 11:17:15 +00:00
|
|
|
// GetMinimumVersion return the minimum version required for that dependency.
|
2022-07-15 22:16:59 +00:00
|
|
|
func (s Swagger) GetMinimumVersion() string {
|
|
|
|
return minimumSwaggerVersion
|
|
|
|
}
|
|
|
|
|
2022-08-03 11:17:15 +00:00
|
|
|
// IsInstalled check if the dependency is installed on the system.
|
2022-07-15 22:16:59 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2022-08-03 11:17:15 +00:00
|
|
|
// GetBinaryPath will search for the binary and return the path if found.
|
2022-07-15 22:16:59 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2022-08-03 11:17:15 +00:00
|
|
|
// GetVersion will find the current version of the dependency.
|
2022-07-15 22:16:59 +00:00
|
|
|
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")
|
|
|
|
|
2022-08-03 11:17:15 +00:00
|
|
|
//nolint:gosec // we trust the binary we are launching
|
2022-07-15 22:16:59 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2022-08-03 11:17:15 +00:00
|
|
|
// IsVersionSupported will compare the current version with the minimum expected version.
|
2022-07-15 22:16:59 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2022-07-16 15:46:09 +00:00
|
|
|
if installedVersion.LT(requiredVersion) {
|
2022-07-15 22:16:59 +00:00
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
2022-08-03 11:17:15 +00:00
|
|
|
// CanBeInstalled define if the dependency installation is handled by the app.
|
2022-07-16 15:46:09 +00:00
|
|
|
func (s Swagger) CanBeInstalled() bool {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2022-08-03 11:17:15 +00:00
|
|
|
// DescribeInstall will list the aciton that will be executed for the dependency update or installation.
|
2022-07-15 22:16:59 +00:00
|
|
|
func (s Swagger) DescribeInstall(path string) string {
|
|
|
|
commands := []string{
|
|
|
|
"The following commands will be executed",
|
|
|
|
fmt.Sprintf("rm -rf %s/swagger ", path),
|
2022-08-02 20:33:47 +00:00
|
|
|
fmt.Sprintf("wget %s -O %s/swagger", s.getDownloadURL(), path),
|
2022-07-15 22:16:59 +00:00
|
|
|
fmt.Sprintf("chmod 644 %s/swagger", path),
|
|
|
|
}
|
|
|
|
|
|
|
|
return strings.Join(commands, "\n")
|
|
|
|
}
|
|
|
|
|
2022-08-03 11:17:15 +00:00
|
|
|
// Install will install or update the dependency.
|
2022-07-15 22:16:59 +00:00
|
|
|
func (s Swagger) Install(path string) error {
|
2022-08-02 20:33:47 +00:00
|
|
|
downloadURL := s.getDownloadURL()
|
|
|
|
content, err := downloadFile(downloadURL)
|
2022-07-15 22:16:59 +00:00
|
|
|
if err != nil {
|
2022-08-02 20:33:47 +00:00
|
|
|
log.Warnf("fail to download file from %s", downloadURL)
|
2022-07-15 22:16:59 +00:00
|
|
|
return errors.Trace(err)
|
|
|
|
}
|
|
|
|
|
2022-08-03 13:36:13 +00:00
|
|
|
//nolint:gosec // we did compute the file path
|
2022-07-15 22:16:59 +00:00
|
|
|
fh, err := os.OpenFile(
|
2022-07-16 22:16:29 +00:00
|
|
|
filepath.Join(path, "swagger"),
|
2022-07-15 22:16:59 +00:00
|
|
|
os.O_RDWR|os.O_CREATE|os.O_TRUNC,
|
2022-08-03 11:17:15 +00:00
|
|
|
0600,
|
2022-07-15 22:16:59 +00:00
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Trace(err)
|
|
|
|
}
|
|
|
|
|
2022-08-03 11:17:15 +00:00
|
|
|
defer func() {
|
|
|
|
if err := fh.Close(); err != nil {
|
|
|
|
log.Errorf("Error closing file: %s", err)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
bContent, err := io.ReadAll(content)
|
2022-07-15 22:16:59 +00:00
|
|
|
if err != nil {
|
|
|
|
return errors.Trace(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = fh.Write(bContent)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Trace(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-08-03 11:17:15 +00:00
|
|
|
// DescribePostInstall will list the post installation action that will be executed.
|
2022-07-15 22:16:59 +00:00
|
|
|
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:
|
|
|
|
|
2022-11-21 17:22:17 +00:00
|
|
|
PATH="$HOME/bin:$PATH"
|
2022-07-15 22:16:59 +00:00
|
|
|
|
|
|
|
You will have to reopen a new terminal to apply the changes or execute the following command:
|
|
|
|
|
|
|
|
source $HOME/.bashrc
|
|
|
|
|
|
|
|
`
|
|
|
|
}
|
|
|
|
|
2022-08-03 11:17:15 +00:00
|
|
|
// PostInstall will execute the post installation or update of the dependency.
|
2022-07-15 22:16:59 +00:00
|
|
|
func (s Swagger) PostInstall(path string) error {
|
|
|
|
lineBashRc := []string{
|
2022-07-25 20:43:53 +00:00
|
|
|
"# Swagger - Added by gouick",
|
2022-07-15 22:16:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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")
|
|
|
|
|
2022-08-03 13:36:13 +00:00
|
|
|
//nolint:gosec // we did compute the file path
|
2022-07-15 22:16:59 +00:00
|
|
|
fh, err := os.OpenFile(
|
2022-07-16 22:16:29 +00:00
|
|
|
filepath.Join(homeDir, ".bashrc"),
|
2022-07-15 22:16:59 +00:00
|
|
|
os.O_APPEND|os.O_CREATE|os.O_WRONLY,
|
2022-08-03 11:17:15 +00:00
|
|
|
0600,
|
2022-07-15 22:16:59 +00:00
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Trace(err)
|
|
|
|
}
|
2022-08-03 11:17:15 +00:00
|
|
|
|
|
|
|
defer func() {
|
|
|
|
if err := fh.Close(); err != nil {
|
|
|
|
log.Errorf("Error closing file: %s", err)
|
|
|
|
}
|
|
|
|
}()
|
2022-07-15 22:16:59 +00:00
|
|
|
|
|
|
|
_, 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"
|
2022-08-03 11:17:15 +00:00
|
|
|
// It doesn't mean that the directory is "writable".
|
2022-07-15 22:16:59 +00:00
|
|
|
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 {
|
2022-07-16 22:16:29 +00:00
|
|
|
return filepath.Join(homeDir, defaultSwaggerInstallDir), nil
|
2022-07-15 22:16:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2022-08-02 20:33:47 +00:00
|
|
|
func (s Swagger) getDownloadURL() string {
|
2022-07-15 22:16:59 +00:00
|
|
|
return fmt.Sprintf("https://github.com/go-swagger/go-swagger/releases/download/v%s/swagger_%s_%s", minimumSwaggerVersion, runtime.GOOS, runtime.GOARCH)
|
|
|
|
}
|