summaryrefslogtreecommitdiffstats
path: root/modules/setting
diff options
context:
space:
mode:
authorLunny Xiao <xiaolunwen@gmail.com>2019-08-24 17:24:45 +0800
committerAntoine GIRARD <sapk@users.noreply.github.com>2019-08-24 11:24:45 +0200
commitf83db078f0603c775cd1b1bb016f996b65a04835 (patch)
tree9895f852c768d43b384ba36259b44d9506b04093 /modules/setting
parent26af3401c36e6316b81b92bf6a776bf2442d251c (diff)
downloadgitea-f83db078f0603c775cd1b1bb016f996b65a04835.tar.gz
gitea-f83db078f0603c775cd1b1bb016f996b65a04835.zip
Move database settings from models to setting (#7806)
* move database settings from models to setting * update docs * fix checkout pr * fix tests * fix lint * remove unsupported tidb options * correct wrong variable name * remove tidb totally
Diffstat (limited to 'modules/setting')
-rw-r--r--modules/setting/database.go171
-rw-r--r--modules/setting/database_sqlite.go16
-rw-r--r--modules/setting/database_test.go94
-rw-r--r--modules/setting/setting.go38
4 files changed, 295 insertions, 24 deletions
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/modules/setting/database_sqlite.go b/modules/setting/database_sqlite.go
new file mode 100644
index 0000000000..623326ddc2
--- /dev/null
+++ b/modules/setting/database_sqlite.go
@@ -0,0 +1,16 @@
+// +build sqlite
+
+// Copyright 2014 The Gogs 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 (
+ _ "github.com/mattn/go-sqlite3"
+)
+
+func init() {
+ EnableSQLite3 = true
+ 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()