build.go 3.5 KB

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