pack.go 3.8 KB

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