feat($upgrade): 支持从旧版本升级, #13

pull/21/merge
ouqiang 2017-09-03 21:30:03 +08:00
parent db1ef3b317
commit 350dc0881e
11 changed files with 112 additions and 15 deletions

4
.gitignore vendored
View File

@ -26,9 +26,7 @@ _testmain.go
.idea
log/*
data/*
conf/install.lock
conf/app.ini
conf/ansible_hosts.ini
conf/*
profile/*
public/resource/javascript/vue.js
gocron

View File

@ -70,7 +70,7 @@
* -s ip:port 监听地址
## To Do List
- [ ] 版本升级
- [x] 版本升级
- [ ] 任务分组
- [ ] 多用户
- [ ] 权限控制

View File

@ -47,7 +47,7 @@ func runWeb(ctx *cli.Context) {
// 设置运行环境
setEnvironment(ctx)
// 初始化应用
app.InitEnv()
app.InitEnv(ctx.App.Version)
// 初始化模块 DB、定时任务等
initModule()
// 捕捉信号,配置热更新等
@ -74,8 +74,12 @@ func initModule() {
}
app.Setting = config
// 初始化DB
models.Db = models.CreateDb()
// 版本升级
upgradeIfNeed()
// 初始化定时任务
serviceTask := new(service.Task)
serviceTask.Initialize()
@ -167,4 +171,20 @@ func shutdown() {
// 释放gRPC连接池
grpcpool.Pool.ReleaseAll()
}
// 判断应用是否需要升级, 当版本号文件版本小于app.VersionId时升级
func upgradeIfNeed() {
currentVersionId := app.GetCurrentVersionId()
if currentVersionId >= app.VersionId {
return
}
migration := new(models.Migration)
logger.Infof("版本升级开始, 当前版本号%d", currentVersionId)
migration.Upgrade(currentVersionId)
app.UpdateVersionFile()
logger.Infof("已升级到最新版本%d", app.VersionId)
}

View File

View File

@ -4,11 +4,11 @@ import (
"errors"
)
// 创建数据库表
type Migration struct{}
func (migration *Migration) Exec(dbName string) error {
// 首次安装, 创建数据库表
func (migration *Migration) Install(dbName string) error {
if !isDatabaseExist(dbName) {
return errors.New("数据库不存在")
}
@ -36,9 +36,29 @@ func (migration *Migration) Exec(dbName string) error {
return nil
}
// 创建数据库
// 判断数据库是否存在
func isDatabaseExist(name string) bool {
_, err := Db.Exec("use ?", name)
return err != nil
}
// 迭代升级数据库, 新建表、新增字段等
func (migration *Migration) Upgrade(oldVersionId int) {
versionIds := []int{}
upgradeFuncs := []func(){}
startIndex := 0
for i, value := range versionIds {
if oldVersionId == value {
startIndex = i + 1
break;
}
}
length := len(versionIds)
for startIndex < length {
upgradeFuncs[startIndex]()
startIndex++
}
}

View File

@ -6,6 +6,9 @@ import (
"github.com/ouqiang/gocron/modules/logger"
"github.com/ouqiang/gocron/modules/utils"
"gopkg.in/ini.v1"
"io/ioutil"
"strconv"
"strings"
)
var (
@ -16,10 +19,12 @@ var (
AppConfig string // 应用配置文件
Installed bool // 应用是否安装过
Setting *ini.Section // 应用配置
VersionId int // 版本号
VersionFile string // 版本号文件
)
func InitEnv() {
func InitEnv(versionString string) {
logger.InitLogger()
wd, err := os.Getwd()
if err != nil {
@ -30,11 +35,13 @@ func InitEnv() {
LogDir = AppDir + "/log"
DataDir = AppDir + "/data"
AppConfig = ConfDir + "/app.ini"
VersionFile = ConfDir + "/.version"
checkDirExists(ConfDir, LogDir, DataDir)
Installed = IsInstalled()
VersionId = ToNumberVersion(versionString)
}
// 判断应用是否安装
// 判断应用是否安装
func IsInstalled() bool {
_, err := os.Stat(ConfDir + "/install.lock")
if os.IsNotExist(err) {
@ -54,6 +61,54 @@ func CreateInstallLock() error {
return err
}
// 更新应用版本号文件
func UpdateVersionFile() {
err := ioutil.WriteFile(VersionFile,
[]byte(strconv.Itoa(VersionId)),
0644,
)
if err != nil {
logger.Fatal(err)
}
}
// 获取应用当前版本号, 从版本号文件中读取
func GetCurrentVersionId() int {
if !utils.FileExist(VersionFile) {
// 默认版本号110, 从v1.1版本开始支持升级
return 110;
}
bytes, err := ioutil.ReadFile(VersionFile)
if err != nil {
logger.Fatal(err)
}
versionId, err := strconv.Atoi(string(bytes))
if err != nil {
logger.Fatal(err)
}
return versionId
}
// 把字符串版本号a.b.c转换为整数版本号abc
func ToNumberVersion(versionString string) int {
versionString = strings.TrimSpace(versionString)
v := strings.Replace(versionString, ".", "", -1)
if len(v) < 3 {
v += "0"
}
versionId, err := strconv.Atoi(v)
if err != nil {
logger.Fatal(err)
}
return versionId
}
// 检测目录是否存在
func checkDirExists(path ...string) {
for _, value := range path {

View File

@ -75,7 +75,7 @@ func Store(ctx *macaron.Context, form InstallForm) string {
models.Db = models.CreateDb()
// 创建数据库表
migration := new(models.Migration)
err = migration.Exec(form.DbName)
err = migration.Install(form.DbName)
if err != nil {
return json.CommonFailure(fmt.Sprintf("创建数据库表失败-%s", err.Error()), err)
}
@ -92,6 +92,9 @@ func Store(ctx *macaron.Context, form InstallForm) string {
return json.CommonFailure("创建文件安装锁失败", err)
}
// 更新版本号文件
app.UpdateVersionFile()
app.Installed = true
// 初始化定时任务
serviceTask := new(service.Task)

View File

@ -16,6 +16,7 @@ import (
"strings"
"text/template"
"bytes"
"encoding/base64"
)
// 定时任务调度管理器
@ -364,7 +365,7 @@ func appendResultToCommand(command string, taskResult TaskResult) string {
}
data := map[string]interface{} {
"Code": code,
"Message": taskResult.Result,
"Message": base64.StdEncoding.EncodeToString([]byte(taskResult.Result)),
}
var buf *bytes.Buffer = new(bytes.Buffer)
tmpl, err := template.New("command").Parse(command)

View File

@ -29,7 +29,7 @@
</div>
</div>
</form>
<table class="ui striped table">
<table class="ui celled table">
<thead>
<tr>
<th>ID</th>

View File

@ -49,7 +49,7 @@
</div>
</div>
</form>
<table class="ui pink table task-list">
<table class="ui celled table task-list">
<thead>
<tr>
<th>ID</th>

View File

@ -48,7 +48,7 @@
</div>
</div>
</form>
<table class="ui pink table">
<table class="ui celled table">
<thead>
<tr>
<th>ID</th>