build.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  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. APIClient *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. UseCache: b.UseCache,
  46. }
  47. return dockerAgent.BuildLocal(
  48. opts,
  49. )
  50. }
  51. // BuildPack uses the cloud-native buildpack client to build a container image
  52. func (b *BuildAgent) BuildPack(dockerAgent *docker.Agent, dst, tag, prevTag string, buildConfig *types.BuildConfig) error {
  53. // retag the image with "pack-cache" tag so that it doesn't re-pull from the registry
  54. if b.ImageExists {
  55. err := dockerAgent.TagImage(
  56. fmt.Sprintf("%s:%s", b.ImageRepo, prevTag),
  57. fmt.Sprintf("%s:%s", b.ImageRepo, "pack-cache"),
  58. )
  59. if err != nil {
  60. return err
  61. }
  62. }
  63. // create pack agent and build opts
  64. packAgent := &pack.Agent{}
  65. opts := &docker.BuildOpts{
  66. ImageRepo: b.ImageRepo,
  67. Tag: tag,
  68. BuildContext: dst,
  69. Env: b.Env,
  70. UseCache: b.UseCache,
  71. }
  72. // call builder
  73. return packAgent.Build(opts, buildConfig, fmt.Sprintf("%s:%s", b.ImageRepo, "pack-cache"))
  74. }
  75. // ResolveDockerPaths returns a path to the dockerfile that is either relative or absolute, and a path
  76. // to the build context that is absolute.
  77. //
  78. // The return value will be relative if the dockerfile exists within the build context, absolute
  79. // otherwise. The second return value is true if the dockerfile exists within the build context,
  80. // false otherwise.
  81. func ResolveDockerPaths(
  82. basePath string,
  83. buildContextPath string,
  84. dockerfilePath string,
  85. ) (
  86. resBuildCtxPath string,
  87. resDockerfilePath string,
  88. isDockerfileRelative bool,
  89. err error,
  90. ) {
  91. resBuildCtxPath, err = filepath.Abs(buildContextPath)
  92. resDockerfilePath = dockerfilePath
  93. // determine if the given dockerfile path is relative
  94. if !filepath.IsAbs(dockerfilePath) {
  95. // if path is relative, join basepath with path
  96. resDockerfilePath = filepath.Join(basePath, dockerfilePath)
  97. }
  98. // compare the path to the dockerfile with the build context
  99. pathComp, err := filepath.Rel(resBuildCtxPath, resDockerfilePath)
  100. if err != nil {
  101. return "", "", false, err
  102. }
  103. if !strings.HasPrefix(pathComp, ".."+string(os.PathSeparator)) {
  104. // return the relative path to the dockerfile
  105. return resBuildCtxPath, pathComp, true, nil
  106. }
  107. resDockerfilePath, err = filepath.Abs(resDockerfilePath)
  108. if err != nil {
  109. return "", "", false, err
  110. }
  111. return resBuildCtxPath, resDockerfilePath, false, nil
  112. }