Browse Source

Feat: format code in one-key (#802)

Loyalsoldier 4 years ago
parent
commit
921c6d71ee
2 changed files with 184 additions and 0 deletions
  1. 4 0
      format.go
  2. 180 0
      infra/vformat/main.go

+ 4 - 0
format.go

@@ -0,0 +1,4 @@
+package core
+
+//go:generate go install -v golang.org/x/tools/cmd/goimports@latest
+//go:generate go run ./infra/vformat/

+ 180 - 0
infra/vformat/main.go

@@ -0,0 +1,180 @@
+package main
+
+import (
+	"fmt"
+	"go/build"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"runtime"
+	"strings"
+)
+
+// 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
+}
+
+func Run(binary string, args []string) (string, error) {
+	cmd := exec.Command(binary, args...)
+	cmd.Env = append(cmd.Env, os.Environ()...)
+	output, cmdErr := cmd.CombinedOutput()
+	if cmdErr != nil {
+		return "", cmdErr
+	}
+	if len(output) > 0 {
+		return string(output), nil
+	}
+	return "", nil
+}
+
+func RunMany(binary string, args, files []string) {
+	fmt.Println("Processing...")
+	for _, file := range files {
+		args2 := append(args, file)
+		output, err := Run(binary, args2)
+		if err != nil {
+			fmt.Println(err)
+			continue
+		}
+		if len(output) > 0 {
+			fmt.Println(output)
+		}
+	}
+}
+
+func main() {
+	pwd, err := os.Getwd()
+	if err != nil {
+		fmt.Println("Can not get current working directory.")
+		os.Exit(1)
+	}
+
+	GOBIN := GetGOBIN()
+	binPath := os.Getenv("PATH")
+	pathSlice := []string{pwd, GOBIN, binPath}
+	binPath = strings.Join(pathSlice, string(os.PathListSeparator))
+	os.Setenv("PATH", binPath)
+
+	suffix := ""
+	if runtime.GOOS == "windows" {
+		suffix = ".exe"
+	}
+	gofmt := "gofmt" + suffix
+	goimports := "goimports" + suffix
+
+	if gofmtPath, err := exec.LookPath(gofmt); err != nil {
+		fmt.Println("Can not find", gofmt, "in system path or current working directory.")
+		os.Exit(1)
+	} else {
+		gofmt = gofmtPath
+	}
+
+	if goimportsPath, err := exec.LookPath(goimports); err != nil {
+		fmt.Println("Can not find", goimports, "in system path or current working directory.")
+		os.Exit(1)
+	} else {
+		goimports = goimportsPath
+	}
+
+	rawFilesSlice := make([]string, 0)
+	walkErr := filepath.Walk("./", func(path string, info os.FileInfo, err error) error {
+		if err != nil {
+			fmt.Println(err)
+			return err
+		}
+
+		if info.IsDir() {
+			return nil
+		}
+
+		dir := filepath.Dir(path)
+		filename := filepath.Base(path)
+		if strings.HasSuffix(filename, ".go") &&
+			!strings.HasSuffix(filename, ".pb.go") &&
+			!strings.Contains(dir, filepath.Join("testing", "mocks")) {
+			rawFilesSlice = append(rawFilesSlice, path)
+		}
+
+		return nil
+	})
+	if walkErr != nil {
+		fmt.Println(walkErr)
+		os.Exit(1)
+	}
+
+	gofmtArgs := []string{
+		"-s", "-l", "-e", "-w",
+	}
+
+	goimportsArgs := []string{
+		"-w",
+		"-local", "github.com/v2fly/v2ray-core",
+	}
+
+	RunMany(gofmt, gofmtArgs, rawFilesSlice)
+	RunMany(goimports, goimportsArgs, rawFilesSlice)
+	fmt.Println("Do NOT forget to commit file changes.")
+}