diff options
author | wxiaoguang <wxiaoguang@gmail.com> | 2021-12-01 15:50:01 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-01 15:50:01 +0800 |
commit | 042cac5fedeec8af53080b9666fe043072f3a6be (patch) | |
tree | b13d57faa71ba8bc9f8b3d40f5be7e3735ac66a4 /models/db | |
parent | a3517d8668482b58cb80ba10a956fe4e27e1a429 (diff) | |
download | gitea-042cac5fedeec8af53080b9666fe043072f3a6be.tar.gz gitea-042cac5fedeec8af53080b9666fe043072f3a6be.zip |
Improve install code to avoid low-level mistakes. (#17779)
* Improve install code to avoid low-level mistakes.
If a user tries to do a re-install in a Gitea database, they gets a warning and double check.
When Gitea runs, it never create empty app.ini automatically.
Also some small (related) refactoring:
* Refactor db.InitEngine related logic make it more clean (especially for the install code)
* Move some i18n strings out from setting.go to make the setting.go can be easily maintained.
* Show errors in CLI code if an incorrect app.ini is used.
* APP_DATA_PATH is created when installing, and checked when starting (no empty directory is created any more).
Diffstat (limited to 'models/db')
-rwxr-xr-x | models/db/engine.go | 68 | ||||
-rw-r--r-- | models/db/install/db.go | 65 |
2 files changed, 95 insertions, 38 deletions
diff --git a/models/db/engine.go b/models/db/engine.go index 0f744d027e..63e1d5547a 100755 --- a/models/db/engine.go +++ b/models/db/engine.go @@ -8,7 +8,6 @@ package db import ( "context" "database/sql" - "errors" "fmt" "io" "reflect" @@ -92,8 +91,8 @@ func init() { } } -// NewEngine returns a new xorm engine from the configuration -func NewEngine() (*xorm.Engine, error) { +// newXORMEngine returns a new XORM engine from the configuration +func newXORMEngine() (*xorm.Engine, error) { connStr, err := setting.DBConnStr() if err != nil { return nil, err @@ -126,40 +125,49 @@ func SyncAllTables() error { return x.StoreEngine("InnoDB").Sync2(tables...) } -// InitEngine sets the xorm.Engine -func InitEngine(ctx context.Context) (err error) { - x, err = NewEngine() +// InitEngine initializes the xorm.Engine and sets it as db.DefaultContext +func InitEngine(ctx context.Context) error { + xormEngine, err := newXORMEngine() if err != nil { - return fmt.Errorf("Failed to connect to database: %v", err) + return fmt.Errorf("failed to connect to database: %v", err) } - x.SetMapper(names.GonicMapper{}) + xormEngine.SetMapper(names.GonicMapper{}) // WARNING: for serv command, MUST remove the output to os.stdout, // so use log file to instead print to stdout. - x.SetLogger(NewXORMLogger(setting.Database.LogSQL)) - x.ShowSQL(setting.Database.LogSQL) - x.SetMaxOpenConns(setting.Database.MaxOpenConns) - x.SetMaxIdleConns(setting.Database.MaxIdleConns) - x.SetConnMaxLifetime(setting.Database.ConnMaxLifetime) + xormEngine.SetLogger(NewXORMLogger(setting.Database.LogSQL)) + xormEngine.ShowSQL(setting.Database.LogSQL) + xormEngine.SetMaxOpenConns(setting.Database.MaxOpenConns) + xormEngine.SetMaxIdleConns(setting.Database.MaxIdleConns) + xormEngine.SetConnMaxLifetime(setting.Database.ConnMaxLifetime) + xormEngine.SetDefaultContext(ctx) + + SetDefaultEngine(ctx, xormEngine) + return nil +} +// SetDefaultEngine sets the default engine for db +func SetDefaultEngine(ctx context.Context, eng *xorm.Engine) { + x = eng DefaultContext = &Context{ Context: ctx, e: x, } - x.SetDefaultContext(ctx) - return nil } -// SetEngine is used by unit test code -func SetEngine(eng *xorm.Engine) { - x = eng - DefaultContext = &Context{ - Context: context.Background(), - e: x, +// UnsetDefaultEngine closes and unsets the default engine +// We hope the SetDefaultEngine and UnsetDefaultEngine can be paired, but it's impossible now, +// there are many calls to InitEngine -> SetDefaultEngine directly to overwrite the `x` and DefaultContext without close +// Global database engine related functions are all racy and there is no graceful close right now. +func UnsetDefaultEngine() { + if x != nil { + _ = x.Close() + x = nil } + DefaultContext = nil } -// InitEngineWithMigration initializes a new xorm.Engine +// InitEngineWithMigration initializes a new xorm.Engine and sets it as the db.DefaultContext // This function must never call .Sync2() if the provided migration function fails. // When called from the "doctor" command, the migration function is a version check // that prevents the doctor from fixing anything in the database if the migration level @@ -226,14 +234,6 @@ func NamesToBean(names ...string) ([]interface{}, error) { return beans, nil } -// Ping tests if database is alive -func Ping() error { - if x != nil { - return x.Ping() - } - return errors.New("database not configured") -} - // DumpDatabase dumps all data from database according the special database SQL syntax to file system. func DumpDatabase(filePath, dbType string) error { var tbs []*schemas.Table @@ -291,11 +291,3 @@ func GetMaxID(beanOrTableName interface{}) (maxID int64, err error) { _, err = x.Select("MAX(id)").Table(beanOrTableName).Get(&maxID) return } - -// FindByMaxID filled results as the condition from database -func FindByMaxID(maxID int64, limit int, results interface{}) error { - return x.Where("id <= ?", maxID). - OrderBy("id DESC"). - Limit(limit). - Find(results) -} diff --git a/models/db/install/db.go b/models/db/install/db.go new file mode 100644 index 0000000000..363a8c8679 --- /dev/null +++ b/models/db/install/db.go @@ -0,0 +1,65 @@ +// 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 install + +import ( + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/setting" + + "xorm.io/xorm" +) + +func getXORMEngine() *xorm.Engine { + return db.DefaultContext.(*db.Context).Engine().(*xorm.Engine) +} + +// CheckDatabaseConnection checks the database connection +func CheckDatabaseConnection() error { + e := db.GetEngine(db.DefaultContext) + _, err := e.Exec("SELECT 1") + return err +} + +// GetMigrationVersion gets the database migration version +func GetMigrationVersion() (int64, error) { + var installedDbVersion int64 + x := getXORMEngine() + exist, err := x.IsTableExist("version") + if err != nil { + return 0, err + } + if !exist { + return 0, nil + } + _, err = x.Table("version").Cols("version").Get(&installedDbVersion) + if err != nil { + return 0, err + } + return installedDbVersion, nil +} + +// HasPostInstallationUsers checks whether there are users after installation +func HasPostInstallationUsers() (bool, error) { + x := getXORMEngine() + exist, err := x.IsTableExist("user") + if err != nil { + return false, err + } + if !exist { + return false, nil + } + + // if there are 2 or more users in database, we consider there are users created after installation + threshold := 2 + if !setting.IsProd { + // to debug easily, with non-prod RUN_MODE, we only check the count to 1 + threshold = 1 + } + res, err := x.Table("user").Cols("id").Limit(threshold).Query() + if err != nil { + return false, err + } + return len(res) >= threshold, nil +} |