1
0

docker.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. package docker
  2. import (
  3. "errors"
  4. "fmt"
  5. "os"
  6. "path"
  7. "path/filepath"
  8. "strings"
  9. "text/template"
  10. "github.com/gookit/color"
  11. "github.com/spf13/cobra"
  12. "github.com/wuntsong-org/go-zero-plus/tools/goctlwt/util"
  13. "github.com/wuntsong-org/go-zero-plus/tools/goctlwt/util/env"
  14. "github.com/wuntsong-org/go-zero-plus/tools/goctlwt/util/pathx"
  15. )
  16. const (
  17. dockerfileName = "Dockerfile"
  18. etcDir = "etc"
  19. yamlEtx = ".yaml"
  20. )
  21. // Docker describes a dockerfile
  22. type Docker struct {
  23. Chinese bool
  24. GoMainFrom string
  25. GoRelPath string
  26. GoFile string
  27. ExeFile string
  28. BaseImage string
  29. HasPort bool
  30. Port int
  31. Argument string
  32. Version string
  33. HasTimezone bool
  34. Timezone string
  35. }
  36. // dockerCommand provides the entry for goctl docker
  37. func dockerCommand(_ *cobra.Command, _ []string) (err error) {
  38. defer func() {
  39. if err == nil {
  40. fmt.Println(color.Green.Render("Done."))
  41. }
  42. }()
  43. goFile := varStringGo
  44. home := varStringHome
  45. version := varStringVersion
  46. remote := varStringRemote
  47. branch := varStringBranch
  48. timezone := varStringTZ
  49. if len(remote) > 0 {
  50. repo, _ := util.CloneIntoGitHome(remote, branch)
  51. if len(repo) > 0 {
  52. home = repo
  53. }
  54. }
  55. if len(version) > 0 {
  56. version = version + "-"
  57. }
  58. if len(home) > 0 {
  59. pathx.RegisterGoctlHome(home)
  60. }
  61. if len(goFile) > 0 && !pathx.FileExists(goFile) {
  62. return fmt.Errorf("file %q not found", goFile)
  63. }
  64. base := varStringBase
  65. port := varIntPort
  66. if _, err := os.Stat(etcDir); os.IsNotExist(err) {
  67. return generateDockerfile(goFile, base, port, version, timezone)
  68. }
  69. cfg, err := findConfig(goFile, etcDir)
  70. if err != nil {
  71. return err
  72. }
  73. if err := generateDockerfile(goFile, base, port, version, timezone, "-f", "etc/"+cfg); err != nil {
  74. return err
  75. }
  76. projDir, ok := pathx.FindProjectPath(goFile)
  77. if ok {
  78. fmt.Printf("Hint: run \"docker build ...\" command in dir:\n %s\n", projDir)
  79. }
  80. return nil
  81. }
  82. func findConfig(file, dir string) (string, error) {
  83. var files []string
  84. err := filepath.Walk(dir, func(path string, f os.FileInfo, _ error) error {
  85. if !f.IsDir() {
  86. if filepath.Ext(f.Name()) == yamlEtx {
  87. files = append(files, f.Name())
  88. }
  89. }
  90. return nil
  91. })
  92. if err != nil {
  93. return "", err
  94. }
  95. if len(files) == 0 {
  96. return "", errors.New("no yaml file")
  97. }
  98. name := strings.TrimSuffix(filepath.Base(file), ".go")
  99. for _, f := range files {
  100. if strings.Index(f, name) == 0 {
  101. return f, nil
  102. }
  103. }
  104. return files[0], nil
  105. }
  106. func generateDockerfile(goFile, base string, port int, version, timezone string, args ...string) error {
  107. var projPath string
  108. var err error
  109. if len(goFile) > 0 {
  110. projPath, err = getFilePath(filepath.Dir(goFile))
  111. if err != nil {
  112. return err
  113. }
  114. }
  115. if len(projPath) == 0 {
  116. projPath = "."
  117. }
  118. out, err := pathx.CreateIfNotExist(dockerfileName)
  119. if err != nil {
  120. return err
  121. }
  122. defer out.Close()
  123. text, err := pathx.LoadTemplate(category, dockerTemplateFile, dockerTemplate)
  124. if err != nil {
  125. return err
  126. }
  127. var builder strings.Builder
  128. for _, arg := range args {
  129. builder.WriteString(`, "` + arg + `"`)
  130. }
  131. var exeName string
  132. if len(varExeName) > 0 {
  133. exeName = varExeName
  134. } else if len(goFile) > 0 {
  135. exeName = pathx.FileNameWithoutExt(filepath.Base(goFile))
  136. } else {
  137. absPath, err := filepath.Abs(projPath)
  138. if err != nil {
  139. return err
  140. }
  141. exeName = filepath.Base(absPath)
  142. }
  143. t := template.Must(template.New("dockerfile").Parse(text))
  144. return t.Execute(out, Docker{
  145. Chinese: env.InChina(),
  146. GoMainFrom: path.Join(projPath, goFile),
  147. GoRelPath: projPath,
  148. GoFile: goFile,
  149. ExeFile: exeName,
  150. BaseImage: base,
  151. HasPort: port > 0,
  152. Port: port,
  153. Argument: builder.String(),
  154. Version: version,
  155. HasTimezone: len(timezone) > 0,
  156. Timezone: timezone,
  157. })
  158. }
  159. func getFilePath(file string) (string, error) {
  160. wd, err := os.Getwd()
  161. if err != nil {
  162. return "", err
  163. }
  164. projPath, ok := pathx.FindGoModPath(filepath.Join(wd, file))
  165. if !ok {
  166. projPath, err = pathx.PathFromGoSrc()
  167. if err != nil {
  168. return "", errors.New("no go.mod found, or not in GOPATH")
  169. }
  170. // ignore project root directory for GOPATH mode
  171. pos := strings.IndexByte(projPath, os.PathSeparator)
  172. if pos >= 0 {
  173. projPath = projPath[pos+1:]
  174. }
  175. }
  176. return projPath, nil
  177. }