diff --git a/tools/build/build.go b/tools/build/build.go new file mode 100644 index 000000000..7a334b5ad --- /dev/null +++ b/tools/build/build.go @@ -0,0 +1,238 @@ +package main + +import ( + "flag" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + "time" +) + +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) { + suffix := "-custom" + if version != "custom" { + suffix = getSuffix(vos, arch) + } + targetDir := filepath.Join(GOPATH, "bin", "v2ray"+suffix) + if version != "custom" { + os.RemoveAll(targetDir) + } + err := os.MkdirAll(targetDir, os.ModeDir|0777) + return targetDir, err +} + +func getTargetFile(vos OS, arch Architecture) string { + suffix := getSuffix(vos, arch) + if vos == "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() + + v2rayOS := getOS() + v2rayArch := getArch() + + if err := os.Chdir(repoRoot); err != nil { + fmt.Println("Unable to switch to V2Ray repo: " + err.Error()) + return + } + 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) + + 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) + if err != nil { + fmt.Println("Unable to build V2Ray: " + err.Error()) + } + + err = copyConfigFiles(targetDir, version, v2rayOS, v2rayArch) + 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") +}