release.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. package github
  2. import (
  3. "archive/zip"
  4. "context"
  5. "fmt"
  6. "io"
  7. "net/http"
  8. "os"
  9. "path/filepath"
  10. "regexp"
  11. "runtime"
  12. "strings"
  13. "github.com/google/go-github/github"
  14. )
  15. func getLatestReleaseDownloadURL() (string, string, error) {
  16. client := github.NewClient(nil)
  17. rel, _, err := client.Repositories.GetLatestRelease(context.Background(), "porter-dev", "porter")
  18. if err != nil {
  19. return "", "", err
  20. }
  21. var re *regexp.Regexp
  22. switch os := runtime.GOOS; os {
  23. case "darwin":
  24. re = regexp.MustCompile(`portersvr_.*_Darwin_x86_64\.zip`)
  25. case "linux":
  26. re = regexp.MustCompile(`portersvr_.*_Linux_x86_64\.zip`)
  27. default:
  28. fmt.Printf("%s.\n", os)
  29. }
  30. staticRE := regexp.MustCompile(`static_.*\.zip`)
  31. releaseURL := ""
  32. staticReleaseURL := ""
  33. // iterate through the assets
  34. for _, asset := range rel.Assets {
  35. if downloadURL := asset.GetBrowserDownloadURL(); re.MatchString(downloadURL) {
  36. releaseURL = downloadURL
  37. } else if staticRE.MatchString(downloadURL) {
  38. staticReleaseURL = downloadURL
  39. }
  40. }
  41. return releaseURL, staticReleaseURL, nil
  42. }
  43. // DownloadLatestServerRelease retrieves the latest Porter server release from Github, unzips
  44. // it, and adds the binary to the porter directory
  45. func DownloadLatestServerRelease(porterDir string) error {
  46. releaseURL, staticReleaseURL, err := getLatestReleaseDownloadURL()
  47. fmt.Println(releaseURL)
  48. if err != nil {
  49. return err
  50. }
  51. zipFile := filepath.Join(porterDir, "portersrv_latest.zip")
  52. err = downloadToFile(releaseURL, zipFile)
  53. if err != nil {
  54. return err
  55. }
  56. err = unzipToDir(zipFile, porterDir)
  57. if err != nil {
  58. return err
  59. }
  60. staticZipFile := filepath.Join(porterDir, "static_latest.zip")
  61. err = downloadToFile(staticReleaseURL, staticZipFile)
  62. if err != nil {
  63. return err
  64. }
  65. staticDir := filepath.Join(porterDir, "static")
  66. err = unzipToDir(staticZipFile, staticDir)
  67. return err
  68. }
  69. func downloadToFile(url string, filepath string) error {
  70. fmt.Println("Downloading:", url)
  71. // Get the data
  72. resp, err := http.Get(url)
  73. if err != nil {
  74. return err
  75. }
  76. defer resp.Body.Close()
  77. // Create the file
  78. out, err := os.Create(filepath)
  79. if err != nil {
  80. return err
  81. }
  82. defer out.Close()
  83. // Write the body to file
  84. _, err = io.Copy(out, resp.Body)
  85. return err
  86. }
  87. func unzipToDir(zipfile string, dir string) error {
  88. r, err := zip.OpenReader(zipfile)
  89. if err != nil {
  90. return err
  91. }
  92. defer r.Close()
  93. for _, f := range r.File {
  94. // Store filename/path for returning and using later on
  95. fpath := filepath.Join(dir, f.Name)
  96. // Check for ZipSlip. More Info: http://bit.ly/2MsjAWE
  97. if !strings.HasPrefix(fpath, filepath.Clean(dir)+string(os.PathSeparator)) {
  98. return fmt.Errorf("%s: illegal file path", fpath)
  99. }
  100. if f.FileInfo().IsDir() {
  101. // Make Folder
  102. os.MkdirAll(fpath, os.ModePerm)
  103. continue
  104. }
  105. // Make File
  106. if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil {
  107. return err
  108. }
  109. outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
  110. if err != nil {
  111. return err
  112. }
  113. rc, err := f.Open()
  114. if err != nil {
  115. return err
  116. }
  117. _, err = io.Copy(outFile, rc)
  118. // Close the file without defer to close before next iteration of loop
  119. outFile.Close()
  120. rc.Close()
  121. if err != nil {
  122. return err
  123. }
  124. }
  125. return nil
  126. }