Files
osmedeus/internal/installer/go_install.go
T
j3ssie baac7a016a feat: add worker management, hooks support, and db cleanup enhancements
- Add worker eval command for distributed function execution with Redis hooks registration
- Add worker set command to update worker fields (alias, public-ip, ssh-enabled, ssh-keys-path)
- Enhance worker status with JSON output, search filtering, and column selection (--columns, --exclude-columns, --search)
- Add --keep-setting flag to install base/validate commands to preserve osm-settings.yaml after base installation
- Fix binary installation in Nix: replace CopyInstalledBinaryToFolder with SymlinkInstalledBinaryToFolder
- Add --clean-ws flag to db clean command for removing workspace data
- Add HooksEnabled field to Run records when creating runs from CLI and API
- Add comprehensive test coverage for hook execution (pre/post hooks, execution order, failure handling)
- Add test coverage for worker commands (eval, set, status with JSON) and db clean operations
- Improve usage documentation for worker subcommands and db operations
2026-02-15 10:47:44 +07:00

148 lines
4.0 KiB
Go

package installer
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"github.com/j3ssie/osmedeus/v5/internal/logger"
"go.uber.org/zap"
)
// GoInstallOutput stores the last go install output for display
var GoInstallOutput string
// IsGoInstalled checks if Go toolchain is available in PATH
func IsGoInstalled() bool {
_, err := exec.LookPath("go")
return err == nil
}
// GetGoVersion returns the installed Go version
func GetGoVersion() (string, error) {
cmd := exec.Command("go", "version")
output, err := cmd.Output()
if err != nil {
return "", err
}
return strings.TrimSpace(string(output)), nil
}
// GetGoBinPath returns the GOBIN or GOPATH/bin directory
func GetGoBinPath() (string, error) {
// Try GOBIN first
cmd := exec.Command("go", "env", "GOBIN")
output, err := cmd.Output()
if err == nil {
gobin := strings.TrimSpace(string(output))
if gobin != "" {
return gobin, nil
}
}
// Fall back to GOPATH/bin
cmd = exec.Command("go", "env", "GOPATH")
output, err = cmd.Output()
if err != nil {
return "", fmt.Errorf("failed to get GOPATH: %w", err)
}
gopath := strings.TrimSpace(string(output))
if gopath == "" {
return "", fmt.Errorf("GOPATH is not set")
}
return filepath.Join(gopath, "bin"), nil
}
// InstallBinaryViaGo installs a binary using `go install` and optionally copies it to binariesFolder
func InstallBinaryViaGo(binaryName string, goPackage string, binariesFolder string) error {
if !IsGoInstalled() {
return fmt.Errorf("go toolchain is not installed")
}
// Ensure package has a version suffix
pkg := goPackage
if !strings.Contains(pkg, "@") {
pkg = pkg + "@latest"
}
logger.Get().Info("Installing via go install",
zap.String("binary", binaryName),
zap.String("package", pkg))
cmd := exec.Command("go", "install", pkg)
cmd.Env = os.Environ()
// Capture output for display
output, err := cmd.CombinedOutput()
GoInstallOutput = string(output)
if err != nil {
if len(output) > 0 {
return fmt.Errorf("failed to install %s via go install: %w\nOutput: %s", pkg, err, string(output))
}
return fmt.Errorf("failed to install %s via go install: %w", pkg, err)
}
// Symlink binary from GOBIN to binaries folder if specified
if binariesFolder != "" {
if err := symlinkGoBinaryToFolder(binaryName, binariesFolder); err != nil {
return fmt.Errorf("failed to symlink binary to folder: %w", err)
}
}
return nil
}
// symlinkGoBinaryToFolder finds a binary installed by go and symlinks it to the target folder
func symlinkGoBinaryToFolder(binaryName string, binariesFolder string) error {
goBinPath, err := GetGoBinPath()
if err != nil {
return err
}
srcPath := filepath.Join(goBinPath, binaryName)
if _, err := os.Stat(srcPath); err != nil {
// Try finding via which
cmd := exec.Command("which", binaryName)
output, whichErr := cmd.Output()
if whichErr != nil {
return fmt.Errorf("binary %s not found after go install (checked %s and PATH)", binaryName, srcPath)
}
srcPath = strings.TrimSpace(string(output))
}
// Ensure binaries folder exists
if err := os.MkdirAll(binariesFolder, 0755); err != nil {
return fmt.Errorf("failed to create binaries folder: %w", err)
}
destPath := filepath.Join(binariesFolder, binaryName)
logger.Get().Info("Symlinking binary to external folder",
zap.String("src", srcPath),
zap.String("dest", destPath))
return symlinkOrCopyFile(srcPath, destPath)
}
// GetGoPackageName returns the go_install package path for a binary
// Returns the GoInstall field if set, otherwise returns empty string
func GetGoPackageName(entry BinaryEntry, binaryName string) string {
if entry.GoInstall != "" {
return entry.GoInstall
}
return ""
}
// ExtractBinaryNameFromGoPackage extracts binary name from a go package path
// e.g., "github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest" -> "nuclei"
func ExtractBinaryNameFromGoPackage(pkg string) string {
// Remove version suffix
pkg = strings.Split(pkg, "@")[0]
// Get last path component
parts := strings.Split(pkg, "/")
return parts[len(parts)-1]
}