You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

models.go 8.1 kB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
9 years ago
10 years ago
10 years ago
11 years ago
11 years ago
8 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package models
  5. import (
  6. "database/sql"
  7. "errors"
  8. "fmt"
  9. "net/url"
  10. "os"
  11. "path"
  12. "strings"
  13. // Needed for the MySQL driver
  14. _ "github.com/go-sql-driver/mysql"
  15. "github.com/go-xorm/core"
  16. "github.com/go-xorm/xorm"
  17. // Needed for the Postgresql driver
  18. _ "github.com/lib/pq"
  19. "code.gitea.io/gitea/models/migrations"
  20. "code.gitea.io/gitea/modules/setting"
  21. )
  22. // Engine represents a xorm engine or session.
  23. type Engine interface {
  24. Delete(interface{}) (int64, error)
  25. Exec(string, ...interface{}) (sql.Result, error)
  26. Find(interface{}, ...interface{}) error
  27. Get(interface{}) (bool, error)
  28. Id(interface{}) *xorm.Session
  29. In(string, ...interface{}) *xorm.Session
  30. Insert(...interface{}) (int64, error)
  31. InsertOne(interface{}) (int64, error)
  32. Iterate(interface{}, xorm.IterFunc) error
  33. SQL(interface{}, ...interface{}) *xorm.Session
  34. Where(interface{}, ...interface{}) *xorm.Session
  35. }
  36. func sessionRelease(sess *xorm.Session) {
  37. if !sess.IsCommitedOrRollbacked {
  38. sess.Rollback()
  39. }
  40. sess.Close()
  41. }
  42. var (
  43. x *xorm.Engine
  44. tables []interface{}
  45. // HasEngine specifies if we have a xorm.Engine
  46. HasEngine bool
  47. // DbCfg holds the database settings
  48. DbCfg struct {
  49. Type, Host, Name, User, Passwd, Path, SSLMode string
  50. }
  51. // EnableSQLite3 use SQLite3
  52. EnableSQLite3 bool
  53. // EnableTiDB enable TiDB
  54. EnableTiDB bool
  55. )
  56. func init() {
  57. tables = append(tables,
  58. new(User), new(PublicKey), new(AccessToken),
  59. new(Repository), new(DeployKey), new(Collaboration), new(Access), new(Upload),
  60. new(Watch), new(Star), new(Follow), new(Action),
  61. new(Issue), new(PullRequest), new(Comment), new(Attachment), new(IssueUser),
  62. new(Label), new(IssueLabel), new(Milestone),
  63. new(Mirror), new(Release), new(LoginSource), new(Webhook),
  64. new(UpdateTask), new(HookTask),
  65. new(Team), new(OrgUser), new(TeamUser), new(TeamRepo),
  66. new(Notice), new(EmailAddress))
  67. gonicNames := []string{"SSL", "UID"}
  68. for _, name := range gonicNames {
  69. core.LintGonicMapper[name] = true
  70. }
  71. }
  72. // LoadConfigs loads the database settings
  73. func LoadConfigs() {
  74. sec := setting.Cfg.Section("database")
  75. DbCfg.Type = sec.Key("DB_TYPE").String()
  76. switch DbCfg.Type {
  77. case "sqlite3":
  78. setting.UseSQLite3 = true
  79. case "mysql":
  80. setting.UseMySQL = true
  81. case "postgres":
  82. setting.UsePostgreSQL = true
  83. case "tidb":
  84. setting.UseTiDB = true
  85. }
  86. DbCfg.Host = sec.Key("HOST").String()
  87. DbCfg.Name = sec.Key("NAME").String()
  88. DbCfg.User = sec.Key("USER").String()
  89. if len(DbCfg.Passwd) == 0 {
  90. DbCfg.Passwd = sec.Key("PASSWD").String()
  91. }
  92. DbCfg.SSLMode = sec.Key("SSL_MODE").String()
  93. DbCfg.Path = sec.Key("PATH").MustString("data/gitea.db")
  94. }
  95. // parsePostgreSQLHostPort parses given input in various forms defined in
  96. // https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING
  97. // and returns proper host and port number.
  98. func parsePostgreSQLHostPort(info string) (string, string) {
  99. host, port := "127.0.0.1", "5432"
  100. if strings.Contains(info, ":") && !strings.HasSuffix(info, "]") {
  101. idx := strings.LastIndex(info, ":")
  102. host = info[:idx]
  103. port = info[idx+1:]
  104. } else if len(info) > 0 {
  105. host = info
  106. }
  107. return host, port
  108. }
  109. func getEngine() (*xorm.Engine, error) {
  110. connStr := ""
  111. var Param = "?"
  112. if strings.Contains(DbCfg.Name, Param) {
  113. Param = "&"
  114. }
  115. switch DbCfg.Type {
  116. case "mysql":
  117. if DbCfg.Host[0] == '/' { // looks like a unix socket
  118. connStr = fmt.Sprintf("%s:%s@unix(%s)/%s%scharset=utf8&parseTime=true",
  119. DbCfg.User, DbCfg.Passwd, DbCfg.Host, DbCfg.Name, Param)
  120. } else {
  121. connStr = fmt.Sprintf("%s:%s@tcp(%s)/%s%scharset=utf8&parseTime=true",
  122. DbCfg.User, DbCfg.Passwd, DbCfg.Host, DbCfg.Name, Param)
  123. }
  124. case "postgres":
  125. host, port := parsePostgreSQLHostPort(DbCfg.Host)
  126. if host[0] == '/' { // looks like a unix socket
  127. connStr = fmt.Sprintf("postgres://%s:%s@:%s/%s%ssslmode=%s&host=%s",
  128. url.QueryEscape(DbCfg.User), url.QueryEscape(DbCfg.Passwd), port, DbCfg.Name, Param, DbCfg.SSLMode, host)
  129. } else {
  130. connStr = fmt.Sprintf("postgres://%s:%s@%s:%s/%s%ssslmode=%s",
  131. url.QueryEscape(DbCfg.User), url.QueryEscape(DbCfg.Passwd), host, port, DbCfg.Name, Param, DbCfg.SSLMode)
  132. }
  133. case "sqlite3":
  134. if !EnableSQLite3 {
  135. return nil, errors.New("this binary version does not build support for SQLite3")
  136. }
  137. if err := os.MkdirAll(path.Dir(DbCfg.Path), os.ModePerm); err != nil {
  138. return nil, fmt.Errorf("Fail to create directories: %v", err)
  139. }
  140. connStr = "file:" + DbCfg.Path + "?cache=shared&mode=rwc"
  141. case "tidb":
  142. if !EnableTiDB {
  143. return nil, errors.New("this binary version does not build support for TiDB")
  144. }
  145. if err := os.MkdirAll(path.Dir(DbCfg.Path), os.ModePerm); err != nil {
  146. return nil, fmt.Errorf("Fail to create directories: %v", err)
  147. }
  148. connStr = "goleveldb://" + DbCfg.Path
  149. default:
  150. return nil, fmt.Errorf("Unknown database type: %s", DbCfg.Type)
  151. }
  152. return xorm.NewEngine(DbCfg.Type, connStr)
  153. }
  154. // NewTestEngine sets a new test xorm.Engine
  155. func NewTestEngine(x *xorm.Engine) (err error) {
  156. x, err = getEngine()
  157. if err != nil {
  158. return fmt.Errorf("Connect to database: %v", err)
  159. }
  160. x.SetMapper(core.GonicMapper{})
  161. return x.StoreEngine("InnoDB").Sync2(tables...)
  162. }
  163. // SetEngine sets the xorm.Engine
  164. func SetEngine() (err error) {
  165. x, err = getEngine()
  166. if err != nil {
  167. return fmt.Errorf("Fail to connect to database: %v", err)
  168. }
  169. x.SetMapper(core.GonicMapper{})
  170. // WARNING: for serv command, MUST remove the output to os.stdout,
  171. // so use log file to instead print to stdout.
  172. logPath := path.Join(setting.LogRootPath, "xorm.log")
  173. if err := os.MkdirAll(path.Dir(logPath), os.ModePerm); err != nil {
  174. return fmt.Errorf("Fail to create dir %s: %v", logPath, err)
  175. }
  176. f, err := os.Create(logPath)
  177. if err != nil {
  178. return fmt.Errorf("Fail to create xorm.log: %v", err)
  179. }
  180. x.SetLogger(xorm.NewSimpleLogger(f))
  181. x.ShowSQL(true)
  182. return nil
  183. }
  184. // NewEngine initializes a new xorm.Engine
  185. func NewEngine() (err error) {
  186. if err = SetEngine(); err != nil {
  187. return err
  188. }
  189. if err = x.Ping(); err != nil {
  190. return err
  191. }
  192. if err = migrations.Migrate(x); err != nil {
  193. return fmt.Errorf("migrate: %v", err)
  194. }
  195. if err = x.StoreEngine("InnoDB").Sync2(tables...); err != nil {
  196. return fmt.Errorf("sync database struct error: %v", err)
  197. }
  198. return nil
  199. }
  200. // Statistic contains the database statistics
  201. type Statistic struct {
  202. Counter struct {
  203. User, Org, PublicKey,
  204. Repo, Watch, Star, Action, Access,
  205. Issue, Comment, Oauth, Follow,
  206. Mirror, Release, LoginSource, Webhook,
  207. Milestone, Label, HookTask,
  208. Team, UpdateTask, Attachment int64
  209. }
  210. }
  211. // GetStatistic returns the database statistics
  212. func GetStatistic() (stats Statistic) {
  213. stats.Counter.User = CountUsers()
  214. stats.Counter.Org = CountOrganizations()
  215. stats.Counter.PublicKey, _ = x.Count(new(PublicKey))
  216. stats.Counter.Repo = CountRepositories(true)
  217. stats.Counter.Watch, _ = x.Count(new(Watch))
  218. stats.Counter.Star, _ = x.Count(new(Star))
  219. stats.Counter.Action, _ = x.Count(new(Action))
  220. stats.Counter.Access, _ = x.Count(new(Access))
  221. stats.Counter.Issue, _ = x.Count(new(Issue))
  222. stats.Counter.Comment, _ = x.Count(new(Comment))
  223. stats.Counter.Oauth = 0
  224. stats.Counter.Follow, _ = x.Count(new(Follow))
  225. stats.Counter.Mirror, _ = x.Count(new(Mirror))
  226. stats.Counter.Release, _ = x.Count(new(Release))
  227. stats.Counter.LoginSource = CountLoginSources()
  228. stats.Counter.Webhook, _ = x.Count(new(Webhook))
  229. stats.Counter.Milestone, _ = x.Count(new(Milestone))
  230. stats.Counter.Label, _ = x.Count(new(Label))
  231. stats.Counter.HookTask, _ = x.Count(new(HookTask))
  232. stats.Counter.Team, _ = x.Count(new(Team))
  233. stats.Counter.UpdateTask, _ = x.Count(new(UpdateTask))
  234. stats.Counter.Attachment, _ = x.Count(new(Attachment))
  235. return
  236. }
  237. // Ping tests if database is alive
  238. func Ping() error {
  239. return x.Ping()
  240. }
  241. // DumpDatabase dumps all data from database to file system.
  242. func DumpDatabase(filePath string) error {
  243. return x.DumpAllToFile(filePath)
  244. }