cmd_init.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  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. "os"
  11. "strings"
  12. "github.com/gogf/gf/v2/frame/g"
  13. "github.com/gogf/gf/v2/os/gcmd"
  14. "github.com/gogf/gf/v2/os/gfile"
  15. "github.com/gogf/gf/v2/os/gproc"
  16. "github.com/gogf/gf/v2/os/gres"
  17. "github.com/gogf/gf/v2/text/gstr"
  18. "github.com/gogf/gf/v2/util/gtag"
  19. "github.com/gogf/gf/cmd/gf/v2/internal/utility/allyes"
  20. "github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
  21. )
  22. var (
  23. Init = cInit{}
  24. )
  25. type cInit struct {
  26. g.Meta `name:"init" brief:"{cInitBrief}" eg:"{cInitEg}"`
  27. }
  28. const (
  29. cInitRepoPrefix = `github.com/gogf/`
  30. cInitMonoRepo = `template-mono`
  31. cInitSingleRepo = `template-single`
  32. cInitBrief = `create and initialize an empty GoFrame project`
  33. cInitEg = `
  34. gf init my-project
  35. gf init my-mono-repo -m
  36. `
  37. cInitNameBrief = `
  38. name for the project. It will create a folder with NAME in current directory.
  39. The NAME will also be the module name for the project.
  40. `
  41. // cInitGitDir the git directory
  42. cInitGitDir = ".git"
  43. // cInitGitignore the gitignore file
  44. cInitGitignore = ".gitignore"
  45. )
  46. func init() {
  47. gtag.Sets(g.MapStrStr{
  48. `cInitBrief`: cInitBrief,
  49. `cInitEg`: cInitEg,
  50. `cInitNameBrief`: cInitNameBrief,
  51. })
  52. }
  53. type cInitInput struct {
  54. g.Meta `name:"init"`
  55. Name string `name:"NAME" arg:"true" v:"required" brief:"{cInitNameBrief}"`
  56. Mono bool `name:"mono" short:"m" brief:"initialize a mono-repo instead a single-repo" orphan:"true"`
  57. Update bool `name:"update" short:"u" brief:"update to the latest goframe version" orphan:"true"`
  58. }
  59. type cInitOutput struct{}
  60. func (c cInit) Index(ctx context.Context, in cInitInput) (out *cInitOutput, err error) {
  61. var (
  62. overwrote = false
  63. )
  64. if !gfile.IsEmpty(in.Name) && !allyes.Check() {
  65. s := gcmd.Scanf(`the folder "%s" is not empty, files might be overwrote, continue? [y/n]: `, in.Name)
  66. if strings.EqualFold(s, "n") {
  67. return
  68. }
  69. overwrote = true
  70. }
  71. mlog.Print("initializing...")
  72. // Create project folder and files.
  73. var (
  74. templateRepoName string
  75. gitignoreFile = in.Name + "/" + cInitGitignore
  76. )
  77. if in.Mono {
  78. templateRepoName = cInitMonoRepo
  79. } else {
  80. templateRepoName = cInitSingleRepo
  81. }
  82. err = gres.Export(templateRepoName, in.Name, gres.ExportOption{
  83. RemovePrefix: templateRepoName,
  84. })
  85. if err != nil {
  86. return
  87. }
  88. // build ignoreFiles from the .gitignore file
  89. ignoreFiles := make([]string, 0, 10)
  90. ignoreFiles = append(ignoreFiles, cInitGitDir)
  91. if overwrote {
  92. err = gfile.ReadLines(gitignoreFile, func(line string) error {
  93. // Add only hidden files or directories
  94. // If other directories are added, it may cause the entire directory to be ignored
  95. // such as 'main' in the .gitignore file, but the path is 'D:\main\my-project'
  96. if line != "" && strings.HasPrefix(line, ".") {
  97. ignoreFiles = append(ignoreFiles, line)
  98. }
  99. return nil
  100. })
  101. // if not found the .gitignore file will skip os.ErrNotExist error
  102. if err != nil && !os.IsNotExist(err) {
  103. return
  104. }
  105. }
  106. // Replace template name to project name.
  107. err = gfile.ReplaceDirFunc(func(path, content string) string {
  108. for _, ignoreFile := range ignoreFiles {
  109. if strings.Contains(path, ignoreFile) {
  110. return content
  111. }
  112. }
  113. return gstr.Replace(gfile.GetContents(path), cInitRepoPrefix+templateRepoName, gfile.Basename(gfile.RealPath(in.Name)))
  114. }, in.Name, "*", true)
  115. if err != nil {
  116. return
  117. }
  118. // Update the GoFrame version.
  119. if in.Update {
  120. mlog.Print("update goframe...")
  121. // go get -u github.com/gogf/gf/v2@latest
  122. updateCommand := `go get -u github.com/gogf/gf/v2@latest`
  123. if in.Name != "." {
  124. updateCommand = fmt.Sprintf(`cd %s && %s`, in.Name, updateCommand)
  125. }
  126. if err = gproc.ShellRun(ctx, updateCommand); err != nil {
  127. mlog.Fatal(err)
  128. }
  129. // go mod tidy
  130. gomModTidyCommand := `go mod tidy`
  131. if in.Name != "." {
  132. gomModTidyCommand = fmt.Sprintf(`cd %s && %s`, in.Name, gomModTidyCommand)
  133. }
  134. if err = gproc.ShellRun(ctx, gomModTidyCommand); err != nil {
  135. mlog.Fatal(err)
  136. }
  137. }
  138. mlog.Print("initialization done! ")
  139. if !in.Mono {
  140. enjoyCommand := `gf run main.go`
  141. if in.Name != "." {
  142. enjoyCommand = fmt.Sprintf(`cd %s && %s`, in.Name, enjoyCommand)
  143. }
  144. mlog.Printf(`you can now run "%s" to start your journey, enjoy!`, enjoyCommand)
  145. }
  146. return
  147. }