build.go 3.4 KB

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