ast_service_enter.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. package ams_ast
  2. import (
  3. "bytes"
  4. "fmt"
  5. "github.com/pkg/errors"
  6. "go/ast"
  7. "go/format"
  8. "go/parser"
  9. "go/token"
  10. "io/ioutil"
  11. "log"
  12. "os"
  13. "path/filepath"
  14. "text/template"
  15. )
  16. // 根据模板文件 生成 service文件
  17. type ServiceRegister struct {
  18. TemplateFile string `json:"TemplateFile"` // 模块文件 resource/package/go_server/service/service.go.tpl
  19. TemplateEnterFile string `json:"TemplateEnterFile"` // 模块注册文件 resource/package/go_server/service/enter.go.tpl
  20. EnterFile string `json:"enterFile"` // 服务主入口文件 go_server/service/enter.go
  21. TargetEnterFile string `json:"targetEnterFile"` // 业务服务入口文件 go_server/service/alias/enter.go
  22. TargetFile string `json:"targetFile"` // 业务服务文件 go_server/service/alias/model.go
  23. ServicePkg string `json:"servicePkg"` // go_server/service/alias
  24. DbAlias string `json:"dbAlias"` // 数据库别名 aic_gold 模块名称
  25. DbName string `json:"dbName"` // 数据库名 aic_boost 数据库名
  26. TableName string `json:"tableName"` // 模型名称 demo_log 表名称
  27. ModelCap string `json:"modelCap"` // 模型名 首字母大写驼峰规则 DemoLog
  28. StructName string `json:"structName"` // 服务结构体名称 DemoLogService
  29. BaseAst
  30. }
  31. // alias 数据库别名 tableName 表名
  32. func BuildServiceRegister(alias, dbName, tableName string) *ServiceRegister {
  33. register := &ServiceRegister{
  34. TemplateFile: filepath.Join(template_root, server_service, "service.go.tpl"),
  35. TemplateEnterFile: filepath.Join(template_root, server_service, "enter.go.tpl"),
  36. DbAlias: alias,
  37. DbName: dbName,
  38. TableName: tableName,
  39. ModelCap: CapitalizeOrLower(toCamelCase(tableName)),
  40. StructName: fmt.Sprintf("%s%s", CapitalizeOrLower(toCamelCase(tableName)), "Service"),
  41. BaseAst: BaseAst{},
  42. }
  43. register.EnterFile = register.enterFile()
  44. register.TargetEnterFile = register.targetEnterFile(alias)
  45. register.TargetFile = register.targetFile(alias, tableName)
  46. register.ServicePkg = register.servicePkg(alias)
  47. return register
  48. }
  49. // 主入口服务名 BizGroup
  50. func (s *ServiceRegister) enterServiceGroup() string {
  51. return fmt.Sprintf("%s%s", CapitalizeOrLower(toCamelCase(s.DbAlias)), "ServiceGroup")
  52. }
  53. // 服务注册入口文件 go_server/service/enter.go
  54. func (s *ServiceRegister) enterFile() string {
  55. return filepath.Join(root, server_service, server_enter)
  56. }
  57. // 目标文件 go_server/service/biz/enter.go
  58. func (s *ServiceRegister) targetEnterFile(alias string) string {
  59. return filepath.Join(root, server_service, alias, server_enter)
  60. }
  61. // 目标文件 go_server/service/biz/user.go
  62. func (s *ServiceRegister) targetFile(alias, tableName string) string {
  63. return filepath.Join(root, server_service, alias, tableName+".go")
  64. }
  65. // 业务库基础服务 go_server/service/base
  66. func (s *ServiceRegister) baseServicePkg() string {
  67. return filepath.Join(server_service, server_biz_base_service)
  68. }
  69. // 服务PKG go_server/service/alias
  70. func (s *ServiceRegister) servicePkg(alias string) string {
  71. return filepath.Join(server_mod, server_service, alias)
  72. }
  73. // 初始化
  74. func (s *ServiceRegister) Initialize() error {
  75. //core.Log.Infof("服务注入开始:%s-%s", s.DbAlias, s.TableName)
  76. var err error
  77. // 创建targetService
  78. if err = s.createTargetService(); err != nil {
  79. //core.Log.Infof("服务文件创建失败:%s", err.Error())
  80. return err
  81. }
  82. //core.Log.Infof("1 服务文件创建完成:service/%s/%s.go", s.DbAlias, s.TableName)
  83. // 创建模块入口文件 注入服务
  84. if err = s.inspectTargetServiceToGroup(); err != nil {
  85. //core.Log.Infof("服务注入失败:%s", err.Error())
  86. return err
  87. }
  88. //core.Log.Infof("2 服务注入完成:service/%s/enter.go", s.DbAlias)
  89. // 注入服务到总入口文件
  90. if err = s.inspectRootService(); err != nil {
  91. //core.Log.Infof("注入服务到总入口文件失败:%s", err.Error())
  92. return err
  93. }
  94. //core.Log.Infof("3 注入服务到总入口文件完成:service/enter.go")
  95. return nil
  96. }
  97. // 创建目标服务文件
  98. func (s *ServiceRegister) createTargetService() error {
  99. var files *template.Template
  100. files, err := template.ParseFiles(s.TemplateFile)
  101. if err != nil {
  102. return err
  103. }
  104. err = os.MkdirAll(filepath.Dir(s.TargetFile), os.ModePerm)
  105. if err != nil {
  106. return err
  107. }
  108. if FileExists(s.TargetFile) {
  109. err = os.Remove(s.TargetFile)
  110. if err != nil {
  111. return err
  112. }
  113. }
  114. var file *os.File
  115. file, err = os.Create(s.TargetFile)
  116. if err != nil {
  117. return err
  118. }
  119. err = files.Execute(file, s)
  120. _ = file.Close()
  121. if err != nil {
  122. return err
  123. }
  124. return nil
  125. }
  126. // 注入子服务到服务组
  127. func (s *ServiceRegister) inspectTargetServiceToGroup() error {
  128. var err error
  129. if err = s.checkTargetEnter(); err != nil {
  130. return err
  131. }
  132. // 创建 token.FileSet
  133. fSet := token.NewFileSet()
  134. // 解析文件
  135. file, err := parser.ParseFile(fSet, s.TargetEnterFile, nil, parser.ParseComments)
  136. if err != nil {
  137. return err
  138. }
  139. // 检查是否存在 ServiceGroup 的结构体声明
  140. classTypeSpec, isHasServiceGroup := s.FindFileHasStruct(file, fmt.Sprintf("ServiceGroup"))
  141. if !isHasServiceGroup {
  142. return errors.New("not found ServiceGroup")
  143. }
  144. // 检查并添加属性- 不带Key
  145. if err = s.checkAndInsertStructFiled(classTypeSpec, s.StructName); err != nil {
  146. return err
  147. }
  148. // 格式化并写回文件
  149. var buf bytes.Buffer
  150. if err = format.Node(&buf, fSet, file); err != nil {
  151. return err
  152. }
  153. return os.WriteFile(s.TargetEnterFile, buf.Bytes(), 0666)
  154. }
  155. // 查找结构中属性 如果不存在则增加该属性 属性类型与名称一致
  156. func (s *ServiceRegister) checkAndInsertStructFiled(typeSpec *ast.TypeSpec, typeName string) error {
  157. hasField := false
  158. if structType, ok := typeSpec.Type.(*ast.StructType); ok {
  159. // 检查是否已有 AssetService 字段
  160. for _, field := range structType.Fields.List {
  161. if ident, ok := field.Type.(*ast.Ident); ok {
  162. if ident.Name == typeName {
  163. hasField = true
  164. break
  165. }
  166. }
  167. //field.Names
  168. }
  169. }
  170. if !hasField {
  171. // 添加 AssetService 字段
  172. structType, ok := typeSpec.Type.(*ast.StructType)
  173. if !ok {
  174. return errors.New("ServiceGroup is not a struct type")
  175. }
  176. // 创建新的字段
  177. newField := &ast.Field{
  178. Names: []*ast.Ident{
  179. {
  180. Name: "",
  181. },
  182. },
  183. Type: &ast.Ident{
  184. Name: typeName,
  185. },
  186. }
  187. // 添加到结构体字段列表
  188. structType.Fields.List = append(structType.Fields.List, newField)
  189. }
  190. return nil
  191. }
  192. // 检查与创建服务组入口文件
  193. func (s *ServiceRegister) checkTargetEnter() error {
  194. if FileExists(s.TargetEnterFile) {
  195. return nil
  196. }
  197. var files *template.Template
  198. files, err := template.ParseFiles(s.TemplateEnterFile)
  199. if err != nil {
  200. return err
  201. }
  202. err = os.MkdirAll(filepath.Dir(s.TargetEnterFile), os.ModePerm)
  203. if err != nil {
  204. return err
  205. }
  206. var file *os.File
  207. file, err = os.Create(s.TargetEnterFile)
  208. if err != nil {
  209. return err
  210. }
  211. err = files.Execute(file, s)
  212. _ = file.Close()
  213. if err != nil {
  214. return err
  215. }
  216. return nil
  217. }
  218. // 注入主服务 EnterFile
  219. func (s *ServiceRegister) inspectRootService() error {
  220. // 创建 token.FileSet
  221. fSet := token.NewFileSet()
  222. // 解析文件
  223. file, err := parser.ParseFile(fSet, s.EnterFile, nil, parser.ParseComments)
  224. if err != nil {
  225. log.Fatal(err)
  226. }
  227. isHasServiceGroup := s.CheckFileStructHasFiled(file, "Group", fmt.Sprintf("%sServiceGroup", s.DbAlias))
  228. if isHasServiceGroup {
  229. return nil
  230. }
  231. // 添加导入声明 -- 需要兼容windows
  232. normalizedPkg := filepath.ToSlash(s.ServicePkg)
  233. s.AddImport(file, normalizedPkg)
  234. // 注入服务
  235. // 创建新的字段
  236. newField := &ast.Field{
  237. Names: []*ast.Ident{
  238. {
  239. Name: s.enterServiceGroup(),
  240. },
  241. },
  242. Type: &ast.Ident{
  243. Name: fmt.Sprintf("%s.ServiceGroup", s.DbAlias),
  244. },
  245. }
  246. classTypeSpec, isHasServiceGroup := s.FindFileHasStruct(file, fmt.Sprintf("Group"))
  247. if !isHasServiceGroup {
  248. return errors.New("not found ServiceGroup")
  249. }
  250. if err = s.addFieldToStruct(classTypeSpec, s.enterServiceGroup(), newField); err != nil {
  251. //core.Log.Infof("服务总入口文件:%s 注入:%+v", err.Error(), newField)
  252. return err
  253. }
  254. // 格式化并写回文件
  255. var buf bytes.Buffer
  256. if err = format.Node(&buf, fSet, file); err != nil {
  257. return err
  258. }
  259. // 保持原始文件的模式
  260. info, err := os.Stat(s.EnterFile)
  261. if err != nil {
  262. return err
  263. }
  264. if err = ioutil.WriteFile(s.EnterFile, buf.Bytes(), info.Mode()); err != nil {
  265. return err
  266. }
  267. return nil
  268. }
  269. func (s *ServiceRegister) addFieldToStruct(typeSpec *ast.TypeSpec, filedName string, newField *ast.Field) error {
  270. hasFiled := false
  271. if structType, ok := typeSpec.Type.(*ast.StructType); ok {
  272. for _, field := range structType.Fields.List {
  273. for _, name := range field.Names {
  274. //core.Log.Infof("已注入服务:%s 待注入服务:%s", name.Name, filedName)
  275. if name.Name == filedName {
  276. hasFiled = true
  277. }
  278. }
  279. }
  280. }
  281. if !hasFiled {
  282. structType, ok := typeSpec.Type.(*ast.StructType)
  283. if !ok {
  284. return errors.New("ServiceGroup is not a struct type")
  285. }
  286. // 添加到结构体字段列表
  287. structType.Fields.List = append(structType.Fields.List, newField)
  288. }
  289. return nil
  290. }
  291. // 回滚
  292. func (s *ServiceRegister) RollBack() error {
  293. // delete targetService
  294. if FileExists(s.TargetFile) {
  295. err := os.Remove(s.TargetFile)
  296. if err != nil {
  297. return err
  298. }
  299. }
  300. if err := s.rollBackSubEnter(); err != nil {
  301. return err
  302. }
  303. // todo:回滚 总入口文件 -- 不需要回滚 模块一旦创建 不做回滚
  304. return nil
  305. }
  306. // 回滚子服务注入
  307. func (s *ServiceRegister) rollBackSubEnter() error {
  308. // 创建 token.FileSet
  309. fSet := token.NewFileSet()
  310. // 解析文件
  311. file, err := parser.ParseFile(fSet, s.TargetEnterFile, nil, parser.ParseComments)
  312. if err != nil {
  313. return err
  314. }
  315. // 模块入口文件 回滚注入服务
  316. // 检查是否存在 ServiceGroup 的结构体声明
  317. //core.Log.Infof("检查文件:%s中是否存在 ServiceGroup 的结构体声明", s.TargetEnterFile)
  318. classTypeSpec, isHasServiceGroup := s.FindFileHasStruct(file, fmt.Sprintf("ServiceGroup"))
  319. if !isHasServiceGroup {
  320. return errors.New("not found ServiceGroup")
  321. }
  322. //core.Log.Infof("检查文件:%s中 存在 ServiceGroup", s.TargetEnterFile)
  323. if err := s.checkAndRemoveStructFiled(classTypeSpec, s.StructName); err != nil {
  324. return err
  325. }
  326. // 格式化并写回文件
  327. var buf bytes.Buffer
  328. if err = format.Node(&buf, fSet, file); err != nil {
  329. return err
  330. }
  331. // 保持原始文件的模式
  332. info, err := os.Stat(s.TargetEnterFile)
  333. if err != nil {
  334. return err
  335. }
  336. if err = ioutil.WriteFile(s.TargetEnterFile, buf.Bytes(), info.Mode()); err != nil {
  337. return err
  338. }
  339. // 回滚 总入口文件
  340. return nil
  341. }
  342. // 查找结构中属性 如果存在则删除该属性
  343. func (s *ServiceRegister) checkAndRemoveStructFiled(typeSpec *ast.TypeSpec, typeName string) error {
  344. if structType, ok := typeSpec.Type.(*ast.StructType); ok {
  345. // 检查是否已有
  346. //core.Log.Infof("检查文件 ServiceGroup 中是否存在Field: %s", typeName)
  347. filteredFields := make([]*ast.Field, 0)
  348. for _, field := range structType.Fields.List {
  349. if ident, ok := field.Type.(*ast.Ident); ok {
  350. //core.Log.Infof("ident.Name:%s typeName:%s", ident.Name, typeName)
  351. if ident.Name == typeName {
  352. continue
  353. }
  354. // Skip this field (effectively removing it)
  355. }
  356. filteredFields = append(filteredFields, field)
  357. }
  358. //core.Log.Infof("len(filteredFields):%d len(structType.Fields.List):%d", len(filteredFields), len(structType.Fields.List))
  359. // If the length changed, we removed at least one field
  360. if len(filteredFields) < len(structType.Fields.List) {
  361. structType.Fields.List = filteredFields
  362. return nil
  363. }
  364. }
  365. return nil
  366. }