pack.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. package pack
  2. import (
  3. "context"
  4. "fmt"
  5. "io/ioutil"
  6. "net/url"
  7. "path/filepath"
  8. "regexp"
  9. "strings"
  10. "github.com/buildpacks/pack"
  11. githubApi "github.com/google/go-github/github"
  12. "github.com/porter-dev/porter/api/types"
  13. "github.com/porter-dev/porter/cli/cmd/docker"
  14. "github.com/porter-dev/porter/cli/cmd/github"
  15. "k8s.io/client-go/util/homedir"
  16. )
  17. type Agent struct{}
  18. func (a *Agent) Build(opts *docker.BuildOpts, buildConfig *types.BuildConfig) error {
  19. //initialize a pack client
  20. client, err := pack.NewClient(pack.WithLogger(newPackLogger()))
  21. if err != nil {
  22. return err
  23. }
  24. absPath, err := filepath.Abs(opts.BuildContext)
  25. if err != nil {
  26. return err
  27. }
  28. buildOpts := pack.BuildOptions{
  29. RelativeBaseDir: filepath.Dir(absPath),
  30. Image: fmt.Sprintf("%s:%s", opts.ImageRepo, opts.Tag),
  31. Builder: "paketobuildpacks/builder:full",
  32. AppPath: opts.BuildContext,
  33. TrustBuilder: true,
  34. Env: opts.Env,
  35. }
  36. if buildConfig != nil {
  37. buildOpts.Builder = buildConfig.Builder
  38. for i := range buildConfig.Buildpacks {
  39. bp := buildConfig.Buildpacks[i]
  40. if bp == "" {
  41. continue
  42. }
  43. u, err := url.Parse(bp)
  44. if err == nil && u.Scheme != "" {
  45. // could be a git repository containing the buildpack
  46. if !strings.HasSuffix(u.Path, ".zip") && u.Host != "github.com" && u.Host != "www.github.com" {
  47. return fmt.Errorf("please provide either a github.com URL or a ZIP file URL")
  48. }
  49. urlPaths := strings.Split(u.Path[1:], "/")
  50. dstDir := filepath.Join(homedir.HomeDir(), ".porter")
  51. bpCustomName := regexp.MustCompile("/|-").ReplaceAllString(u.Path[1:], "_")
  52. var zipFileName string
  53. if strings.HasSuffix(bpCustomName, ".zip") {
  54. zipFileName = bpCustomName
  55. } else {
  56. zipFileName = fmt.Sprintf("%s.zip", bpCustomName)
  57. }
  58. downloader := &github.ZIPDownloader{
  59. ZipFolderDest: dstDir,
  60. AssetFolderDest: dstDir,
  61. ZipName: zipFileName,
  62. RemoveAfterDownload: true,
  63. }
  64. if zipFileName != bpCustomName {
  65. // try to download the repo ZIP from github
  66. githubClient := githubApi.NewClient(nil)
  67. rel, _, err := githubClient.Repositories.GetLatestRelease(
  68. context.Background(),
  69. urlPaths[0],
  70. urlPaths[1],
  71. )
  72. if err == nil {
  73. bp = rel.GetZipballURL()
  74. } else {
  75. // default to the current default branch
  76. repo, _, err := githubClient.Repositories.Get(
  77. context.Background(),
  78. urlPaths[0],
  79. urlPaths[1],
  80. )
  81. if err != nil {
  82. return fmt.Errorf("could not fetch git repo details")
  83. }
  84. bp = fmt.Sprintf("%s/archive/refs/heads/%s.zip", bp, repo.GetDefaultBranch())
  85. }
  86. }
  87. err = downloader.DownloadToFile(bp)
  88. if err != nil {
  89. return err
  90. }
  91. err = downloader.UnzipToDir()
  92. if err != nil {
  93. return err
  94. }
  95. dstFiles, err := ioutil.ReadDir(dstDir)
  96. if err != nil {
  97. return err
  98. }
  99. var bpRealName string
  100. for _, info := range dstFiles {
  101. if info.Mode().IsDir() && strings.Contains(info.Name(), urlPaths[1]) {
  102. bpRealName = filepath.Join(dstDir, info.Name())
  103. }
  104. }
  105. buildOpts.Buildpacks = append(buildOpts.Buildpacks, bpRealName)
  106. } else {
  107. buildOpts.Buildpacks = append(buildOpts.Buildpacks, bp)
  108. }
  109. }
  110. // FIXME: use all the config vars
  111. }
  112. if strings.HasPrefix(buildOpts.Builder, "heroku") {
  113. buildOpts.Buildpacks = append(buildOpts.Buildpacks, "heroku/procfile")
  114. }
  115. return client.Build(context.Background(), buildOpts)
  116. }