Browse Source

protoc: do NOT rely on GOBIN & GOPATH

Add public functions
loyalsoldier 5 years ago
parent
commit
a2a064a54d
1 changed files with 121 additions and 1 deletions
  1. 121 1
      common/common.go

+ 121 - 1
common/common.go

@@ -2,7 +2,16 @@
 // See each sub-package for detail.
 package common
 
-import "v2ray.com/core/common/errors"
+import (
+	"fmt"
+	"go/build"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"v2ray.com/core/common/errors"
+)
 
 //go:generate errorgen
 
@@ -28,3 +37,114 @@ func Must2(v interface{}, err error) interface{} {
 func Error2(v interface{}, err error) error {
 	return err
 }
+
+// envFile returns the name of the Go environment configuration file.
+// Copy from https://github.com/golang/go/blob/c4f2a9788a7be04daf931ac54382fbe2cb754938/src/cmd/go/internal/cfg/cfg.go#L150-L166
+func envFile() (string, error) {
+	if file := os.Getenv("GOENV"); file != "" {
+		if file == "off" {
+			return "", fmt.Errorf("GOENV=off")
+		}
+		return file, nil
+	}
+	dir, err := os.UserConfigDir()
+	if err != nil {
+		return "", err
+	}
+	if dir == "" {
+		return "", fmt.Errorf("missing user-config dir")
+	}
+	return filepath.Join(dir, "go", "env"), nil
+}
+
+// GetRuntimeEnv returns the value of runtime environment variable,
+// that is set by running following command: `go env -w key=value`.
+func GetRuntimeEnv(key string) (string, error) {
+	file, err := envFile()
+	if err != nil {
+		return "", err
+	}
+	if file == "" {
+		return "", fmt.Errorf("missing runtime env file")
+	}
+	var data []byte
+	var runtimeEnv string
+	data, readErr := ioutil.ReadFile(file)
+	if readErr != nil {
+		return "", readErr
+	}
+	envStrings := strings.Split(string(data), "\n")
+	for _, envItem := range envStrings {
+		envItem = strings.TrimSuffix(envItem, "\r")
+		envKeyValue := strings.Split(envItem, "=")
+		if strings.EqualFold(strings.TrimSpace(envKeyValue[0]), key) {
+			runtimeEnv = strings.TrimSpace(envKeyValue[1])
+		}
+	}
+	return runtimeEnv, nil
+}
+
+// GetGOBIN returns GOBIN environment variable as a string. It will NOT be empty.
+func GetGOBIN() string {
+	// The one set by user explicitly by `export GOBIN=/path` or `env GOBIN=/path command`
+	GOBIN := os.Getenv("GOBIN")
+	if GOBIN == "" {
+		var err error
+		// The one set by user by running `go env -w GOBIN=/path`
+		GOBIN, err = GetRuntimeEnv("GOBIN")
+		if err != nil {
+			// The default one that Golang uses
+			return filepath.Join(build.Default.GOPATH, "bin")
+		}
+		if GOBIN == "" {
+			return filepath.Join(build.Default.GOPATH, "bin")
+		}
+		return GOBIN
+	}
+	return GOBIN
+}
+
+// GetGOPATH returns GOPATH environment variable as a string. It will NOT be empty.
+func GetGOPATH() string {
+	// The one set by user explicitly by `export GOPATH=/path` or `env GOPATH=/path command`
+	GOPATH := os.Getenv("GOPATH")
+	if GOPATH == "" {
+		var err error
+		// The one set by user by running `go env -w GOPATH=/path`
+		GOPATH, err = GetRuntimeEnv("GOPATH")
+		if err != nil {
+			// The default one that Golang uses
+			return build.Default.GOPATH
+		}
+		if GOPATH == "" {
+			return build.Default.GOPATH
+		}
+		return GOPATH
+	}
+	return GOPATH
+}
+
+// GetModuleName returns the value of module in `go.mod` file.
+func GetModuleName(path string) (string, error) {
+	gomodPath := filepath.Join(path, "go.mod")
+	gomodBytes, err := ioutil.ReadFile(gomodPath)
+	if err != nil {
+		return "", err
+	}
+	gomodContent := string(gomodBytes)
+	moduleIdx := strings.Index(gomodContent, "module") + 6
+	newLineIdx := strings.Index(gomodContent, "\n")
+
+	var moduleName string
+	if moduleIdx >= 0 {
+		if newLineIdx >= 0 {
+			moduleName = strings.TrimSpace(gomodContent[moduleIdx:newLineIdx])
+			moduleName = strings.TrimSuffix(moduleName, "\r")
+		} else {
+			moduleName = strings.TrimSpace(gomodContent[moduleIdx:])
+		}
+	} else {
+		return "", fmt.Errorf("can not get the value of `module` in path `%s`", gomodPath)
+	}
+	return moduleName, nil
+}