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.

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