github.com/eagleql/xray-core@v1.4.4/common/common.go (about)

     1  // Package common contains common utilities that are shared among other packages.
     2  // See each sub-package for detail.
     3  package common
     4  
     5  import (
     6  	"fmt"
     7  	"go/build"
     8  	"io/ioutil"
     9  	"os"
    10  	"path/filepath"
    11  	"strings"
    12  
    13  	"github.com/eagleql/xray-core/common/errors"
    14  )
    15  
    16  //go:generate go run github.com/eagleql/xray-core/common/errors/errorgen
    17  
    18  var (
    19  	// ErrNoClue is for the situation that existing information is not enough to make a decision. For example, Router may return this error when there is no suitable route.
    20  	ErrNoClue = errors.New("not enough information for making a decision")
    21  )
    22  
    23  // Must panics if err is not nil.
    24  func Must(err error) {
    25  	if err != nil {
    26  		panic(err)
    27  	}
    28  }
    29  
    30  // Must2 panics if the second parameter is not nil, otherwise returns the first parameter.
    31  func Must2(v interface{}, err error) interface{} {
    32  	Must(err)
    33  	return v
    34  }
    35  
    36  // Error2 returns the err from the 2nd parameter.
    37  func Error2(v interface{}, err error) error {
    38  	return err
    39  }
    40  
    41  // envFile returns the name of the Go environment configuration file.
    42  // Copy from https://github.com/golang/go/blob/c4f2a9788a7be04daf931ac54382fbe2cb754938/src/cmd/go/internal/cfg/cfg.go#L150-L166
    43  func envFile() (string, error) {
    44  	if file := os.Getenv("GOENV"); file != "" {
    45  		if file == "off" {
    46  			return "", fmt.Errorf("GOENV=off")
    47  		}
    48  		return file, nil
    49  	}
    50  	dir, err := os.UserConfigDir()
    51  	if err != nil {
    52  		return "", err
    53  	}
    54  	if dir == "" {
    55  		return "", fmt.Errorf("missing user-config dir")
    56  	}
    57  	return filepath.Join(dir, "go", "env"), nil
    58  }
    59  
    60  // GetRuntimeEnv returns the value of runtime environment variable,
    61  // that is set by running following command: `go env -w key=value`.
    62  func GetRuntimeEnv(key string) (string, error) {
    63  	file, err := envFile()
    64  	if err != nil {
    65  		return "", err
    66  	}
    67  	if file == "" {
    68  		return "", fmt.Errorf("missing runtime env file")
    69  	}
    70  	var data []byte
    71  	var runtimeEnv string
    72  	data, readErr := ioutil.ReadFile(file)
    73  	if readErr != nil {
    74  		return "", readErr
    75  	}
    76  	envStrings := strings.Split(string(data), "\n")
    77  	for _, envItem := range envStrings {
    78  		envItem = strings.TrimSuffix(envItem, "\r")
    79  		envKeyValue := strings.Split(envItem, "=")
    80  		if strings.EqualFold(strings.TrimSpace(envKeyValue[0]), key) {
    81  			runtimeEnv = strings.TrimSpace(envKeyValue[1])
    82  		}
    83  	}
    84  	return runtimeEnv, nil
    85  }
    86  
    87  // GetGOBIN returns GOBIN environment variable as a string. It will NOT be empty.
    88  func GetGOBIN() string {
    89  	// The one set by user explicitly by `export GOBIN=/path` or `env GOBIN=/path command`
    90  	GOBIN := os.Getenv("GOBIN")
    91  	if GOBIN == "" {
    92  		var err error
    93  		// The one set by user by running `go env -w GOBIN=/path`
    94  		GOBIN, err = GetRuntimeEnv("GOBIN")
    95  		if err != nil {
    96  			// The default one that Golang uses
    97  			return filepath.Join(build.Default.GOPATH, "bin")
    98  		}
    99  		if GOBIN == "" {
   100  			return filepath.Join(build.Default.GOPATH, "bin")
   101  		}
   102  		return GOBIN
   103  	}
   104  	return GOBIN
   105  }
   106  
   107  // GetGOPATH returns GOPATH environment variable as a string. It will NOT be empty.
   108  func GetGOPATH() string {
   109  	// The one set by user explicitly by `export GOPATH=/path` or `env GOPATH=/path command`
   110  	GOPATH := os.Getenv("GOPATH")
   111  	if GOPATH == "" {
   112  		var err error
   113  		// The one set by user by running `go env -w GOPATH=/path`
   114  		GOPATH, err = GetRuntimeEnv("GOPATH")
   115  		if err != nil {
   116  			// The default one that Golang uses
   117  			return build.Default.GOPATH
   118  		}
   119  		if GOPATH == "" {
   120  			return build.Default.GOPATH
   121  		}
   122  		return GOPATH
   123  	}
   124  	return GOPATH
   125  }
   126  
   127  // GetModuleName returns the value of module in `go.mod` file.
   128  func GetModuleName(pathToProjectRoot string) (string, error) {
   129  	var moduleName string
   130  	loopPath := pathToProjectRoot
   131  	for {
   132  		if idx := strings.LastIndex(loopPath, string(filepath.Separator)); idx >= 0 {
   133  			gomodPath := filepath.Join(loopPath, "go.mod")
   134  			gomodBytes, err := ioutil.ReadFile(gomodPath)
   135  			if err != nil {
   136  				loopPath = loopPath[:idx]
   137  				continue
   138  			}
   139  
   140  			gomodContent := string(gomodBytes)
   141  			moduleIdx := strings.Index(gomodContent, "module ")
   142  			newLineIdx := strings.Index(gomodContent, "\n")
   143  
   144  			if moduleIdx >= 0 {
   145  				if newLineIdx >= 0 {
   146  					moduleName = strings.TrimSpace(gomodContent[moduleIdx+6 : newLineIdx])
   147  					moduleName = strings.TrimSuffix(moduleName, "\r")
   148  				} else {
   149  					moduleName = strings.TrimSpace(gomodContent[moduleIdx+6:])
   150  				}
   151  				return moduleName, nil
   152  			}
   153  			return "", fmt.Errorf("can not get module path in `%s`", gomodPath)
   154  		}
   155  		break
   156  	}
   157  	return moduleName, fmt.Errorf("no `go.mod` file in every parent directory of `%s`", pathToProjectRoot)
   158  }