...

Source file src/oss.terrastruct.com/util-go/xexec/xexec.go

Documentation: oss.terrastruct.com/util-go/xexec

     1  package xexec
     2  
     3  import (
     4  	"io/fs"
     5  	"os"
     6  	"path/filepath"
     7  	"runtime"
     8  	"strings"
     9  )
    10  
    11  // findExecutable is from package os/exec
    12  func findExecutable(file string) error {
    13  	d, err := os.Stat(file)
    14  	if err != nil {
    15  		return err
    16  	}
    17  	m := d.Mode()
    18  	if !m.IsDir() && m&0111 != 0 {
    19  		return nil
    20  	}
    21  	return fs.ErrPermission
    22  }
    23  
    24  // SearchPath searches for all executables that have prefix in their names in
    25  // the directories named by the PATH environment variable.
    26  func SearchPath(prefix string) ([]string, error) {
    27  	var matches []string
    28  	envPath := os.Getenv("PATH")
    29  	dirSet := make(map[string]struct{})
    30  	for _, dir := range filepath.SplitList(envPath) {
    31  		if dir == "" {
    32  			// From exec package:
    33  			// Unix shell semantics: path element "" means "."
    34  			dir = "."
    35  		}
    36  		if _, ok := dirSet[dir]; ok {
    37  			continue
    38  		}
    39  		dirSet[dir] = struct{}{}
    40  		files, err := os.ReadDir(dir)
    41  		if err != nil {
    42  			continue
    43  		}
    44  		for _, f := range files {
    45  			if strings.HasPrefix(f.Name(), prefix) {
    46  				match := filepath.Join(dir, f.Name())
    47  				// Unideal but I don't want to maintain two separate implementations of this
    48  				// function like os/exec.
    49  				if runtime.GOOS == "windows" {
    50  					matches = append(matches, match)
    51  					continue
    52  				}
    53  				err = findExecutable(match)
    54  				if err == nil {
    55  					matches = append(matches, match)
    56  				}
    57  			}
    58  		}
    59  
    60  	}
    61  	return matches, nil
    62  }
    63  

View as plain text