build.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. package main
  2. import (
  3. "flag"
  4. "fmt"
  5. "io/ioutil"
  6. "os"
  7. "os/exec"
  8. "path/filepath"
  9. "runtime"
  10. "strings"
  11. "time"
  12. )
  13. var (
  14. targetOS = flag.String("os", runtime.GOOS, "Target OS of this build.")
  15. targetArch = flag.String("arch", runtime.GOARCH, "Target CPU arch of this build.")
  16. archive = flag.Bool("zip", false, "Whether to make an archive of files or not.")
  17. GOPATH string
  18. repoRoot string
  19. )
  20. type OS string
  21. const (
  22. Windows = OS("windows")
  23. MacOS = OS("darwin")
  24. Linux = OS("linux")
  25. )
  26. type Architecture string
  27. const (
  28. X86 = Architecture("386")
  29. Amd64 = Architecture("amd64")
  30. Arm = Architecture("arm")
  31. Arm64 = Architecture("arm64")
  32. )
  33. func getRepoVersion() (string, error) {
  34. revHead, err := exec.Command("git", "rev-parse", "HEAD").Output()
  35. if err != nil {
  36. return "", err
  37. }
  38. version, err := exec.Command("git", "name-rev", "--tags", "--name-only", strings.TrimSpace(string(revHead))).Output()
  39. if err != nil {
  40. return "", err
  41. }
  42. verStr := strings.TrimSpace(string(version))
  43. if strings.HasSuffix(verStr, "^0") {
  44. verStr = verStr[:len(verStr)-2]
  45. }
  46. if verStr == "undefined" {
  47. verStr = "custom"
  48. }
  49. return verStr, nil
  50. }
  51. func getOS() OS {
  52. if targetOS == nil {
  53. panic("OS is not specified.")
  54. }
  55. osStr := strings.ToLower(*targetOS)
  56. if osStr == "windows" || osStr == "win" {
  57. return Windows
  58. }
  59. if osStr == "darwin" || osStr == "mac" || osStr == "macos" || osStr == "osx" {
  60. return MacOS
  61. }
  62. if osStr == "linux" || osStr == "debian" || osStr == "ubuntu" || osStr == "redhat" || osStr == "centos" {
  63. return Linux
  64. }
  65. panic("Unknown OS " + *targetOS)
  66. }
  67. func getArch() Architecture {
  68. if targetArch == nil {
  69. panic("Arch is not specified.")
  70. }
  71. archStr := strings.ToLower(*targetArch)
  72. if archStr == "x86" || archStr == "386" || archStr == "i386" {
  73. return X86
  74. }
  75. if archStr == "amd64" || archStr == "x86-64" || archStr == "x64" {
  76. return Amd64
  77. }
  78. if archStr == "arm" {
  79. return Arm
  80. }
  81. if archStr == "arm64" {
  82. return Arm64
  83. }
  84. panic("Unknown Arch " + *targetArch)
  85. }
  86. func getSuffix(vos OS, arch Architecture) string {
  87. suffix := "-custom"
  88. switch vos {
  89. case Windows:
  90. switch arch {
  91. case X86:
  92. suffix = "-windows-32"
  93. case Amd64:
  94. suffix = "-windows-64"
  95. }
  96. case MacOS:
  97. suffix = "-macos"
  98. case Linux:
  99. switch arch {
  100. case X86:
  101. suffix = "-linux-32"
  102. case Amd64:
  103. suffix = "-linux-64"
  104. case Arm:
  105. suffix = "-linux-arm"
  106. case Arm64:
  107. suffix = "-linux-arm64"
  108. }
  109. }
  110. return suffix
  111. }
  112. func createTargetDirectory(version string, vos OS, arch Architecture) (string, error) {
  113. suffix := "-custom"
  114. if version != "custom" {
  115. suffix = getSuffix(vos, arch)
  116. }
  117. targetDir := filepath.Join(GOPATH, "bin", "v2ray"+suffix)
  118. if version != "custom" {
  119. os.RemoveAll(targetDir)
  120. }
  121. err := os.MkdirAll(targetDir, os.ModeDir|0777)
  122. return targetDir, err
  123. }
  124. func getTargetFile(vos OS, arch Architecture) string {
  125. suffix := getSuffix(vos, arch)
  126. if vos == "Windows" {
  127. suffix += ".exe"
  128. }
  129. return "v2ray" + suffix
  130. }
  131. func normalizedContent(content []byte, vos OS) []byte {
  132. str := strings.Replace(string(content), "\r\n", "\n", -1)
  133. if vos == Windows {
  134. str = strings.Replace(str, "\n", "\r\n", -1)
  135. }
  136. return []byte(str)
  137. }
  138. func copyConfigFiles(dir string, version string, vos OS, arch Architecture) error {
  139. clientConfig, err := ioutil.ReadFile(filepath.Join(repoRoot, "release", "config", "vpoint_socks_vmess.json"))
  140. if err != nil {
  141. return err
  142. }
  143. clientConfig = normalizedContent(clientConfig, vos)
  144. clientConfigName := "vpoint_socks_vmess.json"
  145. if vos == Windows || vos == MacOS {
  146. clientConfigName = "config.json"
  147. }
  148. err = ioutil.WriteFile(filepath.Join(dir, clientConfigName), clientConfig, 0777)
  149. if err != nil {
  150. return err
  151. }
  152. if vos == Windows || vos == MacOS {
  153. return nil
  154. }
  155. serverConfig, err := ioutil.ReadFile(filepath.Join(repoRoot, "release", "config", "vpoint_vmess_freedom.json"))
  156. if err != nil {
  157. return err
  158. }
  159. serverConfig = normalizedContent(serverConfig, vos)
  160. err = ioutil.WriteFile(filepath.Join(dir, "vpoint_vmess_freedom.json"), serverConfig, 0777)
  161. if err != nil {
  162. return err
  163. }
  164. return nil
  165. }
  166. func buildV2Ray(targetDir, targetFile string, version string, vos OS, arch Architecture) error {
  167. ldFlags := "-s"
  168. if version != "custom" {
  169. year, month, day := time.Now().UTC().Date()
  170. today := fmt.Sprintf("%04d%02d%02d", year, int(month), day)
  171. ldFlags = ldFlags + " -X github.com/v2ray/v2ray-core.version=" + version + " -X github.com/v2ray/v2ray-core.build=" + today
  172. }
  173. target := filepath.Join(targetDir, targetFile)
  174. fmt.Println("Building to " + target)
  175. cmd := exec.Command("go", "build", "-o", target, "-compiler", "gc", "-ldflags", "\""+ldFlags+"\"", "github.com/v2ray/v2ray-core/release/server")
  176. cmd.Env = append(cmd.Env, "GOOS="+string(vos), "GOARCH="+string(arch))
  177. cmd.Env = append(cmd.Env, os.Environ()...)
  178. _, err := cmd.Output()
  179. return err
  180. }
  181. func main() {
  182. flag.Parse()
  183. v2rayOS := getOS()
  184. v2rayArch := getArch()
  185. if err := os.Chdir(repoRoot); err != nil {
  186. fmt.Println("Unable to switch to V2Ray repo: " + err.Error())
  187. return
  188. }
  189. version, err := getRepoVersion()
  190. if err != nil {
  191. fmt.Println("Unable to detect V2Ray version: " + err.Error())
  192. return
  193. }
  194. fmt.Printf("Building V2Ray (%s) for %s %s\n", version, v2rayOS, v2rayArch)
  195. targetDir, err := createTargetDirectory(version, v2rayOS, v2rayArch)
  196. if err != nil {
  197. fmt.Println("Unable to create directory " + targetDir + ": " + err.Error())
  198. }
  199. targetFile := getTargetFile(v2rayOS, v2rayArch)
  200. err = buildV2Ray(targetDir, targetFile, version, v2rayOS, v2rayArch)
  201. if err != nil {
  202. fmt.Println("Unable to build V2Ray: " + err.Error())
  203. }
  204. err = copyConfigFiles(targetDir, version, v2rayOS, v2rayArch)
  205. if err != nil {
  206. fmt.Println("Unable to copy config files: " + err.Error())
  207. }
  208. }
  209. func init() {
  210. GOPATH = os.Getenv("GOPATH")
  211. repoRoot = filepath.Join(GOPATH, "src", "github.com", "v2ray", "v2ray-core")
  212. }