Files
pmg/internal/shim/path.go
T

76 lines
1.7 KiB
Go
Raw Normal View History

package shim
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"sync"
"github.com/safedep/dry/log"
)
const pmgBinSuffix = "/.pmg/bin"
var resolverMu sync.Mutex
func FilterPMGFromPath(pathEnv string) string {
if pathEnv == "" {
return ""
}
entries := filepath.SplitList(pathEnv)
filtered := make([]string, 0, len(entries))
for _, entry := range entries {
if !strings.HasSuffix(entry, pmgBinSuffix) {
filtered = append(filtered, entry)
}
}
return strings.Join(filtered, string(os.PathListSeparator))
}
// ResolveRealBinary finds the real binary path for a command by searching
// PATH with ~/.pmg/bin stripped out. This prevents exec.CommandContext from
// resolving to the shim script, which would cause infinite recursion.
func ResolveRealBinary(name string) (string, error) {
resolverMu.Lock()
defer resolverMu.Unlock()
originalPath := os.Getenv("PATH")
filteredPath := FilterPMGFromPath(originalPath)
if err := os.Setenv("PATH", filteredPath); err != nil {
return "", fmt.Errorf("failed to set filtered PATH: %w", err)
}
defer func() {
if err := os.Setenv("PATH", originalPath); err != nil {
log.Warnf("failed to restore PATH: %v", err)
}
}()
resolved, err := exec.LookPath(name)
if err != nil {
return "", fmt.Errorf("could not find %s in PATH (excluding pmg shims): %w", name, err)
}
return resolved, nil
}
func FilterPMGFromEnv(env []string) []string {
result := make([]string, 0, len(env))
for _, entry := range env {
if pathValue, ok := strings.CutPrefix(entry, "PATH="); ok {
filtered := FilterPMGFromPath(pathValue)
result = append(result, "PATH="+filtered)
} else {
result = append(result, entry)
}
}
return result
}