github.com/goplus/gop@v1.2.6/env/path.go (about) 1 /* 2 * Copyright (c) 2021 The GoPlus Authors (goplus.org). All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package env 18 19 import ( 20 "log" 21 "os" 22 "path/filepath" 23 "syscall" 24 ) 25 26 var ( 27 // This is set by the linker. 28 defaultGopRoot string 29 ) 30 31 // GOPROOT returns the root of the Go+ tree. It uses the GOPROOT environment variable, 32 // if set at process start, or else the root used during the Go+ build. 33 func GOPROOT() string { 34 gopRoot, err := findGopRoot() 35 if err != nil { 36 log.Panicln("GOPROOT not found:", err) 37 } 38 return gopRoot 39 } 40 41 const ( 42 envGOPROOT = "GOPROOT" 43 ) 44 45 func findGopRoot() (string, error) { 46 envGopRoot := os.Getenv(envGOPROOT) 47 if envGopRoot != "" { 48 // GOPROOT must valid 49 if isValidGopRoot(envGopRoot) { 50 return envGopRoot, nil 51 } 52 log.Panicf("\n%s (%s) is not valid\n", envGOPROOT, envGopRoot) 53 } 54 55 // if parent directory is a valid gop root, use it 56 exePath, err := executableRealPath() 57 if err == nil { 58 dir := filepath.Dir(exePath) 59 parentDir := filepath.Dir(dir) 60 if parentDir != dir && isValidGopRoot(parentDir) { 61 return parentDir, nil 62 } 63 } 64 65 // check defaultGopRoot, if it is valid, use it 66 if defaultGopRoot != "" && isValidGopRoot(defaultGopRoot) { 67 return defaultGopRoot, nil 68 } 69 70 // Compatible with old GOPROOT 71 if home := HOME(); home != "" { 72 gopRoot := filepath.Join(home, "gop") 73 if isValidGopRoot(gopRoot) { 74 return gopRoot, nil 75 } 76 goplusRoot := filepath.Join(home, "goplus") 77 if isValidGopRoot(goplusRoot) { 78 return goplusRoot, nil 79 } 80 } 81 return "", syscall.ENOENT 82 } 83 84 // Mockable for testing. 85 var executable = func() (string, error) { 86 return os.Executable() 87 } 88 89 func executableRealPath() (path string, err error) { 90 path, err = executable() 91 if err == nil { 92 path, err = filepath.EvalSymlinks(path) 93 if err == nil { 94 path, err = filepath.Abs(path) 95 } 96 } 97 return 98 } 99 100 func isFileExists(path string) bool { 101 st, err := os.Stat(path) 102 return err == nil && !st.IsDir() 103 } 104 105 func isDirExists(path string) bool { 106 st, err := os.Stat(path) 107 return err == nil && st.IsDir() 108 } 109 110 func isValidGopRoot(path string) bool { 111 return isDirExists(filepath.Join(path, "cmd/gop")) && isFileExists(filepath.Join(path, "go.mod")) 112 }