From 960c322586eceb9598bb0a9985a8dd987dc74807 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Fri, 22 Oct 2021 00:10:49 +0800 Subject: [PATCH] Refactor update checker to use AppState (#17387) We have the `AppState` module now, it can store app related data easily. We do not need to create separate tables for each feature. So the update checker can use `AppState` instead of a one-row dedicate table. And the code of update checker is moved from `models` to `modules`. --- models/migrations/migrations.go | 4 +- models/migrations/v199.go | 13 +--- models/migrations/v201.go | 15 ++++ modules/cron/tasks_extended.go | 3 +- .../updatechecker}/update_checker.go | 69 +++++++------------ routers/web/admin/admin.go | 5 +- 6 files changed, 48 insertions(+), 61 deletions(-) create mode 100644 models/migrations/v201.go rename {models => modules/updatechecker}/update_checker.go (56%) diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index b1c91beef6..2686dfb3cf 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -351,9 +351,11 @@ var migrations = []Migration{ // v198 -> v199 NewMigration("Add issue content history table", addTableIssueContentHistory), // v199 -> v200 - NewMigration("Add remote version table", addRemoteVersionTable), + NewMigration("No-op (remote version is using AppState now)", addRemoteVersionTableNoop), // v200 -> v201 NewMigration("Add table app_state", addTableAppState), + // v201 -> v202 + NewMigration("Drop table remote_version (if exists)", dropTableRemoteVersion), } // GetCurrentDBVersion returns the current db version diff --git a/models/migrations/v199.go b/models/migrations/v199.go index 64b21172c1..4351ba4fa8 100644 --- a/models/migrations/v199.go +++ b/models/migrations/v199.go @@ -5,19 +5,10 @@ package migrations import ( - "fmt" - "xorm.io/xorm" ) -func addRemoteVersionTable(x *xorm.Engine) error { - type RemoteVersion struct { - ID int64 `xorm:"pk autoincr"` - Version string `xorm:"VARCHAR(50)"` - } - - if err := x.Sync2(new(RemoteVersion)); err != nil { - return fmt.Errorf("Sync2: %v", err) - } +func addRemoteVersionTableNoop(x *xorm.Engine) error { + // we used to use a table `remote_version` to store information for updater, now we use `AppState`, so this migration task is a no-op now. return nil } diff --git a/models/migrations/v201.go b/models/migrations/v201.go new file mode 100644 index 0000000000..637c30617c --- /dev/null +++ b/models/migrations/v201.go @@ -0,0 +1,15 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package migrations + +import ( + "xorm.io/xorm" +) + +func dropTableRemoteVersion(x *xorm.Engine) error { + // drop the orphaned table introduced in `v199`, now the update checker also uses AppState, do not need this table + _ = x.DropTables("remote_version") + return nil +} diff --git a/modules/cron/tasks_extended.go b/modules/cron/tasks_extended.go index 6645e71d2c..9a37c40faf 100644 --- a/modules/cron/tasks_extended.go +++ b/modules/cron/tasks_extended.go @@ -11,6 +11,7 @@ import ( "code.gitea.io/gitea/models" repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/updatechecker" ) func registerDeleteInactiveUsers() { @@ -145,7 +146,7 @@ func registerUpdateGiteaChecker() { HTTPEndpoint: "https://dl.gitea.io/gitea/version.json", }, func(ctx context.Context, _ *models.User, config Config) error { updateCheckerConfig := config.(*UpdateCheckerConfig) - return models.GiteaUpdateChecker(updateCheckerConfig.HTTPEndpoint) + return updatechecker.GiteaUpdateChecker(updateCheckerConfig.HTTPEndpoint) }) } diff --git a/models/update_checker.go b/modules/updatechecker/update_checker.go similarity index 56% rename from models/update_checker.go rename to modules/updatechecker/update_checker.go index 5b4fce69ec..01242189fa 100644 --- a/models/update_checker.go +++ b/modules/updatechecker/update_checker.go @@ -2,29 +2,28 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package updatechecker import ( "encoding/json" - "fmt" "io/ioutil" "net/http" - "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/appstate" "code.gitea.io/gitea/modules/proxy" "code.gitea.io/gitea/modules/setting" "github.com/hashicorp/go-version" ) -// RemoteVersion stores the remote version from the JSON endpoint -type RemoteVersion struct { - ID int64 `xorm:"pk autoincr"` - Version string `xorm:"VARCHAR(50)"` +// CheckerState stores the remote version from the JSON endpoint +type CheckerState struct { + LatestVersion string } -func init() { - db.RegisterModel(new(RemoteVersion)) +// Name returns the name of the state item for update checker +func (r *CheckerState) Name() string { + return "update-checker" } // GiteaUpdateChecker returns error when new version of Gitea is available @@ -49,60 +48,33 @@ func GiteaUpdateChecker(httpEndpoint string) error { return err } - type v struct { + type respType struct { Latest struct { Version string `json:"version"` } `json:"latest"` } - ver := v{} - err = json.Unmarshal(body, &ver) + respData := respType{} + err = json.Unmarshal(body, &respData) if err != nil { return err } - return UpdateRemoteVersion(ver.Latest.Version) + return UpdateRemoteVersion(respData.Latest.Version) } // UpdateRemoteVersion updates the latest available version of Gitea func UpdateRemoteVersion(version string) (err error) { - sess := db.NewSession(db.DefaultContext) - defer sess.Close() - if err = sess.Begin(); err != nil { - return err - } - - currentVersion := &RemoteVersion{ID: 1} - has, err := sess.Get(currentVersion) - if err != nil { - return fmt.Errorf("get: %v", err) - } else if !has { - currentVersion.ID = 1 - currentVersion.Version = version - - if _, err = sess.InsertOne(currentVersion); err != nil { - return fmt.Errorf("insert: %v", err) - } - return nil - } - - if _, err = sess.Update(&RemoteVersion{ID: 1, Version: version}); err != nil { - return err - } - - return sess.Commit() + return appstate.AppState.Set(&CheckerState{LatestVersion: version}) } // GetRemoteVersion returns the current remote version (or currently installed verson if fail to fetch from DB) func GetRemoteVersion() string { - e := db.GetEngine(db.DefaultContext) - v := &RemoteVersion{ID: 1} - _, err := e.Get(&v) - if err != nil { - // return current version if fail to fetch from DB - return setting.AppVer + item := new(CheckerState) + if err := appstate.AppState.Get(item); err != nil { + return "" } - return v.Version + return item.LatestVersion } // GetNeedUpdate returns true whether a newer version of Gitea is available @@ -112,7 +84,12 @@ func GetNeedUpdate() bool { // return false to fail silently return false } - remoteVer, err := version.NewVersion(GetRemoteVersion()) + remoteVerStr := GetRemoteVersion() + if remoteVerStr == "" { + // no remote version is known + return false + } + remoteVer, err := version.NewVersion(remoteVerStr) if err != nil { // return false to fail silently return false diff --git a/routers/web/admin/admin.go b/routers/web/admin/admin.go index ca5b157523..223114dae1 100644 --- a/routers/web/admin/admin.go +++ b/routers/web/admin/admin.go @@ -26,6 +26,7 @@ import ( "code.gitea.io/gitea/modules/queue" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/updatechecker" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/forms" "code.gitea.io/gitea/services/mailer" @@ -125,8 +126,8 @@ func Dashboard(ctx *context.Context) { ctx.Data["PageIsAdmin"] = true ctx.Data["PageIsAdminDashboard"] = true ctx.Data["Stats"] = models.GetStatistic() - ctx.Data["NeedUpdate"] = models.GetNeedUpdate() - ctx.Data["RemoteVersion"] = models.GetRemoteVersion() + ctx.Data["NeedUpdate"] = updatechecker.GetNeedUpdate() + ctx.Data["RemoteVersion"] = updatechecker.GetRemoteVersion() // FIXME: update periodically updateSystemStatus() ctx.Data["SysStatus"] = sysStatus