From 0aec3a0b72dfa56d4af138d486f651d37777602d Mon Sep 17 00:00:00 2001 From: Dogan Can Bakir <65292895+dogancanbakir@users.noreply.github.com> Date: Wed, 11 Oct 2023 14:20:09 +0300 Subject: [PATCH] Introduce install type (#204) * minor refactor * introduce install type * remove duplicate log * remove getTool func * add version to log * check go installation * misc fix --------- Co-authored-by: sandeep <8293321+ehsandeep@users.noreply.github.com> --- .github/workflows/setup-test.yaml | 2 +- internal/runner/runner.go | 49 ++++++++++++++----------------- pkg/install.go | 16 ++++++++++ pkg/types/types.go | 8 +++++ 4 files changed, 47 insertions(+), 28 deletions(-) diff --git a/.github/workflows/setup-test.yaml b/.github/workflows/setup-test.yaml index f9a4667..4bd471f 100644 --- a/.github/workflows/setup-test.yaml +++ b/.github/workflows/setup-test.yaml @@ -51,7 +51,7 @@ jobs: - name: Checking tools existence run: | - go run . | grep -vz "not installed" + go run . | grep -v "not installed" working-directory: cmd/pdtm/ - name: Update Run - Update All The Tools diff --git a/internal/runner/runner.go b/internal/runner/runner.go index b987a8a..16e2c89 100644 --- a/internal/runner/runner.go +++ b/internal/runner/runner.go @@ -96,23 +96,28 @@ func (r *Runner) Run() error { gologger.Verbose().Msgf("using path %s", r.options.Path) for _, toolName := range r.options.Install { - if !path.IsSubPath(homeDir, r.options.Path) { gologger.Error().Msgf("skipping install outside home folder: %s", toolName) continue } if i, ok := utils.Contains(toolList, toolName); ok { - tool := getTool(toolName, toolList) - if err := pkg.Install(r.options.Path, toolList[i]); err != nil { + tool := toolList[i] + if tool.InstallType == types.Go && isGoInstalled() { + if err := pkg.GoInstall(r.options.Path, tool); err != nil { + gologger.Error().Msgf("%s: %s", tool.Name, err) + } + printRequirementInfo(tool) + continue + } + + if err := pkg.Install(r.options.Path, tool); err != nil { if errors.Is(err, types.ErrIsInstalled) { - gologger.Info().Msgf("%s: %s", toolName, err) + gologger.Info().Msgf("%s: %s", tool.Name, err) } else { - gologger.Error().Msgf("error while installing %s: %s", toolName, err) - gologger.Info().Msgf("trying to install %s using go install", toolName) - if err := fallbackGoInstall(tool); err != nil { - gologger.Error().Msgf("error while installing %s using go install: %s", toolName, err) - } else { - gologger.Info().Msgf("successfully installed %s using go install", toolName) + gologger.Error().Msgf("error while installing %s: %s", tool.Name, err) + gologger.Info().Msgf("trying to install %s using go install", tool.Name) + if err := pkg.GoInstall(r.options.Path, tool); err != nil { + gologger.Error().Msgf("%s: %s", tool.Name, err) } } } @@ -159,16 +164,15 @@ func (r *Runner) Run() error { return nil } -func fallbackGoInstall(tool *types.Tool) error { - cmd := exec.Command("go", "install", "-v", fmt.Sprintf("github.com/projectdiscovery/%s/%s", tool.Name, tool.GoInstallPath)) - cmd.Env = append(os.Environ(), "GOBIN="+defaultPath) - if output, err := cmd.CombinedOutput(); err != nil { - return fmt.Errorf("go install failed for %s: %s", tool.Name, string(output)) +func isGoInstalled() bool { + cmd := exec.Command("go", "version") + if err := cmd.Run(); err != nil { + return false } - return nil + return true } -func printRequirementInfo(tool *types.Tool) { +func printRequirementInfo(tool types.Tool) { specs := getSpecs(tool) printTitle := true @@ -201,7 +205,7 @@ func getFormattedInstruction(spec types.ToolRequirementSpecification) string { return strings.Replace(spec.Instruction, "$CMD", spec.Command, 1) } -func getSpecs(tool *types.Tool) []types.ToolRequirementSpecification { +func getSpecs(tool types.Tool) []types.ToolRequirementSpecification { var specs []types.ToolRequirementSpecification for _, requirement := range tool.Requirements { if requirement.OS == runtime.GOOS { @@ -255,15 +259,6 @@ func (r *Runner) ListToolsAndEnv(tools []types.Tool) error { // Close the runner instance func (r *Runner) Close() {} -func getTool(toolName string, tools []types.Tool) *types.Tool { - for _, tool := range tools { - if toolName == tool.Name { - return &tool - } - } - return nil -} - func requirementSatisfied(requirementName string) bool { if strings.HasPrefix(requirementName, "lib") { libNames := appendLibExtensionForOS(requirementName) diff --git a/pkg/install.go b/pkg/install.go index b3b77c4..72ddffd 100644 --- a/pkg/install.go +++ b/pkg/install.go @@ -10,6 +10,7 @@ import ( "io" "net/http" "os" + "os/exec" "path/filepath" "runtime" "strconv" @@ -41,6 +42,21 @@ func Install(path string, tool types.Tool) error { return nil } +// GoInstall installs given tool at path +func GoInstall(path string, tool types.Tool) error { + if _, exists := ospath.GetExecutablePath(path, tool.Name); exists { + return types.ErrIsInstalled + } + gologger.Info().Msgf("installing %s with go install...", tool.Name) + cmd := exec.Command("go", "install", "-v", fmt.Sprintf("github.com/projectdiscovery/%s/%s", tool.Name, tool.GoInstallPath)) + cmd.Env = append(os.Environ(), "GOBIN="+path) + if output, err := cmd.CombinedOutput(); err != nil { + return fmt.Errorf("go install failed %s", string(output)) + } + gologger.Info().Msgf("installed %s %s (%s)", tool.Name, tool.Version, au.BrightGreen("latest").String()) + return nil +} + func install(tool types.Tool, path string) (string, error) { builder := &strings.Builder{} builder.WriteString(tool.Name) diff --git a/pkg/types/types.go b/pkg/types/types.go index f4244d7..cbb2ec5 100644 --- a/pkg/types/types.go +++ b/pkg/types/types.go @@ -19,8 +19,16 @@ type Tool struct { GoInstallPath string `json:"go_install_path" yaml:"go_install_path"` Requirements []ToolRequirement `json:"requirements"` Assets map[string]string `json:"assets"` + InstallType InstallType `json:"install_type" yaml:"install_type"` } +type InstallType string + +const ( + Binary InstallType = "binary" + Go InstallType = "go" +) + type ToolRequirement struct { OS string `json:"os"` Specification []ToolRequirementSpecification `json:"specification"`