release.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  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. // Get the data
  71. resp, err := http.Get(url)
  72. if err != nil {
  73. return err
  74. }
  75. defer resp.Body.Close()
  76. // Create the file
  77. out, err := os.Create(filepath)
  78. if err != nil {
  79. return err
  80. }
  81. defer out.Close()
  82. // Write the body to file
  83. _, err = io.Copy(out, resp.Body)
  84. return err
  85. }
  86. func unzipToDir(zipfile string, dir string) error {
  87. r, err := zip.OpenReader(zipfile)
  88. if err != nil {
  89. return err
  90. }
  91. defer r.Close()
  92. for _, f := range r.File {
  93. // Store filename/path for returning and using later on
  94. fpath := filepath.Join(dir, f.Name)
  95. // Check for ZipSlip. More Info: http://bit.ly/2MsjAWE
  96. if !strings.HasPrefix(fpath, filepath.Clean(dir)+string(os.PathSeparator)) {
  97. return fmt.Errorf("%s: illegal file path", fpath)
  98. }
  99. if f.FileInfo().IsDir() {
  100. // Make Folder
  101. os.MkdirAll(fpath, os.ModePerm)
  102. continue
  103. }
  104. // Make File
  105. if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil {
  106. return err
  107. }
  108. outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
  109. if err != nil {
  110. return err
  111. }
  112. rc, err := f.Open()
  113. if err != nil {
  114. return err
  115. }
  116. _, err = io.Copy(outFile, rc)
  117. // Close the file without defer to close before next iteration of loop
  118. outFile.Close()
  119. rc.Close()
  120. if err != nil {
  121. return err
  122. }
  123. }
  124. return nil
  125. }