cmd_docker.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. // Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
  2. //
  3. // This Source Code Form is subject to the terms of the MIT License.
  4. // If a copy of the MIT was not distributed with this file,
  5. // You can obtain one at https://github.com/gogf/gf.
  6. package cmd
  7. import (
  8. "context"
  9. "fmt"
  10. "runtime"
  11. "github.com/gogf/gf/v2/frame/g"
  12. "github.com/gogf/gf/v2/os/gfile"
  13. "github.com/gogf/gf/v2/os/gproc"
  14. "github.com/gogf/gf/v2/text/gstr"
  15. "github.com/gogf/gf/v2/util/gtag"
  16. "github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
  17. )
  18. var (
  19. Docker = cDocker{}
  20. )
  21. type cDocker struct {
  22. g.Meta `name:"docker" usage:"{cDockerUsage}" brief:"{cDockerBrief}" eg:"{cDockerEg}" dc:"{cDockerDc}"`
  23. }
  24. const (
  25. cDockerUsage = `gf docker [MAIN] [OPTION]`
  26. cDockerBrief = `build docker image for current GoFrame project`
  27. cDockerEg = `
  28. gf docker
  29. gf docker -t hub.docker.com/john/image:tag
  30. gf docker -p -t hub.docker.com/john/image:tag
  31. gf docker main.go
  32. gf docker main.go -t hub.docker.com/john/image:tag
  33. gf docker main.go -t hub.docker.com/john/image:tag
  34. gf docker main.go -p -t hub.docker.com/john/image:tag
  35. gf docker main.go -p -tp ["hub.docker.com/john","hub.docker.com/smith"] -tn image:tag
  36. `
  37. cDockerDc = `
  38. The "docker" command builds the GF project to a docker images.
  39. It runs "gf build" firstly to compile the project to binary file.
  40. It then runs "docker build" command automatically to generate the docker image.
  41. You should have docker installed, and there must be a Dockerfile in the root of the project.
  42. `
  43. cDockerMainBrief = `main file path for "gf build", it's "main.go" in default. empty string for no binary build`
  44. cDockerBuildBrief = `binary build options before docker image build, it's "-a amd64 -s linux" in default`
  45. cDockerFileBrief = `file path of the Dockerfile. it's "manifest/docker/Dockerfile" in default`
  46. cDockerShellBrief = `path of the shell file which is executed before docker build`
  47. cDockerPushBrief = `auto push the docker image to docker registry if "-t" option passed`
  48. cDockerTagBrief = `full tag for this docker, pattern like "xxx.xxx.xxx/image:tag"`
  49. cDockerTagNameBrief = `tag name for this docker, pattern like "image:tag". this option is required with TagPrefixes`
  50. cDockerTagPrefixesBrief = `tag prefixes for this docker, which are used for docker push. this option is required with TagName`
  51. cDockerExtraBrief = `extra build options passed to "docker image"`
  52. )
  53. func init() {
  54. gtag.Sets(g.MapStrStr{
  55. `cDockerUsage`: cDockerUsage,
  56. `cDockerBrief`: cDockerBrief,
  57. `cDockerEg`: cDockerEg,
  58. `cDockerDc`: cDockerDc,
  59. `cDockerMainBrief`: cDockerMainBrief,
  60. `cDockerFileBrief`: cDockerFileBrief,
  61. `cDockerShellBrief`: cDockerShellBrief,
  62. `cDockerBuildBrief`: cDockerBuildBrief,
  63. `cDockerPushBrief`: cDockerPushBrief,
  64. `cDockerTagBrief`: cDockerTagBrief,
  65. `cDockerTagNameBrief`: cDockerTagNameBrief,
  66. `cDockerTagPrefixesBrief`: cDockerTagPrefixesBrief,
  67. `cDockerExtraBrief`: cDockerExtraBrief,
  68. })
  69. }
  70. type cDockerInput struct {
  71. g.Meta `name:"docker" config:"gfcli.docker"`
  72. Main string `name:"MAIN" arg:"true" brief:"{cDockerMainBrief}" d:"main.go"`
  73. File string `name:"file" short:"f" brief:"{cDockerFileBrief}" d:"manifest/docker/Dockerfile"`
  74. Shell string `name:"shell" short:"s" brief:"{cDockerShellBrief}" d:"manifest/docker/docker.sh"`
  75. Build string `name:"build" short:"b" brief:"{cDockerBuildBrief}"`
  76. Tag string `name:"tag" short:"t" brief:"{cDockerTagBrief}"`
  77. TagName string `name:"tagName" short:"tn" brief:"{cDockerTagNameBrief}" v:"required-with:TagPrefixes"`
  78. TagPrefixes []string `name:"tagPrefixes" short:"tp" brief:"{cDockerTagPrefixesBrief}" v:"required-with:TagName"`
  79. Push bool `name:"push" short:"p" brief:"{cDockerPushBrief}" orphan:"true"`
  80. Extra string `name:"extra" short:"e" brief:"{cDockerExtraBrief}"`
  81. }
  82. type cDockerOutput struct{}
  83. func (c cDocker) Index(ctx context.Context, in cDockerInput) (out *cDockerOutput, err error) {
  84. // Necessary check.
  85. if gproc.SearchBinary("docker") == "" {
  86. mlog.Fatalf(`command "docker" not found in your environment, please install docker first to proceed this command`)
  87. }
  88. mlog.Debugf(`docker command input: %+v`, in)
  89. // Binary build.
  90. if in.Main != "" && in.Build != "" {
  91. in.Build += " --exitWhenError"
  92. if in.Main != "" {
  93. if err = gproc.ShellRun(ctx, fmt.Sprintf(`gf build %s %s`, in.Main, in.Build)); err != nil {
  94. mlog.Debugf(`build binary failed with error: %+v`, err)
  95. return
  96. }
  97. }
  98. }
  99. // Shell executing.
  100. if in.Shell != "" && gfile.Exists(in.Shell) {
  101. if err = c.exeDockerShell(ctx, in.Shell); err != nil {
  102. mlog.Debugf(`build docker failed with error: %+v`, err)
  103. return
  104. }
  105. }
  106. // Docker build.
  107. var (
  108. dockerBuildOptions string
  109. dockerTags []string
  110. dockerTagBase string
  111. )
  112. if len(in.TagPrefixes) > 0 {
  113. for _, tagPrefix := range in.TagPrefixes {
  114. tagPrefix = gstr.TrimRight(tagPrefix, "/")
  115. dockerTags = append(dockerTags, fmt.Sprintf(`%s/%s`, tagPrefix, in.TagName))
  116. }
  117. }
  118. if len(dockerTags) == 0 {
  119. dockerTags = []string{in.Tag}
  120. }
  121. for i, dockerTag := range dockerTags {
  122. if i > 0 {
  123. err = gproc.ShellRun(ctx, fmt.Sprintf(`docker tag %s %s`, dockerTagBase, dockerTag))
  124. if err != nil {
  125. return
  126. }
  127. continue
  128. }
  129. dockerTagBase = dockerTag
  130. dockerBuildOptions = ""
  131. if dockerTag != "" {
  132. dockerBuildOptions = fmt.Sprintf(`-t %s`, dockerTag)
  133. }
  134. if in.Extra != "" {
  135. dockerBuildOptions = fmt.Sprintf(`%s %s`, dockerBuildOptions, in.Extra)
  136. }
  137. err = gproc.ShellRun(ctx, fmt.Sprintf(`docker build -f %s . %s`, in.File, dockerBuildOptions))
  138. if err != nil {
  139. return
  140. }
  141. }
  142. // Docker push.
  143. if !in.Push {
  144. return
  145. }
  146. for _, dockerTag := range dockerTags {
  147. if dockerTag == "" {
  148. continue
  149. }
  150. err = gproc.ShellRun(ctx, fmt.Sprintf(`docker push %s`, dockerTag))
  151. if err != nil {
  152. return
  153. }
  154. }
  155. return
  156. }
  157. func (c cDocker) exeDockerShell(ctx context.Context, shellFilePath string) error {
  158. if gfile.ExtName(shellFilePath) == "sh" && runtime.GOOS == "windows" {
  159. mlog.Debugf(`ignore shell file "%s", as it cannot be run on windows system`, shellFilePath)
  160. return nil
  161. }
  162. return gproc.ShellRun(ctx, gfile.GetContents(shellFilePath))
  163. }