Browse Source

feat:回滚自动化生产代码

main
songzhibin97 3 years ago
parent
commit
dac4e733fc
  1. 18
      server/api/v1/sys_auto_code.go
  2. 4
      server/model/sys_auto_code.go
  3. 13
      server/model/sys_autocode_history.go
  4. 1
      server/router/sys_auto_code.go
  5. 34
      server/service/sys_auto_code.go
  6. 58
      server/service/sys_autocode_history.go
  7. 1
      server/service/sys_initdb.go
  8. 4
      server/utils/file_operations.go
  9. 41
      server/utils/injectionCode.go

18
server/api/v1/sys_auto_code.go

@ -15,6 +15,24 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
) )
// @Tags AutoCode
// @Summary 回滚
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body uint true "回滚自动生成代码"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"回滚成功"}"
// @Router /autoCode/preview [post]
func RollBack(c *gin.Context) {
var id model.AutoHistoryByID
_ = c.ShouldBindJSON(&id)
if err := service.RollBack(id.ID); err != nil {
response.FailWithMessage(err.Error(), c)
return
}
response.OkWithMessage("回滚成功", c)
}
// @Tags AutoCode // @Tags AutoCode
// @Summary 预览创建后的代码 // @Summary 预览创建后的代码
// @Security ApiKeyAuth // @Security ApiKeyAuth

4
server/model/sys_auto_code.go

