2014-03-25 12:51:42 +04:00
// 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 routers
2014-03-28 15:26:22 +04:00
import (
"errors"
2014-03-30 01:50:51 +04:00
"os"
2014-04-08 23:27:35 +04:00
"os/exec"
2014-05-26 04:11:25 +04:00
"path"
2015-02-05 13:12:37 +03:00
"path/filepath"
2014-03-30 01:50:51 +04:00
"strings"
2014-07-26 08:24:27 +04:00
"github.com/Unknwon/com"
"github.com/Unknwon/macaron"
2014-04-18 17:35:09 +04:00
"github.com/go-xorm/xorm"
2015-02-01 22:39:58 +03:00
"gopkg.in/ini.v1"
2014-03-28 15:26:22 +04:00
"github.com/gogits/gogs/models"
2015-08-17 21:19:29 +03:00
"github.com/gogits/gogs/models/cron"
2014-03-29 02:40:31 +04:00
"github.com/gogits/gogs/modules/auth"
2014-03-28 15:26:22 +04:00
"github.com/gogits/gogs/modules/base"
2014-03-30 01:50:51 +04:00
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/mailer"
2014-03-28 15:26:22 +04:00
"github.com/gogits/gogs/modules/middleware"
2014-05-26 04:11:25 +04:00
"github.com/gogits/gogs/modules/setting"
2014-04-14 02:12:07 +04:00
"github.com/gogits/gogs/modules/social"
2015-07-31 09:50:11 +03:00
"github.com/gogits/gogs/modules/user"
2014-03-28 15:26:22 +04:00
)
2014-06-22 21:14:03 +04:00
const (
INSTALL base . TplName = "install"
)
2014-03-30 01:50:51 +04:00
func checkRunMode ( ) {
2014-12-31 13:37:29 +03:00
switch setting . Cfg . Section ( "" ) . Key ( "RUN_MODE" ) . String ( ) {
2014-03-30 01:50:51 +04:00
case "prod" :
2014-07-26 08:24:27 +04:00
macaron . Env = macaron . PROD
2015-07-15 21:47:51 +03:00
macaron . ColorLog = false
2014-05-26 04:11:25 +04:00
setting . ProdMode = true
2014-03-30 01:50:51 +04:00
}
2014-07-26 08:24:27 +04:00
log . Info ( "Run Mode: %s" , strings . Title ( macaron . Env ) )
2014-03-30 01:50:51 +04:00
}
2014-04-14 02:12:07 +04:00
func NewServices ( ) {
2014-05-26 04:11:25 +04:00
setting . NewServices ( )
2014-04-14 02:12:07 +04:00
social . NewOauthService ( )
}
2014-03-30 01:50:51 +04:00
// GlobalInit is for global configuration reload-able.
func GlobalInit ( ) {
2014-05-26 04:11:25 +04:00
setting . NewConfigContext ( )
2014-05-26 04:57:01 +04:00
log . Trace ( "Custom path: %s" , setting . CustomPath )
2014-05-30 14:34:24 +04:00
log . Trace ( "Log path: %s" , setting . LogRootPath )
2014-03-30 01:50:51 +04:00
mailer . NewMailerContext ( )
models . LoadModelsConfig ( )
2014-04-20 06:13:22 +04:00
NewServices ( )
2014-03-30 18:47:08 +04:00
2014-05-26 04:11:25 +04:00
if setting . InstallLock {
2014-07-27 02:37:18 +04:00
models . LoadRepoConfig ( )
models . NewRepoContext ( )
2014-03-30 18:47:08 +04:00
if err := models . NewEngine ( ) ; err != nil {
2014-07-26 08:24:27 +04:00
log . Fatal ( 4 , "Fail to initialize ORM engine: %v" , err )
2014-03-30 18:47:08 +04:00
}
models . HasEngine = true
2014-04-13 05:30:09 +04:00
cron . NewCronContext ( )
2015-07-25 16:32:04 +03:00
models . InitDeliverHooks ( )
2014-06-20 09:14:54 +04:00
log . NewGitLogger ( path . Join ( setting . LogRootPath , "http.log" ) )
2014-03-30 01:50:51 +04:00
}
2014-05-31 03:19:30 +04:00
if models . EnableSQLite3 {
2015-08-02 07:36:35 +03:00
log . Info ( "SQLite3 Supported" )
2014-05-31 03:19:30 +04:00
}
2015-09-13 03:58:51 +03:00
if models . EnableTidb {
log . Info ( "TiDB Supported" )
}
2014-03-30 01:50:51 +04:00
checkRunMode ( )
}
2015-02-01 20:41:03 +03:00
func InstallInit ( ctx * middleware . Context ) {
2014-05-26 04:11:25 +04:00
if setting . InstallLock {
2014-09-08 03:02:58 +04:00
ctx . Handle ( 404 , "Install" , errors . New ( "Installation is prohibited" ) )
2014-03-28 15:26:22 +04:00
return
}
2014-03-25 12:51:42 +04:00
2014-09-08 03:02:58 +04:00
ctx . Data [ "Title" ] = ctx . Tr ( "install.install" )
2014-03-28 15:26:22 +04:00
ctx . Data [ "PageIsInstall" ] = true
2015-09-06 23:31:22 +03:00
dbOpts := [ ] string { "MySQL" , "PostgreSQL" }
if models . EnableSQLite3 {
dbOpts = append ( dbOpts , "SQLite3" )
}
if models . EnableTidb {
dbOpts = append ( dbOpts , "TiDB" )
}
ctx . Data [ "DbOptions" ] = dbOpts
2015-02-01 20:41:03 +03:00
}
2014-03-30 01:50:51 +04:00
2015-02-01 20:41:03 +03:00
func Install ( ctx * middleware . Context ) {
form := auth . InstallForm { }
2015-07-09 08:17:48 +03:00
// Database settings
2015-02-01 20:41:03 +03:00
form . DbHost = models . DbCfg . Host
form . DbUser = models . DbCfg . User
form . DbName = models . DbCfg . Name
form . DbPath = models . DbCfg . Path
2015-09-12 04:00:12 +03:00
ctx . Data [ "CurDbOption" ] = "MySQL"
switch models . DbCfg . Type {
case "postgres" :
ctx . Data [ "CurDbOption" ] = "PostgreSQL"
case "sqlite3" :
if models . EnableSQLite3 {
2015-09-12 22:31:36 +03:00
ctx . Data [ "CurDbOption" ] = "SQLite3"
}
case "tidb" :
if models . EnableTidb {
ctx . Data [ "CurDbOption" ] = "TiDB"
2015-09-12 04:00:12 +03:00
}
2015-07-09 08:17:48 +03:00
}
// Application general settings
form . AppName = setting . AppName
2015-02-01 20:41:03 +03:00
form . 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" {
2015-07-31 09:50:11 +03:00
form . RunUser = user . CurrentUsername ( )
2015-02-01 20:41:03 +03:00
} else {
form . RunUser = setting . RunUser
2014-04-10 22:37:43 +04:00
}
2014-03-30 01:50:51 +04:00
2015-02-01 20:41:03 +03:00
form . Domain = setting . Domain
2015-08-19 15:36:19 +03:00
form . SSHPort = setting . SSHPort
2015-02-01 20:41:03 +03:00
form . HTTPPort = setting . HttpPort
form . AppUrl = setting . AppUrl
2015-07-09 08:17:48 +03:00
// E-mail service settings
if setting . MailService != nil {
form . SMTPHost = setting . MailService . Host
2015-07-09 11:10:31 +03:00
form . SMTPFrom = setting . MailService . From
2015-07-09 08:17:48 +03:00
form . SMTPEmail = setting . MailService . User
2014-04-27 08:34:48 +04:00
}
2015-07-09 08:17:48 +03:00
form . RegisterConfirm = setting . Service . RegisterEmailConfirm
form . MailNotify = setting . Service . EnableNotifyMail
// Server and other services settings
form . OfflineMode = setting . OfflineMode
2015-08-29 19:22:26 +03:00
form . DisableGravatar = setting . DisableGravatar
2015-07-09 08:17:48 +03:00
form . DisableRegistration = setting . Service . DisableRegistration
2015-09-13 19:14:32 +03:00
form . EnableCaptcha = setting . Service . EnableCaptcha
2015-07-09 08:17:48 +03:00
form . RequireSignInView = setting . Service . RequireSignInView
2014-04-27 08:34:48 +04:00
2014-04-10 22:37:43 +04:00
auth . AssignForm ( form , ctx . Data )
2014-06-22 21:14:03 +04:00
ctx . HTML ( 200 , INSTALL )
2014-04-10 22:37:43 +04:00
}
2014-04-11 00:36:50 +04:00
func InstallPost ( ctx * middleware . Context , form auth . InstallForm ) {
2015-02-01 20:41:03 +03:00
ctx . Data [ "CurDbOption" ] = form . DbType
2014-04-27 08:34:48 +04:00
2014-03-30 01:50:51 +04:00
if ctx . HasError ( ) {
2015-07-08 14:47:56 +03:00
if ctx . HasValue ( "Err_SMTPEmail" ) {
ctx . Data [ "Err_SMTP" ] = true
}
if ctx . HasValue ( "Err_AdminName" ) ||
ctx . HasValue ( "Err_AdminPasswd" ) ||
ctx . HasValue ( "Err_AdminEmail" ) {
ctx . Data [ "Err_Admin" ] = true
}
2014-06-22 21:14:03 +04:00
ctx . HTML ( 200 , INSTALL )
2014-03-30 01:50:51 +04:00
return
}
2014-04-08 23:27:35 +04:00
if _ , err := exec . LookPath ( "git" ) ; err != nil {
2014-09-08 03:02:58 +04:00
ctx . RenderWithErr ( ctx . Tr ( "install.test_git_failed" , err ) , INSTALL , & form )
2014-04-08 23:27:35 +04:00
return
}
2014-03-30 01:50:51 +04:00
// Pass basic check, now test configuration.
// Test database setting.
2015-09-06 23:31:22 +03:00
dbTypes := map [ string ] string { "MySQL" : "mysql" , "PostgreSQL" : "postgres" , "SQLite3" : "sqlite3" , "TiDB" : "tidb" }
2015-02-01 20:41:03 +03:00
models . DbCfg . Type = dbTypes [ form . DbType ]
2014-09-08 03:02:58 +04:00
models . DbCfg . Host = form . DbHost
models . DbCfg . User = form . DbUser
2015-02-01 20:41:03 +03:00
models . DbCfg . Passwd = form . DbPasswd
models . DbCfg . Name = form . DbName
models . DbCfg . SSLMode = form . SSLMode
models . DbCfg . Path = form . DbPath
2014-03-30 01:50:51 +04:00
2015-09-12 22:31:36 +03:00
if ( models . DbCfg . Type == "sqlite3" || models . DbCfg . Type == "tidb" ) &&
len ( models . DbCfg . Path ) == 0 {
ctx . Data [ "Err_DbPath" ] = true
ctx . RenderWithErr ( ctx . Tr ( "install.err_empty_db_path" ) , INSTALL , & form )
return
} else if models . DbCfg . Type == "tidb" &&
strings . ContainsAny ( path . Base ( models . DbCfg . Path ) , ".-" ) {
2015-07-08 14:47:56 +03:00
ctx . Data [ "Err_DbPath" ] = true
2015-09-12 22:31:36 +03:00
ctx . RenderWithErr ( ctx . Tr ( "install.err_invalid_tidb_name" ) , INSTALL , & form )
2015-07-08 14:47:56 +03:00
return
}
2014-03-30 19:09:59 +04:00
// Set test engine.
2014-03-30 18:47:08 +04:00
var x * xorm . Engine
if err := models . NewTestEngine ( x ) ; err != nil {
2014-03-30 19:09:59 +04:00
if strings . Contains ( err . Error ( ) , ` Unknown database type: sqlite3 ` ) {
2015-07-08 14:47:56 +03:00
ctx . Data [ "Err_DbType" ] = true
2014-11-10 13:30:07 +03:00
ctx . RenderWithErr ( ctx . Tr ( "install.sqlite3_not_available" , "http://gogs.io/docs/installation/install_from_binary.html" ) , INSTALL , & form )
2014-03-30 17:39:44 +04:00
} else {
2015-07-08 14:47:56 +03:00
ctx . Data [ "Err_DbSetting" ] = true
2014-09-08 03:02:58 +04:00
ctx . RenderWithErr ( ctx . Tr ( "install.invalid_db_setting" , err ) , INSTALL , & form )
2014-03-30 17:39:44 +04:00
}
2014-03-30 01:50:51 +04:00
return
}
// Test repository root path.
if err := os . MkdirAll ( form . RepoRootPath , os . ModePerm ) ; err != nil {
2014-09-15 03:22:52 +04:00
ctx . Data [ "Err_RepoRootPath" ] = true
2014-09-08 03:02:58 +04:00
ctx . RenderWithErr ( ctx . Tr ( "install.invalid_repo_path" , err ) , INSTALL , & form )
2014-03-30 01:50:51 +04:00
return
}
2014-03-30 19:58:21 +04:00
// Check run user.
2015-07-31 09:50:11 +03:00
curUser := user . CurrentUsername ( )
2014-03-30 19:58:21 +04:00
if form . RunUser != curUser {
2014-09-15 03:22:52 +04:00
ctx . Data [ "Err_RunUser" ] = true
2014-09-08 03:02:58 +04:00
ctx . RenderWithErr ( ctx . Tr ( "install.run_user_not_match" , form . RunUser , curUser ) , INSTALL , & form )
return
}
2015-09-12 22:31:36 +03:00
// Check logic loophole between disable self-registration and no admin account.
if form . DisableRegistration && len ( form . AdminName ) == 0 {
ctx . Data [ "Err_Services" ] = true
ctx . Data [ "Err_Admin" ] = true
ctx . RenderWithErr ( ctx . Tr ( "install.no_admin_and_disable_registration" ) , INSTALL , form )
return
}
2014-09-08 03:02:58 +04:00
// Check admin password.
2015-09-12 22:31:36 +03:00
if len ( form . AdminName ) > 0 && len ( form . AdminPasswd ) == 0 {
ctx . Data [ "Err_Admin" ] = true
ctx . Data [ "Err_AdminPasswd" ] = true
ctx . RenderWithErr ( ctx . Tr ( "install.err_empty_admin_password" ) , INSTALL , form )
return
}
2015-02-01 20:41:03 +03:00
if form . AdminPasswd != form . AdminConfirmPasswd {
2015-08-02 07:36:35 +03:00
ctx . Data [ "Err_Admin" ] = true
2014-09-15 03:22:52 +04:00
ctx . Data [ "Err_AdminPasswd" ] = true
2014-09-08 03:02:58 +04:00
ctx . RenderWithErr ( ctx . Tr ( "form.password_not_match" ) , INSTALL , form )
2014-03-30 19:58:21 +04:00
return
}
2015-02-01 20:41:03 +03:00
if form . AppUrl [ len ( form . AppUrl ) - 1 ] != '/' {
form . AppUrl += "/"
}
2014-03-30 01:50:51 +04:00
// Save settings.
2015-02-01 22:39:58 +03:00
cfg := ini . Empty ( )
2015-02-14 00:48:23 +03:00
if com . IsFile ( setting . CustomConf ) {
// Keeps custom settings if there is already something.
if err := cfg . Append ( setting . CustomConf ) ; err != nil {
log . Error ( 4 , "Fail to load custom conf '%s': %v" , setting . CustomConf , err )
}
}
2015-02-01 22:39:58 +03:00
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 )
2015-07-09 08:17:48 +03:00
cfg . Section ( "" ) . Key ( "APP_NAME" ) . SetValue ( form . AppName )
2015-02-01 22:39:58 +03:00
cfg . Section ( "repository" ) . Key ( "ROOT" ) . SetValue ( form . RepoRootPath )
cfg . Section ( "" ) . Key ( "RUN_USER" ) . SetValue ( form . RunUser )
cfg . Section ( "server" ) . Key ( "DOMAIN" ) . SetValue ( form . Domain )
cfg . Section ( "server" ) . Key ( "HTTP_PORT" ) . SetValue ( form . HTTPPort )
cfg . Section ( "server" ) . Key ( "ROOT_URL" ) . SetValue ( form . AppUrl )
2014-03-30 01:50:51 +04:00
2015-08-19 15:36:19 +03:00
if form . 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 ( form . SSHPort ) )
}
2015-02-01 20:41:03 +03:00
if len ( strings . TrimSpace ( form . SMTPHost ) ) > 0 {
2015-02-01 22:39:58 +03:00
cfg . Section ( "mailer" ) . Key ( "ENABLED" ) . SetValue ( "true" )
cfg . Section ( "mailer" ) . Key ( "HOST" ) . SetValue ( form . SMTPHost )
2015-07-09 11:10:31 +03:00
cfg . Section ( "mailer" ) . Key ( "FROM" ) . SetValue ( form . SMTPFrom )
2015-02-01 22:39:58 +03:00
cfg . Section ( "mailer" ) . Key ( "USER" ) . SetValue ( form . SMTPEmail )
cfg . Section ( "mailer" ) . Key ( "PASSWD" ) . SetValue ( form . SMTPPasswd )
2015-07-09 08:17:48 +03:00
} else {
cfg . Section ( "mailer" ) . Key ( "ENABLED" ) . SetValue ( "false" )
2014-03-30 01:50:51 +04:00
}
2015-07-09 08:17:48 +03:00
cfg . Section ( "service" ) . Key ( "REGISTER_EMAIL_CONFIRM" ) . SetValue ( com . ToStr ( form . RegisterConfirm ) )
cfg . Section ( "service" ) . Key ( "ENABLE_NOTIFY_MAIL" ) . SetValue ( com . ToStr ( form . MailNotify ) )
cfg . Section ( "server" ) . Key ( "OFFLINE_MODE" ) . SetValue ( com . ToStr ( form . OfflineMode ) )
2015-08-29 19:22:26 +03:00
cfg . Section ( "picture" ) . Key ( "DISABLE_GRAVATAR" ) . SetValue ( com . ToStr ( form . DisableGravatar ) )
2015-07-09 08:17:48 +03:00
cfg . Section ( "service" ) . Key ( "DISABLE_REGISTRATION" ) . SetValue ( com . ToStr ( form . DisableRegistration ) )
2015-09-13 19:14:32 +03:00
cfg . Section ( "service" ) . Key ( "ENABLE_CAPTCHA" ) . SetValue ( com . ToStr ( form . EnableCaptcha ) )
2015-07-09 08:17:48 +03:00
cfg . Section ( "service" ) . Key ( "REQUIRE_SIGNIN_VIEW" ) . SetValue ( com . ToStr ( form . RequireSignInView ) )
2014-03-30 01:50:51 +04:00
2015-02-01 22:39:58 +03:00
cfg . Section ( "" ) . Key ( "RUN_MODE" ) . SetValue ( "prod" )
2014-03-30 19:58:21 +04:00
2015-02-01 22:39:58 +03:00
cfg . Section ( "session" ) . Key ( "PROVIDER" ) . SetValue ( "file" )
2014-12-21 06:51:16 +03:00
2015-02-01 22:39:58 +03:00
cfg . Section ( "log" ) . Key ( "MODE" ) . SetValue ( "file" )
2015-02-27 03:45:38 +03:00
cfg . Section ( "log" ) . Key ( "LEVEL" ) . SetValue ( "Info" )
2014-08-27 12:39:36 +04:00
2015-02-01 22:39:58 +03:00
cfg . Section ( "security" ) . Key ( "INSTALL_LOCK" ) . SetValue ( "true" )
cfg . Section ( "security" ) . Key ( "SECRET_KEY" ) . SetValue ( base . GetRandomString ( 15 ) )
2014-03-30 01:50:51 +04:00
2015-02-05 13:12:37 +03:00
os . MkdirAll ( filepath . Dir ( setting . CustomConf ) , os . ModePerm )
if err := cfg . SaveTo ( setting . CustomConf ) ; err != nil {
2014-09-08 03:02:58 +04:00
ctx . RenderWithErr ( ctx . Tr ( "install.save_config_failed" , err ) , INSTALL , & form )
2014-03-30 01:50:51 +04:00
return
}
GlobalInit ( )
2014-03-30 19:09:59 +04:00
// Create admin account.
2015-07-08 14:47:56 +03:00
if len ( form . AdminName ) > 0 {
if err := models . CreateUser ( & models . User {
Name : form . AdminName ,
Email : form . AdminEmail ,
Passwd : form . AdminPasswd ,
IsAdmin : true ,
IsActive : true ,
} ) ; err != nil {
if ! models . IsErrUserAlreadyExist ( err ) {
setting . InstallLock = false
ctx . Data [ "Err_AdminName" ] = true
ctx . Data [ "Err_AdminEmail" ] = true
ctx . RenderWithErr ( ctx . Tr ( "install.invalid_admin_setting" , err ) , INSTALL , & form )
return
}
log . Info ( "Admin account already exist" )
2014-03-30 19:09:59 +04:00
}
}
2014-03-30 01:50:51 +04:00
log . Info ( "First-time run install finished!" )
2014-09-08 03:02:58 +04:00
ctx . Flash . Success ( ctx . Tr ( "install.install_success" ) )
2015-02-01 20:41:03 +03:00
ctx . Redirect ( form . AppUrl + "user/login" )
2014-03-25 12:51:42 +04:00
}