aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmd/cmd.go2
-rw-r--r--cmd/convert.go4
-rw-r--r--cmd/dump.go5
-rw-r--r--cmd/migrate.go2
-rw-r--r--contrib/pr/checkout.go10
-rw-r--r--custom/conf/app.ini.sample4
-rw-r--r--docs/content/doc/advanced/config-cheat-sheet.en-us.md2
-rw-r--r--docs/content/doc/advanced/config-cheat-sheet.zh-cn.md2
-rw-r--r--integrations/integration_test.go26
-rw-r--r--integrations/lfs_getobject_test.go2
-rw-r--r--integrations/migration-test/migration_test.go48
-rw-r--r--models/convert.go8
-rw-r--r--models/migrations/migrations.go8
-rw-r--r--models/migrations/v19.go2
-rw-r--r--models/migrations/v22.go2
-rw-r--r--models/migrations/v26.go2
-rw-r--r--models/migrations/v27.go2
-rw-r--r--models/migrations/v33.go4
-rw-r--r--models/migrations/v45.go4
-rw-r--r--models/migrations/v50.go4
-rw-r--r--models/migrations/v67.go4
-rw-r--r--models/migrations/v81.go2
-rw-r--r--models/models.go148
-rw-r--r--models/models_test.go91
-rw-r--r--models/repo.go6
-rw-r--r--models/unit_tests.go2
-rw-r--r--models/user.go5
-rw-r--r--models/user_heatmap.go8
-rw-r--r--modules/setting/database.go171
-rw-r--r--modules/setting/database_sqlite.go (renamed from models/models_sqlite.go)4
-rw-r--r--modules/setting/database_test.go94
-rw-r--r--modules/setting/setting.go38
-rw-r--r--routers/admin/admin.go4
-rw-r--r--routers/init.go19
-rw-r--r--routers/install.go62
35 files changed, 424 insertions, 377 deletions
diff --git a/cmd/cmd.go b/cmd/cmd.go
index 5a55ac318c..d05eb8b1a2 100644
--- a/cmd/cmd.go
+++ b/cmd/cmd.go
@@ -38,7 +38,7 @@ func initDB() error {
func initDBDisableConsole(disableConsole bool) error {
setting.NewContext()
- models.LoadConfigs()
+ setting.InitDBConfig()
setting.NewXORMLogService(disableConsole)
if err := models.SetEngine(); err != nil {
diff --git a/cmd/convert.go b/cmd/convert.go
index cb0510c722..23a3d8dbe9 100644
--- a/cmd/convert.go
+++ b/cmd/convert.go
@@ -31,9 +31,9 @@ func runConvert(ctx *cli.Context) error {
log.Trace("AppWorkPath: %s", setting.AppWorkPath)
log.Trace("Custom path: %s", setting.CustomPath)
log.Trace("Log path: %s", setting.LogRootPath)
- models.LoadConfigs()
+ setting.InitDBConfig()
- if models.DbCfg.Type != "mysql" {
+ if !setting.Database.UseMySQL {
fmt.Println("This command can only be used with a MySQL database")
return nil
}
diff --git a/cmd/dump.go b/cmd/dump.go
index de289270d4..1bf6901769 100644
--- a/cmd/dump.go
+++ b/cmd/dump.go
@@ -58,7 +58,6 @@ It can be used for backup and capture Gitea server image to send to maintainer`,
func runDump(ctx *cli.Context) error {
setting.NewContext()
setting.NewServices() // cannot access session settings otherwise
- models.LoadConfigs()
err := models.SetEngine()
if err != nil {
@@ -104,8 +103,8 @@ func runDump(ctx *cli.Context) error {
}
targetDBType := ctx.String("database")
- if len(targetDBType) > 0 && targetDBType != models.DbCfg.Type {
- log.Printf("Dumping database %s => %s...", models.DbCfg.Type, targetDBType)
+ if len(targetDBType) > 0 && targetDBType != setting.Database.Type {
+ log.Printf("Dumping database %s => %s...", setting.Database.Type, targetDBType)
} else {
log.Printf("Dumping database...")
}
diff --git a/cmd/migrate.go b/cmd/migrate.go
index dde50a455f..1fa1d09e25 100644
--- a/cmd/migrate.go
+++ b/cmd/migrate.go
@@ -30,7 +30,7 @@ func runMigrate(ctx *cli.Context) error {
log.Trace("AppWorkPath: %s", setting.AppWorkPath)
log.Trace("Custom path: %s", setting.CustomPath)
log.Trace("Log path: %s", setting.LogRootPath)
- models.LoadConfigs()
+ setting.InitDBConfig()
if err := models.NewEngine(migrations.Migrate); err != nil {
log.Fatal("Failed to initialize ORM engine: %v", err)
diff --git a/contrib/pr/checkout.go b/contrib/pr/checkout.go
index 7e6351cc63..490d6760c8 100644
--- a/contrib/pr/checkout.go
+++ b/contrib/pr/checkout.go
@@ -79,16 +79,16 @@ func runPR() {
setting.CheckLFSVersion()
//models.LoadConfigs()
/*
- models.DbCfg.Type = "sqlite3"
- models.DbCfg.Path = ":memory:"
- models.DbCfg.Timeout = 500
+ setting.Database.Type = "sqlite3"
+ setting.Database.Path = ":memory:"
+ setting.Database.Timeout = 500
*/
db := setting.Cfg.Section("database")
db.NewKey("DB_TYPE", "sqlite3")
db.NewKey("PATH", ":memory:")
- setting.LogSQL = true
- models.LoadConfigs()
+
routers.NewServices()
+ setting.Database.LogSQL = true
//x, err = xorm.NewEngine("sqlite3", "file::memory:?cache=shared")
var helper testfixtures.Helper = &testfixtures.SQLite{}
diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample
index 73ca5e0030..f2763e44df 100644
--- a/custom/conf/app.ini.sample
+++ b/custom/conf/app.ini.sample
@@ -275,6 +275,10 @@ LOG_SQL = true
DB_RETRIES = 10
; Backoff time per DB retry (time.Duration)
DB_RETRY_BACKOFF = 3s
+; Max idle database connections on connnection pool, default is 0
+MAX_IDLE_CONNS = 0
+; Database connection max life time, default is 3s
+CONN_MAX_LIFETIME = 3s
[indexer]
; Issue indexer type, currently support: bleve or db, default is bleve
diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md
index ac309cecfa..8b5235f716 100644
--- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md
+++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md
@@ -166,6 +166,8 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
- `LOG_SQL`: **true**: Log the executed SQL.
- `DB_RETRIES`: **10**: How many ORM init / DB connect attempts allowed.
- `DB_RETRY_BACKOFF`: **3s**: time.Duration to wait before trying another ORM init / DB connect attempt, if failure occured.
+- `MAX_IDLE_CONNS` **0**: Max idle database connections on connnection pool, default is 0
+- `CONN_MAX_LIFETIME` **3s**: Database connection max lifetime
## Indexer (`indexer`)
diff --git a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md
index 7a00216b9f..b4b9e4e3a9 100644
--- a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md
+++ b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md
@@ -82,6 +82,8 @@ menu:
- `CHARSET`: **utf8**: 仅当数据库为 MySQL 时有效, 可以为 "utf8" 或 "utf8mb4"。注意:如果使用 "utf8mb4",你的 MySQL InnoDB 版本必须在 5.6 以上。
- `PATH`: Tidb 或者 SQLite3 数据文件存放路径。
- `LOG_SQL`: **true**: 显示生成的SQL,默认为真。
+- `MAX_IDLE_CONNS` **0**: 最大空闲数据库连接
+- `CONN_MAX_LIFETIME` **3s**: 数据库连接最大存活时间
## Indexer (`indexer`)
diff --git a/integrations/integration_test.go b/integrations/integration_test.go
index eaec2d509e..e4d506ee7d 100644
--- a/integrations/integration_test.go
+++ b/integrations/integration_test.go
@@ -59,13 +59,13 @@ func TestMain(m *testing.M) {
routes.RegisterRoutes(mac)
var helper testfixtures.Helper
- if setting.UseMySQL {
+ if setting.Database.UseMySQL {
helper = &testfixtures.MySQL{}
- } else if setting.UsePostgreSQL {
+ } else if setting.Database.UsePostgreSQL {
helper = &testfixtures.PostgreSQL{}
- } else if setting.UseSQLite3 {
+ } else if setting.Database.UseSQLite3 {
helper = &testfixtures.SQLite{}
- } else if setting.UseMSSQL {
+ } else if setting.Database.UseMSSQL {
helper = &testfixtures.SQLServer{}
} else {
fmt.Println("Unsupported RDBMS for integration tests")
@@ -121,12 +121,12 @@ func initIntegrationTest() {
setting.SetCustomPathAndConf("", "", "")
setting.NewContext()
setting.CheckLFSVersion()
- models.LoadConfigs()
+ setting.InitDBConfig()
switch {
- case setting.UseMySQL:
+ case setting.Database.UseMySQL:
db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/",
- models.DbCfg.User, models.DbCfg.Passwd, models.DbCfg.Host))
+ setting.Database.User, setting.Database.Passwd, setting.Database.Host))
defer db.Close()
if err != nil {
log.Fatalf("sql.Open: %v", err)
@@ -134,14 +134,14 @@ func initIntegrationTest() {
if _, err = db.Exec("CREATE DATABASE IF NOT EXISTS testgitea"); err != nil {
log.Fatalf("db.Exec: %v", err)
}
- case setting.UsePostgreSQL:
+ case setting.Database.UsePostgreSQL:
db, err := sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/?sslmode=%s",
- models.DbCfg.User, models.DbCfg.Passwd, models.DbCfg.Host, models.DbCfg.SSLMode))
+ setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.SSLMode))
defer db.Close()
if err != nil {
log.Fatalf("sql.Open: %v", err)
}
- rows, err := db.Query(fmt.Sprintf("SELECT 1 FROM pg_database WHERE datname = '%s'", models.DbCfg.Name))
+ rows, err := db.Query(fmt.Sprintf("SELECT 1 FROM pg_database WHERE datname = '%s'", setting.Database.Name))
if err != nil {
log.Fatalf("db.Query: %v", err)
}
@@ -153,10 +153,10 @@ func initIntegrationTest() {
if _, err = db.Exec("CREATE DATABASE testgitea"); err != nil {
log.Fatalf("db.Exec: %v", err)
}
- case setting.UseMSSQL:
- host, port := models.ParseMSSQLHostPort(models.DbCfg.Host)
+ case setting.Database.UseMSSQL:
+ host, port := setting.ParseMSSQLHostPort(setting.Database.Host)
db, err := sql.Open("mssql", fmt.Sprintf("server=%s; port=%s; database=%s; user id=%s; password=%s;",
- host, port, "master", models.DbCfg.User, models.DbCfg.Passwd))
+ host, port, "master", setting.Database.User, setting.Database.Passwd))
if err != nil {
log.Fatalf("sql.Open: %v", err)
}
diff --git a/integrations/lfs_getobject_test.go b/integrations/lfs_getobject_test.go
index 42b64612fd..bb269d5eeb 100644
--- a/integrations/lfs_getobject_test.go
+++ b/integrations/lfs_getobject_test.go
@@ -39,7 +39,7 @@ func storeObjectInRepo(t *testing.T, repositoryID int64, content *[]byte) string
assert.NoError(t, err)
var lfsMetaObject *models.LFSMetaObject
- if setting.UsePostgreSQL {
+ if setting.Database.UsePostgreSQL {
lfsMetaObject = &models.LFSMetaObject{ID: lfsID, Oid: oid, Size: int64(len(*content)), RepositoryID: repositoryID}
} else {
lfsMetaObject = &models.LFSMetaObject{Oid: oid, Size: int64(len(*content)), RepositoryID: repositoryID}
diff --git a/integrations/migration-test/migration_test.go b/integrations/migration-test/migration_test.go
index 858f339b89..3b47f0d7fc 100644
--- a/integrations/migration-test/migration_test.go
+++ b/integrations/migration-test/migration_test.go
@@ -54,7 +54,7 @@ func initMigrationTest(t *testing.T) {
setting.NewContext()
setting.CheckLFSVersion()
- models.LoadConfigs()
+ setting.InitDBConfig()
setting.NewLogServices(true)
}
@@ -64,7 +64,7 @@ func availableVersions() ([]string, error) {
return nil, err
}
defer migrationsDir.Close()
- versionRE, err := regexp.Compile("gitea-v(?P<version>.+)\\." + regexp.QuoteMeta(models.DbCfg.Type) + "\\.sql.gz")
+ versionRE, err := regexp.Compile("gitea-v(?P<version>.+)\\." + regexp.QuoteMeta(setting.Database.Type) + "\\.sql.gz")
if err != nil {
return nil, err
}
@@ -85,7 +85,7 @@ func availableVersions() ([]string, error) {
}
func readSQLFromFile(version string) (string, error) {
- filename := fmt.Sprintf("integrations/migration-test/gitea-v%s.%s.sql.gz", version, models.DbCfg.Type)
+ filename := fmt.Sprintf("integrations/migration-test/gitea-v%s.%s.sql.gz", version, setting.Database.Type)
if _, err := os.Stat(filename); os.IsNotExist(err) {
return "", nil
@@ -114,17 +114,17 @@ func restoreOldDB(t *testing.T, version string) bool {
data, err := readSQLFromFile(version)
assert.NoError(t, err)
if len(data) == 0 {
- integrations.Printf("No db found to restore for %s version: %s\n", models.DbCfg.Type, version)
+ integrations.Printf("No db found to restore for %s version: %s\n", setting.Database.Type, version)
return false
}
switch {
- case setting.UseSQLite3:
- os.Remove(models.DbCfg.Path)
- err := os.MkdirAll(path.Dir(models.DbCfg.Path), os.ModePerm)
+ case setting.Database.UseSQLite3:
+ os.Remove(setting.Database.Path)
+ err := os.MkdirAll(path.Dir(setting.Database.Path), os.ModePerm)
assert.NoError(t, err)
- db, err := sql.Open("sqlite3", fmt.Sprintf("file:%s?cache=shared&mode=rwc&_busy_timeout=%d", models.DbCfg.Path, models.DbCfg.Timeout))
+ db, err := sql.Open("sqlite3", fmt.Sprintf("file:%s?cache=shared&mode=rwc&_busy_timeout=%d", setting.Database.Path, setting.Database.Timeout))
assert.NoError(t, err)
defer db.Close()
@@ -132,20 +132,20 @@ func restoreOldDB(t *testing.T, version string) bool {
assert.NoError(t, err)
db.Close()
- case setting.UseMySQL:
+ case setting.Database.UseMySQL:
db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/",
- models.DbCfg.User, models.DbCfg.Passwd, models.DbCfg.Host))
+ setting.Database.User, setting.Database.Passwd, setting.Database.Host))
assert.NoError(t, err)
defer db.Close()
- _, err = db.Exec(fmt.Sprintf("DROP DATABASE IF EXISTS %s", models.DbCfg.Name))
+ _, err = db.Exec(fmt.Sprintf("DROP DATABASE IF EXISTS %s", setting.Database.Name))
assert.NoError(t, err)
- _, err = db.Exec(fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s", models.DbCfg.Name))
+ _, err = db.Exec(fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s", setting.Database.Name))
assert.NoError(t, err)
db, err = sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s?multiStatements=true",
- models.DbCfg.User, models.DbCfg.Passwd, models.DbCfg.Host, models.DbCfg.Name))
+ setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.Name))
assert.NoError(t, err)
defer db.Close()
@@ -153,21 +153,21 @@ func restoreOldDB(t *testing.T, version string) bool {
assert.NoError(t, err)
db.Close()
- case setting.UsePostgreSQL:
+ case setting.Database.UsePostgreSQL:
db, err := sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/?sslmode=%s",
- models.DbCfg.User, models.DbCfg.Passwd, models.DbCfg.Host, models.DbCfg.SSLMode))
+ setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.SSLMode))
assert.NoError(t, err)
defer db.Close()
- _, err = db.Exec(fmt.Sprintf("DROP DATABASE IF EXISTS %s", models.DbCfg.Name))
+ _, err = db.Exec(fmt.Sprintf("DROP DATABASE IF EXISTS %s", setting.Database.Name))
assert.NoError(t, err)
- _, err = db.Exec(fmt.Sprintf("CREATE DATABASE %s", models.DbCfg.Name))
+ _, err = db.Exec(fmt.Sprintf("CREATE DATABASE %s", setting.Database.Name))
assert.NoError(t, err)
db.Close()
db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=%s",
- models.DbCfg.User, models.DbCfg.Passwd, models.DbCfg.Host, models.DbCfg.Name, models.DbCfg.SSLMode))
+ setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.Name, setting.Database.SSLMode))
assert.NoError(t, err)
defer db.Close()
@@ -175,10 +175,10 @@ func restoreOldDB(t *testing.T, version string) bool {
assert.NoError(t, err)
db.Close()
- case setting.UseMSSQL:
- host, port := models.ParseMSSQLHostPort(models.DbCfg.Host)
+ case setting.Database.UseMSSQL:
+ host, port := setting.ParseMSSQLHostPort(setting.Database.Host)
db, err := sql.Open("mssql", fmt.Sprintf("server=%s; port=%s; database=%s; user id=%s; password=%s;",
- host, port, "master", models.DbCfg.User, models.DbCfg.Passwd))
+ host, port, "master", setting.Database.User, setting.Database.Passwd))
assert.NoError(t, err)
defer db.Close()
@@ -191,7 +191,7 @@ func restoreOldDB(t *testing.T, version string) bool {
dbname := statement[5 : len(statement)-1]
db.Close()
db, err = sql.Open("mssql", fmt.Sprintf("server=%s; port=%s; database=%s; user id=%s; password=%s;",
- host, port, dbname, models.DbCfg.User, models.DbCfg.Passwd))
+ host, port, dbname, setting.Database.User, setting.Database.Passwd))
assert.NoError(t, err)
defer db.Close()
}
@@ -210,7 +210,7 @@ func wrappedMigrate(x *xorm.Engine) error {
func doMigrationTest(t *testing.T, version string) {
integrations.PrintCurrentTest(t)
- integrations.Printf("Performing migration test for %s version: %s\n", models.DbCfg.Type, version)
+ integrations.Printf("Performing migration test for %s version: %s\n", setting.Database.Type, version)
if !restoreOldDB(t, version) {
return
}
@@ -227,7 +227,7 @@ func doMigrationTest(t *testing.T, version string) {
func TestMigrations(t *testing.T) {
initMigrationTest(t)
- dialect := models.DbCfg.Type
+ dialect := setting.Database.Type
versions, err := availableVersions()
assert.NoError(t, err)
diff --git a/models/convert.go b/models/convert.go
index c34be973c6..025f88b503 100644
--- a/models/convert.go
+++ b/models/convert.go
@@ -4,11 +4,15 @@
package models
-import "fmt"
+import (
+ "fmt"
+
+ "code.gitea.io/gitea/modules/setting"
+)
// ConvertUtf8ToUtf8mb4 converts database and tables from utf8 to utf8mb4 if it's mysql
func ConvertUtf8ToUtf8mb4() error {
- _, err := x.Exec(fmt.Sprintf("ALTER DATABASE `%s` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci", DbCfg.Name))
+ _, err := x.Exec(fmt.Sprintf("ALTER DATABASE `%s` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci", setting.Database.Name))
if err != nil {
return err
}
diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go
index fc086bfd46..7d97741a20 100644
--- a/models/migrations/migrations.go
+++ b/models/migrations/migrations.go
@@ -296,7 +296,7 @@ func dropTableColumns(sess *xorm.Session, tableName string, columnNames ...strin
// TODO: This will not work if there are foreign keys
switch {
- case setting.UseSQLite3:
+ case setting.Database.UseSQLite3:
// First drop the indexes on the columns
res, errIndex := sess.Query(fmt.Sprintf("PRAGMA index_list(`%s`)", tableName))
if errIndex != nil {
@@ -372,7 +372,7 @@ func dropTableColumns(sess *xorm.Session, tableName string, columnNames ...strin
return err
}
- case setting.UsePostgreSQL:
+ case setting.Database.UsePostgreSQL:
cols := ""
for _, col := range columnNames {
if cols != "" {
@@ -383,7 +383,7 @@ func dropTableColumns(sess *xorm.Session, tableName string, columnNames ...strin
if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `%s` %s", tableName, cols)); err != nil {
return fmt.Errorf("Drop table `%s` columns %v: %v", tableName, columnNames, err)
}
- case setting.UseMySQL, setting.UseTiDB:
+ case setting.Database.UseMySQL:
// Drop indexes on columns first
sql := fmt.Sprintf("SHOW INDEX FROM %s WHERE column_name IN ('%s')", tableName, strings.Join(columnNames, "','"))
res, err := sess.Query(sql)
@@ -409,7 +409,7 @@ func dropTableColumns(sess *xorm.Session, tableName string, columnNames ...strin
if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `%s` %s", tableName, cols)); err != nil {
return fmt.Errorf("Drop table `%s` columns %v: %v", tableName, columnNames, err)
}
- case setting.UseMSSQL:
+ case setting.Database.UseMSSQL:
cols := ""
for _, col := range columnNames {
if cols != "" {
diff --git a/models/migrations/v19.go b/models/migrations/v19.go
index 9793f405ad..7728f5add6 100644
--- a/models/migrations/v19.go
+++ b/models/migrations/v19.go
@@ -42,7 +42,7 @@ func generateAndMigrateGitHooks(x *xorm.Engine) (err error) {
}
)
- return x.Where("id > 0").BufferSize(setting.IterateBufferSize).Iterate(new(Repository),
+ return x.Where("id > 0").BufferSize(setting.Database.IterateBufferSize).Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
user := new(User)
diff --git a/models/migrations/v22.go b/models/migrations/v22.go
index f991ae25fa..faac74343b 100644
--- a/models/migrations/v22.go
+++ b/models/migrations/v22.go
@@ -42,7 +42,7 @@ func generateAndMigrateWikiGitHooks(x *xorm.Engine) (err error) {
}
)
- return x.Where("id > 0").BufferSize(setting.IterateBufferSize).Iterate(new(Repository),
+ return x.Where("id > 0").BufferSize(setting.Database.IterateBufferSize).Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
user := new(User)
diff --git a/models/migrations/v26.go b/models/migrations/v26.go
index 3d88c62923..04277191f5 100644
--- a/models/migrations/v26.go
+++ b/models/migrations/v26.go
@@ -36,7 +36,7 @@ func generateAndMigrateGitHookChains(x *xorm.Engine) (err error) {
hookTpl = fmt.Sprintf("#!/usr/bin/env %s\ndata=$(cat)\nexitcodes=\"\"\nhookname=$(basename $0)\nGIT_DIR=${GIT_DIR:-$(dirname $0)}\n\nfor hook in ${GIT_DIR}/hooks/${hookname}.d/*; do\ntest -x \"${hook}\" || continue\necho \"${data}\" | \"${hook}\"\nexitcodes=\"${exitcodes} $?\"\ndone\n\nfor i in ${exitcodes}; do\n[ ${i} -eq 0 ] || exit ${i}\ndone\n", setting.ScriptType)
)
- return x.Where("id > 0").BufferSize(setting.IterateBufferSize).Iterate(new(Repository),
+ return x.Where("id > 0").BufferSize(setting.Database.IterateBufferSize).Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
user := new(User)
diff --git a/models/migrations/v27.go b/models/migrations/v27.go
index e87c7ab68f..12e5fbcdbf 100644
--- a/models/migrations/v27.go
+++ b/models/migrations/v27.go
@@ -41,8 +41,6 @@ func convertIntervalToDuration(x *xorm.Engine) (err error) {
_, err = sess.Exec("ALTER TABLE mirror MODIFY `interval` BIGINT")
case "postgres":
_, err = sess.Exec("ALTER TABLE mirror ALTER COLUMN \"interval\" SET DATA TYPE bigint")
- case "tidb":
- _, err = sess.Exec("ALTER TABLE mirror MODIFY `interval` BIGINT")
case "mssql":
_, err = sess.Exec("ALTER TABLE mirror ALTER COLUMN \"interval\" BIGINT")
case "sqlite3":
diff --git a/models/migrations/v33.go b/models/migrations/v33.go
index ae7612e68c..566951db96 100644
--- a/models/migrations/v33.go
+++ b/models/migrations/v33.go
@@ -15,9 +15,9 @@ import (
func removeActionColumns(x *xorm.Engine) error {
switch {
- case setting.UseSQLite3:
+ case setting.Database.UseSQLite3:
log.Warn("Unable to drop columns in SQLite")
- case setting.UseMySQL, setting.UsePostgreSQL, setting.UseMSSQL, setting.UseTiDB:
+ case setting.Database.UseMySQL, setting.Database.UsePostgreSQL, setting.Database.UseMSSQL:
if _, err := x.Exec("ALTER TABLE action DROP COLUMN act_user_name"); err != nil {
return fmt.Errorf("DROP COLUMN act_user_name: %v", err)
} else if _, err = x.Exec("ALTER TABLE action DROP COLUMN repo_user_name"); err != nil {
diff --git a/models/migrations/v45.go b/models/migrations/v45.go
index 92cb817819..99baff2c8b 100644
--- a/models/migrations/v45.go
+++ b/models/migrations/v45.go
@@ -13,9 +13,9 @@ import (
func removeIndexColumnFromRepoUnitTable(x *xorm.Engine) (err error) {
switch {
- case setting.UseSQLite3:
+ case setting.Database.UseSQLite3:
log.Warn("Unable to drop columns in SQLite")
- case setting.UseMySQL, setting.UsePostgreSQL, setting.UseMSSQL, setting.UseTiDB:
+ case setting.Database.UseMySQL, setting.Database.UsePostgreSQL, setting.Database.UseMSSQL:
if _, err := x.Exec("ALTER TABLE repo_unit DROP COLUMN `index`"); err != nil {
// Ignoring this error in case we run this migration second time (after migration reordering)
log.Warn("DROP COLUMN index: %v", err)
diff --git a/models/migrations/v50.go b/models/migrations/v50.go
index a15914f0ee..23b1bb526e 100644
--- a/models/migrations/v50.go
+++ b/models/migrations/v50.go
@@ -40,9 +40,9 @@ func migrateProtectedBranchStruct(x *xorm.Engine) error {
}
switch {
- case setting.UseSQLite3:
+ case setting.Database.UseSQLite3:
log.Warn("Unable to drop columns in SQLite")
- case setting.UseMySQL, setting.UsePostgreSQL, setting.UseMSSQL, setting.UseTiDB:
+ case setting.Database.UseMySQL, setting.Database.UsePostgreSQL, setting.Database.UseMSSQL:
if _, err := x.Exec("ALTER TABLE protected_branch DROP COLUMN can_push"); err != nil {
// Ignoring this error in case we run this migration second time (after migration reordering)
log.Warn("DROP COLUMN can_push (skipping): %v", err)
diff --git a/models/migrations/v67.go b/models/migrations/v67.go
index 74d3f379cd..6cf3dd4d19 100644
--- a/models/migrations/v67.go
+++ b/models/migrations/v67.go
@@ -80,7 +80,7 @@ func removeStaleWatches(x *xorm.Engine) error {
}
repoCache := make(map[int64]*Repository)
- err := sess.BufferSize(setting.IterateBufferSize).Iterate(new(Watch),
+ err := sess.BufferSize(setting.Database.IterateBufferSize).Iterate(new(Watch),
func(idx int, bean interface{}) error {
watch := bean.(*Watch)
@@ -117,7 +117,7 @@ func removeStaleWatches(x *xorm.Engine) error {
}
repoCache = make(map[int64]*Repository)
- err = sess.BufferSize(setting.IterateBufferSize).
+ err = sess.BufferSize(setting.Database.IterateBufferSize).
Distinct("issue_watch.user_id", "issue.repo_id").
Join("INNER", "issue", "issue_watch.issue_id = issue.id").
Where("issue_watch.is_watching = ?", true).
diff --git a/models/migrations/v81.go b/models/migrations/v81.go
index 56bb8477e6..48e96508d9 100644
--- a/models/migrations/v81.go
+++ b/models/migrations/v81.go
@@ -14,8 +14,6 @@ func changeU2FCounterType(x *xorm.Engine) error {
var err error
switch x.Dialect().DriverName() {
- case "tidb":
- fallthrough
case "mysql":
_, err = x.Exec("ALTER TABLE `u2f_registration` MODIFY `counter` BIGINT")
case "postgres":
diff --git a/models/models.go b/models/models.go
index 4c925fa570..04acc77aa9 100644
--- a/models/models.go
+++ b/models/models.go
@@ -9,12 +9,6 @@ import (
"database/sql"
"errors"
"fmt"
- "net/url"
- "os"
- "path"
- "path/filepath"
- "strings"
- "time"
"code.gitea.io/gitea/modules/setting"
@@ -52,24 +46,11 @@ type Engine interface {
}
var (
- x *xorm.Engine
- supportedDatabases = []string{"mysql", "postgres", "mssql"}
- tables []interface{}
+ x *xorm.Engine
+ tables []interface{}
// HasEngine specifies if we have a xorm.Engine
HasEngine bool
-
- // DbCfg holds the database settings
- DbCfg struct {
- Type, Host, Name, User, Passwd, Path, SSLMode, Charset string
- Timeout int
- }
-
- // EnableSQLite3 use SQLite3
- EnableSQLite3 bool
-
- // EnableTiDB enable TiDB
- EnableTiDB bool
)
func init() {
@@ -139,120 +120,13 @@ func init() {
}
}
-// LoadConfigs loads the database settings
-func LoadConfigs() {
- sec := setting.Cfg.Section("database")
- DbCfg.Type = sec.Key("DB_TYPE").String()
- switch DbCfg.Type {
- case "sqlite3":
- setting.UseSQLite3 = true
- case "mysql":
- setting.UseMySQL = true
- case "postgres":
- setting.UsePostgreSQL = true
- case "tidb":
- setting.UseTiDB = true
- case "mssql":
- setting.UseMSSQL = true
- }
- DbCfg.Host = sec.Key("HOST").String()
- DbCfg.Name = sec.Key("NAME").String()
- DbCfg.User = sec.Key("USER").String()
- if len(DbCfg.Passwd) == 0 {
- DbCfg.Passwd = sec.Key("PASSWD").String()
- }
- DbCfg.SSLMode = sec.Key("SSL_MODE").MustString("disable")
- DbCfg.Charset = sec.Key("CHARSET").In("utf8", []string{"utf8", "utf8mb4"})
- DbCfg.Path = sec.Key("PATH").MustString(filepath.Join(setting.AppDataPath, "gitea.db"))
- DbCfg.Timeout = sec.Key("SQLITE_TIMEOUT").MustInt(500)
-}
-
-// parsePostgreSQLHostPort parses given input in various forms defined in
-// https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING
-// and returns proper host and port number.
-func parsePostgreSQLHostPort(info string) (string, string) {
- host, port := "127.0.0.1", "5432"
- if strings.Contains(info, ":") && !strings.HasSuffix(info, "]") {
- idx := strings.LastIndex(info, ":")
- host = info[:idx]
- port = info[idx+1:]
- } else if len(info) > 0 {
- host = info
- }
- return host, port
-}
-
-func getPostgreSQLConnectionString(dbHost, dbUser, dbPasswd, dbName, dbParam, dbsslMode string) (connStr string) {
- host, port := parsePostgreSQLHostPort(dbHost)
- if host[0] == '/' { // looks like a unix socket
- connStr = fmt.Sprintf("postgres://%s:%s@:%s/%s%ssslmode=%s&host=%s",
- url.PathEscape(dbUser), url.PathEscape(dbPasswd), port, dbName, dbParam, dbsslMode, host)
- } else {
- connStr = fmt.Sprintf("postgres://%s:%s@%s:%s/%s%ssslmode=%s",
- url.PathEscape(dbUser), url.PathEscape(dbPasswd), host, port, dbName, dbParam, dbsslMode)
- }
- return
-}
-
-// ParseMSSQLHostPort splits the host into host and port
-func ParseMSSQLHostPort(info string) (string, string) {
- host, port := "127.0.0.1", "1433"
- if strings.Contains(info, ":") {
- host = strings.Split(info, ":")[0]
- port = strings.Split(info, ":")[1]
- } else if strings.Contains(info, ",") {
- host = strings.Split(info, ",")[0]
- port = strings.TrimSpace(strings.Split(info, ",")[1])
- } else if len(info) > 0 {
- host = info
- }
- return host, port
-}
-
func getEngine() (*xorm.Engine, error) {
- connStr := ""
- var Param = "?"
- if strings.Contains(DbCfg.Name, Param) {
- Param = "&"
- }
- switch DbCfg.Type {
- case "mysql":
- connType := "tcp"
- if DbCfg.Host[0] == '/' { // looks like a unix socket
- connType = "unix"
- }
- tls := DbCfg.SSLMode
- if tls == "disable" { // allow (Postgres-inspired) default value to work in MySQL
- tls = "false"
- }
- connStr = fmt.Sprintf("%s:%s@%s(%s)/%s%scharset=%s&parseTime=true&tls=%s",
- DbCfg.User, DbCfg.Passwd, connType, DbCfg.Host, DbCfg.Name, Param, DbCfg.Charset, tls)
- case "postgres":
- connStr = getPostgreSQLConnectionString(DbCfg.Host, DbCfg.User, DbCfg.Passwd, DbCfg.Name, Param, DbCfg.SSLMode)
- case "mssql":
- host, port := ParseMSSQLHostPort(DbCfg.Host)
- connStr = fmt.Sprintf("server=%s; port=%s; database=%s; user id=%s; password=%s;", host, port, DbCfg.Name, DbCfg.User, DbCfg.Passwd)
- case "sqlite3":
- if !EnableSQLite3 {
- return nil, errors.New("this binary version does not build support for SQLite3")
- }
- if err := os.MkdirAll(path.Dir(DbCfg.Path), os.ModePerm); err != nil {
- return nil, fmt.Errorf("Failed to create directories: %v", err)
- }
- connStr = fmt.Sprintf("file:%s?cache=shared&mode=rwc&_busy_timeout=%d", DbCfg.Path, DbCfg.Timeout)
- case "tidb":
- if !EnableTiDB {
- return nil, errors.New("this binary version does not build support for TiDB")
- }
- if err := os.MkdirAll(path.Dir(DbCfg.Path), os.ModePerm); err != nil {
- return nil, fmt.Errorf("Failed to create directories: %v", err)
- }
- connStr = "goleveldb://" + DbCfg.Path
- default:
- return nil, fmt.Errorf("Unknown database type: %s", DbCfg.Type)
+ connStr, err := setting.DBConnStr()
+ if err != nil {
+ return nil, err
}
- return xorm.NewEngine(DbCfg.Type, connStr)
+ return xorm.NewEngine(setting.Database.Type, connStr)
}
// NewTestEngine sets a new test xorm.Engine
@@ -280,11 +154,11 @@ func SetEngine() (err error) {
x.SetMapper(core.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.LogSQL))
- x.ShowSQL(setting.LogSQL)
- if DbCfg.Type == "mysql" {
- x.SetMaxIdleConns(0)
- x.SetConnMaxLifetime(3 * time.Second)
+ x.SetLogger(NewXORMLogger(setting.Database.LogSQL))
+ x.ShowSQL(setting.Database.LogSQL)
+ if setting.Database.UseMySQL {
+ x.SetMaxIdleConns(setting.Database.MaxIdleConns)
+ x.SetConnMaxLifetime(setting.Database.ConnMaxLifetime)
}
return nil
diff --git a/models/models_test.go b/models/models_test.go
index 6df3b4e048..37e9a352f8 100644
--- a/models/models_test.go
+++ b/models/models_test.go
@@ -1,5 +1,4 @@
-// Copyright 2016 The Gogs Authors. All rights reserved.
-// Copyright 2018 The Gitea Authors. All rights reserved.
+// Copyright 2019 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.
@@ -11,99 +10,19 @@ import (
"path/filepath"
"testing"
+ "code.gitea.io/gitea/modules/setting"
+
"github.com/stretchr/testify/assert"
)
-func Test_parsePostgreSQLHostPort(t *testing.T) {
- tests := []struct {
- HostPort string
- Host string
- Port string
- }{
- {
- HostPort: "127.0.0.1:1234",
- Host: "127.0.0.1",
- Port: "1234",
- },
- {
- HostPort: "127.0.0.1",
- Host: "127.0.0.1",
- Port: "5432",
- },
- {
- HostPort: "[::1]:1234",
- Host: "[::1]",
- Port: "1234",
- },
- {
- HostPort: "[::1]",
- Host: "[::1]",
- Port: "5432",
- },
- {
- HostPort: "/tmp/pg.sock:1234",
- Host: "/tmp/pg.sock",
- Port: "1234",
- },
- {
- HostPort: "/tmp/pg.sock",
- Host: "/tmp/pg.sock",
- Port: "5432",
- },
- }
- for _, test := range tests {
- host, port := parsePostgreSQLHostPort(test.HostPort)
- assert.Equal(t, test.Host, host)
- assert.Equal(t, test.Port, port)
- }
-}
-
-func Test_getPostgreSQLConnectionString(t *testing.T) {
- tests := []struct {
- Host string
- Port string
- User string
- Passwd string
- Name string
- Param string
- SSLMode string
- Output string
- }{
- {
- Host: "/tmp/pg.sock",
- Port: "4321",
- User: "testuser",
- Passwd: "space space !#$%^^%^```-=?=",
- Name: "gitea",
- Param: "",
- SSLMode: "false",
- Output: "postgres://testuser:space%20space%20%21%23$%25%5E%5E%25%5E%60%60%60-=%3F=@:5432/giteasslmode=false&host=/tmp/pg.sock",
- },
- {
- Host: "localhost",
- Port: "1234",
- User: "pgsqlusername",
- Passwd: "I love Gitea!",
- Name: "gitea",
- Param: "",
- SSLMode: "true",
- Output: "postgres://pgsqlusername:I%20love%20Gitea%21@localhost:5432/giteasslmode=true",
- },
- }
-
- for _, test := range tests {
- connStr := getPostgreSQLConnectionString(test.Host, test.User, test.Passwd, test.Name, test.Param, test.SSLMode)
- assert.Equal(t, test.Output, connStr)
- }
-}
-
func TestDumpDatabase(t *testing.T) {
assert.NoError(t, PrepareTestDatabase())
dir, err := ioutil.TempDir(os.TempDir(), "dump")
assert.NoError(t, err)
- for _, dbType := range supportedDatabases {
+ for _, dbName := range setting.SupportedDatabases {
+ dbType := setting.GetDBTypeByName(dbName)
assert.NoError(t, DumpDatabase(filepath.Join(dir, dbType+".sql"), dbType))
}
}
diff --git a/models/repo.go b/models/repo.go
index a70350576e..507521357e 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -2201,7 +2201,7 @@ func GitFsck() {
log.Trace("Doing: GitFsck")
if err := x.
- Where("id>0 AND is_fsck_enabled=?", true).BufferSize(setting.IterateBufferSize).
+ Where("id>0 AND is_fsck_enabled=?", true).BufferSize(setting.Database.IterateBufferSize).
Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
@@ -2225,7 +2225,7 @@ func GitFsck() {
func GitGcRepos() error {
args := append([]string{"gc"}, setting.Git.GCArgs...)
return x.
- Where("id > 0").BufferSize(setting.IterateBufferSize).
+ Where("id > 0").BufferSize(setting.Database.IterateBufferSize).
Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
@@ -2568,7 +2568,7 @@ func (repo *Repository) generateRandomAvatar(e Engine) error {
// RemoveRandomAvatars removes the randomly generated avatars that were created for repositories
func RemoveRandomAvatars() error {
return x.
- Where("id > 0").BufferSize(setting.IterateBufferSize).
+ Where("id > 0").BufferSize(setting.Database.IterateBufferSize).
Iterate(new(Repository),
func(idx int, bean interface{}) error {
repository := bean.(*Repository)
diff --git a/models/unit_tests.go b/models/unit_tests.go
index 80dc4feb96..b53302dad4 100644
--- a/models/unit_tests.go
+++ b/models/unit_tests.go
@@ -49,7 +49,7 @@ func MainTest(m *testing.M, pathToGiteaRoot string) {
setting.RunUser = "runuser"
setting.SSH.Port = 3000
setting.SSH.Domain = "try.gitea.io"
- setting.UseSQLite3 = true
+ setting.Database.UseSQLite3 = true
setting.RepoRootPath, err = ioutil.TempDir(os.TempDir(), "repos")
if err != nil {
fatalTestError("TempDir: %v\n", err)
diff --git a/models/user.go b/models/user.go
index 037ae0397b..c8664cc4c8 100644
--- a/models/user.go
+++ b/models/user.go
@@ -40,7 +40,6 @@ import (
"golang.org/x/crypto/scrypt"
"golang.org/x/crypto/ssh"
"xorm.io/builder"
- "xorm.io/core"
)
// UserType defines the user type
@@ -1432,9 +1431,9 @@ func (opts *SearchUserOptions) toConds() builder.Cond {
if opts.OwnerID > 0 {
var exprCond builder.Cond
- if DbCfg.Type == core.MYSQL {
+ if setting.Database.UseMySQL {
exprCond = builder.Expr("org_user.org_id = user.id")
- } else if DbCfg.Type == core.MSSQL {
+ } else if setting.Database.UseMSSQL {
exprCond = builder.Expr("org_user.org_id = [user].id")
} else {
exprCond = builder.Expr("org_user.org_id = \"user\".id")
diff --git a/models/user_heatmap.go b/models/user_heatmap.go
index b511b5fa62..3d9e0683fc 100644
--- a/models/user_heatmap.go
+++ b/models/user_heatmap.go
@@ -21,13 +21,13 @@ func GetUserHeatmapDataByUser(user *User) ([]*UserHeatmapData, error) {
var groupBy string
var groupByName = "timestamp" // We need this extra case because mssql doesn't allow grouping by alias
switch {
- case setting.UseSQLite3:
+ case setting.Database.UseSQLite3:
groupBy = "strftime('%s', strftime('%Y-%m-%d', created_unix, 'unixepoch'))"
- case setting.UseMySQL:
+ case setting.Database.UseMySQL:
groupBy = "UNIX_TIMESTAMP(DATE(FROM_UNIXTIME(created_unix)))"
- case setting.UsePostgreSQL:
+ case setting.Database.UsePostgreSQL:
groupBy = "extract(epoch from date_trunc('day', to_timestamp(created_unix)))"
- case setting.UseMSSQL:
+ case setting.Database.UseMSSQL:
groupBy = "datediff(SECOND, '19700101', dateadd(DAY, 0, datediff(day, 0, dateadd(s, created_unix, '19700101'))))"
groupByName = groupBy
}
diff --git a/modules/setting/database.go b/modules/setting/database.go
new file mode 100644
index 0000000000..2cac4824df
--- /dev/null
+++ b/modules/setting/database.go
@@ -0,0 +1,171 @@
+// Copyright 2019 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 setting
+
+import (
+ "errors"
+ "fmt"
+ "net/url"
+ "os"
+ "path"
+ "path/filepath"
+ "strings"
+ "time"
+)
+
+var (
+ // SupportedDatabases includes all supported databases type
+ SupportedDatabases = []string{"MySQL", "PostgreSQL", "MSSQL"}
+ dbTypes = map[string]string{"MySQL": "mysql", "PostgreSQL": "postgres", "MSSQL": "mssql", "SQLite3": "sqlite3"}
+
+ // EnableSQLite3 use SQLite3, set by build flag
+ EnableSQLite3 bool
+
+ // Database holds the database settings
+ Database = struct {
+ Type string
+ Host string
+ Name string
+ User string
+ Passwd string
+ SSLMode string
+ Path string
+ LogSQL bool
+ Charset string
+ Timeout int // seconds
+ UseSQLite3 bool
+ UseMySQL bool
+ UseMSSQL bool
+ UsePostgreSQL bool
+ DBConnectRetries int
+ DBConnectBackoff time.Duration
+ MaxIdleConns int
+ ConnMaxLifetime time.Duration
+ IterateBufferSize int
+ }{
+ Timeout: 500,
+ MaxIdleConns: 0,
+ ConnMaxLifetime: 3 * time.Second,
+ }
+)
+
+// GetDBTypeByName returns the dataase type as it defined on XORM according the given name
+func GetDBTypeByName(name string) string {
+ return dbTypes[name]
+}
+
+// InitDBConfig loads the database settings
+func InitDBConfig() {
+ sec := Cfg.Section("database")
+ Database.Type = sec.Key("DB_TYPE").String()
+ switch Database.Type {
+ case "sqlite3":
+ Database.UseSQLite3 = true
+ case "mysql":
+ Database.UseMySQL = true
+ case "postgres":
+ Database.UsePostgreSQL = true
+ case "mssql":
+ Database.UseMSSQL = true
+ }
+ Database.Host = sec.Key("HOST").String()
+ Database.Name = sec.Key("NAME").String()
+ Database.User = sec.Key("USER").String()
+ if len(Database.Passwd) == 0 {
+ Database.Passwd = sec.Key("PASSWD").String()
+ }
+ Database.SSLMode = sec.Key("SSL_MODE").MustString("disable")
+ Database.Charset = sec.Key("CHARSET").In("utf8", []string{"utf8", "utf8mb4"})
+ Database.Path = sec.Key("PATH").MustString(filepath.Join(AppDataPath, "gitea.db"))
+ Database.Timeout = sec.Key("SQLITE_TIMEOUT").MustInt(500)
+ Database.MaxIdleConns = sec.Key("MAX_IDLE_CONNS").MustInt(0)
+ Database.ConnMaxLifetime = sec.Key("CONN_MAX_LIFE_TIME").MustDuration(3 * time.Second)
+
+ Database.IterateBufferSize = sec.Key("ITERATE_BUFFER_SIZE").MustInt(50)
+ Database.LogSQL = sec.Key("LOG_SQL").MustBool(true)
+ Database.DBConnectRetries = sec.Key("DB_RETRIES").MustInt(10)
+ Database.DBConnectBackoff = sec.Key("DB_RETRY_BACKOFF").MustDuration(3 * time.Second)
+}
+
+// DBConnStr returns database connection string
+func DBConnStr() (string, error) {
+ connStr := ""
+ var Param = "?"
+ if strings.Contains(Database.Name, Param) {
+ Param = "&"
+ }
+ switch Database.Type {
+ case "mysql":
+ connType := "tcp"
+ if Database.Host[0] == '/' { // looks like a unix socket
+ connType = "unix"
+ }
+ tls := Database.SSLMode
+ if tls == "disable" { // allow (Postgres-inspired) default value to work in MySQL
+ tls = "false"
+ }
+ connStr = fmt.Sprintf("%s:%s@%s(%s)/%s%scharset=%s&parseTime=true&tls=%s",
+ Database.User, Database.Passwd, connType, Database.Host, Database.Name, Param, Database.Charset, tls)
+ case "postgres":
+ connStr = getPostgreSQLConnectionString(Database.Host, Database.User, Database.Passwd, Database.Name, Param, Database.SSLMode)
+ case "mssql":
+ host, port := ParseMSSQLHostPort(Database.Host)
+ connStr = fmt.Sprintf("server=%s; port=%s; database=%s; user id=%s; password=%s;", host, port, Database.Name, Database.User, Database.Passwd)
+ case "sqlite3":
+ if !EnableSQLite3 {
+ return "", errors.New("this binary version does not build support for SQLite3")
+ }
+ if err := os.MkdirAll(path.Dir(Database.Path), os.ModePerm); err != nil {
+ return "", fmt.Errorf("Failed to create directories: %v", err)
+ }
+ connStr = fmt.Sprintf("file:%s?cache=shared&mode=rwc&_busy_timeout=%d", Database.Path, Database.Timeout)
+ default:
+ return "", fmt.Errorf("Unknown database type: %s", Database.Type)
+ }
+
+ return connStr, nil
+}
+
+// parsePostgreSQLHostPort parses given input in various forms defined in
+// https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING
+// and returns proper host and port number.
+func parsePostgreSQLHostPort(info string) (string, string) {
+ host, port := "127.0.0.1", "5432"
+ if strings.Contains(info, ":") && !strings.HasSuffix(info, "]") {
+ idx := strings.LastIndex(info, ":")
+ host = info[:idx]
+ port = info[idx+1:]
+ } else if len(info) > 0 {
+ host = info
+ }
+ return host, port
+}
+
+func getPostgreSQLConnectionString(dbHost, dbUser, dbPasswd, dbName, dbParam, dbsslMode string) (connStr string) {
+ host, port := parsePostgreSQLHostPort(dbHost)
+ if host[0] == '/' { // looks like a unix socket
+ connStr = fmt.Sprintf("postgres://%s:%s@:%s/%s%ssslmode=%s&host=%s",
+ url.PathEscape(dbUser), url.PathEscape(dbPasswd), port, dbName, dbParam, dbsslMode, host)
+ } else {
+ connStr = fmt.Sprintf("postgres://%s:%s@%s:%s/%s%ssslmode=%s",
+ url.PathEscape(dbUser), url.PathEscape(dbPasswd), host, port, dbName, dbParam, dbsslMode)
+ }
+ return
+}
+
+// ParseMSSQLHostPort splits the host into host and port
+func ParseMSSQLHostPort(info string) (string, string) {
+ host, port := "127.0.0.1", "1433"
+ if strings.Contains(info, ":") {
+ host = strings.Split(info, ":")[0]
+ port = strings.Split(info, ":")[1]
+ } else if strings.Contains(info, ",") {
+ host = strings.Split(info, ",")[0]
+ port = strings.TrimSpace(strings.Split(info, ",")[1])
+ } else if len(info) > 0 {
+ host = info
+ }
+ return host, port
+}
diff --git a/models/models_sqlite.go b/modules/setting/database_sqlite.go
index 3889aceb84..623326ddc2 100644
--- a/models/models_sqlite.go
+++ b/modules/setting/database_sqlite.go
@@ -4,7 +4,7 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
-package models
+package setting
import (
_ "github.com/mattn/go-sqlite3"
@@ -12,5 +12,5 @@ import (
func init() {
EnableSQLite3 = true
- supportedDatabases = append(supportedDatabases, "sqlite3")
+ SupportedDatabases = append(SupportedDatabases, "SQLite3")
}
diff --git a/modules/setting/database_test.go b/modules/setting/database_test.go
new file mode 100644
index 0000000000..a90be2a687
--- /dev/null
+++ b/modules/setting/database_test.go
@@ -0,0 +1,94 @@
+// Copyright 2019 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 setting
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func Test_parsePostgreSQLHostPort(t *testing.T) {
+ tests := []struct {
+ HostPort string
+ Host string
+ Port string
+ }{
+ {
+ HostPort: "127.0.0.1:1234",
+ Host: "127.0.0.1",
+ Port: "1234",
+ },
+ {
+ HostPort: "127.0.0.1",
+ Host: "127.0.0.1",
+ Port: "5432",
+ },
+ {
+ HostPort: "[::1]:1234",
+ Host: "[::1]",
+ Port: "1234",
+ },
+ {
+ HostPort: "[::1]",
+ Host: "[::1]",
+ Port: "5432",
+ },
+ {
+ HostPort: "/tmp/pg.sock:1234",
+ Host: "/tmp/pg.sock",
+ Port: "1234",
+ },
+ {
+ HostPort: "/tmp/pg.sock",
+ Host: "/tmp/pg.sock",
+ Port: "5432",
+ },
+ }
+ for _, test := range tests {
+ host, port := parsePostgreSQLHostPort(test.HostPort)
+ assert.Equal(t, test.Host, host)
+ assert.Equal(t, test.Port, port)
+ }
+}
+
+func Test_getPostgreSQLConnectionString(t *testing.T) {
+ tests := []struct {
+ Host string
+ Port string
+ User string
+ Passwd string
+ Name string
+ Param string
+ SSLMode string
+ Output string
+ }{
+ {
+ Host: "/tmp/pg.sock",
+ Port: "4321",
+ User: "testuser",
+ Passwd: "space space !#$%^^%^```-=?=",
+ Name: "gitea",
+ Param: "",
+ SSLMode: "false",
+ Output: "postgres://testuser:space%20space%20%21%23$%25%5E%5E%25%5E%60%60%60-=%3F=@:5432/giteasslmode=false&host=/tmp/pg.sock",
+ },
+ {
+ Host: "localhost",
+ Port: "1234",
+ User: "pgsqlusername",
+ Passwd: "I love Gitea!",
+ Name: "gitea",
+ Param: "",
+ SSLMode: "true",
+ Output: "postgres://pgsqlusername:I%20love%20Gitea%21@localhost:5432/giteasslmode=true",
+ },
+ }
+
+ for _, test := range tests {
+ connStr := getPostgreSQLConnectionString(test.Host, test.User, test.Passwd, test.Name, test.Param, test.SSLMode)
+ assert.Equal(t, test.Output, connStr)
+ }
+}
diff --git a/modules/setting/setting.go b/modules/setting/setting.go
index 123aa8f103..77b8f20640 100644
--- a/modules/setting/setting.go
+++ b/modules/setting/setting.go
@@ -148,16 +148,6 @@ var (
DisableGitHooks bool
PasswordHashAlgo string
- // Database settings
- UseSQLite3 bool
- UseMySQL bool
- UseMSSQL bool
- UsePostgreSQL bool
- UseTiDB bool
- LogSQL bool
- DBConnectRetries int
- DBConnectBackoff time.Duration
-
// UI settings
UI = struct {
ExplorePagingNum int
@@ -348,16 +338,19 @@ var (
ShowFooterTemplateLoadTime bool
// Global setting objects
- Cfg *ini.File
- CustomPath string // Custom directory path
- CustomConf string
- CustomPID string
- ProdMode bool
- RunUser string
- IsWindows bool
- HasRobotsTxt bool
- InternalToken string // internal access token
- IterateBufferSize int
+ Cfg *ini.File
+ CustomPath string // Custom directory path
+ CustomConf string
+ CustomPID string
+ ProdMode bool
+ RunUser string
+ IsWindows bool
+ HasRobotsTxt bool
+ InternalToken string // internal access token
+
+ // UILocation is the location on the UI, so that we can display the time on UI.
+ // Currently only show the default time.Local, it could be added to app.ini after UI is ready
+ UILocation = time.Local
)
// DateLang transforms standard language locale name to corresponding value in datetime plugin.
@@ -775,10 +768,6 @@ func NewContext() {
CSRFCookieHTTPOnly = sec.Key("CSRF_COOKIE_HTTP_ONLY").MustBool(true)
InternalToken = loadInternalToken(sec)
- IterateBufferSize = Cfg.Section("database").Key("ITERATE_BUFFER_SIZE").MustInt(50)
- LogSQL = Cfg.Section("database").Key("LOG_SQL").MustBool(true)
- DBConnectRetries = Cfg.Section("database").Key("DB_RETRIES").MustInt(10)
- DBConnectBackoff = Cfg.Section("database").Key("DB_RETRY_BACKOFF").MustDuration(3 * time.Second)
sec = Cfg.Section("attachment")
AttachmentPath = sec.Key("PATH").MustString(path.Join(AppDataPath, "attachments"))
@@ -1037,6 +1026,7 @@ func loadOrGenerateInternalToken(sec *ini.Section) string {
// NewServices initializes the services
func NewServices() {
+ InitDBConfig()
newService()
NewLogServices(false)
newCacheService()
diff --git a/routers/admin/admin.go b/routers/admin/admin.go
index 54fbddc58e..496aca375f 100644
--- a/routers/admin/admin.go
+++ b/routers/admin/admin.go
@@ -289,7 +289,7 @@ func Config(ctx *context.Context) {
ctx.Data["LFS"] = setting.LFS
ctx.Data["Service"] = setting.Service
- ctx.Data["DbCfg"] = models.DbCfg
+ ctx.Data["DbCfg"] = setting.Database
ctx.Data["Webhook"] = setting.Webhook
ctx.Data["MailerEnabled"] = false
@@ -333,7 +333,7 @@ func Config(ctx *context.Context) {
ctx.Data["AccessLogTemplate"] = setting.AccessLogTemplate
ctx.Data["DisableRouterLog"] = setting.DisableRouterLog
ctx.Data["EnableXORMLog"] = setting.EnableXORMLog
- ctx.Data["LogSQL"] = setting.LogSQL
+ ctx.Data["LogSQL"] = setting.Database.LogSQL
ctx.HTML(200, tplConfig)
}
diff --git a/routers/init.go b/routers/init.go
index 4724da8627..fdf90904ce 100644
--- a/routers/init.go
+++ b/routers/init.go
@@ -47,16 +47,16 @@ func NewServices() {
// In case of problems connecting to DB, retry connection. Eg, PGSQL in Docker Container on Synology
func initDBEngine() (err error) {
log.Info("Beginning ORM engine initialization.")
- for i := 0; i < setting.DBConnectRetries; i++ {
- log.Info("ORM engine initialization attempt #%d/%d...", i+1, setting.DBConnectRetries)
+ for i := 0; i < setting.Database.DBConnectRetries; i++ {
+ log.Info("ORM engine initialization attempt #%d/%d...", i+1, setting.Database.DBConnectRetries)
if err = models.NewEngine(migrations.Migrate); err == nil {
break
- } else if i == setting.DBConnectRetries-1 {
+ } else if i == setting.Database.DBConnectRetries-1 {
return err
}
- log.Error("ORM engine initialization attempt #%d/%d failed. Error: %v", i+1, setting.DBConnectRetries, err)
- log.Info("Backing off for %d seconds", int64(setting.DBConnectBackoff/time.Second))
- time.Sleep(setting.DBConnectBackoff)
+ log.Error("ORM engine initialization attempt #%d/%d failed. Error: %v", i+1, setting.Database.DBConnectRetries, err)
+ log.Info("Backing off for %d seconds", int64(setting.Database.DBConnectBackoff/time.Second))
+ time.Sleep(setting.Database.DBConnectBackoff)
}
models.HasEngine = true
return nil
@@ -73,7 +73,7 @@ func GlobalInit() {
log.Trace("AppWorkPath: %s", setting.AppWorkPath)
log.Trace("Custom path: %s", setting.CustomPath)
log.Trace("Log path: %s", setting.LogRootPath)
- models.LoadConfigs()
+
NewServices()
if setting.InstallLock {
@@ -102,12 +102,9 @@ func GlobalInit() {
models.InitDeliverHooks()
models.InitTestPullRequests()
}
- if models.EnableSQLite3 {
+ if setting.EnableSQLite3 {
log.Info("SQLite3 Supported")
}
- if models.EnableTiDB {
- log.Info("TiDB Supported")
- }
checkRunMode()
if setting.InstallLock && setting.SSH.StartBuiltinServer {
diff --git a/routers/install.go b/routers/install.go
index 6d29bcf887..16888adc82 100644
--- a/routers/install.go
+++ b/routers/install.go
@@ -40,11 +40,7 @@ func InstallInit(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("install.install")
ctx.Data["PageIsInstall"] = true
- dbOpts := []string{"MySQL", "PostgreSQL", "MSSQL"}
- if models.EnableSQLite3 {
- dbOpts = append(dbOpts, "SQLite3")
- }
- ctx.Data["DbOptions"] = dbOpts
+ ctx.Data["DbOptions"] = setting.SupportedDatabases
}
// Install render installation page
@@ -52,21 +48,21 @@ func Install(ctx *context.Context) {
form := auth.InstallForm{}
// Database settings
- form.DbHost = models.DbCfg.Host
- form.DbUser = models.DbCfg.User
- form.DbPasswd = models.DbCfg.Passwd
- form.DbName = models.DbCfg.Name
- form.DbPath = models.DbCfg.Path
- form.Charset = models.DbCfg.Charset
+ form.DbHost = setting.Database.Host
+ form.DbUser = setting.Database.User
+ form.DbPasswd = setting.Database.Passwd
+ form.DbName = setting.Database.Name
+ form.DbPath = setting.Database.Path
+ form.Charset = setting.Database.Charset
ctx.Data["CurDbOption"] = "MySQL"
- switch models.DbCfg.Type {
+ switch setting.Database.Type {
case "postgres":
ctx.Data["CurDbOption"] = "PostgreSQL"
case "mssql":
ctx.Data["CurDbOption"] = "MSSQL"
case "sqlite3":
- if models.EnableSQLite3 {
+ if setting.EnableSQLite3 {
ctx.Data["CurDbOption"] = "SQLite3"
}
}
@@ -144,18 +140,18 @@ func InstallPost(ctx *context.Context, form auth.InstallForm) {
// Pass basic check, now test configuration.
// Test database setting.
- dbTypes := map[string]string{"MySQL": "mysql", "PostgreSQL": "postgres", "MSSQL": "mssql", "SQLite3": "sqlite3"}
- models.DbCfg.Type = dbTypes[form.DbType]
- models.DbCfg.Host = form.DbHost
- models.DbCfg.User = form.DbUser
- models.DbCfg.Passwd = form.DbPasswd
- models.DbCfg.Name = form.DbName
- models.DbCfg.SSLMode = form.SSLMode
- models.DbCfg.Charset = form.Charset
- models.DbCfg.Path = form.DbPath
-
- if (models.DbCfg.Type == "sqlite3") &&
- len(models.DbCfg.Path) == 0 {
+
+ setting.Database.Type = setting.GetDBTypeByName(form.DbType)
+ setting.Database.Host = form.DbHost
+ setting.Database.User = form.DbUser
+ setting.Database.Passwd = form.DbPasswd
+ setting.Database.Name = form.DbName
+ setting.Database.SSLMode = form.SSLMode
+ setting.Database.Charset = form.Charset
+ setting.Database.Path = form.DbPath
+
+ if (setting.Database.Type == "sqlite3") &&
+ len(setting.Database.Path) == 0 {
ctx.Data["Err_DbPath"] = true
ctx.RenderWithErr(ctx.Tr("install.err_empty_db_path"), tplInstall, &form)
return
@@ -265,14 +261,14 @@ func InstallPost(ctx *context.Context, form auth.InstallForm) {
log.Error("Failed to load custom conf '%s': %v", setting.CustomConf, err)
}
}
- cfg.Section("database").Key("DB_TYPE").SetValue(models.DbCfg.Type)
- cfg.Section("database").Key("HOST").SetValue(models.DbCfg.Host)
- cfg.Section("database").Key("NAME").SetValue(models.DbCfg.Name)
- cfg.Section("database").Key("USER").SetValue(models.DbCfg.User)
- cfg.Section("database").Key("PASSWD").SetValue(models.DbCfg.Passwd)
- cfg.Section("database").Key("SSL_MODE").SetValue(models.DbCfg.SSLMode)
- cfg.Section("database").Key("CHARSET").SetValue(models.DbCfg.Charset)
- cfg.Section("database").Key("PATH").SetValue(models.DbCfg.Path)
+ cfg.Section("database").Key("DB_TYPE").SetValue(setting.Database.Type)
+ cfg.Section("database").Key("HOST").SetValue(setting.Database.Host)
+ cfg.Section("database").Key("NAME").SetValue(setting.Database.Name)
+ cfg.Section("database").Key("USER").SetValue(setting.Database.User)
+ cfg.Section("database").Key("PASSWD").SetValue(setting.Database.Passwd)
+ cfg.Section("database").Key("SSL_MODE").SetValue(setting.Database.SSLMode)
+ cfg.Section("database").Key("CHARSET").SetValue(setting.Database.Charset)
+ cfg.Section("database").Key("PATH").SetValue(setting.Database.Path)
cfg.Section("").Key("APP_NAME").SetValue(form.AppName)
cfg.Section("repository").Key("ROOT").SetValue(form.RepoRootPath)