build.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. package deploy
  2. import (
  3. "fmt"
  4. "os"
  5. "path/filepath"
  6. "strings"
  7. api "github.com/porter-dev/porter/api/client"
  8. "github.com/porter-dev/porter/api/types"
  9. "github.com/porter-dev/porter/cli/cmd/docker"
  10. "github.com/porter-dev/porter/cli/cmd/pack"
  11. )
  12. // BuildAgent builds a new Docker container image for a new version of an application
  13. type BuildAgent struct {
  14. *SharedOpts
  15. client *api.Client
  16. imageRepo string
  17. env map[string]string
  18. imageExists bool
  19. }
  20. // BuildDocker uses the local Docker daemon to build the image
  21. func (b *BuildAgent) BuildDocker(
  22. dockerAgent *docker.Agent,
  23. basePath,
  24. buildCtx,
  25. dockerfilePath,
  26. tag string,
  27. currentTag string,
  28. ) error {
  29. buildCtx, dockerfilePath, isDockerfileInCtx, err := ResolveDockerPaths(
  30. basePath,
  31. buildCtx,
  32. dockerfilePath,
  33. )
  34. if err != nil {
  35. return err
  36. }
  37. opts := &docker.BuildOpts{
  38. ImageRepo: b.imageRepo,
  39. Tag: tag,
  40. CurrentTag: currentTag,
  41. BuildContext: buildCtx,
  42. Env: b.env,
  43. DockerfilePath: dockerfilePath,
  44. IsDockerfileInCtx: isDockerfileInCtx,
  45. }
  46. return dockerAgent.BuildLocal(
  47. opts,
  48. )
  49. }
  50. // BuildPack uses the cloud-native buildpack client to build a container image
  51. func (b *BuildAgent) BuildPack(dockerAgent *docker.Agent, dst, tag string, buildConfig *types.BuildConfig) error {
  52. // retag the image with "pack-cache" tag so that it doesn't re-pull from the registry
  53. if b.imageExists {
  54. err := dockerAgent.TagImage(
  55. fmt.Sprintf("%s:%s", b.imageRepo, tag),
  56. fmt.Sprintf("%s:%s", b.imageRepo, "pack-cache"),
  57. )
  58. if err != nil {
  59. return err
  60. }
  61. }
  62. // create pack agent and build opts
  63. packAgent := &pack.Agent{}
  64. opts := &docker.BuildOpts{
  65. ImageRepo: b.imageRepo,
  66. // We tag the image with a stable param "pack-cache" so that pack can use the
  67. // local image without attempting to re-pull from registry. We handle getting
  68. // registry credentials and pushing/pulling the image.
  69. Tag: "pack-cache",
  70. BuildContext: dst,
  71. Env: b.env,
  72. }
  73. // call builder
  74. err := packAgent.Build(opts, buildConfig)
  75. if err != nil {
  76. return err
  77. }
  78. return dockerAgent.TagImage(
  79. fmt.Sprintf("%s:%s", b.imageRepo, "pack-cache"),
  80. fmt.Sprintf("%s:%s", b.imageRepo, tag),
  81. )
  82. }
  83. // ResolveDockerPaths returns a path to the dockerfile that is either relative or absolute, and a path
  84. // to the build context that is absolute.
  85. //
  86. // The return value will be relative if the dockerfile exists within the build context, absolute
  87. // otherwise. The second return value is true if the dockerfile exists within the build context,
  88. // false otherwise.
  89. func ResolveDockerPaths(
  90. basePath string,
  91. buildContextPath string,
  92. dockerfilePath string,
  93. ) (
  94. resBuildCtxPath string,
  95. resDockerfilePath string,
  96. isDockerfileRelative bool,
  97. err error,
  98. ) {
  99. resBuildCtxPath, err = filepath.Abs(buildContextPath)
  100. resDockerfilePath = dockerfilePath
  101. // determine if the given dockerfile path is relative
  102. if !filepath.IsAbs(dockerfilePath) {
  103. // if path is relative, join basepath with path
  104. resDockerfilePath = filepath.Join(basePath, dockerfilePath)
  105. }
  106. // compare the path to the dockerfile with the build context
  107. pathComp, err := filepath.Rel(resBuildCtxPath, resDockerfilePath)
  108. if err != nil {
  109. return "", "", false, err
  110. }
  111. if !strings.HasPrefix(pathComp, ".."+string(os.PathSeparator)) {
  112. // return the relative path to the dockerfile
  113. return resBuildCtxPath, pathComp, true, nil
  114. }
  115. resDockerfilePath, err = filepath.Abs(resDockerfilePath)
  116. if err != nil {
  117. return "", "", false, err
  118. }
  119. return resBuildCtxPath, resDockerfilePath, false, nil
  120. }