|
|
@@ -0,0 +1,126 @@
|
|
|
+/*
|
|
|
+Copyright (c) 2009 The Go Authors. All rights reserved.
|
|
|
+
|
|
|
+Redistribution and use in source and binary forms, with or without
|
|
|
+modification, are permitted provided that the following conditions are
|
|
|
+met:
|
|
|
+
|
|
|
+* Redistributions of source code must retain the above copyright
|
|
|
+notice, this list of conditions and the following disclaimer.
|
|
|
+* Redistributions in binary form must reproduce the above
|
|
|
+copyright notice, this list of conditions and the following disclaimer
|
|
|
+in the documentation and/or other materials provided with the
|
|
|
+distribution.
|
|
|
+* Neither the name of Google Inc. nor the names of its
|
|
|
+contributors may be used to endorse or promote products derived from
|
|
|
+this software without specific prior written permission.
|
|
|
+
|
|
|
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
+*/
|
|
|
+
|
|
|
+package resolvepath
|
|
|
+
|
|
|
+import (
|
|
|
+ "errors"
|
|
|
+ "os"
|
|
|
+ "os/exec"
|
|
|
+ "path/filepath"
|
|
|
+ "strings"
|
|
|
+)
|
|
|
+
|
|
|
+// ErrNotFound is the error resulting if a path search failed to find an executable file.
|
|
|
+var ErrNotFound = errors.New("executable file not found in %PATH%")
|
|
|
+
|
|
|
+func chkStat(file string) error {
|
|
|
+ d, err := os.Stat(file)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ if d.IsDir() {
|
|
|
+ return os.ErrPermission
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func hasExt(file string) bool {
|
|
|
+ i := strings.LastIndex(file, ".")
|
|
|
+ if i < 0 {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ return strings.LastIndexAny(file, `:\/`) < i
|
|
|
+}
|
|
|
+
|
|
|
+func findExecutable(file string, exts []string) (string, error) {
|
|
|
+ if len(exts) == 0 {
|
|
|
+ return file, chkStat(file)
|
|
|
+ }
|
|
|
+ if hasExt(file) {
|
|
|
+ if chkStat(file) == nil {
|
|
|
+ return file, nil
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for _, e := range exts {
|
|
|
+ if f := file + e; chkStat(f) == nil {
|
|
|
+ return f, nil
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return "", os.ErrNotExist
|
|
|
+}
|
|
|
+
|
|
|
+// LookPath searches for an executable named file in the
|
|
|
+// directories named by the PATH environment variable.
|
|
|
+// If file contains a slash, it is tried directly and the PATH is not consulted.
|
|
|
+// LookPath also uses PATHEXT environment variable to match
|
|
|
+// a suitable candidate.
|
|
|
+// The result may be an absolute path or a path relative to the current directory.
|
|
|
+func LookPath(file string) (string, error) {
|
|
|
+ var exts []string
|
|
|
+ x := os.Getenv(`PATHEXT`)
|
|
|
+ if x != "" {
|
|
|
+ for _, e := range strings.Split(strings.ToLower(x), `;`) {
|
|
|
+ if e == "" {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ if e[0] != '.' {
|
|
|
+ e = "." + e
|
|
|
+ }
|
|
|
+ exts = append(exts, e)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ exts = []string{".com", ".exe", ".bat", ".cmd"}
|
|
|
+ }
|
|
|
+
|
|
|
+ if strings.ContainsAny(file, `:\/`) {
|
|
|
+ if f, err := findExecutable(file, exts); err == nil {
|
|
|
+ return f, nil
|
|
|
+ } else {
|
|
|
+ return "", &exec.Error{file, err}
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // See https://github.com/golang/go/issues/38736
|
|
|
+ // DO NOT lookup current folder
|
|
|
+ //if f, err := findExecutable(filepath.Join(".", file), exts); err == nil {
|
|
|
+ // return f, nil
|
|
|
+ //}
|
|
|
+ path := os.Getenv("path")
|
|
|
+ for _, dir := range filepath.SplitList(path) {
|
|
|
+ // empty dir means dupicate semicolon in PATH, should not resolve files in current working dir...
|
|
|
+ if strings.TrimSpace(dir) == "" {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ if f, err := findExecutable(filepath.Join(dir, file), exts); err == nil {
|
|
|
+ return f, nil
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return "", &exec.Error{file, ErrNotFound}
|
|
|
+}
|