diff --git a/core/format.go b/core/format.go new file mode 100644 index 00000000..439f5ada --- /dev/null +++ b/core/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/ diff --git a/core/xray_test.go b/core/xray_test.go index bb831660..08d1410e 100644 --- a/core/xray_test.go +++ b/core/xray_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/golang/protobuf/proto" + "github.com/xtls/xray-core/app/dispatcher" "github.com/xtls/xray-core/app/proxyman" "github.com/xtls/xray-core/common" diff --git a/infra/vformat/main.go b/infra/vformat/main.go new file mode 100644 index 00000000..e6c50d32 --- /dev/null +++ b/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/xtls/xray-core", + } + + RunMany(gofmt, gofmtArgs, rawFilesSlice) + RunMany(goimports, goimportsArgs, rawFilesSlice) + fmt.Println("Do NOT forget to commit file changes.") +}