release.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  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, 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. releaseURL := ""
  31. // iterate through the assets
  32. for _, asset := range rel.Assets {
  33. if downloadURL := asset.GetBrowserDownloadURL(); re.MatchString(downloadURL) {
  34. releaseURL = downloadURL
  35. break
  36. }
  37. }
  38. return releaseURL, nil
  39. }
  40. // DownloadLatestServerRelease retrieves the latest Porter server release from Github, unzips
  41. // it, and adds the binary to the porter directory
  42. func DownloadLatestServerRelease(porterDir string) error {
  43. releaseURL, err := getLatestReleaseDownloadURL()
  44. fmt.Println(releaseURL)
  45. if err != nil {
  46. return err
  47. }
  48. zipFile := filepath.Join(porterDir, "portersrv_latest.zip")
  49. err = downloadToFile(releaseURL, zipFile)
  50. if err != nil {
  51. return err
  52. }
  53. err = unzipToDir(zipFile, porterDir)
  54. return err
  55. }
  56. func downloadToFile(url string, filepath string) error {
  57. // Get the data
  58. resp, err := http.Get(url)
  59. if err != nil {
  60. return err
  61. }
  62. defer resp.Body.Close()
  63. // Create the file
  64. out, err := os.Create(filepath)
  65. if err != nil {
  66. return err
  67. }
  68. defer out.Close()
  69. // Write the body to file
  70. _, err = io.Copy(out, resp.Body)
  71. return err
  72. }
  73. func unzipToDir(zipfile string, dir string) error {
  74. r, err := zip.OpenReader(zipfile)
  75. if err != nil {
  76. return err
  77. }
  78. defer r.Close()
  79. for _, f := range r.File {
  80. // Store filename/path for returning and using later on
  81. fpath := filepath.Join(dir, f.Name)
  82. // Check for ZipSlip. More Info: http://bit.ly/2MsjAWE
  83. if !strings.HasPrefix(fpath, filepath.Clean(dir)+string(os.PathSeparator)) {
  84. return fmt.Errorf("%s: illegal file path", fpath)
  85. }
  86. if f.FileInfo().IsDir() {
  87. // Make Folder
  88. os.MkdirAll(fpath, os.ModePerm)
  89. continue
  90. }
  91. // Make File
  92. if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil {
  93. return err
  94. }
  95. outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
  96. if err != nil {
  97. return err
  98. }
  99. rc, err := f.Open()
  100. if err != nil {
  101. return err
  102. }
  103. _, err = io.Copy(outFile, rc)
  104. // Close the file without defer to close before next iteration of loop
  105. outFile.Close()
  106. rc.Close()
  107. if err != nil {
  108. return err
  109. }
  110. }
  111. return nil
  112. }