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  }