genservice_generate.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  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 genservice
  7. import (
  8. "fmt"
  9. "github.com/gogf/gf/v2/container/garray"
  10. "github.com/gogf/gf/v2/frame/g"
  11. "github.com/gogf/gf/v2/os/gfile"
  12. "github.com/gogf/gf/v2/text/gregex"
  13. "github.com/gogf/gf/v2/text/gstr"
  14. "github.com/gogf/gf/cmd/gf/v2/internal/consts"
  15. "github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
  16. "github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
  17. )
  18. type generateServiceFilesInput struct {
  19. CGenServiceInput
  20. DstFilePath string // Absolute file path for generated service go file.
  21. SrcStructFunctions map[string]*garray.StrArray
  22. SrcImportedPackages []string
  23. SrcPackageName string
  24. DstPackageName string
  25. SrcCodeCommentedMap map[string]string
  26. }
  27. func (c CGenService) generateServiceFile(in generateServiceFilesInput) (ok bool, err error) {
  28. var (
  29. generatedContent string
  30. allFuncArray = garray.NewStrArray() // Used for check whether interface dirty, going to change file content.
  31. importedPackagesContent = fmt.Sprintf(
  32. "import (\n%s\n)", gstr.Join(in.SrcImportedPackages, "\n"),
  33. )
  34. )
  35. generatedContent += gstr.ReplaceByMap(consts.TemplateGenServiceContentHead, g.MapStrStr{
  36. "{Imports}": importedPackagesContent,
  37. "{PackageName}": in.DstPackageName,
  38. })
  39. // Type definitions.
  40. generatedContent += "type("
  41. generatedContent += "\n"
  42. for structName, funcArray := range in.SrcStructFunctions {
  43. allFuncArray.Append(funcArray.Slice()...)
  44. // Add comments to a method.
  45. for index, funcName := range funcArray.Slice() {
  46. if commentedInfo, exist := in.SrcCodeCommentedMap[fmt.Sprintf("%s-%s", structName, funcName)]; exist {
  47. funcName = commentedInfo + funcName
  48. _ = funcArray.Set(index, funcName)
  49. }
  50. }
  51. generatedContent += gstr.Trim(gstr.ReplaceByMap(consts.TemplateGenServiceContentInterface, g.MapStrStr{
  52. "{InterfaceName}": "I" + structName,
  53. "{FuncDefinition}": funcArray.Join("\n\t"),
  54. }))
  55. generatedContent += "\n"
  56. }
  57. generatedContent += ")"
  58. generatedContent += "\n"
  59. // Generating variable and register definitions.
  60. var (
  61. variableContent string
  62. generatingInterfaceCheck string
  63. )
  64. // Variable definitions.
  65. for structName := range in.SrcStructFunctions {
  66. generatingInterfaceCheck = fmt.Sprintf(`[^\w\d]+%s.I%s[^\w\d]`, in.DstPackageName, structName)
  67. if gregex.IsMatchString(generatingInterfaceCheck, generatedContent) {
  68. continue
  69. }
  70. variableContent += gstr.Trim(gstr.ReplaceByMap(consts.TemplateGenServiceContentVariable, g.MapStrStr{
  71. "{StructName}": structName,
  72. "{InterfaceName}": "I" + structName,
  73. }))
  74. variableContent += "\n"
  75. }
  76. if variableContent != "" {
  77. generatedContent += "var("
  78. generatedContent += "\n"
  79. generatedContent += variableContent
  80. generatedContent += ")"
  81. generatedContent += "\n"
  82. }
  83. // Variable register function definitions.
  84. for structName := range in.SrcStructFunctions {
  85. generatingInterfaceCheck = fmt.Sprintf(`[^\w\d]+%s.I%s[^\w\d]`, in.DstPackageName, structName)
  86. if gregex.IsMatchString(generatingInterfaceCheck, generatedContent) {
  87. continue
  88. }
  89. generatedContent += gstr.Trim(gstr.ReplaceByMap(consts.TemplateGenServiceContentRegister, g.MapStrStr{
  90. "{StructName}": structName,
  91. "{InterfaceName}": "I" + structName,
  92. }))
  93. generatedContent += "\n\n"
  94. }
  95. // Replace empty braces that have new line.
  96. generatedContent, _ = gregex.ReplaceString(`{[\s\t]+}`, `{}`, generatedContent)
  97. // Remove package name calls of `dstPackageName` in produced codes.
  98. generatedContent, _ = gregex.ReplaceString(fmt.Sprintf(`\*{0,1}%s\.`, in.DstPackageName), ``, generatedContent)
  99. // Write file content to disk.
  100. if gfile.Exists(in.DstFilePath) {
  101. if !utils.IsFileDoNotEdit(in.DstFilePath) {
  102. mlog.Printf(`ignore file as it is manually maintained: %s`, in.DstFilePath)
  103. return false, nil
  104. }
  105. if !c.isToGenerateServiceGoFile(in.DstPackageName, in.DstFilePath, allFuncArray) {
  106. mlog.Printf(`not dirty, ignore generating service go file: %s`, in.DstFilePath)
  107. return false, nil
  108. }
  109. }
  110. mlog.Printf(`generating service go file: %s`, in.DstFilePath)
  111. if err = gfile.PutContents(in.DstFilePath, generatedContent); err != nil {
  112. return true, err
  113. }
  114. return true, nil
  115. }
  116. // isToGenerateServiceGoFile checks and returns whether the service content dirty.
  117. func (c CGenService) isToGenerateServiceGoFile(dstPackageName, filePath string, funcArray *garray.StrArray) bool {
  118. var (
  119. err error
  120. fileContent = gfile.GetContents(filePath)
  121. generatedFuncArray = garray.NewSortedStrArrayFrom(funcArray.Slice())
  122. contentFuncArray = garray.NewSortedStrArray()
  123. )
  124. if fileContent == "" {
  125. return true
  126. }
  127. // remove all comments.
  128. fileContent, err = gregex.ReplaceString(`/[/|\*](.*)`, "", fileContent)
  129. if err != nil {
  130. panic(err)
  131. return false
  132. }
  133. matches, _ := gregex.MatchAllString(`\s+interface\s+{([\s\S]+?)}`, fileContent)
  134. for _, match := range matches {
  135. contentFuncArray.Append(gstr.SplitAndTrim(match[1], "\n")...)
  136. }
  137. if generatedFuncArray.Len() != contentFuncArray.Len() {
  138. mlog.Debugf(
  139. `dirty, generatedFuncArray.Len()[%d] != contentFuncArray.Len()[%d]`,
  140. generatedFuncArray.Len(), contentFuncArray.Len(),
  141. )
  142. return true
  143. }
  144. var funcDefinition string
  145. for i := 0; i < generatedFuncArray.Len(); i++ {
  146. funcDefinition, _ = gregex.ReplaceString(
  147. fmt.Sprintf(`\*{0,1}%s\.`, dstPackageName), ``, generatedFuncArray.At(i),
  148. )
  149. if funcDefinition != contentFuncArray.At(i) {
  150. mlog.Debugf(`dirty, %s != %s`, funcDefinition, contentFuncArray.At(i))
  151. return true
  152. }
  153. }
  154. return false
  155. }
  156. // generateInitializationFile generates `logic.go`.
  157. func (c CGenService) generateInitializationFile(in CGenServiceInput, importSrcPackages []string) (err error) {
  158. var (
  159. logicPackageName = gstr.ToLower(gfile.Basename(in.SrcFolder))
  160. logicFilePath = gfile.Join(in.SrcFolder, logicPackageName+".go")
  161. logicImports string
  162. generatedContent string
  163. )
  164. if !utils.IsFileDoNotEdit(logicFilePath) {
  165. mlog.Debugf(`ignore file as it is manually maintained: %s`, logicFilePath)
  166. return nil
  167. }
  168. for _, importSrcPackage := range importSrcPackages {
  169. logicImports += fmt.Sprintf(`%s_ "%s"%s`, "\t", importSrcPackage, "\n")
  170. }
  171. generatedContent = gstr.ReplaceByMap(consts.TemplateGenServiceLogicContent, g.MapStrStr{
  172. "{PackageName}": logicPackageName,
  173. "{Imports}": logicImports,
  174. })
  175. mlog.Printf(`generating init go file: %s`, logicFilePath)
  176. if err = gfile.PutContents(logicFilePath, generatedContent); err != nil {
  177. return err
  178. }
  179. utils.GoFmt(logicFilePath)
  180. return nil
  181. }
  182. // getDstFileNameCase call gstr.Case* function to convert the s to specified case.
  183. func (c CGenService) getDstFileNameCase(str, caseStr string) string {
  184. switch gstr.ToLower(caseStr) {
  185. case gstr.ToLower("Lower"):
  186. return gstr.ToLower(str)
  187. case gstr.ToLower("Camel"):
  188. return gstr.CaseCamel(str)
  189. case gstr.ToLower("CamelLower"):
  190. return gstr.CaseCamelLower(str)
  191. case gstr.ToLower("Kebab"):
  192. return gstr.CaseKebab(str)
  193. case gstr.ToLower("KebabScreaming"):
  194. return gstr.CaseKebabScreaming(str)
  195. case gstr.ToLower("SnakeFirstUpper"):
  196. return gstr.CaseSnakeFirstUpper(str)
  197. case gstr.ToLower("SnakeScreaming"):
  198. return gstr.CaseSnakeScreaming(str)
  199. }
  200. return gstr.CaseSnake(str)
  201. }