diff --git a/tools/build/build.go b/tools/build/build.go index 7a334b5a..1f6799be 100644 --- a/tools/build/build.go +++ b/tools/build/build.go @@ -3,130 +3,26 @@ package main import ( "flag" "fmt" - "io/ioutil" "os" - "os/exec" "path/filepath" "runtime" - "strings" - "time" + + "github.com/v2ray/v2ray-core/tools/git" ) var ( targetOS = flag.String("os", runtime.GOOS, "Target OS of this build.") targetArch = flag.String("arch", runtime.GOARCH, "Target CPU arch of this build.") archive = flag.Bool("zip", false, "Whether to make an archive of files or not.") - - GOPATH string - repoRoot string -) - -type OS string - -const ( - Windows = OS("windows") - MacOS = OS("darwin") - Linux = OS("linux") -) - -type Architecture string - -const ( - X86 = Architecture("386") - Amd64 = Architecture("amd64") - Arm = Architecture("arm") - Arm64 = Architecture("arm64") ) -func getRepoVersion() (string, error) { - revHead, err := exec.Command("git", "rev-parse", "HEAD").Output() - if err != nil { - return "", err - } - version, err := exec.Command("git", "name-rev", "--tags", "--name-only", strings.TrimSpace(string(revHead))).Output() - if err != nil { - return "", err - } - verStr := strings.TrimSpace(string(version)) - if strings.HasSuffix(verStr, "^0") { - verStr = verStr[:len(verStr)-2] - } - if verStr == "undefined" { - verStr = "custom" - } - return verStr, nil -} - -func getOS() OS { - if targetOS == nil { - panic("OS is not specified.") - } - osStr := strings.ToLower(*targetOS) - if osStr == "windows" || osStr == "win" { - return Windows - } - if osStr == "darwin" || osStr == "mac" || osStr == "macos" || osStr == "osx" { - return MacOS - } - if osStr == "linux" || osStr == "debian" || osStr == "ubuntu" || osStr == "redhat" || osStr == "centos" { - return Linux - } - panic("Unknown OS " + *targetOS) -} - -func getArch() Architecture { - if targetArch == nil { - panic("Arch is not specified.") - } - archStr := strings.ToLower(*targetArch) - if archStr == "x86" || archStr == "386" || archStr == "i386" { - return X86 - } - if archStr == "amd64" || archStr == "x86-64" || archStr == "x64" { - return Amd64 - } - if archStr == "arm" { - return Arm - } - if archStr == "arm64" { - return Arm64 - } - panic("Unknown Arch " + *targetArch) -} - -func getSuffix(vos OS, arch Architecture) string { - suffix := "-custom" - switch vos { - case Windows: - switch arch { - case X86: - suffix = "-windows-32" - case Amd64: - suffix = "-windows-64" - } - case MacOS: - suffix = "-macos" - case Linux: - switch arch { - case X86: - suffix = "-linux-32" - case Amd64: - suffix = "-linux-64" - case Arm: - suffix = "-linux-arm" - case Arm64: - suffix = "-linux-arm64" - } - - } - return suffix -} - -func createTargetDirectory(version string, vos OS, arch Architecture) (string, error) { +func createTargetDirectory(version string, goOS GoOS, goArch GoArch) (string, error) { suffix := "-custom" if version != "custom" { - suffix = getSuffix(vos, arch) + suffix = getSuffix(goOS, goArch) } + GOPATH := os.Getenv("GOPATH") + targetDir := filepath.Join(GOPATH, "bin", "v2ray"+suffix) if version != "custom" { os.RemoveAll(targetDir) @@ -135,104 +31,45 @@ func createTargetDirectory(version string, vos OS, arch Architecture) (string, e return targetDir, err } -func getTargetFile(vos OS, arch Architecture) string { - suffix := getSuffix(vos, arch) - if vos == "Windows" { +func getTargetFile(goOS GoOS) string { + suffix := "" + if goOS == "Windows" { suffix += ".exe" } return "v2ray" + suffix } -func normalizedContent(content []byte, vos OS) []byte { - str := strings.Replace(string(content), "\r\n", "\n", -1) - if vos == Windows { - str = strings.Replace(str, "\n", "\r\n", -1) - } - return []byte(str) -} - -func copyConfigFiles(dir string, version string, vos OS, arch Architecture) error { - clientConfig, err := ioutil.ReadFile(filepath.Join(repoRoot, "release", "config", "vpoint_socks_vmess.json")) - if err != nil { - return err - } - clientConfig = normalizedContent(clientConfig, vos) - clientConfigName := "vpoint_socks_vmess.json" - if vos == Windows || vos == MacOS { - clientConfigName = "config.json" - } - err = ioutil.WriteFile(filepath.Join(dir, clientConfigName), clientConfig, 0777) - if err != nil { - return err - } - - if vos == Windows || vos == MacOS { - return nil - } - - serverConfig, err := ioutil.ReadFile(filepath.Join(repoRoot, "release", "config", "vpoint_vmess_freedom.json")) - if err != nil { - return err - } - serverConfig = normalizedContent(serverConfig, vos) - err = ioutil.WriteFile(filepath.Join(dir, "vpoint_vmess_freedom.json"), serverConfig, 0777) - if err != nil { - return err - } - return nil -} - -func buildV2Ray(targetDir, targetFile string, version string, vos OS, arch Architecture) error { - ldFlags := "-s" - if version != "custom" { - year, month, day := time.Now().UTC().Date() - today := fmt.Sprintf("%04d%02d%02d", year, int(month), day) - ldFlags = ldFlags + " -X github.com/v2ray/v2ray-core.version=" + version + " -X github.com/v2ray/v2ray-core.build=" + today - } - target := filepath.Join(targetDir, targetFile) - fmt.Println("Building to " + target) - cmd := exec.Command("go", "build", "-o", target, "-compiler", "gc", "-ldflags", "\""+ldFlags+"\"", "github.com/v2ray/v2ray-core/release/server") - cmd.Env = append(cmd.Env, "GOOS="+string(vos), "GOARCH="+string(arch)) - cmd.Env = append(cmd.Env, os.Environ()...) - _, err := cmd.Output() - return err -} - func main() { flag.Parse() + fmt.Println(os.Args) - v2rayOS := getOS() - v2rayArch := getArch() + v2rayOS := parseOS(*targetOS) + v2rayArch := parseArch(*targetArch) - if err := os.Chdir(repoRoot); err != nil { - fmt.Println("Unable to switch to V2Ray repo: " + err.Error()) - return + version, err := git.RepoVersionHead() + if version == git.VersionUndefined { + version = "custom" } - version, err := getRepoVersion() if err != nil { fmt.Println("Unable to detect V2Ray version: " + err.Error()) return } fmt.Printf("Building V2Ray (%s) for %s %s\n", version, v2rayOS, v2rayArch) + version = "v1.0" targetDir, err := createTargetDirectory(version, v2rayOS, v2rayArch) if err != nil { fmt.Println("Unable to create directory " + targetDir + ": " + err.Error()) } - targetFile := getTargetFile(v2rayOS, v2rayArch) - err = buildV2Ray(targetDir, targetFile, version, v2rayOS, v2rayArch) + targetFile := getTargetFile(v2rayOS) + err = buildV2Ray(filepath.Join(targetDir, targetFile), version, v2rayOS, v2rayArch) if err != nil { fmt.Println("Unable to build V2Ray: " + err.Error()) } - err = copyConfigFiles(targetDir, version, v2rayOS, v2rayArch) + err = copyConfigFiles(targetDir, v2rayOS) if err != nil { fmt.Println("Unable to copy config files: " + err.Error()) } } - -func init() { - GOPATH = os.Getenv("GOPATH") - repoRoot = filepath.Join(GOPATH, "src", "github.com", "v2ray", "v2ray-core") -} diff --git a/tools/build/config.go b/tools/build/config.go new file mode 100644 index 00000000..067ec418 --- /dev/null +++ b/tools/build/config.go @@ -0,0 +1,43 @@ +package main + +import ( + "io/ioutil" + "os" + "path/filepath" + "strings" +) + +func copyConfigFile(src, dest string, goOS GoOS) error { + content, err := ioutil.ReadFile(src) + if err != nil { + return err + } + str := string(content) + str = strings.Replace(str, "\r\n", "\n", -1) + if goOS == Windows { + str = strings.Replace(str, "\n", "\r\n", -1) + } + return ioutil.WriteFile(dest, []byte(str), 0777) +} + +func copyConfigFiles(dir string, goOS GoOS) error { + GOPATH := os.Getenv("GOPATH") + srcDir := filepath.Join(GOPATH, "src", "github.com", "v2ray", "v2ray-core", "release", "config") + src := filepath.Join(srcDir, "vpoint_socks_vmess.json") + dest := filepath.Join(dir, "vpoint_socks_vmess.json") + if goOS == Windows || goOS == MacOS { + dest = filepath.Join(dir, "config.json") + } + err := copyConfigFile(src, dest, goOS) + if err != nil { + return err + } + + if goOS == Windows || goOS == MacOS { + return nil + } + + src = filepath.Join(srcDir, "vpoint_vmess_freedom.json") + dest = filepath.Join(dir, "vpoint_vmess_freedom.json") + return copyConfigFile(src, dest, goOS) +} diff --git a/tools/build/env.go b/tools/build/env.go new file mode 100644 index 00000000..a557b3d1 --- /dev/null +++ b/tools/build/env.go @@ -0,0 +1,83 @@ +package main + +import ( + "strings" +) + +type GoOS string + +const ( + Windows = GoOS("windows") + MacOS = GoOS("darwin") + Linux = GoOS("linux") + UnknownOS = GoOS("unknown") +) + +type GoArch string + +const ( + X86 = GoArch("386") + Amd64 = GoArch("amd64") + Arm = GoArch("arm") + Arm64 = GoArch("arm64") + UnknownArch = GoArch("unknown") +) + +func parseOS(rawOS string) GoOS { + osStr := strings.ToLower(rawOS) + if osStr == "windows" || osStr == "win" { + return Windows + } + if osStr == "darwin" || osStr == "mac" || osStr == "macos" || osStr == "osx" { + return MacOS + } + if osStr == "linux" || osStr == "debian" || osStr == "ubuntu" || osStr == "redhat" || osStr == "centos" { + return Linux + } + return UnknownOS +} + +func parseArch(rawArch string) GoArch { + archStr := strings.ToLower(rawArch) + if archStr == "x86" || archStr == "386" || archStr == "i386" { + return X86 + } + if archStr == "amd64" || archStr == "x86-64" || archStr == "x64" { + return Amd64 + } + if archStr == "arm" { + return Arm + } + if archStr == "arm64" { + return Arm64 + } + return UnknownArch +} + +func getSuffix(os GoOS, arch GoArch) string { + suffix := "-custom" + switch os { + case Windows: + switch arch { + case X86: + suffix = "-windows-32" + case Amd64: + suffix = "-windows-64" + } + case MacOS: + suffix = "-macos" + case Linux: + switch arch { + case X86: + suffix = "-linux-32" + case Amd64: + suffix = "-linux-64" + case Arm: + suffix = "-linux-arm" + case Arm64: + suffix = "-linux-arm64" + } + + } + return suffix +} diff --git a/tools/build/env_test.go b/tools/build/env_test.go new file mode 100644 index 00000000..45c22e60 --- /dev/null +++ b/tools/build/env_test.go @@ -0,0 +1,26 @@ +package main + +import ( + "testing" + + "github.com/v2ray/v2ray-core/testing/unit" +) + +func TestParseOS(t *testing.T) { + assert := unit.Assert(t) + + assert.Pointer(parseOS("windows")).Equals(Windows) + assert.Pointer(parseOS("macos")).Equals(MacOS) + assert.Pointer(parseOS("linux")).Equals(Linux) + assert.Pointer(parseOS("test")).Equals(UnknownOS) +} + +func TestParseArch(t *testing.T) { + assert := unit.Assert(t) + + assert.Pointer(parseArch("x86")).Equals(X86) + assert.Pointer(parseArch("x64")).Equals(Amd64) + assert.Pointer(parseArch("arm")).Equals(Arm) + assert.Pointer(parseArch("arm64")).Equals(Arm64) + assert.Pointer(parseArch("test")).Equals(UnknownArch) +} diff --git a/tools/build/go.go b/tools/build/go.go new file mode 100644 index 00000000..017d2ba9 --- /dev/null +++ b/tools/build/go.go @@ -0,0 +1,22 @@ +package main + +import ( + "fmt" + "os" + "os/exec" + "time" +) + +func buildV2Ray(targetFile string, version string, goOS GoOS, goArch GoArch) error { + ldFlags := "-s" + if version != "" { + year, month, day := time.Now().UTC().Date() + today := fmt.Sprintf("%04d%02d%02d", year, int(month), day) + ldFlags = ldFlags + " -X github.com/v2ray/v2ray-core.version=" + version + " -X github.com/v2ray/v2ray-core.build=" + today + } + cmd := exec.Command("go", "build", "-o", targetFile, "-compiler", "gc", "-ldflags", ldFlags, "github.com/v2ray/v2ray-core/release/server") + cmd.Env = append(cmd.Env, "GOOS="+string(goOS), "GOARCH="+string(goArch)) + cmd.Env = append(cmd.Env, os.Environ()...) + _, err := cmd.Output() + return err +} diff --git a/tools/build/go_test.go b/tools/build/go_test.go new file mode 100644 index 00000000..65785ae0 --- /dev/null +++ b/tools/build/go_test.go @@ -0,0 +1,46 @@ +package main + +import ( + "bytes" + "fmt" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + "testing" + "time" + + "github.com/v2ray/v2ray-core/testing/unit" +) + +func TestBuildAndRun(t *testing.T) { + assert := unit.Assert(t) + + gopath := os.Getenv("GOPATH") + target := filepath.Join(gopath, "src", "v2ray_test") + fmt.Println(target) + goOS := parseOS(runtime.GOOS) + goArch := parseArch(runtime.GOARCH) + err := buildV2Ray(target, "v1.0", goOS, goArch) + assert.Error(err).IsNil() + + outBuffer := bytes.NewBuffer(make([]byte, 0, 1024)) + errBuffer := bytes.NewBuffer(make([]byte, 0, 1024)) + configFile := filepath.Join(gopath, "src", "github.com", "v2ray", "v2ray-core", "release", "config", "vpoint_socks_vmess.json") + cmd := exec.Command(target, "--config="+configFile) + cmd.Stdout = outBuffer + cmd.Stderr = errBuffer + cmd.Start() + + <-time.After(1 * time.Second) + cmd.Process.Kill() + + outStr := string(outBuffer.Bytes()) + errStr := string(errBuffer.Bytes()) + + assert.Bool(strings.Contains(outStr, "v1.0")).IsTrue() + assert.Int(len(errStr)).Equals(0) + + os.Remove(target) +}