aboutsummaryrefslogtreecommitdiff
path: root/routes/install.go
diff options
context:
space:
mode:
Diffstat (limited to 'routes/install.go')
-rw-r--r--routes/install.go392
1 files changed, 392 insertions, 0 deletions
diff --git a/routes/install.go b/routes/install.go
new file mode 100644
index 00000000..948c67c2
--- /dev/null
+++ b/routes/install.go
@@ -0,0 +1,392 @@
+// 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 routes
+
+import (
+ "net/mail"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+
+ "github.com/Unknwon/com"
+ "github.com/go-xorm/xorm"
+ log "gopkg.in/clog.v1"
+ "gopkg.in/ini.v1"
+ "gopkg.in/macaron.v1"
+
+ "github.com/gogits/git-module"
+
+ "github.com/gogits/gogs/models"
+ "github.com/gogits/gogs/pkg/context"
+ "github.com/gogits/gogs/pkg/cron"
+ "github.com/gogits/gogs/pkg/form"
+ "github.com/gogits/gogs/pkg/mailer"
+ "github.com/gogits/gogs/pkg/markup"
+ "github.com/gogits/gogs/pkg/setting"
+ "github.com/gogits/gogs/pkg/ssh"
+ "github.com/gogits/gogs/pkg/template/highlight"
+ "github.com/gogits/gogs/pkg/tool"
+ "github.com/gogits/gogs/pkg/user"
+)
+
+const (
+ INSTALL = "install"
+)
+
+func checkRunMode() {
+ if setting.ProdMode {
+ macaron.Env = macaron.PROD
+ macaron.ColorLog = false
+ } else {
+ git.Debug = true
+ }
+ log.Info("Run Mode: %s", strings.Title(macaron.Env))
+}
+
+func NewServices() {
+ setting.NewServices()
+ mailer.NewContext()
+}
+
+// GlobalInit is for global configuration reload-able.
+func GlobalInit() {
+ setting.NewContext()
+ log.Trace("Custom path: %s", setting.CustomPath)
+ log.Trace("Log path: %s", setting.LogRootPath)
+ models.LoadConfigs()
+ NewServices()
+
+ if setting.InstallLock {
+ highlight.NewContext()
+ markup.NewSanitizer()
+ if err := models.NewEngine(); err != nil {
+ log.Fatal(2, "Fail to initialize ORM engine: %v", err)
+ }
+ models.HasEngine = true
+
+ models.LoadRepoConfig()
+ models.NewRepoContext()
+
+ // Booting long running goroutines.
+ cron.NewContext()
+ models.InitSyncMirrors()
+ models.InitDeliverHooks()
+ models.InitTestPullRequests()
+ }
+ if models.EnableSQLite3 {
+ log.Info("SQLite3 Supported")
+ }
+ if setting.SupportMiniWinService {
+ log.Info("Builtin Windows Service Supported")
+ }
+ checkRunMode()
+
+ if setting.InstallLock && setting.SSH.StartBuiltinServer {
+ ssh.Listen(setting.SSH.ListenHost, setting.SSH.ListenPort, setting.SSH.ServerCiphers)
+ log.Info("SSH server started on %s:%v", setting.SSH.ListenHost, setting.SSH.ListenPort)
+ log.Trace("SSH server cipher list: %v", setting.SSH.ServerCiphers)
+ }
+}
+
+func InstallInit(c *context.Context) {
+ if setting.InstallLock {
+ c.NotFound()
+ return
+ }
+
+ c.Title("install.install")
+ c.PageIs("Install")
+
+ dbOpts := []string{"MySQL", "PostgreSQL", "MSSQL"}
+ if models.EnableSQLite3 {
+ dbOpts = append(dbOpts, "SQLite3")
+ }
+ c.Data["DbOptions"] = dbOpts
+}
+
+func Install(c *context.Context) {
+ f := form.Install{}
+
+ // Database settings
+ f.DbHost = models.DbCfg.Host
+ f.DbUser = models.DbCfg.User
+ f.DbName = models.DbCfg.Name
+ f.DbPath = models.DbCfg.Path
+
+ c.Data["CurDbOption"] = "MySQL"
+ switch models.DbCfg.Type {
+ case "postgres":
+ c.Data["CurDbOption"] = "PostgreSQL"
+ case "mssql":
+ c.Data["CurDbOption"] = "MSSQL"
+ case "sqlite3":
+ if models.EnableSQLite3 {
+ c.Data["CurDbOption"] = "SQLite3"
+ }
+ }
+
+ // Application general settings
+ f.AppName = setting.AppName
+ f.RepoRootPath = setting.RepoRootPath
+
+ // Note(unknwon): it's hard for Windows users change a running user,
+ // so just use current one if config says default.
+ if setting.IsWindows && setting.RunUser == "git" {
+ f.RunUser = user.CurrentUsername()
+ } else {
+ f.RunUser = setting.RunUser
+ }
+
+ f.Domain = setting.Domain
+ f.SSHPort = setting.SSH.Port
+ f.UseBuiltinSSHServer = setting.SSH.StartBuiltinServer
+ f.HTTPPort = setting.HTTPPort
+ f.AppUrl = setting.AppURL
+ f.LogRootPath = setting.LogRootPath
+
+ // E-mail service settings
+ if setting.MailService != nil {
+ f.SMTPHost = setting.MailService.Host
+ f.SMTPFrom = setting.MailService.From
+ f.SMTPUser = setting.MailService.User
+ }
+ f.RegisterConfirm = setting.Service.RegisterEmailConfirm
+ f.MailNotify = setting.Service.EnableNotifyMail
+
+ // Server and other services settings
+ f.OfflineMode = setting.OfflineMode
+ f.DisableGravatar = setting.DisableGravatar
+ f.EnableFederatedAvatar = setting.EnableFederatedAvatar
+ f.DisableRegistration = setting.Service.DisableRegistration
+ f.EnableCaptcha = setting.Service.EnableCaptcha
+ f.RequireSignInView = setting.Service.RequireSignInView
+
+ form.Assign(f, c.Data)
+ c.Success(INSTALL)
+}
+
+func InstallPost(c *context.Context, f form.Install) {
+ c.Data["CurDbOption"] = f.DbType
+
+ if c.HasError() {
+ if c.HasValue("Err_SMTPEmail") {
+ c.FormErr("SMTP")
+ }
+ if c.HasValue("Err_AdminName") ||
+ c.HasValue("Err_AdminPasswd") ||
+ c.HasValue("Err_AdminEmail") {
+ c.FormErr("Admin")
+ }
+
+ c.Success(INSTALL)
+ return
+ }
+
+ if _, err := exec.LookPath("git"); err != nil {
+ c.RenderWithErr(c.Tr("install.test_git_failed", err), INSTALL, &f)
+ return
+ }
+
+ // Pass basic check, now test configuration.
+ // Test database setting.
+ dbTypes := map[string]string{"MySQL": "mysql", "PostgreSQL": "postgres", "MSSQL": "mssql", "SQLite3": "sqlite3", "TiDB": "tidb"}
+ models.DbCfg.Type = dbTypes[f.DbType]
+ models.DbCfg.Host = f.DbHost
+ models.DbCfg.User = f.DbUser
+ models.DbCfg.Passwd = f.DbPasswd
+ models.DbCfg.Name = f.DbName
+ models.DbCfg.SSLMode = f.SSLMode
+ models.DbCfg.Path = f.DbPath
+
+ if models.DbCfg.Type == "sqlite3" && len(models.DbCfg.Path) == 0 {
+ c.FormErr("DbPath")
+ c.RenderWithErr(c.Tr("install.err_empty_db_path"), INSTALL, &f)
+ return
+ }
+
+ // Set test engine.
+ var x *xorm.Engine
+ if err := models.NewTestEngine(x); err != nil {
+ if strings.Contains(err.Error(), `Unknown database type: sqlite3`) {
+ c.FormErr("DbType")
+ c.RenderWithErr(c.Tr("install.sqlite3_not_available", "https://gogs.io/docs/installation/install_from_binary.html"), INSTALL, &f)
+ } else {
+ c.FormErr("DbSetting")
+ c.RenderWithErr(c.Tr("install.invalid_db_setting", err), INSTALL, &f)
+ }
+ return
+ }
+
+ // Test repository root path.
+ f.RepoRootPath = strings.Replace(f.RepoRootPath, "\\", "/", -1)
+ if err := os.MkdirAll(f.RepoRootPath, os.ModePerm); err != nil {
+ c.FormErr("RepoRootPath")
+ c.RenderWithErr(c.Tr("install.invalid_repo_path", err), INSTALL, &f)
+ return
+ }
+
+ // Test log root path.
+ f.LogRootPath = strings.Replace(f.LogRootPath, "\\", "/", -1)
+ if err := os.MkdirAll(f.LogRootPath, os.ModePerm); err != nil {
+ c.FormErr("LogRootPath")
+ c.RenderWithErr(c.Tr("install.invalid_log_root_path", err), INSTALL, &f)
+ return
+ }
+
+ currentUser, match := setting.IsRunUserMatchCurrentUser(f.RunUser)
+ if !match {
+ c.FormErr("RunUser")
+ c.RenderWithErr(c.Tr("install.run_user_not_match", f.RunUser, currentUser), INSTALL, &f)
+ return
+ }
+
+ // Check host address and port
+ if len(f.SMTPHost) > 0 && !strings.Contains(f.SMTPHost, ":") {
+ c.FormErr("SMTP", "SMTPHost")
+ c.RenderWithErr(c.Tr("install.smtp_host_missing_port"), INSTALL, &f)
+ return
+ }
+
+ // Make sure FROM field is valid
+ if len(f.SMTPFrom) > 0 {
+ _, err := mail.ParseAddress(f.SMTPFrom)
+ if err != nil {
+ c.FormErr("SMTP", "SMTPFrom")
+ c.RenderWithErr(c.Tr("install.invalid_smtp_from", err), INSTALL, &f)
+ return
+ }
+ }
+
+ // Check logic loophole between disable self-registration and no admin account.
+ if f.DisableRegistration && len(f.AdminName) == 0 {
+ c.FormErr("Services", "Admin")
+ c.RenderWithErr(c.Tr("install.no_admin_and_disable_registration"), INSTALL, f)
+ return
+ }
+
+ // Check admin password.
+ if len(f.AdminName) > 0 && len(f.AdminPasswd) == 0 {
+ c.FormErr("Admin", "AdminPasswd")
+ c.RenderWithErr(c.Tr("install.err_empty_admin_password"), INSTALL, f)
+ return
+ }
+ if f.AdminPasswd != f.AdminConfirmPasswd {
+ c.FormErr("Admin", "AdminPasswd")
+ c.RenderWithErr(c.Tr("form.password_not_match"), INSTALL, f)
+ return
+ }
+
+ if f.AppUrl[len(f.AppUrl)-1] != '/' {
+ f.AppUrl += "/"
+ }
+
+ // Save settings.
+ cfg := ini.Empty()
+ if com.IsFile(setting.CustomConf) {
+ // Keeps custom settings if there is already something.
+ if err := cfg.Append(setting.CustomConf); err != nil {
+ log.Error(2, "Fail 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("PATH").SetValue(models.DbCfg.Path)
+
+ cfg.Section("").Key("APP_NAME").SetValue(f.AppName)
+ cfg.Section("repository").Key("ROOT").SetValue(f.RepoRootPath)
+ cfg.Section("").Key("RUN_USER").SetValue(f.RunUser)
+ cfg.Section("server").Key("DOMAIN").SetValue(f.Domain)
+ cfg.Section("server").Key("HTTP_PORT").SetValue(f.HTTPPort)
+ cfg.Section("server").Key("ROOT_URL").SetValue(f.AppUrl)
+
+ if f.SSHPort == 0 {
+ cfg.Section("server").Key("DISABLE_SSH").SetValue("true")
+ } else {
+ cfg.Section("server").Key("DISABLE_SSH").SetValue("false")
+ cfg.Section("server").Key("SSH_PORT").SetValue(com.ToStr(f.SSHPort))
+ cfg.Section("server").Key("START_SSH_SERVER").SetValue(com.ToStr(f.UseBuiltinSSHServer))
+ }
+
+ if len(strings.TrimSpace(f.SMTPHost)) > 0 {
+ cfg.Section("mailer").Key("ENABLED").SetValue("true")
+ cfg.Section("mailer").Key("HOST").SetValue(f.SMTPHost)
+ cfg.Section("mailer").Key("FROM").SetValue(f.SMTPFrom)
+ cfg.Section("mailer").Key("USER").SetValue(f.SMTPUser)
+ cfg.Section("mailer").Key("PASSWD").SetValue(f.SMTPPasswd)
+ } else {
+ cfg.Section("mailer").Key("ENABLED").SetValue("false")
+ }
+ cfg.Section("service").Key("REGISTER_EMAIL_CONFIRM").SetValue(com.ToStr(f.RegisterConfirm))
+ cfg.Section("service").Key("ENABLE_NOTIFY_MAIL").SetValue(com.ToStr(f.MailNotify))
+
+ cfg.Section("server").Key("OFFLINE_MODE").SetValue(com.ToStr(f.OfflineMode))
+ cfg.Section("picture").Key("DISABLE_GRAVATAR").SetValue(com.ToStr(f.DisableGravatar))
+ cfg.Section("picture").Key("ENABLE_FEDERATED_AVATAR").SetValue(com.ToStr(f.EnableFederatedAvatar))
+ cfg.Section("service").Key("DISABLE_REGISTRATION").SetValue(com.ToStr(f.DisableRegistration))
+ cfg.Section("service").Key("ENABLE_CAPTCHA").SetValue(com.ToStr(f.EnableCaptcha))
+ cfg.Section("service").Key("REQUIRE_SIGNIN_VIEW").SetValue(com.ToStr(f.RequireSignInView))
+
+ cfg.Section("").Key("RUN_MODE").SetValue("prod")
+
+ cfg.Section("session").Key("PROVIDER").SetValue("file")
+
+ mode := "file"
+ if f.EnableConsoleMode {
+ mode = "console, file"
+ }
+ cfg.Section("log").Key("MODE").SetValue(mode)
+ cfg.Section("log").Key("LEVEL").SetValue("Info")
+ cfg.Section("log").Key("ROOT_PATH").SetValue(f.LogRootPath)
+
+ cfg.Section("security").Key("INSTALL_LOCK").SetValue("true")
+ secretKey, err := tool.RandomString(15)
+ if err != nil {
+ c.RenderWithErr(c.Tr("install.secret_key_failed", err), INSTALL, &f)
+ return
+ }
+ cfg.Section("security").Key("SECRET_KEY").SetValue(secretKey)
+
+ os.MkdirAll(filepath.Dir(setting.CustomConf), os.ModePerm)
+ if err := cfg.SaveTo(setting.CustomConf); err != nil {
+ c.RenderWithErr(c.Tr("install.save_config_failed", err), INSTALL, &f)
+ return
+ }
+
+ GlobalInit()
+
+ // Create admin account
+ if len(f.AdminName) > 0 {
+ u := &models.User{
+ Name: f.AdminName,
+ Email: f.AdminEmail,
+ Passwd: f.AdminPasswd,
+ IsAdmin: true,
+ IsActive: true,
+ }
+ if err := models.CreateUser(u); err != nil {
+ if !models.IsErrUserAlreadyExist(err) {
+ setting.InstallLock = false
+ c.FormErr("AdminName", "AdminEmail")
+ c.RenderWithErr(c.Tr("install.invalid_admin_setting", err), INSTALL, &f)
+ return
+ }
+ log.Info("Admin account already exist")
+ u, _ = models.GetUserByName(u.Name)
+ }
+
+ // Auto-login for admin
+ c.Session.Set("uid", u.ID)
+ c.Session.Set("uname", u.Name)
+ }
+
+ log.Info("First-time run install finished!")
+ c.Flash.Success(c.Tr("install.install_success"))
+ c.Redirect(f.AppUrl + "user/login")
+}