@ -2,6 +2,10 @@ package model
import "errors" import "errors"
type AutoHistoryByID struct {
ID uint `json:"id"`
}
// 初始版本自动化代码工具 // 初始版本自动化代码工具
type AutoCodeStruct struct { type AutoCodeStruct struct {
StructName string `json:"structName"` // Struct名称 StructName string `json:"structName"` // Struct名称

13
server/model/sys_autocode_history.go

@ -0,0 +1,13 @@
package model
import "gin-vue-admin/global"
// 自动迁移代码记录,用于回滚,重放使用
type SysAutoCodeHistory struct {
global.GVA_MODEL
TableName string
AutoCodeMeta string `gorm:"type:text"` // 其他meta信息 path;path
InjectionMeta string `gorm:"type:text"` // 注入的内容 RouterPath@functionName@RouterString;
Flag int // 表示对应状态 0 代表创建, 1 代表回滚 ...
}

1
server/router/sys_auto_code.go

@ -8,6 +8,7 @@ import (
func InitAutoCodeRouter(Router *gin.RouterGroup) { func InitAutoCodeRouter(Router *gin.RouterGroup) {
AutoCodeRouter := Router.Group("autoCode") AutoCodeRouter := Router.Group("autoCode")
{ {
AutoCodeRouter.POST("rollback", v1.RollBack) // 回滚
AutoCodeRouter.POST("preview", v1.PreviewTemp) // 获取自动创建代码预览 AutoCodeRouter.POST("preview", v1.PreviewTemp) // 获取自动创建代码预览
AutoCodeRouter.POST("createTemp", v1.CreateTemp) // 创建自动化代码 AutoCodeRouter.POST("createTemp", v1.CreateTemp) // 创建自动化代码
AutoCodeRouter.GET("getTables", v1.GetTables) // 获取对应数据库的表 AutoCodeRouter.GET("getTables", v1.GetTables) // 获取对应数据库的表

34
server/service/sys_auto_code.go

@ -2,6 +2,7 @@ package service
import ( import (
"errors" "errors"
"fmt"
"gin-vue-admin/global" "gin-vue-admin/global"
"gin-vue-admin/model" "gin-vue-admin/model"
"gin-vue-admin/model/request" "gin-vue-admin/model/request"
@ -143,6 +144,35 @@ func CreateTemp(autoCode model.AutoCodeStruct) (err error) {
return err return err
} }
err = utils.AutoInjectionCode(initializeRouterFilePath, "Routers", "router.Init"+autoCode.StructName+"Router(PrivateGroup)") err = utils.AutoInjectionCode(initializeRouterFilePath, "Routers", "router.Init"+autoCode.StructName+"Router(PrivateGroup)")
if err != nil {
return err
}
injectionCodeMeta := strings.Builder{}
injectionCodeMeta.WriteString(fmt.Sprintf("%s@%s@%s", initializeGormFilePath, "MysqlTables", "model."+autoCode.StructName+"{},"))
injectionCodeMeta.WriteString(";")
injectionCodeMeta.WriteString(fmt.Sprintf("%s@%s@%s", initializeRouterFilePath, "Routers", "router.Init"+autoCode.StructName+"Router(PrivateGroup)"))
// 保存生成信息
bf := strings.Builder{}
for _, data := range dataList {
if len(data.autoMoveFilePath) != 0 {
bf.WriteString(data.autoMoveFilePath)
bf.WriteString(";")
}
}
if autoCode.TableName != "" {
err = CreateAutoCodeHistory(bf.String(),
injectionCodeMeta.String(),
autoCode.TableName,
)
} else {
err = CreateAutoCodeHistory(bf.String(),
injectionCodeMeta.String(),
autoCode.StructName,
)
}
if err != nil { if err != nil {
return err return err
} }
@ -215,6 +245,10 @@ func GetColumn(tableName string, dbName string) (err error, Columns []request.Co
return err, Columns return err, Columns
} }
func DropTable(tableName string) error {
return global.GVA_DB.Exec("DROP TABLE " + tableName).Error
}
//@author: [SliverHorn](https://github.com/SliverHorn) //@author: [SliverHorn](https://github.com/SliverHorn)
//@author: [songzhibin97](https://github.com/songzhibin97) //@author: [songzhibin97](https://github.com/songzhibin97)
//@function: addAutoMoveFile //@function: addAutoMoveFile

58
server/service/sys_autocode_history.go

@ -0,0 +1,58 @@
package service
import (
"errors"
"gin-vue-admin/global"
"gin-vue-admin/model"
"gin-vue-admin/utils"
"strings"
"go.uber.org/zap"
)
// CreateAutoCodeHistory RouterPath : RouterPath@RouterString;RouterPath2@RouterString2
func CreateAutoCodeHistory(autoCodeMeta string, injectionMeta string, tableName string) error {
return global.GVA_DB.Create(&model.SysAutoCodeHistory{
AutoCodeMeta: autoCodeMeta,
InjectionMeta: injectionMeta,
TableName: tableName,
}).Error
}
func RollBack(id uint) error {
md := model.SysAutoCodeHistory{}
if err := global.GVA_DB.First(&md, id).Error; err != nil {
return err
}
// 切分数据
err, dbNames := GetTables(global.GVA_CONFIG.Mysql.Dbname)
if err != nil {
return err
}
// 删除表
for _, name := range dbNames {
if strings.Contains(strings.ToUpper(strings.Replace(name.TableName, "_", "", -1)), strings.ToUpper(md.TableName)) {
// 删除表
if err = DropTable(name.TableName); err != nil {
global.GVA_LOG.Error("ClearTag DropTable:", zap.Error(err))
}
}
}
// 删除文件
for _, path := range strings.Split(md.AutoCodeMeta, ";") {
_ = utils.DeLFile(path)
}
// 清除注入
for _, v := range strings.Split(md.InjectionMeta, ";") {
// RouterPath@functionName@RouterString
meta := strings.Split(v, "@")
if len(meta) != 3 {
return errors.New("split InjectionMeta Err")
}
_ = utils.AutoClearCode(meta[0], meta[2])
}
md.Flag = 1
return global.GVA_DB.Save(&md).Error
}

1
server/service/sys_initdb.go

@ -131,6 +131,7 @@ func InitDB(conf request.InitDB) error {
model.ExaSimpleUploader{}, model.ExaSimpleUploader{},
model.ExaCustomer{}, model.ExaCustomer{},
model.SysOperationRecord{}, model.SysOperationRecord{},
model.SysAutoCodeHistory{},
) )
if err != nil { if err != nil {
global.GVA_DB = nil global.GVA_DB = nil

4
server/utils/file_operations.go

@ -42,6 +42,10 @@ Redirect:
return os.Rename(src, dst) return os.Rename(src, dst)
} }
func DeLFile(filePath string) error {
return os.RemoveAll(filePath)
}
//@author: [songzhibin97](https://github.com/songzhibin97) //@author: [songzhibin97](https://github.com/songzhibin97)
//@function: TrimSpace //@function: TrimSpace
//@description: 去除结构体空格 //@description: 去除结构体空格

41
server/utils/injectionCode.go

@ -1,6 +1,7 @@
package utils package utils
import ( import (
"errors"
"fmt" "fmt"
"go/ast" "go/ast"
"go/parser" "go/parser"
@ -15,9 +16,18 @@ import (
//@param: filepath string, funcName string, codeData string //@param: filepath string, funcName string, codeData string
//@return: error //@return: error
const (
startComment = "Code generated by gin-vue-admin Begin; DO NOT EDIT."
endComment = "Code generated by gin-vue-admin End; DO NOT EDIT."
)
//@author: [LeonardWang](https://github.com/WangLeonard)
//@function: AutoInjectionCode
//@description: 向文件中固定注释位置写入代码
//@param: filepath string, funcName string, codeData string
//@return: error
func AutoInjectionCode(filepath string, funcName string, codeData string) error { func AutoInjectionCode(filepath string, funcName string, codeData string) error {
startComment := "Code generated by gin-vue-admin Begin; DO NOT EDIT."
endComment := "Code generated by gin-vue-admin End; DO NOT EDIT."
srcData, err := ioutil.ReadFile(filepath) srcData, err := ioutil.ReadFile(filepath)
if err != nil { if err != nil {
return err return err
@ -141,3 +151,30 @@ func checkExist(srcData *[]byte, startPos int, endPos int, blockStmt *ast.BlockS
} }
return false return false
} }
func AutoClearCode(filepath string, codeData string) error {
srcData, err := ioutil.ReadFile(filepath)
if err != nil {
return err
}
srcData, err = cleanCode(codeData, string(srcData))
if err != nil {
return err
}
return ioutil.WriteFile(filepath, srcData, 0600)
}
func cleanCode(clearCode string, srcData string) ([]byte, error) {
bf := make([]rune, 0, 1024)
for i, v := range srcData {
if v == '\n' {
if strings.TrimSpace(string(bf)) == clearCode {
return append([]byte(srcData[:i-len(bf)]), []byte(srcData[i+1:])...), nil
}
bf = (bf)[:0]
continue
}
bf = append(bf, v)
}
return []byte(srcData), errors.New("未找到内容")
}
Loading…
Cancel
Save