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

384 lines
12 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  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 routers
  5. import (
  6. "errors"
  7. "os"
  8. "os/exec"
  9. "path"
  10. "path/filepath"
  11. "strings"
  12. "github.com/Unknwon/com"
  13. "github.com/go-xorm/xorm"
  14. "gopkg.in/ini.v1"
  15. "gopkg.in/macaron.v1"
  16. "github.com/gogits/git-module"
  17. "github.com/gogits/gogs/models"
  18. "github.com/gogits/gogs/modules/auth"
  19. "github.com/gogits/gogs/modules/base"
  20. "github.com/gogits/gogs/modules/cron"
  21. "github.com/gogits/gogs/modules/log"
  22. "github.com/gogits/gogs/modules/mailer"
  23. "github.com/gogits/gogs/modules/markdown"
  24. "github.com/gogits/gogs/modules/middleware"
  25. "github.com/gogits/gogs/modules/setting"
  26. "github.com/gogits/gogs/modules/ssh"
  27. "github.com/gogits/gogs/modules/template/highlight"
  28. "github.com/gogits/gogs/modules/user"
  29. )
  30. const (
  31. INSTALL base.TplName = "install"
  32. )
  33. func checkRunMode() {
  34. switch setting.Cfg.Section("").Key("RUN_MODE").String() {
  35. case "prod":
  36. macaron.Env = macaron.PROD
  37. macaron.ColorLog = false
  38. setting.ProdMode = true
  39. default:
  40. git.Debug = true
  41. }
  42. log.Info("Run Mode: %s", strings.Title(macaron.Env))
  43. }
  44. func NewServices() {
  45. setting.NewServices()
  46. mailer.NewContext()
  47. }
  48. // GlobalInit is for global configuration reload-able.
  49. func GlobalInit() {
  50. setting.NewContext()
  51. highlight.NewContext()
  52. log.Trace("Custom path: %s", setting.CustomPath)
  53. log.Trace("Log path: %s", setting.LogRootPath)
  54. models.LoadConfigs()
  55. NewServices()
  56. if setting.InstallLock {
  57. models.LoadRepoConfig()
  58. models.NewRepoContext()
  59. if err := models.NewEngine(); err != nil {
  60. log.Fatal(4, "Fail to initialize ORM engine: %v", err)
  61. }
  62. models.HasEngine = true
  63. cron.NewContext()
  64. models.InitDeliverHooks()
  65. models.InitTestPullRequests()
  66. log.NewGitLogger(path.Join(setting.LogRootPath, "http.log"))
  67. }
  68. if models.EnableSQLite3 {
  69. log.Info("SQLite3 Supported")
  70. }
  71. if models.EnableTidb {
  72. log.Info("TiDB Supported")
  73. }
  74. if setting.SupportMiniWinService {
  75. log.Info("Builtin Windows Service Supported")
  76. }
  77. checkRunMode()
  78. if setting.SSH.StartBuiltinServer {
  79. ssh.Listen(setting.SSH.ListenPort)
  80. log.Info("SSH server started on :%v", setting.SSH.ListenPort)
  81. }
  82. // Build Sanitizer
  83. markdown.BuildSanitizer()
  84. }
  85. func InstallInit(ctx *middleware.Context) {
  86. if setting.InstallLock {
  87. ctx.Handle(404, "Install", errors.New("Installation is prohibited"))
  88. return
  89. }
  90. ctx.Data["Title"] = ctx.Tr("install.install")
  91. ctx.Data["PageIsInstall"] = true
  92. dbOpts := []string{"MySQL", "PostgreSQL"}
  93. if models.EnableSQLite3 {
  94. dbOpts = append(dbOpts, "SQLite3")
  95. }
  96. if models.EnableTidb {
  97. dbOpts = append(dbOpts, "TiDB")
  98. }
  99. ctx.Data["DbOptions"] = dbOpts
  100. }
  101. func Install(ctx *middleware.Context) {
  102. form := auth.InstallForm{}
  103. // Database settings
  104. form.DbHost = models.DbCfg.Host
  105. form.DbUser = models.DbCfg.User
  106. form.DbName = models.DbCfg.Name
  107. form.DbPath = models.DbCfg.Path
  108. ctx.Data["CurDbOption"] = "MySQL"
  109. switch models.DbCfg.Type {
  110. case "postgres":
  111. ctx.Data["CurDbOption"] = "PostgreSQL"
  112. case "sqlite3":
  113. if models.EnableSQLite3 {
  114. ctx.Data["CurDbOption"] = "SQLite3"
  115. }
  116. case "tidb":
  117. if models.EnableTidb {
  118. ctx.Data["CurDbOption"] = "TiDB"
  119. }
  120. }
  121. // Application general settings
  122. form.AppName = setting.AppName
  123. form.RepoRootPath = setting.RepoRootPath
  124. // Note(unknwon): it's hard for Windows users change a running user,
  125. // so just use current one if config says default.
  126. if setting.IsWindows && setting.RunUser == "git" {
  127. form.RunUser = user.CurrentUsername()
  128. } else {
  129. form.RunUser = setting.RunUser
  130. }
  131. form.Domain = setting.Domain
  132. form.SSHPort = setting.SSH.Port
  133. form.HTTPPort = setting.HttpPort
  134. form.AppUrl = setting.AppUrl
  135. form.LogRootPath = setting.LogRootPath
  136. // E-mail service settings
  137. if setting.MailService != nil {
  138. form.SMTPHost = setting.MailService.Host
  139. form.SMTPFrom = setting.MailService.From
  140. form.SMTPEmail = setting.MailService.User
  141. }
  142. form.RegisterConfirm = setting.Service.RegisterEmailConfirm
  143. form.MailNotify = setting.Service.EnableNotifyMail
  144. // Server and other services settings
  145. form.OfflineMode = setting.OfflineMode
  146. form.DisableGravatar = setting.DisableGravatar
  147. form.DisableRegistration = setting.Service.DisableRegistration
  148. form.EnableCaptcha = setting.Service.EnableCaptcha
  149. form.RequireSignInView = setting.Service.RequireSignInView
  150. auth.AssignForm(form, ctx.Data)
  151. ctx.HTML(200, INSTALL)
  152. }
  153. func InstallPost(ctx *middleware.Context, form auth.InstallForm) {
  154. ctx.Data["CurDbOption"] = form.DbType
  155. if ctx.HasError() {
  156. if ctx.HasValue("Err_SMTPEmail") {
  157. ctx.Data["Err_SMTP"] = true
  158. }
  159. if ctx.HasValue("Err_AdminName") ||
  160. ctx.HasValue("Err_AdminPasswd") ||
  161. ctx.HasValue("Err_AdminEmail") {
  162. ctx.Data["Err_Admin"] = true
  163. }
  164. ctx.HTML(200, INSTALL)
  165. return
  166. }
  167. if _, err := exec.LookPath("git"); err != nil {
  168. ctx.RenderWithErr(ctx.Tr("install.test_git_failed", err), INSTALL, &form)
  169. return
  170. }
  171. // Pass basic check, now test configuration.
  172. // Test database setting.
  173. dbTypes := map[string]string{"MySQL": "mysql", "PostgreSQL": "postgres", "SQLite3": "sqlite3", "TiDB": "tidb"}
  174. models.DbCfg.Type = dbTypes[form.DbType]
  175. models.DbCfg.Host = form.DbHost
  176. models.DbCfg.User = form.DbUser
  177. models.DbCfg.Passwd = form.DbPasswd
  178. models.DbCfg.Name = form.DbName
  179. models.DbCfg.SSLMode = form.SSLMode
  180. models.DbCfg.Path = form.DbPath
  181. if (models.DbCfg.Type == "sqlite3" || models.DbCfg.Type == "tidb") &&
  182. len(models.DbCfg.Path) == 0 {
  183. ctx.Data["Err_DbPath"] = true
  184. ctx.RenderWithErr(ctx.Tr("install.err_empty_db_path"), INSTALL, &form)
  185. return
  186. } else if models.DbCfg.Type == "tidb" &&
  187. strings.ContainsAny(path.Base(models.DbCfg.Path), ".-") {
  188. ctx.Data["Err_DbPath"] = true
  189. ctx.RenderWithErr(ctx.Tr("install.err_invalid_tidb_name"), INSTALL, &form)
  190. return
  191. }
  192. // Set test engine.
  193. var x *xorm.Engine
  194. if err := models.NewTestEngine(x); err != nil {
  195. if strings.Contains(err.Error(), `Unknown database type: sqlite3`) {
  196. ctx.Data["Err_DbType"] = true
  197. ctx.RenderWithErr(ctx.Tr("install.sqlite3_not_available", "http://gogs.io/docs/installation/install_from_binary.html"), INSTALL, &form)
  198. } else {
  199. ctx.Data["Err_DbSetting"] = true
  200. ctx.RenderWithErr(ctx.Tr("install.invalid_db_setting", err), INSTALL, &form)
  201. }
  202. return
  203. }
  204. // Test repository root path.
  205. form.RepoRootPath = strings.Replace(form.RepoRootPath, "\\", "/", -1)
  206. if err := os.MkdirAll(form.RepoRootPath, os.ModePerm); err != nil {
  207. ctx.Data["Err_RepoRootPath"] = true
  208. ctx.RenderWithErr(ctx.Tr("install.invalid_repo_path", err), INSTALL, &form)
  209. return
  210. }
  211. // Test log root path.
  212. form.LogRootPath = strings.Replace(form.LogRootPath, "\\", "/", -1)
  213. if err := os.MkdirAll(form.LogRootPath, os.ModePerm); err != nil {
  214. ctx.Data["Err_LogRootPath"] = true
  215. ctx.RenderWithErr(ctx.Tr("install.invalid_log_root_path", err), INSTALL, &form)
  216. return
  217. }
  218. // Check run user.
  219. curUser := user.CurrentUsername()
  220. if form.RunUser != curUser {
  221. ctx.Data["Err_RunUser"] = true
  222. ctx.RenderWithErr(ctx.Tr("install.run_user_not_match", form.RunUser, curUser), INSTALL, &form)
  223. return
  224. }
  225. // Check logic loophole between disable self-registration and no admin account.
  226. if form.DisableRegistration && len(form.AdminName) == 0 {
  227. ctx.Data["Err_Services"] = true
  228. ctx.Data["Err_Admin"] = true
  229. ctx.RenderWithErr(ctx.Tr("install.no_admin_and_disable_registration"), INSTALL, form)
  230. return
  231. }
  232. // Check admin password.
  233. if len(form.AdminName) > 0 && len(form.AdminPasswd) == 0 {
  234. ctx.Data["Err_Admin"] = true
  235. ctx.Data["Err_AdminPasswd"] = true
  236. ctx.RenderWithErr(ctx.Tr("install.err_empty_admin_password"), INSTALL, form)
  237. return
  238. }
  239. if form.AdminPasswd != form.AdminConfirmPasswd {
  240. ctx.Data["Err_Admin"] = true
  241. ctx.Data["Err_AdminPasswd"] = true
  242. ctx.RenderWithErr(ctx.Tr("form.password_not_match"), INSTALL, form)
  243. return
  244. }
  245. if form.AppUrl[len(form.AppUrl)-1] != '/' {
  246. form.AppUrl += "/"
  247. }
  248. // Save settings.
  249. cfg := ini.Empty()
  250. if com.IsFile(setting.CustomConf) {
  251. // Keeps custom settings if there is already something.
  252. if err := cfg.Append(setting.CustomConf); err != nil {
  253. log.Error(4, "Fail to load custom conf '%s': %v", setting.CustomConf, err)
  254. }
  255. }
  256. cfg.Section("database").Key("DB_TYPE").SetValue(models.DbCfg.Type)
  257. cfg.Section("database").Key("HOST").SetValue(models.DbCfg.Host)
  258. cfg.Section("database").Key("NAME").SetValue(models.DbCfg.Name)
  259. cfg.Section("database").Key("USER").SetValue(models.DbCfg.User)
  260. cfg.Section("database").Key("PASSWD").SetValue(models.DbCfg.Passwd)
  261. cfg.Section("database").Key("SSL_MODE").SetValue(models.DbCfg.SSLMode)
  262. cfg.Section("database").Key("PATH").SetValue(models.DbCfg.Path)
  263. cfg.Section("").Key("APP_NAME").SetValue(form.AppName)
  264. cfg.Section("repository").Key("ROOT").SetValue(form.RepoRootPath)
  265. cfg.Section("").Key("RUN_USER").SetValue(form.RunUser)
  266. cfg.Section("server").Key("DOMAIN").SetValue(form.Domain)
  267. cfg.Section("server").Key("HTTP_PORT").SetValue(form.HTTPPort)
  268. cfg.Section("server").Key("ROOT_URL").SetValue(form.AppUrl)
  269. if form.SSHPort == 0 {
  270. cfg.Section("server").Key("DISABLE_SSH").SetValue("true")
  271. } else {
  272. cfg.Section("server").Key("DISABLE_SSH").SetValue("false")
  273. cfg.Section("server").Key("SSH_PORT").SetValue(com.ToStr(form.SSHPort))
  274. }
  275. if len(strings.TrimSpace(form.SMTPHost)) > 0 {
  276. cfg.Section("mailer").Key("ENABLED").SetValue("true")
  277. cfg.Section("mailer").Key("HOST").SetValue(form.SMTPHost)
  278. cfg.Section("mailer").Key("FROM").SetValue(form.SMTPFrom)
  279. cfg.Section("mailer").Key("USER").SetValue(form.SMTPEmail)
  280. cfg.Section("mailer").Key("PASSWD").SetValue(form.SMTPPasswd)
  281. } else {
  282. cfg.Section("mailer").Key("ENABLED").SetValue("false")
  283. }
  284. cfg.Section("service").Key("REGISTER_EMAIL_CONFIRM").SetValue(com.ToStr(form.RegisterConfirm))
  285. cfg.Section("service").Key("ENABLE_NOTIFY_MAIL").SetValue(com.ToStr(form.MailNotify))
  286. cfg.Section("server").Key("OFFLINE_MODE").SetValue(com.ToStr(form.OfflineMode))
  287. cfg.Section("picture").Key("DISABLE_GRAVATAR").SetValue(com.ToStr(form.DisableGravatar))
  288. cfg.Section("service").Key("DISABLE_REGISTRATION").SetValue(com.ToStr(form.DisableRegistration))
  289. cfg.Section("service").Key("ENABLE_CAPTCHA").SetValue(com.ToStr(form.EnableCaptcha))
  290. cfg.Section("service").Key("REQUIRE_SIGNIN_VIEW").SetValue(com.ToStr(form.RequireSignInView))
  291. cfg.Section("").Key("RUN_MODE").SetValue("prod")
  292. cfg.Section("session").Key("PROVIDER").SetValue("file")
  293. cfg.Section("log").Key("MODE").SetValue("file")
  294. cfg.Section("log").Key("LEVEL").SetValue("Info")
  295. cfg.Section("log").Key("ROOT_PATH").SetValue(form.LogRootPath)
  296. cfg.Section("security").Key("INSTALL_LOCK").SetValue("true")
  297. cfg.Section("security").Key("SECRET_KEY").SetValue(base.GetRandomString(15))
  298. os.MkdirAll(filepath.Dir(setting.CustomConf), os.ModePerm)
  299. if err := cfg.SaveTo(setting.CustomConf); err != nil {
  300. ctx.RenderWithErr(ctx.Tr("install.save_config_failed", err), INSTALL, &form)
  301. return
  302. }
  303. GlobalInit()
  304. // Create admin account
  305. if len(form.AdminName) > 0 {
  306. u := &models.User{
  307. Name: form.AdminName,
  308. Email: form.AdminEmail,
  309. Passwd: form.AdminPasswd,
  310. IsAdmin: true,
  311. IsActive: true,
  312. }
  313. if err := models.CreateUser(u); err != nil {
  314. if !models.IsErrUserAlreadyExist(err) {
  315. setting.InstallLock = false
  316. ctx.Data["Err_AdminName"] = true
  317. ctx.Data["Err_AdminEmail"] = true
  318. ctx.RenderWithErr(ctx.Tr("install.invalid_admin_setting", err), INSTALL, &form)
  319. return
  320. }
  321. log.Info("Admin account already exist")
  322. u, _ = models.GetUserByName(u.Name)
  323. }
  324. // Auto-login for admin
  325. ctx.Session.Set("uid", u.Id)
  326. ctx.Session.Set("uname", u.Name)
  327. }
  328. log.Info("First-time run install finished!")
  329. ctx.Flash.Success(ctx.Tr("install.install_success"))
  330. ctx.Redirect(form.AppUrl + "user/login")
  331. }