diff options
Diffstat (limited to 'internal/conf')
-rw-r--r-- | internal/conf/conf.go | 502 | ||||
-rw-r--r-- | internal/conf/log.go | 131 | ||||
-rw-r--r-- | internal/conf/static.go | 206 |
3 files changed, 435 insertions, 404 deletions
diff --git a/internal/conf/conf.go b/internal/conf/conf.go index 46133ab8..b708eb83 100644 --- a/internal/conf/conf.go +++ b/internal/conf/conf.go @@ -9,7 +9,6 @@ import ( "net/mail" "net/url" "os" - "path" "path/filepath" "strconv" "strings" @@ -18,13 +17,12 @@ import ( _ "github.com/go-macaron/cache/memcache" _ "github.com/go-macaron/cache/redis" _ "github.com/go-macaron/session/redis" + "github.com/gogs/go-libravatar" "github.com/mcuadros/go-version" "github.com/pkg/errors" "gopkg.in/ini.v1" log "unknwon.dev/clog/v2" - "github.com/gogs/go-libravatar" - "gogs.io/gogs/internal/assets/conf" "gogs.io/gogs/internal/osutil" ) @@ -184,18 +182,18 @@ func Init(customConf string) error { Repository.Root = ensureAbs(Repository.Root) Repository.Upload.TempPath = ensureAbs(Repository.Upload.TempPath) - // ******************************* + // ***************************** // ----- Database settings ----- - // ******************************* + // ***************************** if err = File.Section("database").MapTo(&Database); err != nil { return errors.Wrap(err, "mapping [database] section") } Database.Path = ensureAbs(Database.Path) - // ******************************* + // ***************************** // ----- Security settings ----- - // ******************************* + // ***************************** if err = File.Section("security").MapTo(&Security); err != nil { return errors.Wrap(err, "mapping [security] section") @@ -245,37 +243,40 @@ func Init(customConf string) error { return errors.Wrap(err, "mapping [service] section") } - // *********************************** + // ************************* // ----- User settings ----- - // *********************************** + // ************************* if err = File.Section("user").MapTo(&User); err != nil { return errors.Wrap(err, "mapping [user] section") } - // *********************************** + // **************************** // ----- Session settings ----- - // *********************************** + // **************************** if err = File.Section("session").MapTo(&Session); err != nil { return errors.Wrap(err, "mapping [session] section") } - handleDeprecated() + // ******************************* + // ----- Attachment settings ----- + // ******************************* + + if err = File.Section("attachment").MapTo(&Attachment); err != nil { + return errors.Wrap(err, "mapping [attachment] section") + } + Attachment.Path = ensureAbs(Attachment.Path) - // TODO + // ************************* + // ----- Time settings ----- + // ************************* - sec := File.Section("attachment") - AttachmentPath = sec.Key("PATH").MustString(filepath.Join(Server.AppDataPath, "attachments")) - if !filepath.IsAbs(AttachmentPath) { - AttachmentPath = path.Join(workDir, AttachmentPath) + if err = File.Section("time").MapTo(&Time); err != nil { + return errors.Wrap(err, "mapping [time] section") } - AttachmentAllowedTypes = strings.Replace(sec.Key("ALLOWED_TYPES").MustString("image/jpeg,image/png"), "|", ",", -1) - AttachmentMaxSize = sec.Key("MAX_SIZE").MustInt64(4) - AttachmentMaxFiles = sec.Key("MAX_FILES").MustInt(5) - AttachmentEnabled = sec.Key("ENABLED").MustBool(true) - TimeFormat = map[string]string{ + Time.FormatLayout = map[string]string{ "ANSIC": time.ANSIC, "UnixDate": time.UnixDate, "RubyDate": time.RubyDate, @@ -291,89 +292,104 @@ func Init(customConf string) error { "StampMilli": time.StampMilli, "StampMicro": time.StampMicro, "StampNano": time.StampNano, - }[File.Section("time").Key("FORMAT").MustString("RFC1123")] - - sec = File.Section("picture") - AvatarUploadPath = sec.Key("AVATAR_UPLOAD_PATH").MustString(filepath.Join(Server.AppDataPath, "avatars")) - if !filepath.IsAbs(AvatarUploadPath) { - AvatarUploadPath = path.Join(workDir, AvatarUploadPath) + }[Time.Format] + if Time.FormatLayout == "" { + return fmt.Errorf("unrecognized '[time] FORMAT': %s", Time.Format) } - RepositoryAvatarUploadPath = sec.Key("REPOSITORY_AVATAR_UPLOAD_PATH").MustString(filepath.Join(Server.AppDataPath, "repo-avatars")) - if !filepath.IsAbs(RepositoryAvatarUploadPath) { - RepositoryAvatarUploadPath = path.Join(workDir, RepositoryAvatarUploadPath) + + // **************************** + // ----- Picture settings ----- + // **************************** + + if err = File.Section("picture").MapTo(&Picture); err != nil { + return errors.Wrap(err, "mapping [picture] section") } - switch source := sec.Key("GRAVATAR_SOURCE").MustString("gravatar"); source { - case "duoshuo": - GravatarSource = "http://gravatar.duoshuo.com/avatar/" + Picture.AvatarUploadPath = ensureAbs(Picture.AvatarUploadPath) + Picture.RepositoryAvatarUploadPath = ensureAbs(Picture.RepositoryAvatarUploadPath) + + switch Picture.GravatarSource { case "gravatar": - GravatarSource = "https://secure.gravatar.com/avatar/" + Picture.GravatarSource = "https://secure.gravatar.com/avatar/" case "libravatar": - GravatarSource = "https://seccdn.libravatar.org/avatar/" - default: - GravatarSource = source + Picture.GravatarSource = "https://seccdn.libravatar.org/avatar/" } - DisableGravatar = sec.Key("DISABLE_GRAVATAR").MustBool() - EnableFederatedAvatar = sec.Key("ENABLE_FEDERATED_AVATAR").MustBool(true) + if Server.OfflineMode { - DisableGravatar = true - EnableFederatedAvatar = false + Picture.DisableGravatar = true + Picture.EnableFederatedAvatar = false } - if DisableGravatar { - EnableFederatedAvatar = false + if Picture.DisableGravatar { + Picture.EnableFederatedAvatar = false } + if Picture.EnableFederatedAvatar { + gravatarURL, err := url.Parse(Picture.GravatarSource) + if err != nil { + return errors.Wrapf(err, "parse Gravatar source %q", Picture.GravatarSource) + } - if EnableFederatedAvatar { - LibravatarService = libravatar.New() - parts := strings.Split(GravatarSource, "/") - if len(parts) >= 3 { - if parts[0] == "https:" { - LibravatarService.SetUseHTTPS(true) - LibravatarService.SetSecureFallbackHost(parts[2]) - } else { - LibravatarService.SetUseHTTPS(false) - LibravatarService.SetFallbackHost(parts[2]) - } + Picture.LibravatarService = libravatar.New() + if gravatarURL.Scheme == "https" { + Picture.LibravatarService.SetUseHTTPS(true) + Picture.LibravatarService.SetSecureFallbackHost(gravatarURL.Host) + } else { + Picture.LibravatarService.SetUseHTTPS(false) + Picture.LibravatarService.SetFallbackHost(gravatarURL.Host) } } - if err = File.Section("http").MapTo(&HTTP); err != nil { - log.Fatal("Failed to map HTTP settings: %v", err) + // *************************** + // ----- Mirror settings ----- + // *************************** + + if err = File.Section("mirror").MapTo(&Mirror); err != nil { + return errors.Wrap(err, "mapping [mirror] section") + } + + if Mirror.DefaultInterval <= 0 { + Mirror.DefaultInterval = 8 + } + + // ************************* + // ----- I18n settings ----- + // ************************* + + I18n = new(i18n) + if err = File.Section("i18n").MapTo(I18n); err != nil { + return errors.Wrap(err, "mapping [i18n] section") + } + I18n.dateLangs = File.Section("i18n.datelang").KeysHash() + + handleDeprecated() + + if err = File.Section("cache").MapTo(&Cache); err != nil { + return errors.Wrap(err, "mapping [cache] section") + } else if err = File.Section("http").MapTo(&HTTP); err != nil { + return errors.Wrap(err, "mapping [http] section") + } else if err = File.Section("release").MapTo(&Release); err != nil { + return errors.Wrap(err, "mapping [release] section") } else if err = File.Section("webhook").MapTo(&Webhook); err != nil { - log.Fatal("Failed to map Webhook settings: %v", err) - } else if err = File.Section("release.attachment").MapTo(&Release.Attachment); err != nil { - log.Fatal("Failed to map Release.Attachment settings: %v", err) + return errors.Wrap(err, "mapping [webhook] section") } else if err = File.Section("markdown").MapTo(&Markdown); err != nil { - log.Fatal("Failed to map Markdown settings: %v", err) + return errors.Wrap(err, "mapping [markdown] section") } else if err = File.Section("smartypants").MapTo(&Smartypants); err != nil { - log.Fatal("Failed to map Smartypants settings: %v", err) + return errors.Wrap(err, "mapping [smartypants] section") } else if err = File.Section("admin").MapTo(&Admin); err != nil { - log.Fatal("Failed to map Admin settings: %v", err) + return errors.Wrap(err, "mapping [admin] section") } else if err = File.Section("cron").MapTo(&Cron); err != nil { - log.Fatal("Failed to map Cron settings: %v", err) + return errors.Wrap(err, "mapping [cron] section") } else if err = File.Section("git").MapTo(&Git); err != nil { - log.Fatal("Failed to map Git settings: %v", err) - } else if err = File.Section("mirror").MapTo(&Mirror); err != nil { - log.Fatal("Failed to map Mirror settings: %v", err) + return errors.Wrap(err, "mapping [git] section") } else if err = File.Section("api").MapTo(&API); err != nil { - log.Fatal("Failed to map API settings: %v", err) + return errors.Wrap(err, "mapping [api] section") } else if err = File.Section("ui").MapTo(&UI); err != nil { - log.Fatal("Failed to map UI settings: %v", err) + return errors.Wrap(err, "mapping [ui] section") } else if err = File.Section("prometheus").MapTo(&Prometheus); err != nil { - log.Fatal("Failed to map Prometheus settings: %v", err) + return errors.Wrap(err, "mapping [prometheus] section") + } else if err = File.Section("other").MapTo(&Other); err != nil { + return errors.Wrap(err, "mapping [other] section") } - if Mirror.DefaultInterval <= 0 { - Mirror.DefaultInterval = 24 - } - - Langs = File.Section("i18n").Key("LANGS").Strings(",") - Names = File.Section("i18n").Key("NAMES").Strings(",") - dateLangs = File.Section("i18n.datelang").KeysHash() - - ShowFooterBranding = File.Section("other").Key("SHOW_FOOTER_BRANDING").MustBool() - ShowFooterTemplateLoadTime = File.Section("other").Key("SHOW_FOOTER_TEMPLATE_LOAD_TIME").MustBool() - - HasRobotsTxt = osutil.IsFile(path.Join(CustomDir(), "robots.txt")) + HasRobotsTxt = osutil.IsFile(filepath.Join(CustomDir(), "robots.txt")) return nil } @@ -384,325 +400,3 @@ func MustInit(customConf string) { panic(err) } } - -// TODO - -var ( - HTTP struct { - AccessControlAllowOrigin string - } - - // Database settings - UseSQLite3 bool - UseMySQL bool - UsePostgreSQL bool - UseMSSQL bool - - // Webhook settings - Webhook struct { - Types []string - QueueLength int - DeliverTimeout int - SkipTLSVerify bool `ini:"SKIP_TLS_VERIFY"` - PagingNum int - } - - // Release settigns - Release struct { - Attachment struct { - Enabled bool - TempPath string - AllowedTypes []string `delim:"|"` - MaxSize int64 - MaxFiles int - } `ini:"-"` - } - - // Markdown sttings - Markdown struct { - EnableHardLineBreak bool - CustomURLSchemes []string `ini:"CUSTOM_URL_SCHEMES"` - FileExtensions []string - } - - // Smartypants settings - Smartypants struct { - Enabled bool - Fractions bool - Dashes bool - LatexDashes bool - AngledQuotes bool - } - - // Admin settings - Admin struct { - DisableRegularOrgCreation bool - } - - // Picture settings - AvatarUploadPath string - RepositoryAvatarUploadPath string - GravatarSource string - DisableGravatar bool - EnableFederatedAvatar bool - LibravatarService *libravatar.Libravatar - - // Log settings - LogRootPath string - LogModes []string - LogConfigs []interface{} - - // Attachment settings - AttachmentPath string - AttachmentAllowedTypes string - AttachmentMaxSize int64 - AttachmentMaxFiles int - AttachmentEnabled bool - - // Time settings - TimeFormat string - - // Cache settings - CacheAdapter string - CacheInterval int - CacheConn string - - // Cron tasks - Cron struct { - UpdateMirror struct { - Enabled bool - RunAtStart bool - Schedule string - } `ini:"cron.update_mirrors"` - RepoHealthCheck struct { - Enabled bool - RunAtStart bool - Schedule string - Timeout time.Duration - Args []string `delim:" "` - } `ini:"cron.repo_health_check"` - CheckRepoStats struct { - Enabled bool - RunAtStart bool - Schedule string - } `ini:"cron.check_repo_stats"` - RepoArchiveCleanup struct { - Enabled bool - RunAtStart bool - Schedule string - OlderThan time.Duration - } `ini:"cron.repo_archive_cleanup"` - } - - // Git settings - Git struct { - Version string `ini:"-"` - DisableDiffHighlight bool - MaxGitDiffLines int - MaxGitDiffLineCharacters int - MaxGitDiffFiles int - GCArgs []string `ini:"GC_ARGS" delim:" "` - Timeout struct { - Migrate int - Mirror int - Clone int - Pull int - GC int `ini:"GC"` - } `ini:"git.timeout"` - } - - // Mirror settings - Mirror struct { - DefaultInterval int - } - - // API settings - API struct { - MaxResponseItems int - } - - // UI settings - UI struct { - ExplorePagingNum int - IssuePagingNum int - FeedMaxCommitNum int - ThemeColorMetaTag string - MaxDisplayFileSize int64 - - Admin struct { - UserPagingNum int - RepoPagingNum int - NoticePagingNum int - OrgPagingNum int - } `ini:"ui.admin"` - User struct { - RepoPagingNum int - NewsFeedPagingNum int - CommitsPagingNum int - } `ini:"ui.user"` - } - - // Prometheus settings - Prometheus struct { - Enabled bool - EnableBasicAuth bool - BasicAuthUsername string - BasicAuthPassword string - } - - // I18n settings - Langs []string - Names []string - dateLangs map[string]string - - // Highlight settings are loaded in modules/template/hightlight.go - - // Other settings - ShowFooterBranding bool - ShowFooterTemplateLoadTime bool - - // Global setting objects - HasRobotsTxt bool -) - -// DateLang transforms standard language locale name to corresponding value in datetime plugin. -func DateLang(lang string) string { - name, ok := dateLangs[lang] - if ok { - return name - } - return "en" -} - -// InitLogging initializes the logging service of the application. -func InitLogging() { - LogRootPath = File.Section("log").Key("ROOT_PATH").MustString(filepath.Join(WorkDir(), "log")) - - // Because we always create a console logger as the primary logger at init time, - // we need to remove it in case the user doesn't configure to use it after the - // logging service is initalized. - hasConsole := false - - // Iterate over [log.*] sections to initialize individual logger. - LogModes = strings.Split(File.Section("log").Key("MODE").MustString("console"), ",") - LogConfigs = make([]interface{}, len(LogModes)) - levelMappings := map[string]log.Level{ - "trace": log.LevelTrace, - "info": log.LevelInfo, - "warn": log.LevelWarn, - "error": log.LevelError, - "fatal": log.LevelFatal, - } - - type config struct { - Buffer int64 - Config interface{} - } - for i, mode := range LogModes { - mode = strings.ToLower(strings.TrimSpace(mode)) - secName := "log." + mode - sec, err := File.GetSection(secName) - if err != nil { - log.Fatal("Missing configuration section [%s] for %q logger", secName, mode) - return - } - - level := levelMappings[strings.ToLower(sec.Key("LEVEL").MustString("trace"))] - buffer := sec.Key("BUFFER_LEN").MustInt64(100) - c := new(config) - switch mode { - case log.DefaultConsoleName: - hasConsole = true - c = &config{ - Buffer: buffer, - Config: log.ConsoleConfig{ - Level: level, - }, - } - err = log.NewConsole(c.Buffer, c.Config) - - case log.DefaultFileName: - logPath := filepath.Join(LogRootPath, "gogs.log") - logDir := filepath.Dir(logPath) - err = os.MkdirAll(logDir, os.ModePerm) - if err != nil { - log.Fatal("Failed to create log directory %q: %v", logDir, err) - return - } - - c = &config{ - Buffer: buffer, - Config: log.FileConfig{ - Level: level, - Filename: logPath, - FileRotationConfig: log.FileRotationConfig{ - Rotate: sec.Key("LOG_ROTATE").MustBool(true), - Daily: sec.Key("DAILY_ROTATE").MustBool(true), - MaxSize: 1 << uint(sec.Key("MAX_SIZE_SHIFT").MustInt(28)), - MaxLines: sec.Key("MAX_LINES").MustInt64(1000000), - MaxDays: sec.Key("MAX_DAYS").MustInt64(7), - }, - }, - } - err = log.NewFile(c.Buffer, c.Config) - - case log.DefaultSlackName: - c = &config{ - Buffer: buffer, - Config: log.SlackConfig{ - Level: level, - URL: sec.Key("URL").String(), - }, - } - err = log.NewSlack(c.Buffer, c.Config) - - case log.DefaultDiscordName: - c = &config{ - Buffer: buffer, - Config: log.DiscordConfig{ - Level: level, - URL: sec.Key("URL").String(), - Username: sec.Key("USERNAME").String(), - }, - } - - default: - continue - } - - if err != nil { - log.Fatal("Failed to init %s logger: %v", mode, err) - return - } - LogConfigs[i] = c - - log.Trace("Log mode: %s (%s)", strings.Title(mode), strings.Title(strings.ToLower(level.String()))) - } - - if !hasConsole { - log.Remove(log.DefaultConsoleName) - } -} - -func newCacheService() { - CacheAdapter = File.Section("cache").Key("ADAPTER").In("memory", []string{"memory", "redis", "memcache"}) - switch CacheAdapter { - case "memory": - CacheInterval = File.Section("cache").Key("INTERVAL").MustInt(60) - case "redis", "memcache": - CacheConn = strings.Trim(File.Section("cache").Key("HOST").String(), "\" ") - default: - log.Fatal("Unrecognized cache adapter %q", CacheAdapter) - return - } - - log.Trace("Cache service is enabled") -} - -func NewServices() { - newCacheService() -} - -// HookMode indicates whether program starts as Git server-side hook callback. -// All operations should be done synchronously to prevent program exits before finishing. -var HookMode bool diff --git a/internal/conf/log.go b/internal/conf/log.go new file mode 100644 index 00000000..fdb1d64e --- /dev/null +++ b/internal/conf/log.go @@ -0,0 +1,131 @@ +// Copyright 2020 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 conf + +import ( + "os" + "path/filepath" + "strings" + + log "unknwon.dev/clog/v2" +) + +// Log settings +var Log struct { + RootPath string + Modes []string + Configs []interface{} +} + +// InitLogging initializes the logging service of the application. +func InitLogging() { + Log.RootPath = File.Section("log").Key("ROOT_PATH").MustString(filepath.Join(WorkDir(), "log")) + + // Because we always create a console logger as the primary logger at init time, + // we need to remove it in case the user doesn't configure to use it after the + // logging service is initalized. + hasConsole := false + + // Iterate over [log.*] sections to initialize individual logger. + Log.Modes = strings.Split(File.Section("log").Key("MODE").MustString("console"), ",") + Log.Configs = make([]interface{}, 0, len(Log.Modes)) + levelMappings := map[string]log.Level{ + "trace": log.LevelTrace, + "info": log.LevelInfo, + "warn": log.LevelWarn, + "error": log.LevelError, + "fatal": log.LevelFatal, + } + + type config struct { + Buffer int64 + Config interface{} + } + for _, mode := range Log.Modes { + mode = strings.ToLower(strings.TrimSpace(mode)) + secName := "log." + mode + sec, err := File.GetSection(secName) + if err != nil { + log.Fatal("Missing configuration section [%s] for %q logger", secName, mode) + return + } + + level := levelMappings[strings.ToLower(sec.Key("LEVEL").MustString("trace"))] + buffer := sec.Key("BUFFER_LEN").MustInt64(100) + var c *config + switch mode { + case log.DefaultConsoleName: + hasConsole = true + c = &config{ + Buffer: buffer, + Config: log.ConsoleConfig{ + Level: level, + }, + } + err = log.NewConsole(c.Buffer, c.Config) + + case log.DefaultFileName: + logPath := filepath.Join(Log.RootPath, "gogs.log") + logDir := filepath.Dir(logPath) + err = os.MkdirAll(logDir, os.ModePerm) + if err != nil { + log.Fatal("Failed to create log directory %q: %v", logDir, err) + return + } + + c = &config{ + Buffer: buffer, + Config: log.FileConfig{ + Level: level, + Filename: logPath, + FileRotationConfig: log.FileRotationConfig{ + Rotate: sec.Key("LOG_ROTATE").MustBool(true), + Daily: sec.Key("DAILY_ROTATE").MustBool(true), + MaxSize: 1 << uint(sec.Key("MAX_SIZE_SHIFT").MustInt(28)), + MaxLines: sec.Key("MAX_LINES").MustInt64(1000000), + MaxDays: sec.Key("MAX_DAYS").MustInt64(7), + }, + }, + } + err = log.NewFile(c.Buffer, c.Config) + + case log.DefaultSlackName: + c = &config{ + Buffer: buffer, + Config: log.SlackConfig{ + Level: level, + URL: sec.Key("URL").String(), + }, + } + err = log.NewSlack(c.Buffer, c.Config) + + case log.DefaultDiscordName: + c = &config{ + Buffer: buffer, + Config: log.DiscordConfig{ + Level: level, + URL: sec.Key("URL").String(), + Username: sec.Key("USERNAME").String(), + }, + } + err = log.NewDiscord(c.Buffer, c.Config) + + default: + continue + } + + if err != nil { + log.Fatal("Failed to init %s logger: %v", mode, err) + return + } + + Log.Configs = append(Log.Configs, c) + log.Trace("Log mode: %s (%s)", strings.Title(mode), strings.Title(strings.ToLower(level.String()))) + } + + if !hasConsole { + log.Remove(log.DefaultConsoleName) + } +} diff --git a/internal/conf/static.go b/internal/conf/static.go index 641feec0..cb58ac17 100644 --- a/internal/conf/static.go +++ b/internal/conf/static.go @@ -7,6 +7,9 @@ package conf import ( "net/url" "os" + "time" + + "github.com/gogs/go-libravatar" ) // ℹ️ README: This file contains static values that should only be set at initialization time. @@ -227,8 +230,199 @@ var ( // Deprecated: Use MaxLifeTime instead, will be removed in 0.13. SessionLifeTime int64 } + + // Cache settings + Cache struct { + Adapter string + Interval int + Host string + } + + // HTTP settings + HTTP struct { + AccessControlAllowOrigin string + } + + // Attachment settings + Attachment struct { + Enabled bool + Path string + AllowedTypes []string `delim:"|"` + MaxSize int64 + MaxFiles int + } + + // Release settigns + Release struct { + Attachment struct { + Enabled bool + AllowedTypes []string `delim:"|"` + MaxSize int64 + MaxFiles int + } `ini:"release.attachment"` + } + + // Time settings + Time struct { + Format string + + // Derived from other static values + FormatLayout string `ini:"-"` // Actual layout of the Format. + } + + // Picture settings + Picture struct { + AvatarUploadPath string + RepositoryAvatarUploadPath string + GravatarSource string + DisableGravatar bool + EnableFederatedAvatar bool + + // Derived from other static values + LibravatarService *libravatar.Libravatar `ini:"-"` // Initialized client for federated avatar. + } + + // Mirror settings + Mirror struct { + DefaultInterval int + } + + // I18n settings + I18n *i18n + + // Webhook settings + Webhook struct { + Types []string + QueueLength int + DeliverTimeout int + SkipTLSVerify bool `ini:"SKIP_TLS_VERIFY"` + PagingNum int + } + + // Markdown sttings + Markdown struct { + EnableHardLineBreak bool + CustomURLSchemes []string `ini:"CUSTOM_URL_SCHEMES"` + FileExtensions []string + } + + // Smartypants settings + Smartypants struct { + Enabled bool + Fractions bool + Dashes bool + LatexDashes bool + AngledQuotes bool + } + + // Admin settings + Admin struct { + DisableRegularOrgCreation bool + } + + // Cron tasks + Cron struct { + UpdateMirror struct { + Enabled bool + RunAtStart bool + Schedule string + } `ini:"cron.update_mirrors"` + RepoHealthCheck struct { + Enabled bool + RunAtStart bool + Schedule string + Timeout time.Duration + Args []string `delim:" "` + } `ini:"cron.repo_health_check"` + CheckRepoStats struct { + Enabled bool + RunAtStart bool + Schedule string + } `ini:"cron.check_repo_stats"` + RepoArchiveCleanup struct { + Enabled bool + RunAtStart bool + Schedule string + OlderThan time.Duration + } `ini:"cron.repo_archive_cleanup"` + } + + // Git settings + Git struct { + Version string `ini:"-"` + DisableDiffHighlight bool + MaxGitDiffLines int + MaxGitDiffLineCharacters int + MaxGitDiffFiles int + GCArgs []string `ini:"GC_ARGS" delim:" "` + Timeout struct { + Migrate int + Mirror int + Clone int + Pull int + GC int `ini:"GC"` + } `ini:"git.timeout"` + } + + // API settings + API struct { + MaxResponseItems int + } + + // UI settings + UI struct { + ExplorePagingNum int + IssuePagingNum int + FeedMaxCommitNum int + ThemeColorMetaTag string + MaxDisplayFileSize int64 + + Admin struct { + UserPagingNum int + RepoPagingNum int + NoticePagingNum int + OrgPagingNum int + } `ini:"ui.admin"` + User struct { + RepoPagingNum int + NewsFeedPagingNum int + CommitsPagingNum int + } `ini:"ui.user"` + } + + // Prometheus settings + Prometheus struct { + Enabled bool + EnableBasicAuth bool + BasicAuthUsername string + BasicAuthPassword string + } + + // Other settings + Other struct { + ShowFooterBranding bool + ShowFooterTemplateLoadTime bool + } + + // Global setting + HasRobotsTxt bool ) +type i18n struct { + Langs []string `delim:","` + Names []string `delim:","` + dateLangs map[string]string +} + +// DateLang transforms standard language locale name to corresponding value in datetime plugin. +func (i *i18n) DateLang(lang string) string { + name, ok := i.dateLangs[lang] + if ok { + return name + } + return "en" +} + // handleDeprecated transfers deprecated values to the new ones when set. func handleDeprecated() { if App.AppName != "" { @@ -294,3 +488,15 @@ func handleDeprecated() { Session.SessionLifeTime = 0 } } + +// HookMode indicates whether program starts as Git server-side hook callback. +// All operations should be done synchronously to prevent program exits before finishing. +var HookMode bool + +// Indicates which database backend is currently being used. +var ( + UseSQLite3 bool + UseMySQL bool + UsePostgreSQL bool + UseMSSQL bool +) |