From fd9a6cdf8d0d48d4ffdb0afa5bd5f71ca197a84b Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 12 Jan 2023 00:27:11 +0800 Subject: [PATCH 01/20] Refactor the setting to make unit test easier --- cmd/cmd.go | 4 +- cmd/doctor.go | 4 +- cmd/dump.go | 2 +- models/migrations/base/tests.go | 4 +- modules/doctor/doctor.go | 5 +- modules/setting/admin.go | 16 + modules/setting/api.go | 40 + modules/setting/attachment.go | 4 +- modules/setting/cache.go | 4 +- modules/setting/camo.go | 22 + modules/setting/config.go | 19 + modules/setting/cors.go | 13 - modules/setting/database.go | 2 +- modules/setting/federation.go | 4 +- modules/setting/git.go | 5 +- modules/setting/i18n.go | 17 + modules/setting/indexer.go | 4 +- modules/setting/lfs.go | 6 +- modules/setting/log.go | 38 +- modules/setting/mailer.go | 18 +- modules/setting/markup.go | 22 +- modules/setting/metrics.go | 21 + modules/setting/migrations.go | 4 +- modules/setting/mime_type_map.go | 4 +- modules/setting/mirror.go | 6 +- .../setting/{oauth2_client.go => oauth2.go} | 37 +- modules/setting/other.go | 21 + modules/setting/packages.go | 4 +- modules/setting/picture.go | 14 +- modules/setting/project.go | 8 - modules/setting/proxy.go | 4 +- modules/setting/queue.go | 4 +- modules/setting/repository.go | 16 +- modules/setting/security.go | 147 +++ modules/setting/server.go | 318 +++++ modules/setting/service.go | 22 +- modules/setting/session.go | 4 +- modules/setting/setting.go | 1034 +---------------- modules/setting/ssh.go | 193 +++ modules/setting/task.go | 6 +- modules/setting/time.go | 64 + modules/setting/ui.go | 161 +++ modules/setting/webhook.go | 4 +- routers/init.go | 4 +- routers/install/setting.go | 6 +- .../migration-test/migration_test.go | 4 +- tests/test_utils.go | 2 +- 47 files changed, 1259 insertions(+), 1106 deletions(-) create mode 100644 modules/setting/admin.go create mode 100644 modules/setting/api.go create mode 100644 modules/setting/camo.go create mode 100644 modules/setting/config.go create mode 100644 modules/setting/metrics.go rename modules/setting/{oauth2_client.go => oauth2.go} (74%) create mode 100644 modules/setting/other.go create mode 100644 modules/setting/security.go create mode 100644 modules/setting/server.go create mode 100644 modules/setting/ssh.go create mode 100644 modules/setting/time.go create mode 100644 modules/setting/ui.go diff --git a/cmd/cmd.go b/cmd/cmd.go index 493519e1359a..849f3b7dc3c0 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -58,8 +58,8 @@ func confirm() (bool, error) { func initDB(ctx context.Context) error { setting.LoadFromExisting() - setting.InitDBConfig() - setting.NewXORMLogService(false) + setting.ParseDBSetting() + setting.ParseXORMLogSetting(false) if setting.Database.Type == "" { log.Fatal(`Database settings are missing from the configuration file: %q. diff --git a/cmd/doctor.go b/cmd/doctor.go index ceb6e3fbabe5..316cd095fece 100644 --- a/cmd/doctor.go +++ b/cmd/doctor.go @@ -88,13 +88,13 @@ func runRecreateTable(ctx *cli.Context) error { golog.SetOutput(log.NewLoggerAsWriter("INFO", log.GetLogger(log.DEFAULT))) setting.LoadFromExisting() - setting.InitDBConfig() + setting.ParseDBSetting() setting.EnableXORMLog = ctx.Bool("debug") setting.Database.LogSQL = ctx.Bool("debug") setting.Cfg.Section("log").Key("XORM").SetValue(",") - setting.NewXORMLogService(!ctx.Bool("debug")) + setting.ParseXORMLogSetting(!ctx.Bool("debug")) stdCtx, cancel := installSignals() defer cancel() diff --git a/cmd/dump.go b/cmd/dump.go index f40ddbac23e8..909ab6d44fe7 100644 --- a/cmd/dump.go +++ b/cmd/dump.go @@ -194,7 +194,7 @@ func runDump(ctx *cli.Context) error { log.Error("Is '%s' really the right config path?\n", setting.CustomConf) return fmt.Errorf("gitea is not initialized") } - setting.NewServices() // cannot access session settings otherwise + setting.LoadSettings() // cannot access session settings otherwise stdCtx, cancel := installSignals() defer cancel() diff --git a/models/migrations/base/tests.go b/models/migrations/base/tests.go index a9bcd20f674b..7086bf1fd65b 100644 --- a/models/migrations/base/tests.go +++ b/models/migrations/base/tests.go @@ -154,8 +154,8 @@ func MainTest(m *testing.M) { fmt.Printf("Unable to InitFull: %v\n", err) os.Exit(1) } - setting.InitDBConfig() - setting.NewLogServices(true) + setting.ParseDBSetting() + setting.ParseLogSettings(true) exitStatus := m.Run() diff --git a/modules/doctor/doctor.go b/modules/doctor/doctor.go index 2025edc58ddf..5b3d27f4c9c4 100644 --- a/modules/doctor/doctor.go +++ b/modules/doctor/doctor.go @@ -45,9 +45,8 @@ func (w *wrappedLevelLogger) Log(skip int, level log.Level, format string, v ... func initDBDisableConsole(ctx context.Context, disableConsole bool) error { setting.LoadFromExisting() - setting.InitDBConfig() - - setting.NewXORMLogService(disableConsole) + setting.ParseDBSetting() + setting.ParseXORMLogSetting(disableConsole) if err := db.InitEngine(ctx); err != nil { return fmt.Errorf("db.InitEngine: %w", err) } diff --git a/modules/setting/admin.go b/modules/setting/admin.go new file mode 100644 index 000000000000..c7cfcfd2ae47 --- /dev/null +++ b/modules/setting/admin.go @@ -0,0 +1,16 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package setting + +// Admin settings +var Admin struct { + DisableRegularOrgCreation bool + DefaultEmailNotification string +} + +func parseAdminSetting(rootCfg Config) { + mustMapSetting(rootCfg, "admin", &Admin) + sec := Cfg.Section("admin") + Admin.DefaultEmailNotification = sec.Key("DEFAULT_EMAIL_NOTIFICATIONS").MustString("enabled") +} diff --git a/modules/setting/api.go b/modules/setting/api.go new file mode 100644 index 000000000000..7a888e77bdf5 --- /dev/null +++ b/modules/setting/api.go @@ -0,0 +1,40 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package setting + +import ( + "net/url" + "path" + + "code.gitea.io/gitea/modules/log" +) + +// API settings +var API = struct { + EnableSwagger bool + SwaggerURL string + MaxResponseItems int + DefaultPagingNum int + DefaultGitTreesPerPage int + DefaultMaxBlobSize int64 +}{ + EnableSwagger: true, + SwaggerURL: "", + MaxResponseItems: 50, + DefaultPagingNum: 30, + DefaultGitTreesPerPage: 1000, + DefaultMaxBlobSize: 10485760, +} + +func parseAPISetting(rootCfg Config) { + mustMapSetting(rootCfg, "api", &API) + + defaultAppURL := string(Protocol) + "://" + Domain + ":" + HTTPPort + u, err := url.Parse(rootCfg.Section("server").Key("ROOT_URL").MustString(defaultAppURL)) + if err != nil { + log.Fatal("Invalid ROOT_URL '%s': %s", AppURL, err) + } + u.Path = path.Join(u.Path, "api", "swagger") + API.SwaggerURL = u.String() +} diff --git a/modules/setting/attachment.go b/modules/setting/attachment.go index 68a2e87204e3..70e4bdf13b54 100644 --- a/modules/setting/attachment.go +++ b/modules/setting/attachment.go @@ -20,8 +20,8 @@ var Attachment = struct { Enabled: true, } -func newAttachmentService() { - sec := Cfg.Section("attachment") +func parseAttachmentSetting(rootCfg Config) { + sec := rootCfg.Section("attachment") storageType := sec.Key("STORAGE_TYPE").MustString("") Attachment.Storage = getStorage("attachments", storageType, sec) diff --git a/modules/setting/cache.go b/modules/setting/cache.go index 2da79adb3beb..931742e2b3ca 100644 --- a/modules/setting/cache.go +++ b/modules/setting/cache.go @@ -49,8 +49,8 @@ var CacheService = struct { // MemcacheMaxTTL represents the maximum memcache TTL const MemcacheMaxTTL = 30 * 24 * time.Hour -func newCacheService() { - sec := Cfg.Section("cache") +func parseCacheSetting(rootCfg Config) { + sec := rootCfg.Section("cache") if err := sec.MapTo(&CacheService); err != nil { log.Fatal("Failed to map Cache settings: %v", err) } diff --git a/modules/setting/camo.go b/modules/setting/camo.go new file mode 100644 index 000000000000..f385cbcca0c0 --- /dev/null +++ b/modules/setting/camo.go @@ -0,0 +1,22 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package setting + +import "code.gitea.io/gitea/modules/log" + +var Camo = struct { + Enabled bool + ServerURL string `ini:"SERVER_URL"` + HMACKey string `ini:"HMAC_KEY"` + Allways bool +}{} + +func parseCamoSetting(rootCfg Config) { + mustMapSetting(rootCfg, "camo", &Camo) + if Camo.Enabled { + if Camo.ServerURL == "" || Camo.HMACKey == "" { + log.Fatal(`Camo settings require "SERVER_URL" and HMAC_KEY`) + } + } +} diff --git a/modules/setting/config.go b/modules/setting/config.go new file mode 100644 index 000000000000..1d57945628fb --- /dev/null +++ b/modules/setting/config.go @@ -0,0 +1,19 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package setting + +import ( + "code.gitea.io/gitea/modules/log" + ini "gopkg.in/ini.v1" +) + +type Config interface { + Section(section string) *ini.Section +} + +func mustMapSetting(rootCfg Config, sectionName string, setting interface{}) { + if err := rootCfg.Section(sectionName).MapTo(setting); err != nil { + log.Fatal("Failed to map %s settings: %v", sectionName, err) + } +} diff --git a/modules/setting/cors.go b/modules/setting/cors.go index ae0736e8307c..e86ea46ea9fc 100644 --- a/modules/setting/cors.go +++ b/modules/setting/cors.go @@ -5,8 +5,6 @@ package setting import ( "time" - - "code.gitea.io/gitea/modules/log" ) // CORSConfig defines CORS settings @@ -26,14 +24,3 @@ var CORSConfig = struct { Headers: []string{"Content-Type", "User-Agent"}, XFrameOptions: "SAMEORIGIN", } - -func newCORSService() { - sec := Cfg.Section("cors") - if err := sec.MapTo(&CORSConfig); err != nil { - log.Fatal("Failed to map cors settings: %v", err) - } - - if CORSConfig.Enabled { - log.Info("CORS Service Enabled") - } -} diff --git a/modules/setting/database.go b/modules/setting/database.go index 5480f9dffd90..ca2bfade888b 100644 --- a/modules/setting/database.go +++ b/modules/setting/database.go @@ -57,7 +57,7 @@ var ( ) // InitDBConfig loads the database settings -func InitDBConfig() { +func ParseDBSetting() { sec := Cfg.Section("database") Database.Type = sec.Key("DB_TYPE").String() defaultCharset := "utf8" diff --git a/modules/setting/federation.go b/modules/setting/federation.go index acab3eb58004..5220e6cd81ef 100644 --- a/modules/setting/federation.go +++ b/modules/setting/federation.go @@ -33,8 +33,8 @@ var ( // HttpsigAlgs is a constant slice of httpsig algorithm objects var HttpsigAlgs []httpsig.Algorithm -func newFederationService() { - if err := Cfg.Section("federation").MapTo(&Federation); err != nil { +func parseFederationSetting(rootCfg Config) { + if err := rootCfg.Section("federation").MapTo(&Federation); err != nil { log.Fatal("Failed to map Federation settings: %v", err) } else if !httpsig.IsSupportedDigestAlgorithm(Federation.DigestAlgorithm) { log.Fatal("unsupported digest algorithm: %s", Federation.DigestAlgorithm) diff --git a/modules/setting/git.go b/modules/setting/git.go index a05f77a97e0f..04fe9bbb1061 100644 --- a/modules/setting/git.go +++ b/modules/setting/git.go @@ -67,9 +67,8 @@ var Git = struct { }, } -func newGit() { - sec := Cfg.Section("git") - +func parseGitSetting(rootCfg Config) { + sec := rootCfg.Section("git") if err := sec.MapTo(&Git); err != nil { log.Fatal("Failed to map Git settings: %v", err) } diff --git a/modules/setting/i18n.go b/modules/setting/i18n.go index 0e67b18a3e35..067154a1be13 100644 --- a/modules/setting/i18n.go +++ b/modules/setting/i18n.go @@ -47,3 +47,20 @@ func defaultI18nNames() (res []string) { } return res } + +var ( + // I18n settings + Langs []string + Names []string +) + +func parseI18nSetting(rootCfg Config) { + Langs = rootCfg.Section("i18n").Key("LANGS").Strings(",") + if len(Langs) == 0 { + Langs = defaultI18nLangs() + } + Names = rootCfg.Section("i18n").Key("NAMES").Strings(",") + if len(Names) == 0 { + Names = defaultI18nNames() + } +} diff --git a/modules/setting/indexer.go b/modules/setting/indexer.go index 1b1c8f7e7f5c..0761fe4e4862 100644 --- a/modules/setting/indexer.go +++ b/modules/setting/indexer.go @@ -45,8 +45,8 @@ var Indexer = struct { ExcludeVendored: true, } -func newIndexerService() { - sec := Cfg.Section("indexer") +func parseIndexerSetting(rootCfg Config) { + sec := rootCfg.Section("indexer") Indexer.IssueType = sec.Key("ISSUE_INDEXER_TYPE").MustString("bleve") Indexer.IssuePath = filepath.ToSlash(sec.Key("ISSUE_INDEXER_PATH").MustString(filepath.ToSlash(filepath.Join(AppDataPath, "indexers/issues.bleve")))) if !filepath.IsAbs(Indexer.IssuePath) { diff --git a/modules/setting/lfs.go b/modules/setting/lfs.go index 6f8e875c1d41..881520bec6be 100644 --- a/modules/setting/lfs.go +++ b/modules/setting/lfs.go @@ -25,13 +25,13 @@ var LFS = struct { Storage }{} -func newLFSService() { - sec := Cfg.Section("server") +func parseLFSSetting(rootCfg Config) { + sec := rootCfg.Section("server") if err := sec.MapTo(&LFS); err != nil { log.Fatal("Failed to map LFS settings: %v", err) } - lfsSec := Cfg.Section("lfs") + lfsSec := rootCfg.Section("lfs") storageType := lfsSec.Key("STORAGE_TYPE").MustString("") // Specifically default PATH to LFS_CONTENT_PATH diff --git a/modules/setting/log.go b/modules/setting/log.go index 8a2d47eda767..d61abfa1a76c 100644 --- a/modules/setting/log.go +++ b/modules/setting/log.go @@ -25,6 +25,20 @@ var ( logDescriptions = make(map[string]*LogDescription) ) +var ( + // Log settings + LogLevel log.Level + StacktraceLogLevel string + LogRootPath string + EnableSSHLog bool + EnableXORMLog bool + + DisableRouterLog bool + + EnableAccessLog bool + AccessLogTemplate string +) + // GetLogDescriptions returns a race safe set of descriptions func GetLogDescriptions() map[string]*LogDescription { descriptionLock.RLock() @@ -253,7 +267,7 @@ func generateNamedLogger(key string, options defaultLogOptions) *LogDescription return &description } -func newAccessLogService() { +func parseAccessLogSetting() { EnableAccessLog = Cfg.Section("log").Key("ENABLE_ACCESS_LOG").MustBool(false) AccessLogTemplate = Cfg.Section("log").Key("ACCESS_LOG_TEMPLATE").MustString( `{{.Ctx.RemoteAddr}} - {{.Identity}} {{.Start.Format "[02/Jan/2006:15:04:05 -0700]" }} "{{.Ctx.Req.Method}} {{.Ctx.Req.URL.RequestURI}} {{.Ctx.Req.Proto}}" {{.ResponseWriter.Status}} {{.ResponseWriter.Size}} "{{.Ctx.Req.Referer}}\" \"{{.Ctx.Req.UserAgent}}"`, @@ -269,7 +283,7 @@ func newAccessLogService() { } } -func newRouterLogService() { +func parseRouterLogSetting() { Cfg.Section("log").Key("ROUTER").MustString("console") // Allow [log] DISABLE_ROUTER_LOG to override [server] DISABLE_ROUTER_LOG DisableRouterLog = Cfg.Section("log").Key("DISABLE_ROUTER_LOG").MustBool(DisableRouterLog) @@ -283,7 +297,7 @@ func newRouterLogService() { } } -func newLogService() { +func parseLogSetting() { options := newDefaultLogOptions() options.bufferLength = Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000) EnableSSHLog = Cfg.Section("log").Key("ENABLE_SSH_LOG").MustBool(false) @@ -340,19 +354,19 @@ func newLogService() { // RestartLogsWithPIDSuffix restarts the logs with a PID suffix on files func RestartLogsWithPIDSuffix() { filenameSuffix = fmt.Sprintf(".%d", os.Getpid()) - NewLogServices(false) + ParseLogSettings(false) } -// NewLogServices creates all the log services -func NewLogServices(disableConsole bool) { - newLogService() - newRouterLogService() - newAccessLogService() - NewXORMLogService(disableConsole) +// ParseLogSettings creates all the log services +func ParseLogSettings(disableConsole bool) { + parseLogSetting() + parseRouterLogSetting() + parseAccessLogSetting() + ParseXORMLogSetting(disableConsole) } -// NewXORMLogService initializes xorm logger service -func NewXORMLogService(disableConsole bool) { +// ParseXORMLogSetting initializes xorm logger setting +func ParseXORMLogSetting(disableConsole bool) { EnableXORMLog = Cfg.Section("log").Key("ENABLE_XORM_LOG").MustBool(true) if EnableXORMLog { options := newDefaultLogOptions() diff --git a/modules/setting/mailer.go b/modules/setting/mailer.go index e7cc812eef8a..77fab58534cb 100644 --- a/modules/setting/mailer.go +++ b/modules/setting/mailer.go @@ -49,8 +49,14 @@ type Mailer struct { // MailService the global mailer var MailService *Mailer -func newMailService() { - sec := Cfg.Section("mailer") +func parseMailSettings(rootCfg Config) { + parseMailerSetting(rootCfg) + parseRegisterMailSetting(rootCfg) + parseNotifyMailSetting(rootCfg) +} + +func parseMailerSetting(rootCfg Config) { + sec := rootCfg.Section("mailer") // Check mailer setting. if !sec.Key("ENABLED").MustBool() { return @@ -228,8 +234,8 @@ func newMailService() { log.Info("Mail Service Enabled") } -func newRegisterMailService() { - if !Cfg.Section("service").Key("REGISTER_EMAIL_CONFIRM").MustBool() { +func parseRegisterMailSetting(rootCfg Config) { + if !rootCfg.Section("service").Key("REGISTER_EMAIL_CONFIRM").MustBool() { return } else if MailService == nil { log.Warn("Register Mail Service: Mail Service is not enabled") @@ -239,8 +245,8 @@ func newRegisterMailService() { log.Info("Register Mail Service Enabled") } -func newNotifyMailService() { - if !Cfg.Section("service").Key("ENABLE_NOTIFY_MAIL").MustBool() { +func parseNotifyMailSetting(rootCfg Config) { + if !rootCfg.Section("service").Key("ENABLE_NOTIFY_MAIL").MustBool() { return } else if MailService == nil { log.Warn("Notify Mail Service: Mail Service is not enabled") diff --git a/modules/setting/markup.go b/modules/setting/markup.go index c262234b6a28..1d24d5df428e 100644 --- a/modules/setting/markup.go +++ b/modules/setting/markup.go @@ -25,6 +25,20 @@ const ( RenderContentModeIframe = "iframe" ) +// Markdown settings +var Markdown = struct { + EnableHardLineBreakInComments bool + EnableHardLineBreakInDocuments bool + CustomURLSchemes []string `ini:"CUSTOM_URL_SCHEMES"` + FileExtensions []string + EnableMath bool +}{ + EnableHardLineBreakInComments: true, + EnableHardLineBreakInDocuments: false, + FileExtensions: strings.Split(".md,.markdown,.mdown,.mkd", ","), + EnableMath: true, +} + // MarkupRenderer defines the external parser configured in ini type MarkupRenderer struct { Enabled bool @@ -46,12 +60,14 @@ type MarkupSanitizerRule struct { AllowDataURIImages bool } -func newMarkup() { - MermaidMaxSourceCharacters = Cfg.Section("markup").Key("MERMAID_MAX_SOURCE_CHARACTERS").MustInt(5000) +func parseMarkupSetting(rootCfg Config) { + mustMapSetting(Cfg, "markdown", &Markdown) + + MermaidMaxSourceCharacters = rootCfg.Section("markup").Key("MERMAID_MAX_SOURCE_CHARACTERS").MustInt(5000) ExternalMarkupRenderers = make([]*MarkupRenderer, 0, 10) ExternalSanitizerRules = make([]MarkupSanitizerRule, 0, 10) - for _, sec := range Cfg.Section("markup").ChildSections() { + for _, sec := range rootCfg.Section("markup").ChildSections() { name := strings.TrimPrefix(sec.Name(), "markup.") if name == "" { log.Warn("name is empty, markup " + sec.Name() + "ignored") diff --git a/modules/setting/metrics.go b/modules/setting/metrics.go new file mode 100644 index 000000000000..196f8eb3cd60 --- /dev/null +++ b/modules/setting/metrics.go @@ -0,0 +1,21 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package setting + +// Metrics settings +var Metrics = struct { + Enabled bool + Token string + EnabledIssueByLabel bool + EnabledIssueByRepository bool +}{ + Enabled: false, + Token: "", + EnabledIssueByLabel: false, + EnabledIssueByRepository: false, +} + +func parseMetricsSetting(rootCfg Config) { + mustMapSetting(Cfg, "metrics", &Metrics) +} diff --git a/modules/setting/migrations.go b/modules/setting/migrations.go index 2f6d08b6b88b..aa8b429fa365 100644 --- a/modules/setting/migrations.go +++ b/modules/setting/migrations.go @@ -16,8 +16,8 @@ var Migrations = struct { RetryBackoff: 3, } -func newMigrationsService() { - sec := Cfg.Section("migrations") +func parseMigrationsSetting(rootCfg Config) { + sec := rootCfg.Section("migrations") Migrations.MaxAttempts = sec.Key("MAX_ATTEMPTS").MustInt(Migrations.MaxAttempts) Migrations.RetryBackoff = sec.Key("RETRY_BACKOFF").MustInt(Migrations.RetryBackoff) diff --git a/modules/setting/mime_type_map.go b/modules/setting/mime_type_map.go index 6a0847bd7e2b..41a1b5e7e58c 100644 --- a/modules/setting/mime_type_map.go +++ b/modules/setting/mime_type_map.go @@ -14,8 +14,8 @@ var MimeTypeMap = struct { Map: map[string]string{}, } -func newMimeTypeMap() { - sec := Cfg.Section("repository.mimetype_mapping") +func parseMimeTypeMap(rootCfg Config) { + sec := rootCfg.Section("repository.mimetype_mapping") keys := sec.Keys() m := make(map[string]string, len(keys)) for _, key := range keys { diff --git a/modules/setting/mirror.go b/modules/setting/mirror.go index 9ddce97dafef..7a0ab516f2f6 100644 --- a/modules/setting/mirror.go +++ b/modules/setting/mirror.go @@ -24,16 +24,16 @@ var Mirror = struct { DefaultInterval: 8 * time.Hour, } -func newMirror() { +func parseMirrorSetting(rootCfg Config) { // Handle old configuration through `[repository]` `DISABLE_MIRRORS` // - please note this was badly named and only disabled the creation of new pull mirrors // FIXME: DEPRECATED to be removed in v1.18.0 deprecatedSetting("repository", "DISABLE_MIRRORS", "mirror", "ENABLED") - if Cfg.Section("repository").Key("DISABLE_MIRRORS").MustBool(false) { + if rootCfg.Section("repository").Key("DISABLE_MIRRORS").MustBool(false) { Mirror.DisableNewPull = true } - if err := Cfg.Section("mirror").MapTo(&Mirror); err != nil { + if err := rootCfg.Section("mirror").MapTo(&Mirror); err != nil { log.Fatal("Failed to map Mirror settings: %v", err) } diff --git a/modules/setting/oauth2_client.go b/modules/setting/oauth2.go similarity index 74% rename from modules/setting/oauth2_client.go rename to modules/setting/oauth2.go index 6492af82d2c0..186b268d831a 100644 --- a/modules/setting/oauth2_client.go +++ b/modules/setting/oauth2.go @@ -4,6 +4,9 @@ package setting import ( + "math" + "path/filepath" + "code.gitea.io/gitea/modules/log" "gopkg.in/ini.v1" @@ -59,8 +62,8 @@ var OAuth2Client struct { AccountLinking OAuth2AccountLinkingType } -func newOAuth2Client() { - sec := Cfg.Section("oauth2_client") +func parseOAuth2ClientSetting(rootCfg Config) { + sec := rootCfg.Section("oauth2_client") OAuth2Client.RegisterEmailConfirm = sec.Key("REGISTER_EMAIL_CONFIRM").MustBool(Service.RegisterEmailConfirm) OAuth2Client.OpenIDConnectScopes = parseScopes(sec, "OPENID_CONNECT_SCOPES") OAuth2Client.EnableAutoRegistration = sec.Key("ENABLE_AUTO_REGISTRATION").MustBool() @@ -87,3 +90,33 @@ func parseScopes(sec *ini.Section, name string) []string { } return scopes } + +var OAuth2 = struct { + Enable bool + AccessTokenExpirationTime int64 + RefreshTokenExpirationTime int64 + InvalidateRefreshTokens bool + JWTSigningAlgorithm string `ini:"JWT_SIGNING_ALGORITHM"` + JWTSecretBase64 string `ini:"JWT_SECRET"` + JWTSigningPrivateKeyFile string `ini:"JWT_SIGNING_PRIVATE_KEY_FILE"` + MaxTokenLength int +}{ + Enable: true, + AccessTokenExpirationTime: 3600, + RefreshTokenExpirationTime: 730, + InvalidateRefreshTokens: false, + JWTSigningAlgorithm: "RS256", + JWTSigningPrivateKeyFile: "jwt/private.pem", + MaxTokenLength: math.MaxInt16, +} + +func parseOAuth2Setting(rootCfg Config) { + if err := rootCfg.Section("oauth2").MapTo(&OAuth2); err != nil { + log.Fatal("Failed to OAuth2 settings: %v", err) + return + } + + if !filepath.IsAbs(OAuth2.JWTSigningPrivateKeyFile) { + OAuth2.JWTSigningPrivateKeyFile = filepath.Join(AppDataPath, OAuth2.JWTSigningPrivateKeyFile) + } +} diff --git a/modules/setting/other.go b/modules/setting/other.go new file mode 100644 index 000000000000..69b511ede9df --- /dev/null +++ b/modules/setting/other.go @@ -0,0 +1,21 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package setting + +var ( + // Other settings + ShowFooterBranding bool + ShowFooterVersion bool + ShowFooterTemplateLoadTime bool + EnableFeed bool +) + +func parseOtherSetting(rootCfg Config) { + sec := Cfg.Section("other") + ShowFooterBranding = sec.Key("SHOW_FOOTER_BRANDING").MustBool(false) + ShowFooterVersion = sec.Key("SHOW_FOOTER_VERSION").MustBool(true) + ShowFooterTemplateLoadTime = sec.Key("SHOW_FOOTER_TEMPLATE_LOAD_TIME").MustBool(true) + EnableSitemap = sec.Key("ENABLE_SITEMAP").MustBool(true) + EnableFeed = sec.Key("ENABLE_FEED").MustBool(true) +} diff --git a/modules/setting/packages.go b/modules/setting/packages.go index 120fbb5bda8e..2f191a38660e 100644 --- a/modules/setting/packages.go +++ b/modules/setting/packages.go @@ -43,8 +43,8 @@ var ( } ) -func newPackages() { - sec := Cfg.Section("packages") +func parsePackagesSetting(rootCfg Config) { + sec := rootCfg.Section("packages") if err := sec.MapTo(&Packages); err != nil { log.Fatal("Failed to map Packages settings: %v", err) } diff --git a/modules/setting/picture.go b/modules/setting/picture.go index a814af822fba..ac6f9916df22 100644 --- a/modules/setting/picture.go +++ b/modules/setting/picture.go @@ -32,10 +32,10 @@ var ( }{} ) -func newPictureService() { - sec := Cfg.Section("picture") +func parsePictureSetting(rootCfg Config) { + sec := rootCfg.Section("picture") - avatarSec := Cfg.Section("avatar") + avatarSec := rootCfg.Section("avatar") storageType := sec.Key("AVATAR_STORAGE_TYPE").MustString("") // Specifically default PATH to AVATAR_UPLOAD_PATH avatarSec.Key("PATH").MustString( @@ -64,7 +64,7 @@ func newPictureService() { EnableFederatedAvatar = sec.Key("ENABLE_FEDERATED_AVATAR").MustBool(GetDefaultEnableFederatedAvatar(DisableGravatar)) deprecatedSettingDB("", "ENABLE_FEDERATED_AVATAR") - newRepoAvatarService() + parseRepoAvatarSetting(rootCfg) } func GetDefaultDisableGravatar() bool { @@ -82,10 +82,10 @@ func GetDefaultEnableFederatedAvatar(disableGravatar bool) bool { return v } -func newRepoAvatarService() { - sec := Cfg.Section("picture") +func parseRepoAvatarSetting(rootCfg Config) { + sec := rootCfg.Section("picture") - repoAvatarSec := Cfg.Section("repo-avatar") + repoAvatarSec := rootCfg.Section("repo-avatar") storageType := sec.Key("REPOSITORY_AVATAR_STORAGE_TYPE").MustString("") // Specifically default PATH to AVATAR_UPLOAD_PATH repoAvatarSec.Key("PATH").MustString( diff --git a/modules/setting/project.go b/modules/setting/project.go index 53e09e8dad82..4cc415df0dad 100644 --- a/modules/setting/project.go +++ b/modules/setting/project.go @@ -3,8 +3,6 @@ package setting -import "code.gitea.io/gitea/modules/log" - // Project settings var ( Project = struct { @@ -15,9 +13,3 @@ var ( ProjectBoardBugTriageType: []string{"Needs Triage", "High Priority", "Low Priority", "Closed"}, } ) - -func newProject() { - if err := Cfg.Section("project").MapTo(&Project); err != nil { - log.Fatal("Failed to map Project settings: %v", err) - } -} diff --git a/modules/setting/proxy.go b/modules/setting/proxy.go index fed33395edec..6a036d600672 100644 --- a/modules/setting/proxy.go +++ b/modules/setting/proxy.go @@ -21,8 +21,8 @@ var Proxy = struct { ProxyHosts: []string{}, } -func newProxyService() { - sec := Cfg.Section("proxy") +func parseProxySetting(rootCfg Config) { + sec := rootCfg.Section("proxy") Proxy.Enabled = sec.Key("PROXY_ENABLED").MustBool(false) Proxy.ProxyURL = sec.Key("PROXY_URL").MustString("") if Proxy.ProxyURL != "" { diff --git a/modules/setting/queue.go b/modules/setting/queue.go index a67d0d849a0c..2bfc64e59da2 100644 --- a/modules/setting/queue.go +++ b/modules/setting/queue.go @@ -82,9 +82,9 @@ func GetQueueSettings(name string) QueueSettings { return q } -// NewQueueService sets up the default settings for Queues +// ParseQueueSettings sets up the default settings for Queues // This is exported for tests to be able to use the queue -func NewQueueService() { +func ParseQueueSettings() { sec := Cfg.Section("queue") Queue.DataDir = filepath.ToSlash(sec.Key("DATADIR").MustString("queues/")) if !filepath.IsAbs(Queue.DataDir) { diff --git a/modules/setting/repository.go b/modules/setting/repository.go index d78b63a1f3f7..531ed11fb2a4 100644 --- a/modules/setting/repository.go +++ b/modules/setting/repository.go @@ -268,10 +268,10 @@ var ( }{} ) -func newRepository() { +func parseRepositorySetting(rootCfg Config) { var err error // Determine and create root git repository path. - sec := Cfg.Section("repository") + sec := rootCfg.Section("repository") Repository.DisableHTTPGit = sec.Key("DISABLE_HTTP_GIT").MustBool() Repository.UseCompatSSHURI = sec.Key("USE_COMPAT_SSH_URI").MustBool() Repository.MaxCreationLimit = sec.Key("MAX_CREATION_LIMIT").MustInt(-1) @@ -293,19 +293,19 @@ func newRepository() { log.Warn("SCRIPT_TYPE %q is not on the current PATH. Are you sure that this is the correct SCRIPT_TYPE?", ScriptType) } - if err = Cfg.Section("repository").MapTo(&Repository); err != nil { + if err = sec.MapTo(&Repository); err != nil { log.Fatal("Failed to map Repository settings: %v", err) - } else if err = Cfg.Section("repository.editor").MapTo(&Repository.Editor); err != nil { + } else if err = rootCfg.Section("repository.editor").MapTo(&Repository.Editor); err != nil { log.Fatal("Failed to map Repository.Editor settings: %v", err) - } else if err = Cfg.Section("repository.upload").MapTo(&Repository.Upload); err != nil { + } else if err = rootCfg.Section("repository.upload").MapTo(&Repository.Upload); err != nil { log.Fatal("Failed to map Repository.Upload settings: %v", err) - } else if err = Cfg.Section("repository.local").MapTo(&Repository.Local); err != nil { + } else if err = rootCfg.Section("repository.local").MapTo(&Repository.Local); err != nil { log.Fatal("Failed to map Repository.Local settings: %v", err) - } else if err = Cfg.Section("repository.pull-request").MapTo(&Repository.PullRequest); err != nil { + } else if err = rootCfg.Section("repository.pull-request").MapTo(&Repository.PullRequest); err != nil { log.Fatal("Failed to map Repository.PullRequest settings: %v", err) } - if !Cfg.Section("packages").Key("ENABLED").MustBool(true) { + if !rootCfg.Section("packages").Key("ENABLED").MustBool(true) { Repository.DisabledRepoUnits = append(Repository.DisabledRepoUnits, "repo.packages") } diff --git a/modules/setting/security.go b/modules/setting/security.go new file mode 100644 index 000000000000..aeb7b6b935f3 --- /dev/null +++ b/modules/setting/security.go @@ -0,0 +1,147 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package setting + +import ( + "net/url" + "os" + "strings" + + "code.gitea.io/gitea/modules/generate" + "code.gitea.io/gitea/modules/log" + + ini "gopkg.in/ini.v1" +) + +var ( + // Security settings + InstallLock bool + SecretKey string + LogInRememberDays int + CookieUserName string + CookieRememberName string + ReverseProxyAuthUser string + ReverseProxyAuthEmail string + ReverseProxyAuthFullName string + ReverseProxyLimit int + ReverseProxyTrustedProxies []string + MinPasswordLength int + ImportLocalPaths bool + DisableGitHooks bool + DisableWebhooks bool + OnlyAllowPushIfGiteaEnvironmentSet bool + PasswordComplexity []string + PasswordHashAlgo string + PasswordCheckPwn bool + SuccessfulTokensCacheSize int +) + +// loadSecret load the secret from ini by uriKey or verbatimKey, only one of them could be set +// If the secret is loaded from uriKey (file), the file should be non-empty, to guarantee the behavior stable and clear. +func loadSecret(sec *ini.Section, uriKey, verbatimKey string) string { + // don't allow setting both URI and verbatim string + uri := sec.Key(uriKey).String() + verbatim := sec.Key(verbatimKey).String() + if uri != "" && verbatim != "" { + log.Fatal("Cannot specify both %s and %s", uriKey, verbatimKey) + } + + // if we have no URI, use verbatim + if uri == "" { + return verbatim + } + + tempURI, err := url.Parse(uri) + if err != nil { + log.Fatal("Failed to parse %s (%s): %v", uriKey, uri, err) + } + switch tempURI.Scheme { + case "file": + buf, err := os.ReadFile(tempURI.RequestURI()) + if err != nil { + log.Fatal("Failed to read %s (%s): %v", uriKey, tempURI.RequestURI(), err) + } + val := strings.TrimSpace(string(buf)) + if val == "" { + // The file shouldn't be empty, otherwise we can not know whether the user has ever set the KEY or KEY_URI + // For example: if INTERNAL_TOKEN_URI=file:///empty-file, + // Then if the token is re-generated during installation and saved to INTERNAL_TOKEN + // Then INTERNAL_TOKEN and INTERNAL_TOKEN_URI both exist, that's a fatal error (they shouldn't) + log.Fatal("Failed to read %s (%s): the file is empty", uriKey, tempURI.RequestURI()) + } + return val + + // only file URIs are allowed + default: + log.Fatal("Unsupported URI-Scheme %q (INTERNAL_TOKEN_URI = %q)", tempURI.Scheme, uri) + return "" + } +} + +// generateSaveInternalToken generates and saves the internal token to app.ini +func generateSaveInternalToken() { + token, err := generate.NewInternalToken() + if err != nil { + log.Fatal("Error generate internal token: %v", err) + } + + InternalToken = token + CreateOrAppendToCustomConf("security.INTERNAL_TOKEN", func(cfg *ini.File) { + cfg.Section("security").Key("INTERNAL_TOKEN").SetValue(token) + }) +} + +func parseSecuritySetting(rootCfg Config) { + sec := rootCfg.Section("security") + InstallLock = sec.Key("INSTALL_LOCK").MustBool(false) + LogInRememberDays = sec.Key("LOGIN_REMEMBER_DAYS").MustInt(7) + CookieUserName = sec.Key("COOKIE_USERNAME").MustString("gitea_awesome") + SecretKey = loadSecret(sec, "SECRET_KEY_URI", "SECRET_KEY") + if SecretKey == "" { + // FIXME: https://github.com/go-gitea/gitea/issues/16832 + // Until it supports rotating an existing secret key, we shouldn't move users off of the widely used default value + SecretKey = "!#@FDEWREWR&*(" //nolint:gosec + } + + CookieRememberName = sec.Key("COOKIE_REMEMBER_NAME").MustString("gitea_incredible") + + ReverseProxyAuthUser = sec.Key("REVERSE_PROXY_AUTHENTICATION_USER").MustString("X-WEBAUTH-USER") + ReverseProxyAuthEmail = sec.Key("REVERSE_PROXY_AUTHENTICATION_EMAIL").MustString("X-WEBAUTH-EMAIL") + ReverseProxyAuthFullName = sec.Key("REVERSE_PROXY_AUTHENTICATION_FULL_NAME").MustString("X-WEBAUTH-FULLNAME") + + ReverseProxyLimit = sec.Key("REVERSE_PROXY_LIMIT").MustInt(1) + ReverseProxyTrustedProxies = sec.Key("REVERSE_PROXY_TRUSTED_PROXIES").Strings(",") + if len(ReverseProxyTrustedProxies) == 0 { + ReverseProxyTrustedProxies = []string{"127.0.0.0/8", "::1/128"} + } + + MinPasswordLength = sec.Key("MIN_PASSWORD_LENGTH").MustInt(6) + ImportLocalPaths = sec.Key("IMPORT_LOCAL_PATHS").MustBool(false) + DisableGitHooks = sec.Key("DISABLE_GIT_HOOKS").MustBool(true) + DisableWebhooks = sec.Key("DISABLE_WEBHOOKS").MustBool(false) + OnlyAllowPushIfGiteaEnvironmentSet = sec.Key("ONLY_ALLOW_PUSH_IF_GITEA_ENVIRONMENT_SET").MustBool(true) + PasswordHashAlgo = sec.Key("PASSWORD_HASH_ALGO").MustString("pbkdf2") + CSRFCookieHTTPOnly = sec.Key("CSRF_COOKIE_HTTP_ONLY").MustBool(true) + PasswordCheckPwn = sec.Key("PASSWORD_CHECK_PWN").MustBool(false) + SuccessfulTokensCacheSize = sec.Key("SUCCESSFUL_TOKENS_CACHE_SIZE").MustInt(20) + + InternalToken = loadSecret(sec, "INTERNAL_TOKEN_URI", "INTERNAL_TOKEN") + if InstallLock && InternalToken == "" { + // if Gitea has been installed but the InternalToken hasn't been generated (upgrade from an old release), we should generate + // some users do cluster deployment, they still depend on this auto-generating behavior. + generateSaveInternalToken() + } + + cfgdata := sec.Key("PASSWORD_COMPLEXITY").Strings(",") + if len(cfgdata) == 0 { + cfgdata = []string{"off"} + } + PasswordComplexity = make([]string, 0, len(cfgdata)) + for _, name := range cfgdata { + name := strings.ToLower(strings.Trim(name, `"`)) + if name != "" { + PasswordComplexity = append(PasswordComplexity, name) + } + } +} diff --git a/modules/setting/server.go b/modules/setting/server.go new file mode 100644 index 000000000000..9620f0bc9053 --- /dev/null +++ b/modules/setting/server.go @@ -0,0 +1,318 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package setting + +import ( + "encoding/base64" + "net" + "net/url" + "os" + "path" + "path/filepath" + "strconv" + "strings" + "time" + + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/user" + "code.gitea.io/gitea/modules/util" +) + +var ManifestData string + +// MakeManifestData generates web app manifest JSON +func MakeManifestData(appName, appURL, absoluteAssetURL string) []byte { + type manifestIcon struct { + Src string `json:"src"` + Type string `json:"type"` + Sizes string `json:"sizes"` + } + + type manifestJSON struct { + Name string `json:"name"` + ShortName string `json:"short_name"` + StartURL string `json:"start_url"` + Icons []manifestIcon `json:"icons"` + } + + bytes, err := json.Marshal(&manifestJSON{ + Name: appName, + ShortName: appName, + StartURL: appURL, + Icons: []manifestIcon{ + { + Src: absoluteAssetURL + "/assets/img/logo.png", + Type: "image/png", + Sizes: "512x512", + }, + { + Src: absoluteAssetURL + "/assets/img/logo.svg", + Type: "image/svg+xml", + Sizes: "512x512", + }, + }, + }) + if err != nil { + log.Error("unable to marshal manifest JSON. Error: %v", err) + return make([]byte, 0) + } + + return bytes +} + +// MakeAbsoluteAssetURL returns the absolute asset url prefix without a trailing slash +func MakeAbsoluteAssetURL(appURL, staticURLPrefix string) string { + parsedPrefix, err := url.Parse(strings.TrimSuffix(staticURLPrefix, "/")) + if err != nil { + log.Fatal("Unable to parse STATIC_URL_PREFIX: %v", err) + } + + if err == nil && parsedPrefix.Hostname() == "" { + if staticURLPrefix == "" { + return strings.TrimSuffix(appURL, "/") + } + + // StaticURLPrefix is just a path + return util.URLJoin(appURL, strings.TrimSuffix(staticURLPrefix, "/")) + } + + return strings.TrimSuffix(staticURLPrefix, "/") +} + +func parseServerSetting(rootCfg Config) { + LogLevel = getLogLevel(Cfg.Section("log"), "LEVEL", log.INFO) + StacktraceLogLevel = getStacktraceLogLevel(Cfg.Section("log"), "STACKTRACE_LEVEL", "None") + LogRootPath = Cfg.Section("log").Key("ROOT_PATH").MustString(path.Join(AppWorkPath, "log")) + forcePathSeparator(LogRootPath) + + sec := Cfg.Section("server") + AppName = Cfg.Section("").Key("APP_NAME").MustString("Gitea: Git with a cup of tea") + + Domain = sec.Key("DOMAIN").MustString("localhost") + HTTPAddr = sec.Key("HTTP_ADDR").MustString("0.0.0.0") + HTTPPort = sec.Key("HTTP_PORT").MustString("3000") + + Protocol = HTTP + protocolCfg := sec.Key("PROTOCOL").String() + switch protocolCfg { + case "https": + Protocol = HTTPS + // FIXME: DEPRECATED to be removed in v1.18.0 + if sec.HasKey("ENABLE_ACME") { + EnableAcme = sec.Key("ENABLE_ACME").MustBool(false) + } else { + deprecatedSetting("server", "ENABLE_LETSENCRYPT", "server", "ENABLE_ACME") + EnableAcme = sec.Key("ENABLE_LETSENCRYPT").MustBool(false) + } + if EnableAcme { + AcmeURL = sec.Key("ACME_URL").MustString("") + AcmeCARoot = sec.Key("ACME_CA_ROOT").MustString("") + // FIXME: DEPRECATED to be removed in v1.18.0 + if sec.HasKey("ACME_ACCEPTTOS") { + AcmeTOS = sec.Key("ACME_ACCEPTTOS").MustBool(false) + } else { + deprecatedSetting("server", "LETSENCRYPT_ACCEPTTOS", "server", "ACME_ACCEPTTOS") + AcmeTOS = sec.Key("LETSENCRYPT_ACCEPTTOS").MustBool(false) + } + if !AcmeTOS { + log.Fatal("ACME TOS is not accepted (ACME_ACCEPTTOS).") + } + // FIXME: DEPRECATED to be removed in v1.18.0 + if sec.HasKey("ACME_DIRECTORY") { + AcmeLiveDirectory = sec.Key("ACME_DIRECTORY").MustString("https") + } else { + deprecatedSetting("server", "LETSENCRYPT_DIRECTORY", "server", "ACME_DIRECTORY") + AcmeLiveDirectory = sec.Key("LETSENCRYPT_DIRECTORY").MustString("https") + } + // FIXME: DEPRECATED to be removed in v1.18.0 + if sec.HasKey("ACME_EMAIL") { + AcmeEmail = sec.Key("ACME_EMAIL").MustString("") + } else { + deprecatedSetting("server", "LETSENCRYPT_EMAIL", "server", "ACME_EMAIL") + AcmeEmail = sec.Key("LETSENCRYPT_EMAIL").MustString("") + } + } else { + CertFile = sec.Key("CERT_FILE").String() + KeyFile = sec.Key("KEY_FILE").String() + if len(CertFile) > 0 && !filepath.IsAbs(CertFile) { + CertFile = filepath.Join(CustomPath, CertFile) + } + if len(KeyFile) > 0 && !filepath.IsAbs(KeyFile) { + KeyFile = filepath.Join(CustomPath, KeyFile) + } + } + SSLMinimumVersion = sec.Key("SSL_MIN_VERSION").MustString("") + SSLMaximumVersion = sec.Key("SSL_MAX_VERSION").MustString("") + SSLCurvePreferences = sec.Key("SSL_CURVE_PREFERENCES").Strings(",") + SSLCipherSuites = sec.Key("SSL_CIPHER_SUITES").Strings(",") + case "fcgi": + Protocol = FCGI + case "fcgi+unix", "unix", "http+unix": + switch protocolCfg { + case "fcgi+unix": + Protocol = FCGIUnix + case "unix": + log.Warn("unix PROTOCOL value is deprecated, please use http+unix") + fallthrough + case "http+unix": + Protocol = HTTPUnix + } + UnixSocketPermissionRaw := sec.Key("UNIX_SOCKET_PERMISSION").MustString("666") + UnixSocketPermissionParsed, err := strconv.ParseUint(UnixSocketPermissionRaw, 8, 32) + if err != nil || UnixSocketPermissionParsed > 0o777 { + log.Fatal("Failed to parse unixSocketPermission: %s", UnixSocketPermissionRaw) + } + + UnixSocketPermission = uint32(UnixSocketPermissionParsed) + if !filepath.IsAbs(HTTPAddr) { + HTTPAddr = filepath.Join(AppWorkPath, HTTPAddr) + } + } + UseProxyProtocol = sec.Key("USE_PROXY_PROTOCOL").MustBool(false) + ProxyProtocolTLSBridging = sec.Key("PROXY_PROTOCOL_TLS_BRIDGING").MustBool(false) + ProxyProtocolHeaderTimeout = sec.Key("PROXY_PROTOCOL_HEADER_TIMEOUT").MustDuration(5 * time.Second) + ProxyProtocolAcceptUnknown = sec.Key("PROXY_PROTOCOL_ACCEPT_UNKNOWN").MustBool(false) + GracefulRestartable = sec.Key("ALLOW_GRACEFUL_RESTARTS").MustBool(true) + GracefulHammerTime = sec.Key("GRACEFUL_HAMMER_TIME").MustDuration(60 * time.Second) + StartupTimeout = sec.Key("STARTUP_TIMEOUT").MustDuration(0 * time.Second) + PerWriteTimeout = sec.Key("PER_WRITE_TIMEOUT").MustDuration(PerWriteTimeout) + PerWritePerKbTimeout = sec.Key("PER_WRITE_PER_KB_TIMEOUT").MustDuration(PerWritePerKbTimeout) + + defaultAppURL := string(Protocol) + "://" + Domain + ":" + HTTPPort + AppURL = sec.Key("ROOT_URL").MustString(defaultAppURL) + + // Check validity of AppURL + appURL, err := url.Parse(AppURL) + if err != nil { + log.Fatal("Invalid ROOT_URL '%s': %s", AppURL, err) + } + // Remove default ports from AppURL. + // (scheme-based URL normalization, RFC 3986 section 6.2.3) + if (appURL.Scheme == string(HTTP) && appURL.Port() == "80") || (appURL.Scheme == string(HTTPS) && appURL.Port() == "443") { + appURL.Host = appURL.Hostname() + } + // This should be TrimRight to ensure that there is only a single '/' at the end of AppURL. + AppURL = strings.TrimRight(appURL.String(), "/") + "/" + + // Suburl should start with '/' and end without '/', such as '/{subpath}'. + // This value is empty if site does not have sub-url. + AppSubURL = strings.TrimSuffix(appURL.Path, "/") + StaticURLPrefix = strings.TrimSuffix(sec.Key("STATIC_URL_PREFIX").MustString(AppSubURL), "/") + + // Check if Domain differs from AppURL domain than update it to AppURL's domain + urlHostname := appURL.Hostname() + if urlHostname != Domain && net.ParseIP(urlHostname) == nil && urlHostname != "" { + Domain = urlHostname + } + + AbsoluteAssetURL = MakeAbsoluteAssetURL(AppURL, StaticURLPrefix) + AssetVersion = strings.ReplaceAll(AppVer, "+", "~") // make sure the version string is clear (no real escaping is needed) + + manifestBytes := MakeManifestData(AppName, AppURL, AbsoluteAssetURL) + ManifestData = `application/json;base64,` + base64.StdEncoding.EncodeToString(manifestBytes) + + var defaultLocalURL string + switch Protocol { + case HTTPUnix: + defaultLocalURL = "http://unix/" + case FCGI: + defaultLocalURL = AppURL + case FCGIUnix: + defaultLocalURL = AppURL + default: + defaultLocalURL = string(Protocol) + "://" + if HTTPAddr == "0.0.0.0" { + defaultLocalURL += net.JoinHostPort("localhost", HTTPPort) + "/" + } else { + defaultLocalURL += net.JoinHostPort(HTTPAddr, HTTPPort) + "/" + } + } + LocalURL = sec.Key("LOCAL_ROOT_URL").MustString(defaultLocalURL) + LocalURL = strings.TrimRight(LocalURL, "/") + "/" + LocalUseProxyProtocol = sec.Key("LOCAL_USE_PROXY_PROTOCOL").MustBool(UseProxyProtocol) + RedirectOtherPort = sec.Key("REDIRECT_OTHER_PORT").MustBool(false) + PortToRedirect = sec.Key("PORT_TO_REDIRECT").MustString("80") + RedirectorUseProxyProtocol = sec.Key("REDIRECTOR_USE_PROXY_PROTOCOL").MustBool(UseProxyProtocol) + OfflineMode = sec.Key("OFFLINE_MODE").MustBool() + DisableRouterLog = sec.Key("DISABLE_ROUTER_LOG").MustBool() + if len(StaticRootPath) == 0 { + StaticRootPath = AppWorkPath + } + StaticRootPath = sec.Key("STATIC_ROOT_PATH").MustString(StaticRootPath) + StaticCacheTime = sec.Key("STATIC_CACHE_TIME").MustDuration(6 * time.Hour) + AppDataPath = sec.Key("APP_DATA_PATH").MustString(path.Join(AppWorkPath, "data")) + if !filepath.IsAbs(AppDataPath) { + log.Info("The provided APP_DATA_PATH: %s is not absolute - it will be made absolute against the work path: %s", AppDataPath, AppWorkPath) + AppDataPath = filepath.ToSlash(filepath.Join(AppWorkPath, AppDataPath)) + } + + EnableGzip = sec.Key("ENABLE_GZIP").MustBool() + EnablePprof = sec.Key("ENABLE_PPROF").MustBool(false) + PprofDataPath = sec.Key("PPROF_DATA_PATH").MustString(path.Join(AppWorkPath, "data/tmp/pprof")) + if !filepath.IsAbs(PprofDataPath) { + PprofDataPath = filepath.Join(AppWorkPath, PprofDataPath) + } + + landingPage := sec.Key("LANDING_PAGE").MustString("home") + switch landingPage { + case "explore": + LandingPageURL = LandingPageExplore + case "organizations": + LandingPageURL = LandingPageOrganizations + case "login": + LandingPageURL = LandingPageLogin + case "": + case "home": + LandingPageURL = LandingPageHome + default: + LandingPageURL = LandingPage(landingPage) + } + + parseRunModeSetting(rootCfg) +} + +// IsRunUserMatchCurrentUser returns false if configured run user does not match +// actual user that runs the app. The first return value is the actual user name. +// This check is ignored under Windows since SSH remote login is not the main +// method to login on Windows. +func IsRunUserMatchCurrentUser(runUser string) (string, bool) { + if IsWindows || SSH.StartBuiltinServer { + return "", true + } + + currentUser := user.CurrentUsername() + return currentUser, runUser == currentUser +} + +func parseRunModeSetting(rootCfg Config) { + RunUser = Cfg.Section("").Key("RUN_USER").MustString(user.CurrentUsername()) + // The following is a purposefully undocumented option. Please do not run Gitea as root. It will only cause future headaches. + // Please don't use root as a bandaid to "fix" something that is broken, instead the broken thing should instead be fixed properly. + unsafeAllowRunAsRoot := Cfg.Section("").Key("I_AM_BEING_UNSAFE_RUNNING_AS_ROOT").MustBool(false) + RunMode = os.Getenv("GITEA_RUN_MODE") + if RunMode == "" { + RunMode = Cfg.Section("").Key("RUN_MODE").MustString("prod") + } + IsProd = strings.EqualFold(RunMode, "prod") + // Does not check run user when the install lock is off. + if InstallLock { + currentUser, match := IsRunUserMatchCurrentUser(RunUser) + if !match { + log.Fatal("Expect user '%s' but current user is: %s", RunUser, currentUser) + } + } + + // check if we run as root + if os.Getuid() == 0 { + if !unsafeAllowRunAsRoot { + // Special thanks to VLC which inspired the wording of this messaging. + log.Fatal("Gitea is not supposed to be run as root. Sorry. If you need to use privileged TCP ports please instead use setcap and the `cap_net_bind_service` permission") + } + log.Critical("You are running Gitea using the root user, and have purposely chosen to skip built-in protections around this. You have been warned against this.") + } + + SSH.BuiltinServerUser = Cfg.Section("server").Key("BUILTIN_SSH_SERVER_USER").MustString(RunUser) + SSH.User = Cfg.Section("server").Key("SSH_USER").MustString(SSH.BuiltinServerUser) +} diff --git a/modules/setting/service.go b/modules/setting/service.go index 7b4bfc5c7b6b..75e525ec4a79 100644 --- a/modules/setting/service.go +++ b/modules/setting/service.go @@ -12,6 +12,14 @@ import ( "code.gitea.io/gitea/modules/structs" ) +// enumerates all the types of captchas +const ( + ImageCaptcha = "image" + ReCaptcha = "recaptcha" + HCaptcha = "hcaptcha" + MCaptcha = "mcaptcha" +) + // Service settings var Service = struct { DefaultUserVisibility string @@ -103,8 +111,8 @@ func (a AllowedVisibility) ToVisibleTypeSlice() (result []structs.VisibleType) { return result } -func newService() { - sec := Cfg.Section("service") +func parseServiceSetting(rootCfg Config) { + sec := rootCfg.Section("service") Service.ActiveCodeLives = sec.Key("ACTIVE_CODE_LIVE_MINUTES").MustInt(180) Service.ResetPwdCodeLives = sec.Key("RESET_PASSWD_CODE_LIVE_MINUTES").MustInt(180) Service.DisableRegistration = sec.Key("DISABLE_REGISTRATION").MustBool() @@ -180,11 +188,13 @@ func newService() { } Service.ValidSiteURLSchemes = schemes - if err := Cfg.Section("service.explore").MapTo(&Service.Explore); err != nil { - log.Fatal("Failed to map service.explore settings: %v", err) - } + mustMapSetting(rootCfg, "service.explore", &Service.Explore) + + loadOpenIDSetting(rootCfg) +} - sec = Cfg.Section("openid") +func loadOpenIDSetting(rootCfg Config) { + sec := rootCfg.Section("openid") Service.EnableOpenIDSignIn = sec.Key("ENABLE_OPENID_SIGNIN").MustBool(!InstallLock) Service.EnableOpenIDSignUp = sec.Key("ENABLE_OPENID_SIGNUP").MustBool(!Service.DisableRegistration && Service.EnableOpenIDSignIn) pats := sec.Key("WHITELISTED_URIS").Strings(" ") diff --git a/modules/setting/session.go b/modules/setting/session.go index 082538c3858e..e0db309cbc39 100644 --- a/modules/setting/session.go +++ b/modules/setting/session.go @@ -39,8 +39,8 @@ var SessionConfig = struct { SameSite: http.SameSiteLaxMode, } -func newSessionService() { - sec := Cfg.Section("session") +func parseSessionSetting(rootCfg Config) { + sec := rootCfg.Section("session") SessionConfig.Provider = sec.Key("PROVIDER").In("memory", []string{"memory", "file", "redis", "mysql", "postgres", "couchbase", "memcache", "db"}) SessionConfig.ProviderConfig = strings.Trim(sec.Key("PROVIDER_CONFIG").MustString(path.Join(AppDataPath, "sessions")), "\" ") diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 07290fbfeb9f..1baf8fe43a4c 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -5,11 +5,7 @@ package setting import ( - "encoding/base64" "fmt" - "math" - "net" - "net/url" "os" "os/exec" "path" @@ -17,17 +13,11 @@ import ( "runtime" "strconv" "strings" - "text/template" "time" - "code.gitea.io/gitea/modules/container" - "code.gitea.io/gitea/modules/generate" - "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/user" "code.gitea.io/gitea/modules/util" - gossh "golang.org/x/crypto/ssh" ini "gopkg.in/ini.v1" ) @@ -54,14 +44,6 @@ const ( LandingPageLogin LandingPage = "/user/login" ) -// enumerates all the types of captchas -const ( - ImageCaptcha = "image" - ReCaptcha = "recaptcha" - HCaptcha = "hcaptcha" - MCaptcha = "mcaptcha" -) - // settings var ( // AppVer is the version of the current build of Gitea. It is set in main.go from main.Version. @@ -137,310 +119,11 @@ var ( StaticURLPrefix string AbsoluteAssetURL string - SSH = struct { - Disabled bool `ini:"DISABLE_SSH"` - StartBuiltinServer bool `ini:"START_SSH_SERVER"` - BuiltinServerUser string `ini:"BUILTIN_SSH_SERVER_USER"` - UseProxyProtocol bool `ini:"SSH_SERVER_USE_PROXY_PROTOCOL"` - Domain string `ini:"SSH_DOMAIN"` - Port int `ini:"SSH_PORT"` - User string `ini:"SSH_USER"` - ListenHost string `ini:"SSH_LISTEN_HOST"` - ListenPort int `ini:"SSH_LISTEN_PORT"` - RootPath string `ini:"SSH_ROOT_PATH"` - ServerCiphers []string `ini:"SSH_SERVER_CIPHERS"` - ServerKeyExchanges []string `ini:"SSH_SERVER_KEY_EXCHANGES"` - ServerMACs []string `ini:"SSH_SERVER_MACS"` - ServerHostKeys []string `ini:"SSH_SERVER_HOST_KEYS"` - KeyTestPath string `ini:"SSH_KEY_TEST_PATH"` - KeygenPath string `ini:"SSH_KEYGEN_PATH"` - AuthorizedKeysBackup bool `ini:"SSH_AUTHORIZED_KEYS_BACKUP"` - AuthorizedPrincipalsBackup bool `ini:"SSH_AUTHORIZED_PRINCIPALS_BACKUP"` - AuthorizedKeysCommandTemplate string `ini:"SSH_AUTHORIZED_KEYS_COMMAND_TEMPLATE"` - AuthorizedKeysCommandTemplateTemplate *template.Template `ini:"-"` - MinimumKeySizeCheck bool `ini:"-"` - MinimumKeySizes map[string]int `ini:"-"` - CreateAuthorizedKeysFile bool `ini:"SSH_CREATE_AUTHORIZED_KEYS_FILE"` - CreateAuthorizedPrincipalsFile bool `ini:"SSH_CREATE_AUTHORIZED_PRINCIPALS_FILE"` - ExposeAnonymous bool `ini:"SSH_EXPOSE_ANONYMOUS"` - AuthorizedPrincipalsAllow []string `ini:"SSH_AUTHORIZED_PRINCIPALS_ALLOW"` - AuthorizedPrincipalsEnabled bool `ini:"-"` - TrustedUserCAKeys []string `ini:"SSH_TRUSTED_USER_CA_KEYS"` - TrustedUserCAKeysFile string `ini:"SSH_TRUSTED_USER_CA_KEYS_FILENAME"` - TrustedUserCAKeysParsed []gossh.PublicKey `ini:"-"` - PerWriteTimeout time.Duration `ini:"SSH_PER_WRITE_TIMEOUT"` - PerWritePerKbTimeout time.Duration `ini:"SSH_PER_WRITE_PER_KB_TIMEOUT"` - }{ - Disabled: false, - StartBuiltinServer: false, - Domain: "", - Port: 22, - ServerCiphers: []string{"chacha20-poly1305@openssh.com", "aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-gcm@openssh.com", "aes256-gcm@openssh.com"}, - ServerKeyExchanges: []string{"curve25519-sha256", "ecdh-sha2-nistp256", "ecdh-sha2-nistp384", "ecdh-sha2-nistp521", "diffie-hellman-group14-sha256", "diffie-hellman-group14-sha1"}, - ServerMACs: []string{"hmac-sha2-256-etm@openssh.com", "hmac-sha2-256", "hmac-sha1"}, - KeygenPath: "ssh-keygen", - MinimumKeySizeCheck: true, - MinimumKeySizes: map[string]int{"ed25519": 256, "ed25519-sk": 256, "ecdsa": 256, "ecdsa-sk": 256, "rsa": 2047}, - ServerHostKeys: []string{"ssh/gitea.rsa", "ssh/gogs.rsa"}, - AuthorizedKeysCommandTemplate: "{{.AppPath}} --config={{.CustomConf}} serv key-{{.Key.ID}}", - PerWriteTimeout: PerWriteTimeout, - PerWritePerKbTimeout: PerWritePerKbTimeout, - } - - // Security settings - InstallLock bool - SecretKey string - LogInRememberDays int - CookieUserName string - CookieRememberName string - ReverseProxyAuthUser string - ReverseProxyAuthEmail string - ReverseProxyAuthFullName string - ReverseProxyLimit int - ReverseProxyTrustedProxies []string - MinPasswordLength int - ImportLocalPaths bool - DisableGitHooks bool - DisableWebhooks bool - OnlyAllowPushIfGiteaEnvironmentSet bool - PasswordComplexity []string - PasswordHashAlgo string - PasswordCheckPwn bool - SuccessfulTokensCacheSize int - - Camo = struct { - Enabled bool - ServerURL string `ini:"SERVER_URL"` - HMACKey string `ini:"HMAC_KEY"` - Allways bool - }{} - - // UI settings - UI = struct { - ExplorePagingNum int - SitemapPagingNum int - IssuePagingNum int - RepoSearchPagingNum int - MembersPagingNum int - FeedMaxCommitNum int - FeedPagingNum int - PackagesPagingNum int - GraphMaxCommitNum int - CodeCommentLines int - ReactionMaxUserNum int - ThemeColorMetaTag string - MaxDisplayFileSize int64 - ShowUserEmail bool - DefaultShowFullName bool - DefaultTheme string - Themes []string - Reactions []string - ReactionsLookup container.Set[string] `ini:"-"` - CustomEmojis []string - CustomEmojisMap map[string]string `ini:"-"` - SearchRepoDescription bool - UseServiceWorker bool - OnlyShowRelevantRepos bool - - Notification struct { - MinTimeout time.Duration - TimeoutStep time.Duration - MaxTimeout time.Duration - EventSourceUpdateTime time.Duration - } `ini:"ui.notification"` - - SVG struct { - Enabled bool `ini:"ENABLE_RENDER"` - } `ini:"ui.svg"` - - CSV struct { - MaxFileSize int64 - } `ini:"ui.csv"` - - Admin struct { - UserPagingNum int - RepoPagingNum int - NoticePagingNum int - OrgPagingNum int - } `ini:"ui.admin"` - User struct { - RepoPagingNum int - } `ini:"ui.user"` - Meta struct { - Author string - Description string - Keywords string - } `ini:"ui.meta"` - }{ - ExplorePagingNum: 20, - SitemapPagingNum: 20, - IssuePagingNum: 20, - RepoSearchPagingNum: 20, - MembersPagingNum: 20, - FeedMaxCommitNum: 5, - FeedPagingNum: 20, - PackagesPagingNum: 20, - GraphMaxCommitNum: 100, - CodeCommentLines: 4, - ReactionMaxUserNum: 10, - ThemeColorMetaTag: `#6cc644`, - MaxDisplayFileSize: 8388608, - DefaultTheme: `auto`, - Themes: []string{`auto`, `gitea`, `arc-green`}, - Reactions: []string{`+1`, `-1`, `laugh`, `hooray`, `confused`, `heart`, `rocket`, `eyes`}, - CustomEmojis: []string{`git`, `gitea`, `codeberg`, `gitlab`, `github`, `gogs`}, - CustomEmojisMap: map[string]string{"git": ":git:", "gitea": ":gitea:", "codeberg": ":codeberg:", "gitlab": ":gitlab:", "github": ":github:", "gogs": ":gogs:"}, - Notification: struct { - MinTimeout time.Duration - TimeoutStep time.Duration - MaxTimeout time.Duration - EventSourceUpdateTime time.Duration - }{ - MinTimeout: 10 * time.Second, - TimeoutStep: 10 * time.Second, - MaxTimeout: 60 * time.Second, - EventSourceUpdateTime: 10 * time.Second, - }, - SVG: struct { - Enabled bool `ini:"ENABLE_RENDER"` - }{ - Enabled: true, - }, - CSV: struct { - MaxFileSize int64 - }{ - MaxFileSize: 524288, - }, - Admin: struct { - UserPagingNum int - RepoPagingNum int - NoticePagingNum int - OrgPagingNum int - }{ - UserPagingNum: 50, - RepoPagingNum: 50, - NoticePagingNum: 25, - OrgPagingNum: 50, - }, - User: struct { - RepoPagingNum int - }{ - RepoPagingNum: 15, - }, - Meta: struct { - Author string - Description string - Keywords string - }{ - Author: "Gitea - Git with a cup of tea", - Description: "Gitea (Git with a cup of tea) is a painless self-hosted Git service written in Go", - Keywords: "go,git,self-hosted,gitea", - }, - } - - // Markdown settings - Markdown = struct { - EnableHardLineBreakInComments bool - EnableHardLineBreakInDocuments bool - CustomURLSchemes []string `ini:"CUSTOM_URL_SCHEMES"` - FileExtensions []string - EnableMath bool - }{ - EnableHardLineBreakInComments: true, - EnableHardLineBreakInDocuments: false, - FileExtensions: strings.Split(".md,.markdown,.mdown,.mkd", ","), - EnableMath: true, - } - - // Admin settings - Admin struct { - DisableRegularOrgCreation bool - DefaultEmailNotification string - } - - // Log settings - LogLevel log.Level - StacktraceLogLevel string - LogRootPath string - EnableSSHLog bool - EnableXORMLog bool - - DisableRouterLog bool - - EnableAccessLog bool - AccessLogTemplate string - - // Time settings - TimeFormat string - // UILocation is the location on the UI, so that we can display the time on UI. - DefaultUILocation = time.Local - CSRFCookieName = "_csrf" CSRFCookieHTTPOnly = true - ManifestData string - - // API settings - API = struct { - EnableSwagger bool - SwaggerURL string - MaxResponseItems int - DefaultPagingNum int - DefaultGitTreesPerPage int - DefaultMaxBlobSize int64 - }{ - EnableSwagger: true, - SwaggerURL: "", - MaxResponseItems: 50, - DefaultPagingNum: 30, - DefaultGitTreesPerPage: 1000, - DefaultMaxBlobSize: 10485760, - } - - OAuth2 = struct { - Enable bool - AccessTokenExpirationTime int64 - RefreshTokenExpirationTime int64 - InvalidateRefreshTokens bool - JWTSigningAlgorithm string `ini:"JWT_SIGNING_ALGORITHM"` - JWTSecretBase64 string `ini:"JWT_SECRET"` - JWTSigningPrivateKeyFile string `ini:"JWT_SIGNING_PRIVATE_KEY_FILE"` - MaxTokenLength int - }{ - Enable: true, - AccessTokenExpirationTime: 3600, - RefreshTokenExpirationTime: 730, - InvalidateRefreshTokens: false, - JWTSigningAlgorithm: "RS256", - JWTSigningPrivateKeyFile: "jwt/private.pem", - MaxTokenLength: math.MaxInt16, - } - - // Metrics settings - Metrics = struct { - Enabled bool - Token string - EnabledIssueByLabel bool - EnabledIssueByRepository bool - }{ - Enabled: false, - Token: "", - EnabledIssueByLabel: false, - EnabledIssueByRepository: false, - } - - // I18n settings - Langs []string - Names []string - // Highlight settings are loaded in modules/template/highlight.go - // Other settings - ShowFooterBranding bool - ShowFooterVersion bool - ShowFooterTemplateLoadTime bool - EnableFeed bool - // Global setting objects Cfg *ini.File CustomPath string // Custom directory path @@ -532,19 +215,6 @@ func forcePathSeparator(path string) { } } -// IsRunUserMatchCurrentUser returns false if configured run user does not match -// actual user that runs the app. The first return value is the actual user name. -// This check is ignored under Windows since SSH remote login is not the main -// method to login on Windows. -func IsRunUserMatchCurrentUser(runUser string) (string, bool) { - if IsWindows || SSH.StartBuiltinServer { - return "", true - } - - currentUser := user.CurrentUsername() - return currentUser, runUser == currentUser -} - func createPIDFile(pidPath string) { currentPid := os.Getpid() if err := os.MkdirAll(filepath.Dir(pidPath), os.ModePerm); err != nil { @@ -651,639 +321,24 @@ func loadFromConf(allowEmpty bool, extraConfig string) { Cfg.NameMapper = ini.SnackCase - homeDir, err := util.HomeDir() - if err != nil { - log.Fatal("Failed to get home directory: %v", err) - } - homeDir = strings.ReplaceAll(homeDir, "\\", "/") - - LogLevel = getLogLevel(Cfg.Section("log"), "LEVEL", log.INFO) - StacktraceLogLevel = getStacktraceLogLevel(Cfg.Section("log"), "STACKTRACE_LEVEL", "None") - LogRootPath = Cfg.Section("log").Key("ROOT_PATH").MustString(path.Join(AppWorkPath, "log")) - forcePathSeparator(LogRootPath) - - sec := Cfg.Section("server") - AppName = Cfg.Section("").Key("APP_NAME").MustString("Gitea: Git with a cup of tea") - - Domain = sec.Key("DOMAIN").MustString("localhost") - HTTPAddr = sec.Key("HTTP_ADDR").MustString("0.0.0.0") - HTTPPort = sec.Key("HTTP_PORT").MustString("3000") - - Protocol = HTTP - protocolCfg := sec.Key("PROTOCOL").String() - switch protocolCfg { - case "https": - Protocol = HTTPS - // FIXME: DEPRECATED to be removed in v1.18.0 - if sec.HasKey("ENABLE_ACME") { - EnableAcme = sec.Key("ENABLE_ACME").MustBool(false) - } else { - deprecatedSetting("server", "ENABLE_LETSENCRYPT", "server", "ENABLE_ACME") - EnableAcme = sec.Key("ENABLE_LETSENCRYPT").MustBool(false) - } - if EnableAcme { - AcmeURL = sec.Key("ACME_URL").MustString("") - AcmeCARoot = sec.Key("ACME_CA_ROOT").MustString("") - // FIXME: DEPRECATED to be removed in v1.18.0 - if sec.HasKey("ACME_ACCEPTTOS") { - AcmeTOS = sec.Key("ACME_ACCEPTTOS").MustBool(false) - } else { - deprecatedSetting("server", "LETSENCRYPT_ACCEPTTOS", "server", "ACME_ACCEPTTOS") - AcmeTOS = sec.Key("LETSENCRYPT_ACCEPTTOS").MustBool(false) - } - if !AcmeTOS { - log.Fatal("ACME TOS is not accepted (ACME_ACCEPTTOS).") - } - // FIXME: DEPRECATED to be removed in v1.18.0 - if sec.HasKey("ACME_DIRECTORY") { - AcmeLiveDirectory = sec.Key("ACME_DIRECTORY").MustString("https") - } else { - deprecatedSetting("server", "LETSENCRYPT_DIRECTORY", "server", "ACME_DIRECTORY") - AcmeLiveDirectory = sec.Key("LETSENCRYPT_DIRECTORY").MustString("https") - } - // FIXME: DEPRECATED to be removed in v1.18.0 - if sec.HasKey("ACME_EMAIL") { - AcmeEmail = sec.Key("ACME_EMAIL").MustString("") - } else { - deprecatedSetting("server", "LETSENCRYPT_EMAIL", "server", "ACME_EMAIL") - AcmeEmail = sec.Key("LETSENCRYPT_EMAIL").MustString("") - } - } else { - CertFile = sec.Key("CERT_FILE").String() - KeyFile = sec.Key("KEY_FILE").String() - if len(CertFile) > 0 && !filepath.IsAbs(CertFile) { - CertFile = filepath.Join(CustomPath, CertFile) - } - if len(KeyFile) > 0 && !filepath.IsAbs(KeyFile) { - KeyFile = filepath.Join(CustomPath, KeyFile) - } - } - SSLMinimumVersion = sec.Key("SSL_MIN_VERSION").MustString("") - SSLMaximumVersion = sec.Key("SSL_MAX_VERSION").MustString("") - SSLCurvePreferences = sec.Key("SSL_CURVE_PREFERENCES").Strings(",") - SSLCipherSuites = sec.Key("SSL_CIPHER_SUITES").Strings(",") - case "fcgi": - Protocol = FCGI - case "fcgi+unix", "unix", "http+unix": - switch protocolCfg { - case "fcgi+unix": - Protocol = FCGIUnix - case "unix": - log.Warn("unix PROTOCOL value is deprecated, please use http+unix") - fallthrough - case "http+unix": - Protocol = HTTPUnix - } - UnixSocketPermissionRaw := sec.Key("UNIX_SOCKET_PERMISSION").MustString("666") - UnixSocketPermissionParsed, err := strconv.ParseUint(UnixSocketPermissionRaw, 8, 32) - if err != nil || UnixSocketPermissionParsed > 0o777 { - log.Fatal("Failed to parse unixSocketPermission: %s", UnixSocketPermissionRaw) - } - - UnixSocketPermission = uint32(UnixSocketPermissionParsed) - if !filepath.IsAbs(HTTPAddr) { - HTTPAddr = filepath.Join(AppWorkPath, HTTPAddr) - } - } - UseProxyProtocol = sec.Key("USE_PROXY_PROTOCOL").MustBool(false) - ProxyProtocolTLSBridging = sec.Key("PROXY_PROTOCOL_TLS_BRIDGING").MustBool(false) - ProxyProtocolHeaderTimeout = sec.Key("PROXY_PROTOCOL_HEADER_TIMEOUT").MustDuration(5 * time.Second) - ProxyProtocolAcceptUnknown = sec.Key("PROXY_PROTOCOL_ACCEPT_UNKNOWN").MustBool(false) - GracefulRestartable = sec.Key("ALLOW_GRACEFUL_RESTARTS").MustBool(true) - GracefulHammerTime = sec.Key("GRACEFUL_HAMMER_TIME").MustDuration(60 * time.Second) - StartupTimeout = sec.Key("STARTUP_TIMEOUT").MustDuration(0 * time.Second) - PerWriteTimeout = sec.Key("PER_WRITE_TIMEOUT").MustDuration(PerWriteTimeout) - PerWritePerKbTimeout = sec.Key("PER_WRITE_PER_KB_TIMEOUT").MustDuration(PerWritePerKbTimeout) - - defaultAppURL := string(Protocol) + "://" + Domain + ":" + HTTPPort - AppURL = sec.Key("ROOT_URL").MustString(defaultAppURL) - - // Check validity of AppURL - appURL, err := url.Parse(AppURL) - if err != nil { - log.Fatal("Invalid ROOT_URL '%s': %s", AppURL, err) - } - // Remove default ports from AppURL. - // (scheme-based URL normalization, RFC 3986 section 6.2.3) - if (appURL.Scheme == string(HTTP) && appURL.Port() == "80") || (appURL.Scheme == string(HTTPS) && appURL.Port() == "443") { - appURL.Host = appURL.Hostname() - } - // This should be TrimRight to ensure that there is only a single '/' at the end of AppURL. - AppURL = strings.TrimRight(appURL.String(), "/") + "/" - - // Suburl should start with '/' and end without '/', such as '/{subpath}'. - // This value is empty if site does not have sub-url. - AppSubURL = strings.TrimSuffix(appURL.Path, "/") - StaticURLPrefix = strings.TrimSuffix(sec.Key("STATIC_URL_PREFIX").MustString(AppSubURL), "/") - - // Check if Domain differs from AppURL domain than update it to AppURL's domain - urlHostname := appURL.Hostname() - if urlHostname != Domain && net.ParseIP(urlHostname) == nil && urlHostname != "" { - Domain = urlHostname - } - - AbsoluteAssetURL = MakeAbsoluteAssetURL(AppURL, StaticURLPrefix) - AssetVersion = strings.ReplaceAll(AppVer, "+", "~") // make sure the version string is clear (no real escaping is needed) - - manifestBytes := MakeManifestData(AppName, AppURL, AbsoluteAssetURL) - ManifestData = `application/json;base64,` + base64.StdEncoding.EncodeToString(manifestBytes) - - var defaultLocalURL string - switch Protocol { - case HTTPUnix: - defaultLocalURL = "http://unix/" - case FCGI: - defaultLocalURL = AppURL - case FCGIUnix: - defaultLocalURL = AppURL - default: - defaultLocalURL = string(Protocol) + "://" - if HTTPAddr == "0.0.0.0" { - defaultLocalURL += net.JoinHostPort("localhost", HTTPPort) + "/" - } else { - defaultLocalURL += net.JoinHostPort(HTTPAddr, HTTPPort) + "/" - } - } - LocalURL = sec.Key("LOCAL_ROOT_URL").MustString(defaultLocalURL) - LocalURL = strings.TrimRight(LocalURL, "/") + "/" - LocalUseProxyProtocol = sec.Key("LOCAL_USE_PROXY_PROTOCOL").MustBool(UseProxyProtocol) - RedirectOtherPort = sec.Key("REDIRECT_OTHER_PORT").MustBool(false) - PortToRedirect = sec.Key("PORT_TO_REDIRECT").MustString("80") - RedirectorUseProxyProtocol = sec.Key("REDIRECTOR_USE_PROXY_PROTOCOL").MustBool(UseProxyProtocol) - OfflineMode = sec.Key("OFFLINE_MODE").MustBool() - DisableRouterLog = sec.Key("DISABLE_ROUTER_LOG").MustBool() - if len(StaticRootPath) == 0 { - StaticRootPath = AppWorkPath - } - StaticRootPath = sec.Key("STATIC_ROOT_PATH").MustString(StaticRootPath) - StaticCacheTime = sec.Key("STATIC_CACHE_TIME").MustDuration(6 * time.Hour) - AppDataPath = sec.Key("APP_DATA_PATH").MustString(path.Join(AppWorkPath, "data")) - if !filepath.IsAbs(AppDataPath) { - log.Info("The provided APP_DATA_PATH: %s is not absolute - it will be made absolute against the work path: %s", AppDataPath, AppWorkPath) - AppDataPath = filepath.ToSlash(filepath.Join(AppWorkPath, AppDataPath)) - } - - EnableGzip = sec.Key("ENABLE_GZIP").MustBool() - EnablePprof = sec.Key("ENABLE_PPROF").MustBool(false) - PprofDataPath = sec.Key("PPROF_DATA_PATH").MustString(path.Join(AppWorkPath, "data/tmp/pprof")) - if !filepath.IsAbs(PprofDataPath) { - PprofDataPath = filepath.Join(AppWorkPath, PprofDataPath) - } - - landingPage := sec.Key("LANDING_PAGE").MustString("home") - switch landingPage { - case "explore": - LandingPageURL = LandingPageExplore - case "organizations": - LandingPageURL = LandingPageOrganizations - case "login": - LandingPageURL = LandingPageLogin - case "": - case "home": - LandingPageURL = LandingPageHome - default: - LandingPageURL = LandingPage(landingPage) - } - - if len(SSH.Domain) == 0 { - SSH.Domain = Domain - } - SSH.RootPath = path.Join(homeDir, ".ssh") - serverCiphers := sec.Key("SSH_SERVER_CIPHERS").Strings(",") - if len(serverCiphers) > 0 { - SSH.ServerCiphers = serverCiphers - } - serverKeyExchanges := sec.Key("SSH_SERVER_KEY_EXCHANGES").Strings(",") - if len(serverKeyExchanges) > 0 { - SSH.ServerKeyExchanges = serverKeyExchanges - } - serverMACs := sec.Key("SSH_SERVER_MACS").Strings(",") - if len(serverMACs) > 0 { - SSH.ServerMACs = serverMACs - } - SSH.KeyTestPath = os.TempDir() - if err = Cfg.Section("server").MapTo(&SSH); err != nil { - log.Fatal("Failed to map SSH settings: %v", err) - } - for i, key := range SSH.ServerHostKeys { - if !filepath.IsAbs(key) { - SSH.ServerHostKeys[i] = filepath.Join(AppDataPath, key) - } - } - - SSH.KeygenPath = sec.Key("SSH_KEYGEN_PATH").MustString("ssh-keygen") - SSH.Port = sec.Key("SSH_PORT").MustInt(22) - SSH.ListenPort = sec.Key("SSH_LISTEN_PORT").MustInt(SSH.Port) - SSH.UseProxyProtocol = sec.Key("SSH_SERVER_USE_PROXY_PROTOCOL").MustBool(false) - - // When disable SSH, start builtin server value is ignored. - if SSH.Disabled { - SSH.StartBuiltinServer = false - } - - SSH.TrustedUserCAKeysFile = sec.Key("SSH_TRUSTED_USER_CA_KEYS_FILENAME").MustString(filepath.Join(SSH.RootPath, "gitea-trusted-user-ca-keys.pem")) - - for _, caKey := range SSH.TrustedUserCAKeys { - pubKey, _, _, _, err := gossh.ParseAuthorizedKey([]byte(caKey)) - if err != nil { - log.Fatal("Failed to parse TrustedUserCaKeys: %s %v", caKey, err) - } - - SSH.TrustedUserCAKeysParsed = append(SSH.TrustedUserCAKeysParsed, pubKey) - } - if len(SSH.TrustedUserCAKeys) > 0 { - // Set the default as email,username otherwise we can leave it empty - sec.Key("SSH_AUTHORIZED_PRINCIPALS_ALLOW").MustString("username,email") - } else { - sec.Key("SSH_AUTHORIZED_PRINCIPALS_ALLOW").MustString("off") - } - - SSH.AuthorizedPrincipalsAllow, SSH.AuthorizedPrincipalsEnabled = parseAuthorizedPrincipalsAllow(sec.Key("SSH_AUTHORIZED_PRINCIPALS_ALLOW").Strings(",")) - - SSH.MinimumKeySizeCheck = sec.Key("MINIMUM_KEY_SIZE_CHECK").MustBool(SSH.MinimumKeySizeCheck) - minimumKeySizes := Cfg.Section("ssh.minimum_key_sizes").Keys() - for _, key := range minimumKeySizes { - if key.MustInt() != -1 { - SSH.MinimumKeySizes[strings.ToLower(key.Name())] = key.MustInt() - } else { - delete(SSH.MinimumKeySizes, strings.ToLower(key.Name())) - } - } - - SSH.AuthorizedKeysBackup = sec.Key("SSH_AUTHORIZED_KEYS_BACKUP").MustBool(true) - SSH.CreateAuthorizedKeysFile = sec.Key("SSH_CREATE_AUTHORIZED_KEYS_FILE").MustBool(true) - - SSH.AuthorizedPrincipalsBackup = false - SSH.CreateAuthorizedPrincipalsFile = false - if SSH.AuthorizedPrincipalsEnabled { - SSH.AuthorizedPrincipalsBackup = sec.Key("SSH_AUTHORIZED_PRINCIPALS_BACKUP").MustBool(true) - SSH.CreateAuthorizedPrincipalsFile = sec.Key("SSH_CREATE_AUTHORIZED_PRINCIPALS_FILE").MustBool(true) - } - - SSH.ExposeAnonymous = sec.Key("SSH_EXPOSE_ANONYMOUS").MustBool(false) - SSH.AuthorizedKeysCommandTemplate = sec.Key("SSH_AUTHORIZED_KEYS_COMMAND_TEMPLATE").MustString(SSH.AuthorizedKeysCommandTemplate) - - SSH.AuthorizedKeysCommandTemplateTemplate = template.Must(template.New("").Parse(SSH.AuthorizedKeysCommandTemplate)) - - SSH.PerWriteTimeout = sec.Key("SSH_PER_WRITE_TIMEOUT").MustDuration(PerWriteTimeout) - SSH.PerWritePerKbTimeout = sec.Key("SSH_PER_WRITE_PER_KB_TIMEOUT").MustDuration(PerWritePerKbTimeout) - - if err = Cfg.Section("oauth2").MapTo(&OAuth2); err != nil { - log.Fatal("Failed to OAuth2 settings: %v", err) - return - } - - if !filepath.IsAbs(OAuth2.JWTSigningPrivateKeyFile) { - OAuth2.JWTSigningPrivateKeyFile = filepath.Join(AppDataPath, OAuth2.JWTSigningPrivateKeyFile) - } - - sec = Cfg.Section("admin") - Admin.DefaultEmailNotification = sec.Key("DEFAULT_EMAIL_NOTIFICATIONS").MustString("enabled") - - sec = Cfg.Section("security") - InstallLock = sec.Key("INSTALL_LOCK").MustBool(false) - LogInRememberDays = sec.Key("LOGIN_REMEMBER_DAYS").MustInt(7) - CookieUserName = sec.Key("COOKIE_USERNAME").MustString("gitea_awesome") - SecretKey = loadSecret(sec, "SECRET_KEY_URI", "SECRET_KEY") - if SecretKey == "" { - // FIXME: https://github.com/go-gitea/gitea/issues/16832 - // Until it supports rotating an existing secret key, we shouldn't move users off of the widely used default value - SecretKey = "!#@FDEWREWR&*(" //nolint:gosec - } - - CookieRememberName = sec.Key("COOKIE_REMEMBER_NAME").MustString("gitea_incredible") - - ReverseProxyAuthUser = sec.Key("REVERSE_PROXY_AUTHENTICATION_USER").MustString("X-WEBAUTH-USER") - ReverseProxyAuthEmail = sec.Key("REVERSE_PROXY_AUTHENTICATION_EMAIL").MustString("X-WEBAUTH-EMAIL") - ReverseProxyAuthFullName = sec.Key("REVERSE_PROXY_AUTHENTICATION_FULL_NAME").MustString("X-WEBAUTH-FULLNAME") - - ReverseProxyLimit = sec.Key("REVERSE_PROXY_LIMIT").MustInt(1) - ReverseProxyTrustedProxies = sec.Key("REVERSE_PROXY_TRUSTED_PROXIES").Strings(",") - if len(ReverseProxyTrustedProxies) == 0 { - ReverseProxyTrustedProxies = []string{"127.0.0.0/8", "::1/128"} - } - - MinPasswordLength = sec.Key("MIN_PASSWORD_LENGTH").MustInt(6) - ImportLocalPaths = sec.Key("IMPORT_LOCAL_PATHS").MustBool(false) - DisableGitHooks = sec.Key("DISABLE_GIT_HOOKS").MustBool(true) - DisableWebhooks = sec.Key("DISABLE_WEBHOOKS").MustBool(false) - OnlyAllowPushIfGiteaEnvironmentSet = sec.Key("ONLY_ALLOW_PUSH_IF_GITEA_ENVIRONMENT_SET").MustBool(true) - PasswordHashAlgo = sec.Key("PASSWORD_HASH_ALGO").MustString("pbkdf2") - CSRFCookieHTTPOnly = sec.Key("CSRF_COOKIE_HTTP_ONLY").MustBool(true) - PasswordCheckPwn = sec.Key("PASSWORD_CHECK_PWN").MustBool(false) - SuccessfulTokensCacheSize = sec.Key("SUCCESSFUL_TOKENS_CACHE_SIZE").MustInt(20) - - InternalToken = loadSecret(sec, "INTERNAL_TOKEN_URI", "INTERNAL_TOKEN") - if InstallLock && InternalToken == "" { - // if Gitea has been installed but the InternalToken hasn't been generated (upgrade from an old release), we should generate - // some users do cluster deployment, they still depend on this auto-generating behavior. - generateSaveInternalToken() - } - - cfgdata := sec.Key("PASSWORD_COMPLEXITY").Strings(",") - if len(cfgdata) == 0 { - cfgdata = []string{"off"} - } - PasswordComplexity = make([]string, 0, len(cfgdata)) - for _, name := range cfgdata { - name := strings.ToLower(strings.Trim(name, `"`)) - if name != "" { - PasswordComplexity = append(PasswordComplexity, name) - } - } - - newAttachmentService() - newLFSService() - - timeFormatKey := Cfg.Section("time").Key("FORMAT").MustString("") - if timeFormatKey != "" { - TimeFormat = map[string]string{ - "ANSIC": time.ANSIC, - "UnixDate": time.UnixDate, - "RubyDate": time.RubyDate, - "RFC822": time.RFC822, - "RFC822Z": time.RFC822Z, - "RFC850": time.RFC850, - "RFC1123": time.RFC1123, - "RFC1123Z": time.RFC1123Z, - "RFC3339": time.RFC3339, - "RFC3339Nano": time.RFC3339Nano, - "Kitchen": time.Kitchen, - "Stamp": time.Stamp, - "StampMilli": time.StampMilli, - "StampMicro": time.StampMicro, - "StampNano": time.StampNano, - }[timeFormatKey] - // When the TimeFormatKey does not exist in the previous map e.g.'2006-01-02 15:04:05' - if len(TimeFormat) == 0 { - TimeFormat = timeFormatKey - TestTimeFormat, _ := time.Parse(TimeFormat, TimeFormat) - if TestTimeFormat.Format(time.RFC3339) != "2006-01-02T15:04:05Z" { - log.Warn("Provided TimeFormat: %s does not create a fully specified date and time.", TimeFormat) - log.Warn("In order to display dates and times correctly please check your time format has 2006, 01, 02, 15, 04 and 05") - } - log.Trace("Custom TimeFormat: %s", TimeFormat) - } - } - - zone := Cfg.Section("time").Key("DEFAULT_UI_LOCATION").String() - if zone != "" { - DefaultUILocation, err = time.LoadLocation(zone) - if err != nil { - log.Fatal("Load time zone failed: %v", err) - } else { - log.Info("Default UI Location is %v", zone) - } - } - if DefaultUILocation == nil { - DefaultUILocation = time.Local - } - - RunUser = Cfg.Section("").Key("RUN_USER").MustString(user.CurrentUsername()) - // The following is a purposefully undocumented option. Please do not run Gitea as root. It will only cause future headaches. - // Please don't use root as a bandaid to "fix" something that is broken, instead the broken thing should instead be fixed properly. - unsafeAllowRunAsRoot := Cfg.Section("").Key("I_AM_BEING_UNSAFE_RUNNING_AS_ROOT").MustBool(false) - RunMode = os.Getenv("GITEA_RUN_MODE") - if RunMode == "" { - RunMode = Cfg.Section("").Key("RUN_MODE").MustString("prod") - } - IsProd = strings.EqualFold(RunMode, "prod") - // Does not check run user when the install lock is off. - if InstallLock { - currentUser, match := IsRunUserMatchCurrentUser(RunUser) - if !match { - log.Fatal("Expect user '%s' but current user is: %s", RunUser, currentUser) - } - } - - // check if we run as root - if os.Getuid() == 0 { - if !unsafeAllowRunAsRoot { - // Special thanks to VLC which inspired the wording of this messaging. - log.Fatal("Gitea is not supposed to be run as root. Sorry. If you need to use privileged TCP ports please instead use setcap and the `cap_net_bind_service` permission") - } - log.Critical("You are running Gitea using the root user, and have purposely chosen to skip built-in protections around this. You have been warned against this.") - } - - SSH.BuiltinServerUser = Cfg.Section("server").Key("BUILTIN_SSH_SERVER_USER").MustString(RunUser) - SSH.User = Cfg.Section("server").Key("SSH_USER").MustString(SSH.BuiltinServerUser) - - newRepository() - - newPictureService() - - newPackages() - - if err = Cfg.Section("ui").MapTo(&UI); err != nil { - log.Fatal("Failed to map UI settings: %v", err) - } else if err = Cfg.Section("markdown").MapTo(&Markdown); err != nil { - log.Fatal("Failed to map Markdown settings: %v", err) - } else if err = Cfg.Section("admin").MapTo(&Admin); err != nil { - log.Fatal("Fail to map Admin settings: %v", err) - } else if err = Cfg.Section("api").MapTo(&API); err != nil { - log.Fatal("Failed to map API settings: %v", err) - } else if err = Cfg.Section("metrics").MapTo(&Metrics); err != nil { - log.Fatal("Failed to map Metrics settings: %v", err) - } else if err = Cfg.Section("camo").MapTo(&Camo); err != nil { - log.Fatal("Failed to map Camo settings: %v", err) - } - - if Camo.Enabled { - if Camo.ServerURL == "" || Camo.HMACKey == "" { - log.Fatal(`Camo settings require "SERVER_URL" and HMAC_KEY`) - } - } - - u := *appURL - u.Path = path.Join(u.Path, "api", "swagger") - API.SwaggerURL = u.String() - - newGit() - - newMirror() - - Langs = Cfg.Section("i18n").Key("LANGS").Strings(",") - if len(Langs) == 0 { - Langs = defaultI18nLangs() - } - Names = Cfg.Section("i18n").Key("NAMES").Strings(",") - if len(Names) == 0 { - Names = defaultI18nNames() - } - - ShowFooterBranding = Cfg.Section("other").Key("SHOW_FOOTER_BRANDING").MustBool(false) - ShowFooterVersion = Cfg.Section("other").Key("SHOW_FOOTER_VERSION").MustBool(true) - ShowFooterTemplateLoadTime = Cfg.Section("other").Key("SHOW_FOOTER_TEMPLATE_LOAD_TIME").MustBool(true) - EnableSitemap = Cfg.Section("other").Key("ENABLE_SITEMAP").MustBool(true) - EnableFeed = Cfg.Section("other").Key("ENABLE_FEED").MustBool(true) - - UI.ShowUserEmail = Cfg.Section("ui").Key("SHOW_USER_EMAIL").MustBool(true) - UI.DefaultShowFullName = Cfg.Section("ui").Key("DEFAULT_SHOW_FULL_NAME").MustBool(false) - UI.SearchRepoDescription = Cfg.Section("ui").Key("SEARCH_REPO_DESCRIPTION").MustBool(true) - UI.UseServiceWorker = Cfg.Section("ui").Key("USE_SERVICE_WORKER").MustBool(false) - UI.OnlyShowRelevantRepos = Cfg.Section("ui").Key("ONLY_SHOW_RELEVANT_REPOS").MustBool(false) - - HasRobotsTxt, err = util.IsFile(path.Join(CustomPath, "robots.txt")) - if err != nil { - log.Error("Unable to check if %s is a file. Error: %v", path.Join(CustomPath, "robots.txt"), err) - } - - newMarkup() - - UI.ReactionsLookup = make(container.Set[string]) - for _, reaction := range UI.Reactions { - UI.ReactionsLookup.Add(reaction) - } - UI.CustomEmojisMap = make(map[string]string) - for _, emoji := range UI.CustomEmojis { - UI.CustomEmojisMap[emoji] = ":" + emoji + ":" - } -} - -func parseAuthorizedPrincipalsAllow(values []string) ([]string, bool) { - anything := false - email := false - username := false - for _, value := range values { - v := strings.ToLower(strings.TrimSpace(value)) - switch v { - case "off": - return []string{"off"}, false - case "email": - email = true - case "username": - username = true - case "anything": - anything = true - } - } - if anything { - return []string{"anything"}, true - } - - authorizedPrincipalsAllow := []string{} - if username { - authorizedPrincipalsAllow = append(authorizedPrincipalsAllow, "username") - } - if email { - authorizedPrincipalsAllow = append(authorizedPrincipalsAllow, "email") - } - - return authorizedPrincipalsAllow, true -} - -// loadSecret load the secret from ini by uriKey or verbatimKey, only one of them could be set -// If the secret is loaded from uriKey (file), the file should be non-empty, to guarantee the behavior stable and clear. -func loadSecret(sec *ini.Section, uriKey, verbatimKey string) string { - // don't allow setting both URI and verbatim string - uri := sec.Key(uriKey).String() - verbatim := sec.Key(verbatimKey).String() - if uri != "" && verbatim != "" { - log.Fatal("Cannot specify both %s and %s", uriKey, verbatimKey) - } - - // if we have no URI, use verbatim - if uri == "" { - return verbatim - } - - tempURI, err := url.Parse(uri) - if err != nil { - log.Fatal("Failed to parse %s (%s): %v", uriKey, uri, err) - } - switch tempURI.Scheme { - case "file": - buf, err := os.ReadFile(tempURI.RequestURI()) - if err != nil { - log.Fatal("Failed to read %s (%s): %v", uriKey, tempURI.RequestURI(), err) - } - val := strings.TrimSpace(string(buf)) - if val == "" { - // The file shouldn't be empty, otherwise we can not know whether the user has ever set the KEY or KEY_URI - // For example: if INTERNAL_TOKEN_URI=file:///empty-file, - // Then if the token is re-generated during installation and saved to INTERNAL_TOKEN - // Then INTERNAL_TOKEN and INTERNAL_TOKEN_URI both exist, that's a fatal error (they shouldn't) - log.Fatal("Failed to read %s (%s): the file is empty", uriKey, tempURI.RequestURI()) - } - return val - - // only file URIs are allowed - default: - log.Fatal("Unsupported URI-Scheme %q (INTERNAL_TOKEN_URI = %q)", tempURI.Scheme, uri) - return "" - } -} - -// generateSaveInternalToken generates and saves the internal token to app.ini -func generateSaveInternalToken() { - token, err := generate.NewInternalToken() - if err != nil { - log.Fatal("Error generate internal token: %v", err) - } - - InternalToken = token - CreateOrAppendToCustomConf("security.INTERNAL_TOKEN", func(cfg *ini.File) { - cfg.Section("security").Key("INTERNAL_TOKEN").SetValue(token) - }) -} - -// MakeAbsoluteAssetURL returns the absolute asset url prefix without a trailing slash -func MakeAbsoluteAssetURL(appURL, staticURLPrefix string) string { - parsedPrefix, err := url.Parse(strings.TrimSuffix(staticURLPrefix, "/")) - if err != nil { - log.Fatal("Unable to parse STATIC_URL_PREFIX: %v", err) - } - - if err == nil && parsedPrefix.Hostname() == "" { - if staticURLPrefix == "" { - return strings.TrimSuffix(appURL, "/") - } - - // StaticURLPrefix is just a path - return util.URLJoin(appURL, strings.TrimSuffix(staticURLPrefix, "/")) - } - - return strings.TrimSuffix(staticURLPrefix, "/") -} - -// MakeManifestData generates web app manifest JSON -func MakeManifestData(appName, appURL, absoluteAssetURL string) []byte { - type manifestIcon struct { - Src string `json:"src"` - Type string `json:"type"` - Sizes string `json:"sizes"` - } - - type manifestJSON struct { - Name string `json:"name"` - ShortName string `json:"short_name"` - StartURL string `json:"start_url"` - Icons []manifestIcon `json:"icons"` - } - - bytes, err := json.Marshal(&manifestJSON{ - Name: appName, - ShortName: appName, - StartURL: appURL, - Icons: []manifestIcon{ - { - Src: absoluteAssetURL + "/assets/img/logo.png", - Type: "image/png", - Sizes: "512x512", - }, - { - Src: absoluteAssetURL + "/assets/img/logo.svg", - Type: "image/svg+xml", - Sizes: "512x512", - }, - }, - }) - if err != nil { - log.Error("unable to marshal manifest JSON. Error: %v", err) - return make([]byte, 0) - } - - return bytes + parseServerSetting(Cfg) + parseSSHSetting(Cfg) + parseOAuth2Setting(Cfg) + parseSecuritySetting(Cfg) + parseAttachmentSetting(Cfg) + parseLFSSetting(Cfg) + parseTimeSetting(Cfg) + parseRepositorySetting(Cfg) + parsePictureSetting(Cfg) + parsePackagesSetting(Cfg) + parseUISetting(Cfg) + parseAdminSetting(Cfg) + parseAPISetting(Cfg) + parseMetricsSetting(Cfg) + parseI18nSetting(Cfg) + parseGitSetting(Cfg) + parseMirrorSetting(Cfg) + parseMarkupSetting(Cfg) } // CreateOrAppendToCustomConf creates or updates the custom config. @@ -1331,31 +386,34 @@ func CreateOrAppendToCustomConf(purpose string, callback func(cfg *ini.File)) { } } -// NewServices initializes the services -func NewServices() { - InitDBConfig() - newService() - newOAuth2Client() - NewLogServices(false) - newCacheService() - newSessionService() - newCORSService() - newMailService() - newRegisterMailService() - newNotifyMailService() - newProxyService() - newWebhookService() - newMigrationsService() - newIndexerService() - newTaskService() - NewQueueService() - newProject() - newMimeTypeMap() - newFederationService() +// LoadSettings initializes the settings for normal start up +func LoadSettings() { + ParseDBSetting() + parseServiceSetting(Cfg) + parseOAuth2ClientSetting(Cfg) + ParseLogSettings(false) + parseCacheSetting(Cfg) + parseSessionSetting(Cfg) + mustMapSetting(Cfg, "cors", &CORSConfig) + if CORSConfig.Enabled { + log.Info("CORS Service Enabled") + } + + parseMailSettings(Cfg) + parseProxySetting(Cfg) + parseWebhookSetting(Cfg) + parseMigrationsSetting(Cfg) + parseIndexerSetting(Cfg) + parseTaskSetting(Cfg) + ParseQueueSettings() + mustMapSetting(Cfg, "project", &Project) + parseMimeTypeMap(Cfg) + parseFederationSetting(Cfg) } -// NewServicesForInstall initializes the services for install -func NewServicesForInstall() { - newService() - newMailService() +// LoadSettingsForInstall initializes the settings for install +func LoadSettingsForInstall() { + ParseDBSetting() + parseServiceSetting(Cfg) + parseMailerSetting(Cfg) } diff --git a/modules/setting/ssh.go b/modules/setting/ssh.go new file mode 100644 index 000000000000..1121c91e2f01 --- /dev/null +++ b/modules/setting/ssh.go @@ -0,0 +1,193 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package setting + +import ( + "os" + "path" + "path/filepath" + "strings" + "text/template" + "time" + + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/util" + + gossh "golang.org/x/crypto/ssh" +) + +var SSH = struct { + Disabled bool `ini:"DISABLE_SSH"` + StartBuiltinServer bool `ini:"START_SSH_SERVER"` + BuiltinServerUser string `ini:"BUILTIN_SSH_SERVER_USER"` + UseProxyProtocol bool `ini:"SSH_SERVER_USE_PROXY_PROTOCOL"` + Domain string `ini:"SSH_DOMAIN"` + Port int `ini:"SSH_PORT"` + User string `ini:"SSH_USER"` + ListenHost string `ini:"SSH_LISTEN_HOST"` + ListenPort int `ini:"SSH_LISTEN_PORT"` + RootPath string `ini:"SSH_ROOT_PATH"` + ServerCiphers []string `ini:"SSH_SERVER_CIPHERS"` + ServerKeyExchanges []string `ini:"SSH_SERVER_KEY_EXCHANGES"` + ServerMACs []string `ini:"SSH_SERVER_MACS"` + ServerHostKeys []string `ini:"SSH_SERVER_HOST_KEYS"` + KeyTestPath string `ini:"SSH_KEY_TEST_PATH"` + KeygenPath string `ini:"SSH_KEYGEN_PATH"` + AuthorizedKeysBackup bool `ini:"SSH_AUTHORIZED_KEYS_BACKUP"` + AuthorizedPrincipalsBackup bool `ini:"SSH_AUTHORIZED_PRINCIPALS_BACKUP"` + AuthorizedKeysCommandTemplate string `ini:"SSH_AUTHORIZED_KEYS_COMMAND_TEMPLATE"` + AuthorizedKeysCommandTemplateTemplate *template.Template `ini:"-"` + MinimumKeySizeCheck bool `ini:"-"` + MinimumKeySizes map[string]int `ini:"-"` + CreateAuthorizedKeysFile bool `ini:"SSH_CREATE_AUTHORIZED_KEYS_FILE"` + CreateAuthorizedPrincipalsFile bool `ini:"SSH_CREATE_AUTHORIZED_PRINCIPALS_FILE"` + ExposeAnonymous bool `ini:"SSH_EXPOSE_ANONYMOUS"` + AuthorizedPrincipalsAllow []string `ini:"SSH_AUTHORIZED_PRINCIPALS_ALLOW"` + AuthorizedPrincipalsEnabled bool `ini:"-"` + TrustedUserCAKeys []string `ini:"SSH_TRUSTED_USER_CA_KEYS"` + TrustedUserCAKeysFile string `ini:"SSH_TRUSTED_USER_CA_KEYS_FILENAME"` + TrustedUserCAKeysParsed []gossh.PublicKey `ini:"-"` + PerWriteTimeout time.Duration `ini:"SSH_PER_WRITE_TIMEOUT"` + PerWritePerKbTimeout time.Duration `ini:"SSH_PER_WRITE_PER_KB_TIMEOUT"` +}{ + Disabled: false, + StartBuiltinServer: false, + Domain: "", + Port: 22, + ServerCiphers: []string{"chacha20-poly1305@openssh.com", "aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-gcm@openssh.com", "aes256-gcm@openssh.com"}, + ServerKeyExchanges: []string{"curve25519-sha256", "ecdh-sha2-nistp256", "ecdh-sha2-nistp384", "ecdh-sha2-nistp521", "diffie-hellman-group14-sha256", "diffie-hellman-group14-sha1"}, + ServerMACs: []string{"hmac-sha2-256-etm@openssh.com", "hmac-sha2-256", "hmac-sha1"}, + KeygenPath: "ssh-keygen", + MinimumKeySizeCheck: true, + MinimumKeySizes: map[string]int{"ed25519": 256, "ed25519-sk": 256, "ecdsa": 256, "ecdsa-sk": 256, "rsa": 2047}, + ServerHostKeys: []string{"ssh/gitea.rsa", "ssh/gogs.rsa"}, + AuthorizedKeysCommandTemplate: "{{.AppPath}} --config={{.CustomConf}} serv key-{{.Key.ID}}", + PerWriteTimeout: PerWriteTimeout, + PerWritePerKbTimeout: PerWritePerKbTimeout, +} + +func parseAuthorizedPrincipalsAllow(values []string) ([]string, bool) { + anything := false + email := false + username := false + for _, value := range values { + v := strings.ToLower(strings.TrimSpace(value)) + switch v { + case "off": + return []string{"off"}, false + case "email": + email = true + case "username": + username = true + case "anything": + anything = true + } + } + if anything { + return []string{"anything"}, true + } + + authorizedPrincipalsAllow := []string{} + if username { + authorizedPrincipalsAllow = append(authorizedPrincipalsAllow, "username") + } + if email { + authorizedPrincipalsAllow = append(authorizedPrincipalsAllow, "email") + } + + return authorizedPrincipalsAllow, true +} + +func parseSSHSetting(rootCfg Config) { + sec := rootCfg.Section("server") + if len(SSH.Domain) == 0 { + SSH.Domain = Domain + } + + homeDir, err := util.HomeDir() + if err != nil { + log.Fatal("Failed to get home directory: %v", err) + } + homeDir = strings.ReplaceAll(homeDir, "\\", "/") + + SSH.RootPath = path.Join(homeDir, ".ssh") + serverCiphers := sec.Key("SSH_SERVER_CIPHERS").Strings(",") + if len(serverCiphers) > 0 { + SSH.ServerCiphers = serverCiphers + } + serverKeyExchanges := sec.Key("SSH_SERVER_KEY_EXCHANGES").Strings(",") + if len(serverKeyExchanges) > 0 { + SSH.ServerKeyExchanges = serverKeyExchanges + } + serverMACs := sec.Key("SSH_SERVER_MACS").Strings(",") + if len(serverMACs) > 0 { + SSH.ServerMACs = serverMACs + } + SSH.KeyTestPath = os.TempDir() + if err = Cfg.Section("server").MapTo(&SSH); err != nil { + log.Fatal("Failed to map SSH settings: %v", err) + } + for i, key := range SSH.ServerHostKeys { + if !filepath.IsAbs(key) { + SSH.ServerHostKeys[i] = filepath.Join(AppDataPath, key) + } + } + + SSH.KeygenPath = sec.Key("SSH_KEYGEN_PATH").MustString("ssh-keygen") + SSH.Port = sec.Key("SSH_PORT").MustInt(22) + SSH.ListenPort = sec.Key("SSH_LISTEN_PORT").MustInt(SSH.Port) + SSH.UseProxyProtocol = sec.Key("SSH_SERVER_USE_PROXY_PROTOCOL").MustBool(false) + + // When disable SSH, start builtin server value is ignored. + if SSH.Disabled { + SSH.StartBuiltinServer = false + } + + SSH.TrustedUserCAKeysFile = sec.Key("SSH_TRUSTED_USER_CA_KEYS_FILENAME").MustString(filepath.Join(SSH.RootPath, "gitea-trusted-user-ca-keys.pem")) + + for _, caKey := range SSH.TrustedUserCAKeys { + pubKey, _, _, _, err := gossh.ParseAuthorizedKey([]byte(caKey)) + if err != nil { + log.Fatal("Failed to parse TrustedUserCaKeys: %s %v", caKey, err) + } + + SSH.TrustedUserCAKeysParsed = append(SSH.TrustedUserCAKeysParsed, pubKey) + } + if len(SSH.TrustedUserCAKeys) > 0 { + // Set the default as email,username otherwise we can leave it empty + sec.Key("SSH_AUTHORIZED_PRINCIPALS_ALLOW").MustString("username,email") + } else { + sec.Key("SSH_AUTHORIZED_PRINCIPALS_ALLOW").MustString("off") + } + + SSH.AuthorizedPrincipalsAllow, SSH.AuthorizedPrincipalsEnabled = parseAuthorizedPrincipalsAllow(sec.Key("SSH_AUTHORIZED_PRINCIPALS_ALLOW").Strings(",")) + + SSH.MinimumKeySizeCheck = sec.Key("MINIMUM_KEY_SIZE_CHECK").MustBool(SSH.MinimumKeySizeCheck) + minimumKeySizes := Cfg.Section("ssh.minimum_key_sizes").Keys() + for _, key := range minimumKeySizes { + if key.MustInt() != -1 { + SSH.MinimumKeySizes[strings.ToLower(key.Name())] = key.MustInt() + } else { + delete(SSH.MinimumKeySizes, strings.ToLower(key.Name())) + } + } + + SSH.AuthorizedKeysBackup = sec.Key("SSH_AUTHORIZED_KEYS_BACKUP").MustBool(true) + SSH.CreateAuthorizedKeysFile = sec.Key("SSH_CREATE_AUTHORIZED_KEYS_FILE").MustBool(true) + + SSH.AuthorizedPrincipalsBackup = false + SSH.CreateAuthorizedPrincipalsFile = false + if SSH.AuthorizedPrincipalsEnabled { + SSH.AuthorizedPrincipalsBackup = sec.Key("SSH_AUTHORIZED_PRINCIPALS_BACKUP").MustBool(true) + SSH.CreateAuthorizedPrincipalsFile = sec.Key("SSH_CREATE_AUTHORIZED_PRINCIPALS_FILE").MustBool(true) + } + + SSH.ExposeAnonymous = sec.Key("SSH_EXPOSE_ANONYMOUS").MustBool(false) + SSH.AuthorizedKeysCommandTemplate = sec.Key("SSH_AUTHORIZED_KEYS_COMMAND_TEMPLATE").MustString(SSH.AuthorizedKeysCommandTemplate) + + SSH.AuthorizedKeysCommandTemplateTemplate = template.Must(template.New("").Parse(SSH.AuthorizedKeysCommandTemplate)) + + SSH.PerWriteTimeout = sec.Key("SSH_PER_WRITE_TIMEOUT").MustDuration(PerWriteTimeout) + SSH.PerWritePerKbTimeout = sec.Key("SSH_PER_WRITE_PER_KB_TIMEOUT").MustDuration(PerWritePerKbTimeout) +} diff --git a/modules/setting/task.go b/modules/setting/task.go index cfb0f5466840..35dac48c4fc8 100644 --- a/modules/setting/task.go +++ b/modules/setting/task.go @@ -5,9 +5,9 @@ package setting // FIXME: DEPRECATED to be removed in v1.18.0 // - will need to set default for [queue.task] LENGTH to 1000 though -func newTaskService() { - taskSec := Cfg.Section("task") - queueTaskSec := Cfg.Section("queue.task") +func parseTaskSetting(rootCfg Config) { + taskSec := rootCfg.Section("task") + queueTaskSec := rootCfg.Section("queue.task") deprecatedSetting("task", "QUEUE_TYPE", "queue.task", "TYPE") deprecatedSetting("task", "QUEUE_CONN_STR", "queue.task", "CONN_STR") diff --git a/modules/setting/time.go b/modules/setting/time.go new file mode 100644 index 000000000000..864aa1c65904 --- /dev/null +++ b/modules/setting/time.go @@ -0,0 +1,64 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package setting + +import ( + "time" + + "code.gitea.io/gitea/modules/log" +) + +var ( + // Time settings + TimeFormat string + // UILocation is the location on the UI, so that we can display the time on UI. + DefaultUILocation = time.Local +) + +func parseTimeSetting(rootCfg Config) { + timeFormatKey := rootCfg.Section("time").Key("FORMAT").MustString("") + if timeFormatKey != "" { + TimeFormat = map[string]string{ + "ANSIC": time.ANSIC, + "UnixDate": time.UnixDate, + "RubyDate": time.RubyDate, + "RFC822": time.RFC822, + "RFC822Z": time.RFC822Z, + "RFC850": time.RFC850, + "RFC1123": time.RFC1123, + "RFC1123Z": time.RFC1123Z, + "RFC3339": time.RFC3339, + "RFC3339Nano": time.RFC3339Nano, + "Kitchen": time.Kitchen, + "Stamp": time.Stamp, + "StampMilli": time.StampMilli, + "StampMicro": time.StampMicro, + "StampNano": time.StampNano, + }[timeFormatKey] + // When the TimeFormatKey does not exist in the previous map e.g.'2006-01-02 15:04:05' + if len(TimeFormat) == 0 { + TimeFormat = timeFormatKey + TestTimeFormat, _ := time.Parse(TimeFormat, TimeFormat) + if TestTimeFormat.Format(time.RFC3339) != "2006-01-02T15:04:05Z" { + log.Warn("Provided TimeFormat: %s does not create a fully specified date and time.", TimeFormat) + log.Warn("In order to display dates and times correctly please check your time format has 2006, 01, 02, 15, 04 and 05") + } + log.Trace("Custom TimeFormat: %s", TimeFormat) + } + } + + zone := rootCfg.Section("time").Key("DEFAULT_UI_LOCATION").String() + if zone != "" { + var err error + DefaultUILocation, err = time.LoadLocation(zone) + if err != nil { + log.Fatal("Load time zone failed: %v", err) + } else { + log.Info("Default UI Location is %v", zone) + } + } + if DefaultUILocation == nil { + DefaultUILocation = time.Local + } +} diff --git a/modules/setting/ui.go b/modules/setting/ui.go new file mode 100644 index 000000000000..3c2d1cd529b6 --- /dev/null +++ b/modules/setting/ui.go @@ -0,0 +1,161 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package setting + +import ( + "path" + "time" + + "code.gitea.io/gitea/modules/container" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/util" +) + +// UI settings +var UI = struct { + ExplorePagingNum int + SitemapPagingNum int + IssuePagingNum int + RepoSearchPagingNum int + MembersPagingNum int + FeedMaxCommitNum int + FeedPagingNum int + PackagesPagingNum int + GraphMaxCommitNum int + CodeCommentLines int + ReactionMaxUserNum int + ThemeColorMetaTag string + MaxDisplayFileSize int64 + ShowUserEmail bool + DefaultShowFullName bool + DefaultTheme string + Themes []string + Reactions []string + ReactionsLookup container.Set[string] `ini:"-"` + CustomEmojis []string + CustomEmojisMap map[string]string `ini:"-"` + SearchRepoDescription bool + UseServiceWorker bool + OnlyShowRelevantRepos bool + + Notification struct { + MinTimeout time.Duration + TimeoutStep time.Duration + MaxTimeout time.Duration + EventSourceUpdateTime time.Duration + } `ini:"ui.notification"` + + SVG struct { + Enabled bool `ini:"ENABLE_RENDER"` + } `ini:"ui.svg"` + + CSV struct { + MaxFileSize int64 + } `ini:"ui.csv"` + + Admin struct { + UserPagingNum int + RepoPagingNum int + NoticePagingNum int + OrgPagingNum int + } `ini:"ui.admin"` + User struct { + RepoPagingNum int + } `ini:"ui.user"` + Meta struct { + Author string + Description string + Keywords string + } `ini:"ui.meta"` +}{ + ExplorePagingNum: 20, + SitemapPagingNum: 20, + IssuePagingNum: 20, + RepoSearchPagingNum: 20, + MembersPagingNum: 20, + FeedMaxCommitNum: 5, + FeedPagingNum: 20, + PackagesPagingNum: 20, + GraphMaxCommitNum: 100, + CodeCommentLines: 4, + ReactionMaxUserNum: 10, + ThemeColorMetaTag: `#6cc644`, + MaxDisplayFileSize: 8388608, + DefaultTheme: `auto`, + Themes: []string{`auto`, `gitea`, `arc-green`}, + Reactions: []string{`+1`, `-1`, `laugh`, `hooray`, `confused`, `heart`, `rocket`, `eyes`}, + CustomEmojis: []string{`git`, `gitea`, `codeberg`, `gitlab`, `github`, `gogs`}, + CustomEmojisMap: map[string]string{"git": ":git:", "gitea": ":gitea:", "codeberg": ":codeberg:", "gitlab": ":gitlab:", "github": ":github:", "gogs": ":gogs:"}, + Notification: struct { + MinTimeout time.Duration + TimeoutStep time.Duration + MaxTimeout time.Duration + EventSourceUpdateTime time.Duration + }{ + MinTimeout: 10 * time.Second, + TimeoutStep: 10 * time.Second, + MaxTimeout: 60 * time.Second, + EventSourceUpdateTime: 10 * time.Second, + }, + SVG: struct { + Enabled bool `ini:"ENABLE_RENDER"` + }{ + Enabled: true, + }, + CSV: struct { + MaxFileSize int64 + }{ + MaxFileSize: 524288, + }, + Admin: struct { + UserPagingNum int + RepoPagingNum int + NoticePagingNum int + OrgPagingNum int + }{ + UserPagingNum: 50, + RepoPagingNum: 50, + NoticePagingNum: 25, + OrgPagingNum: 50, + }, + User: struct { + RepoPagingNum int + }{ + RepoPagingNum: 15, + }, + Meta: struct { + Author string + Description string + Keywords string + }{ + Author: "Gitea - Git with a cup of tea", + Description: "Gitea (Git with a cup of tea) is a painless self-hosted Git service written in Go", + Keywords: "go,git,self-hosted,gitea", + }, +} + +func parseUISetting(rootCfg Config) { + mustMapSetting(rootCfg, "ui", &UI) + sec := rootCfg.Section("ui") + UI.ShowUserEmail = sec.Key("SHOW_USER_EMAIL").MustBool(true) + UI.DefaultShowFullName = sec.Key("DEFAULT_SHOW_FULL_NAME").MustBool(false) + UI.SearchRepoDescription = sec.Key("SEARCH_REPO_DESCRIPTION").MustBool(true) + UI.UseServiceWorker = sec.Key("USE_SERVICE_WORKER").MustBool(false) + UI.OnlyShowRelevantRepos = sec.Key("ONLY_SHOW_RELEVANT_REPOS").MustBool(false) + + UI.ReactionsLookup = make(container.Set[string]) + for _, reaction := range UI.Reactions { + UI.ReactionsLookup.Add(reaction) + } + UI.CustomEmojisMap = make(map[string]string) + for _, emoji := range UI.CustomEmojis { + UI.CustomEmojisMap[emoji] = ":" + emoji + ":" + } + + var err error + HasRobotsTxt, err = util.IsFile(path.Join(CustomPath, "robots.txt")) + if err != nil { + log.Error("Unable to check if %s is a file. Error: %v", path.Join(CustomPath, "robots.txt"), err) + } +} diff --git a/modules/setting/webhook.go b/modules/setting/webhook.go index 51e36c3419bd..e9a1714ee9ba 100644 --- a/modules/setting/webhook.go +++ b/modules/setting/webhook.go @@ -29,8 +29,8 @@ var Webhook = struct { ProxyHosts: []string{}, } -func newWebhookService() { - sec := Cfg.Section("webhook") +func parseWebhookSetting(rootCfg Config) { + sec := rootCfg.Section("webhook") Webhook.QueueLength = sec.Key("QUEUE_LENGTH").MustInt(1000) Webhook.DeliverTimeout = sec.Key("DELIVER_TIMEOUT").MustInt(5) Webhook.SkipTLSVerify = sec.Key("SKIP_TLS_VERIFY").MustBool() diff --git a/routers/init.go b/routers/init.go index 61af51222050..f5181aa83481 100644 --- a/routers/init.go +++ b/routers/init.go @@ -70,7 +70,7 @@ func mustInitCtx(ctx context.Context, fn func(ctx context.Context) error) { // InitGitServices init new services for git, this is also called in `contrib/pr/checkout.go` func InitGitServices() { - setting.NewServices() + setting.LoadSettings() mustInit(storage.Init) mustInit(repo_service.Init) } @@ -124,7 +124,7 @@ func GlobalInitInstalled(ctx context.Context) { // Setup i18n translation.InitLocales(ctx) - setting.NewServices() + setting.LoadSettings() mustInit(storage.Init) mailer.NewContext(ctx) diff --git a/routers/install/setting.go b/routers/install/setting.go index b76219f45d36..da3e59b95a3b 100644 --- a/routers/install/setting.go +++ b/routers/install/setting.go @@ -27,8 +27,8 @@ func PreloadSettings(ctx context.Context) bool { if setting.EnableSQLite3 { log.Info("SQLite3 is supported") } - setting.InitDBConfig() - setting.NewServicesForInstall() + + setting.LoadSettingsForInstall() svg.Init() } @@ -38,7 +38,7 @@ func PreloadSettings(ctx context.Context) bool { // reloadSettings reloads the existing settings and starts up the database func reloadSettings(ctx context.Context) { setting.LoadFromExisting() - setting.InitDBConfig() + setting.ParseDBSetting() if setting.InstallLock { if err := common.InitDBEngine(ctx); err == nil { log.Info("ORM engine initialization successful!") diff --git a/tests/integration/migration-test/migration_test.go b/tests/integration/migration-test/migration_test.go index 170a6dd444c3..e2f0c8b24705 100644 --- a/tests/integration/migration-test/migration_test.go +++ b/tests/integration/migration-test/migration_test.go @@ -83,8 +83,8 @@ func initMigrationTest(t *testing.T) func() { } assert.NoError(t, git.InitFull(context.Background())) - setting.InitDBConfig() - setting.NewLogServices(true) + setting.ParseDBSetting() + setting.ParseLogSettings(true) return deferFn } diff --git a/tests/test_utils.go b/tests/test_utils.go index 721edc86f80c..f78842834d8f 100644 --- a/tests/test_utils.go +++ b/tests/test_utils.go @@ -65,7 +65,7 @@ func InitTest(requireGitea bool) { log.Fatal("git.InitOnceWithSync: %v", err) } - setting.InitDBConfig() + setting.ParseDBSetting() if err := storage.Init(); err != nil { fmt.Printf("Init storage failed: %v", err) os.Exit(1) From 6bf6937cb5cc88b779e4c72bc7c5eb73b23e00c8 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 12 Jan 2023 00:35:36 +0800 Subject: [PATCH 02/20] Fix name --- cmd/dump.go | 2 +- modules/setting/setting.go | 8 ++++---- routers/init.go | 4 ++-- routers/install/setting.go | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cmd/dump.go b/cmd/dump.go index 909ab6d44fe7..332e317871bd 100644 --- a/cmd/dump.go +++ b/cmd/dump.go @@ -194,7 +194,7 @@ func runDump(ctx *cli.Context) error { log.Error("Is '%s' really the right config path?\n", setting.CustomConf) return fmt.Errorf("gitea is not initialized") } - setting.LoadSettings() // cannot access session settings otherwise + setting.ParseSettings() // cannot access session settings otherwise stdCtx, cancel := installSignals() defer cancel() diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 1baf8fe43a4c..02ff0e710de3 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -386,8 +386,8 @@ func CreateOrAppendToCustomConf(purpose string, callback func(cfg *ini.File)) { } } -// LoadSettings initializes the settings for normal start up -func LoadSettings() { +// ParseSettings initializes the settings for normal start up +func ParseSettings() { ParseDBSetting() parseServiceSetting(Cfg) parseOAuth2ClientSetting(Cfg) @@ -411,8 +411,8 @@ func LoadSettings() { parseFederationSetting(Cfg) } -// LoadSettingsForInstall initializes the settings for install -func LoadSettingsForInstall() { +// ParseSettingsForInstall initializes the settings for install +func ParseSettingsForInstall() { ParseDBSetting() parseServiceSetting(Cfg) parseMailerSetting(Cfg) diff --git a/routers/init.go b/routers/init.go index f5181aa83481..f205c727cb86 100644 --- a/routers/init.go +++ b/routers/init.go @@ -70,7 +70,7 @@ func mustInitCtx(ctx context.Context, fn func(ctx context.Context) error) { // InitGitServices init new services for git, this is also called in `contrib/pr/checkout.go` func InitGitServices() { - setting.LoadSettings() + setting.ParseSettings() mustInit(storage.Init) mustInit(repo_service.Init) } @@ -124,7 +124,7 @@ func GlobalInitInstalled(ctx context.Context) { // Setup i18n translation.InitLocales(ctx) - setting.LoadSettings() + setting.ParseSettings() mustInit(storage.Init) mailer.NewContext(ctx) diff --git a/routers/install/setting.go b/routers/install/setting.go index da3e59b95a3b..ae6135e32f32 100644 --- a/routers/install/setting.go +++ b/routers/install/setting.go @@ -28,7 +28,7 @@ func PreloadSettings(ctx context.Context) bool { log.Info("SQLite3 is supported") } - setting.LoadSettingsForInstall() + setting.ParseSettingsForInstall() svg.Init() } From efe1f6efbad736e6e7e7260d3d21a2e1c18a9b42 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 12 Jan 2023 16:15:54 +0800 Subject: [PATCH 03/20] fix lint --- modules/setting/mailer_test.go | 2 +- modules/setting/setting.go | 2 ++ routers/api/v1/repo/main_test.go | 2 +- services/webhook/main_test.go | 2 +- tests/integration/migration-test/migration_test.go | 2 +- 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/modules/setting/mailer_test.go b/modules/setting/mailer_test.go index 0fc9b0e73f97..480914b9b2b9 100644 --- a/modules/setting/mailer_test.go +++ b/modules/setting/mailer_test.go @@ -34,7 +34,7 @@ func TestParseMailerConfig(t *testing.T) { sec.NewKey("HOST", host) // Check mailer setting - parseMailerConfig(iniFile) + parseMailerSetting(iniFile) assert.EqualValues(t, kase.SMTPAddr, MailService.SMTPAddr) assert.EqualValues(t, kase.SMTPPort, MailService.SMTPPort) diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 02ff0e710de3..fd1fd0921c62 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -339,6 +339,8 @@ func loadFromConf(allowEmpty bool, extraConfig string) { parseGitSetting(Cfg) parseMirrorSetting(Cfg) parseMarkupSetting(Cfg) + parseOtherSetting(Cfg) + parseCamoSetting(Cfg) } // CreateOrAppendToCustomConf creates or updates the custom config. diff --git a/routers/api/v1/repo/main_test.go b/routers/api/v1/repo/main_test.go index 543fb922d6ba..f16d0f209611 100644 --- a/routers/api/v1/repo/main_test.go +++ b/routers/api/v1/repo/main_test.go @@ -14,7 +14,7 @@ import ( func TestMain(m *testing.M) { setting.LoadForTest() - setting.NewQueueService() + setting.ParseQueueSettings() unittest.MainTest(m, &unittest.TestOptions{ GiteaRootPath: filepath.Join("..", "..", "..", ".."), SetUp: webhook_service.Init, diff --git a/services/webhook/main_test.go b/services/webhook/main_test.go index 6cf9410735c8..b5b3b1f99c82 100644 --- a/services/webhook/main_test.go +++ b/services/webhook/main_test.go @@ -16,7 +16,7 @@ import ( func TestMain(m *testing.M) { setting.LoadForTest() - setting.NewQueueService() + setting.ParseQueueSettings() // for tests, allow only loopback IPs setting.Webhook.AllowedHostList = hostmatcher.MatchBuiltinLoopback diff --git a/tests/integration/migration-test/migration_test.go b/tests/integration/migration-test/migration_test.go index e2f0c8b24705..4ddc3313d7bd 100644 --- a/tests/integration/migration-test/migration_test.go +++ b/tests/integration/migration-test/migration_test.go @@ -292,7 +292,7 @@ func doMigrationTest(t *testing.T, version string) { return } - setting.NewXORMLogService(false) + setting.ParseXORMLogSetting(false) err := db.InitEngineWithMigration(context.Background(), wrappedMigrate) assert.NoError(t, err) From b9d89dd12c06f60ad8aa207e016339db1eb72a49 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 12 Jan 2023 17:15:31 +0800 Subject: [PATCH 04/20] More improvements --- modules/setting/admin.go | 2 +- modules/setting/attachment.go | 2 +- modules/setting/cache.go | 2 +- modules/setting/config.go | 3 + modules/setting/cors.go | 9 ++ modules/setting/lfs.go | 2 +- modules/setting/log.go | 55 ++++++----- modules/setting/markup.go | 2 +- modules/setting/metrics.go | 2 +- modules/setting/other.go | 3 +- modules/setting/packages.go | 2 +- modules/setting/picture.go | 4 +- modules/setting/project.go | 4 + modules/setting/repository.go | 2 +- modules/setting/security.go | 3 + modules/setting/server.go | 147 ++++++++++++++++++---------- modules/setting/setting.go | 163 +++++++++++--------------------- modules/setting/ssh.go | 8 +- modules/setting/storage.go | 10 +- modules/setting/storage_test.go | 24 ++--- modules/setting/ui.go | 9 -- 21 files changed, 236 insertions(+), 222 deletions(-) diff --git a/modules/setting/admin.go b/modules/setting/admin.go index c7cfcfd2ae47..5bbb7e283501 100644 --- a/modules/setting/admin.go +++ b/modules/setting/admin.go @@ -11,6 +11,6 @@ var Admin struct { func parseAdminSetting(rootCfg Config) { mustMapSetting(rootCfg, "admin", &Admin) - sec := Cfg.Section("admin") + sec := rootCfg.Section("admin") Admin.DefaultEmailNotification = sec.Key("DEFAULT_EMAIL_NOTIFICATIONS").MustString("enabled") } diff --git a/modules/setting/attachment.go b/modules/setting/attachment.go index 70e4bdf13b54..48452a11a85e 100644 --- a/modules/setting/attachment.go +++ b/modules/setting/attachment.go @@ -24,7 +24,7 @@ func parseAttachmentSetting(rootCfg Config) { sec := rootCfg.Section("attachment") storageType := sec.Key("STORAGE_TYPE").MustString("") - Attachment.Storage = getStorage("attachments", storageType, sec) + Attachment.Storage = getStorage(rootCfg, "attachments", storageType, sec) Attachment.AllowedTypes = sec.Key("ALLOWED_TYPES").MustString(".csv,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.xls,.xlsx,.zip") Attachment.MaxSize = sec.Key("MAX_SIZE").MustInt64(4) diff --git a/modules/setting/cache.go b/modules/setting/cache.go index 931742e2b3ca..59678b6f5486 100644 --- a/modules/setting/cache.go +++ b/modules/setting/cache.go @@ -79,7 +79,7 @@ func parseCacheSetting(rootCfg Config) { Service.EnableCaptcha = false } - sec = Cfg.Section("cache.last_commit") + sec = rootCfg.Section("cache.last_commit") if !CacheService.Enabled { CacheService.LastCommit.Enabled = false } diff --git a/modules/setting/config.go b/modules/setting/config.go index 1d57945628fb..30fb40c418da 100644 --- a/modules/setting/config.go +++ b/modules/setting/config.go @@ -5,11 +5,14 @@ package setting import ( "code.gitea.io/gitea/modules/log" + ini "gopkg.in/ini.v1" ) type Config interface { Section(section string) *ini.Section + NewSection(name string) (*ini.Section, error) + GetSection(name string) (*ini.Section, error) } func mustMapSetting(rootCfg Config, sectionName string, setting interface{}) { diff --git a/modules/setting/cors.go b/modules/setting/cors.go index e86ea46ea9fc..04acb13f3493 100644 --- a/modules/setting/cors.go +++ b/modules/setting/cors.go @@ -5,6 +5,8 @@ package setting import ( "time" + + "code.gitea.io/gitea/modules/log" ) // CORSConfig defines CORS settings @@ -24,3 +26,10 @@ var CORSConfig = struct { Headers: []string{"Content-Type", "User-Agent"}, XFrameOptions: "SAMEORIGIN", } + +func parseCorsSetting(rootCfg Config) { + mustMapSetting(rootCfg, "cors", &CORSConfig) + if CORSConfig.Enabled { + log.Info("CORS Service Enabled") + } +} diff --git a/modules/setting/lfs.go b/modules/setting/lfs.go index 881520bec6be..865454844ba7 100644 --- a/modules/setting/lfs.go +++ b/modules/setting/lfs.go @@ -40,7 +40,7 @@ func parseLFSSetting(rootCfg Config) { lfsSec.Key("PATH").MustString( sec.Key("LFS_CONTENT_PATH").String()) - LFS.Storage = getStorage("lfs", storageType, lfsSec) + LFS.Storage = getStorage(rootCfg, "lfs", storageType, lfsSec) // Rest of LFS service settings if LFS.LocksPagingNum == 0 { diff --git a/modules/setting/log.go b/modules/setting/log.go index d61abfa1a76c..0e4c7d0b3a1c 100644 --- a/modules/setting/log.go +++ b/modules/setting/log.go @@ -227,12 +227,12 @@ func generateLogConfig(sec *ini.Section, name string, defaults defaultLogOptions return mode, jsonConfig, levelName } -func generateNamedLogger(key string, options defaultLogOptions) *LogDescription { +func generateNamedLogger(rootCfg Config, key string, options defaultLogOptions) *LogDescription { description := LogDescription{ Name: key, } - sections := strings.Split(Cfg.Section("log").Key(strings.ToUpper(key)).MustString(""), ",") + sections := strings.Split(rootCfg.Section("log").Key(strings.ToUpper(key)).MustString(""), ",") for i := 0; i < len(sections); i++ { sections[i] = strings.TrimSpace(sections[i]) @@ -242,9 +242,9 @@ func generateNamedLogger(key string, options defaultLogOptions) *LogDescription if len(name) == 0 || (name == "console" && options.disableConsole) { continue } - sec, err := Cfg.GetSection("log." + name + "." + key) + sec, err := rootCfg.GetSection("log." + name + "." + key) if err != nil { - sec, _ = Cfg.NewSection("log." + name + "." + key) + sec, _ = rootCfg.NewSection("log." + name + "." + key) } provider, config, levelName := generateLogConfig(sec, name, options) @@ -267,46 +267,49 @@ func generateNamedLogger(key string, options defaultLogOptions) *LogDescription return &description } -func parseAccessLogSetting() { - EnableAccessLog = Cfg.Section("log").Key("ENABLE_ACCESS_LOG").MustBool(false) - AccessLogTemplate = Cfg.Section("log").Key("ACCESS_LOG_TEMPLATE").MustString( +func parseAccessLogSetting(rootCfg Config) { + sec := rootCfg.Section("log") + EnableAccessLog = sec.Key("ENABLE_ACCESS_LOG").MustBool(false) + AccessLogTemplate = sec.Key("ACCESS_LOG_TEMPLATE").MustString( `{{.Ctx.RemoteAddr}} - {{.Identity}} {{.Start.Format "[02/Jan/2006:15:04:05 -0700]" }} "{{.Ctx.Req.Method}} {{.Ctx.Req.URL.RequestURI}} {{.Ctx.Req.Proto}}" {{.ResponseWriter.Status}} {{.ResponseWriter.Size}} "{{.Ctx.Req.Referer}}\" \"{{.Ctx.Req.UserAgent}}"`, ) // the `MustString` updates the default value, and `log.ACCESS` is used by `generateNamedLogger("access")` later - _ = Cfg.Section("log").Key("ACCESS").MustString("file") + _ = sec.Key("ACCESS").MustString("file") if EnableAccessLog { options := newDefaultLogOptions() options.filename = filepath.Join(LogRootPath, "access.log") options.flags = "" // For the router we don't want any prefixed flags - options.bufferLength = Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000) - generateNamedLogger("access", options) + options.bufferLength = sec.Key("BUFFER_LEN").MustInt64(10000) + generateNamedLogger(rootCfg, "access", options) } } -func parseRouterLogSetting() { - Cfg.Section("log").Key("ROUTER").MustString("console") +func parseRouterLogSetting(rootCfg Config) { + sec := rootCfg.Section("log") + sec.Key("ROUTER").MustString("console") // Allow [log] DISABLE_ROUTER_LOG to override [server] DISABLE_ROUTER_LOG - DisableRouterLog = Cfg.Section("log").Key("DISABLE_ROUTER_LOG").MustBool(DisableRouterLog) + DisableRouterLog = sec.Key("DISABLE_ROUTER_LOG").MustBool(DisableRouterLog) if !DisableRouterLog { options := newDefaultLogOptions() options.filename = filepath.Join(LogRootPath, "router.log") options.flags = "date,time" // For the router we don't want any prefixed flags - options.bufferLength = Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000) - generateNamedLogger("router", options) + options.bufferLength = sec.Key("BUFFER_LEN").MustInt64(10000) + generateNamedLogger(rootCfg, "router", options) } } -func parseLogSetting() { +func parseLogSetting(rootCfg Config) { + sec := rootCfg.Section("log") options := newDefaultLogOptions() - options.bufferLength = Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000) - EnableSSHLog = Cfg.Section("log").Key("ENABLE_SSH_LOG").MustBool(false) + options.bufferLength = sec.Key("BUFFER_LEN").MustInt64(10000) + EnableSSHLog = sec.Key("ENABLE_SSH_LOG").MustBool(false) description := LogDescription{ Name: log.DEFAULT, } - sections := strings.Split(Cfg.Section("log").Key("MODE").MustString("console"), ",") + sections := strings.Split(sec.Key("MODE").MustString("console"), ",") useConsole := false for _, name := range sections { @@ -318,11 +321,11 @@ func parseLogSetting() { useConsole = true } - sec, err := Cfg.GetSection("log." + name + ".default") + sec, err := rootCfg.GetSection("log." + name + ".default") if err != nil { - sec, err = Cfg.GetSection("log." + name) + sec, err = rootCfg.GetSection("log." + name) if err != nil { - sec, _ = Cfg.NewSection("log." + name) + sec, _ = rootCfg.NewSection("log." + name) } } @@ -359,9 +362,9 @@ func RestartLogsWithPIDSuffix() { // ParseLogSettings creates all the log services func ParseLogSettings(disableConsole bool) { - parseLogSetting() - parseRouterLogSetting() - parseAccessLogSetting() + parseLogSetting(Cfg) + parseRouterLogSetting(Cfg) + parseAccessLogSetting(Cfg) ParseXORMLogSetting(disableConsole) } @@ -375,6 +378,6 @@ func ParseXORMLogSetting(disableConsole bool) { options.disableConsole = disableConsole Cfg.Section("log").Key("XORM").MustString(",") - generateNamedLogger("xorm", options) + generateNamedLogger(Cfg, "xorm", options) } } diff --git a/modules/setting/markup.go b/modules/setting/markup.go index 1d24d5df428e..b08c338c5763 100644 --- a/modules/setting/markup.go +++ b/modules/setting/markup.go @@ -61,7 +61,7 @@ type MarkupSanitizerRule struct { } func parseMarkupSetting(rootCfg Config) { - mustMapSetting(Cfg, "markdown", &Markdown) + mustMapSetting(rootCfg, "markdown", &Markdown) MermaidMaxSourceCharacters = rootCfg.Section("markup").Key("MERMAID_MAX_SOURCE_CHARACTERS").MustInt(5000) ExternalMarkupRenderers = make([]*MarkupRenderer, 0, 10) diff --git a/modules/setting/metrics.go b/modules/setting/metrics.go index 196f8eb3cd60..767c3136bd9f 100644 --- a/modules/setting/metrics.go +++ b/modules/setting/metrics.go @@ -17,5 +17,5 @@ var Metrics = struct { } func parseMetricsSetting(rootCfg Config) { - mustMapSetting(Cfg, "metrics", &Metrics) + mustMapSetting(rootCfg, "metrics", &Metrics) } diff --git a/modules/setting/other.go b/modules/setting/other.go index 69b511ede9df..81a3db994d81 100644 --- a/modules/setting/other.go +++ b/modules/setting/other.go @@ -9,10 +9,11 @@ var ( ShowFooterVersion bool ShowFooterTemplateLoadTime bool EnableFeed bool + EnableSitemap bool ) func parseOtherSetting(rootCfg Config) { - sec := Cfg.Section("other") + sec := rootCfg.Section("other") ShowFooterBranding = sec.Key("SHOW_FOOTER_BRANDING").MustBool(false) ShowFooterVersion = sec.Key("SHOW_FOOTER_VERSION").MustBool(true) ShowFooterTemplateLoadTime = sec.Key("SHOW_FOOTER_TEMPLATE_LOAD_TIME").MustBool(true) diff --git a/modules/setting/packages.go b/modules/setting/packages.go index 2f191a38660e..7fa214e9aaf9 100644 --- a/modules/setting/packages.go +++ b/modules/setting/packages.go @@ -49,7 +49,7 @@ func parsePackagesSetting(rootCfg Config) { log.Fatal("Failed to map Packages settings: %v", err) } - Packages.Storage = getStorage("packages", "", nil) + Packages.Storage = getStorage(rootCfg, "packages", "", nil) appURL, _ := url.Parse(AppURL) Packages.RegistryHost = appURL.Host diff --git a/modules/setting/picture.go b/modules/setting/picture.go index ac6f9916df22..79118011a9b3 100644 --- a/modules/setting/picture.go +++ b/modules/setting/picture.go @@ -41,7 +41,7 @@ func parsePictureSetting(rootCfg Config) { avatarSec.Key("PATH").MustString( sec.Key("AVATAR_UPLOAD_PATH").String()) - Avatar.Storage = getStorage("avatars", storageType, avatarSec) + Avatar.Storage = getStorage(rootCfg, "avatars", storageType, avatarSec) Avatar.MaxWidth = sec.Key("AVATAR_MAX_WIDTH").MustInt(4096) Avatar.MaxHeight = sec.Key("AVATAR_MAX_HEIGHT").MustInt(3072) @@ -91,7 +91,7 @@ func parseRepoAvatarSetting(rootCfg Config) { repoAvatarSec.Key("PATH").MustString( sec.Key("REPOSITORY_AVATAR_UPLOAD_PATH").String()) - RepoAvatar.Storage = getStorage("repo-avatars", storageType, repoAvatarSec) + RepoAvatar.Storage = getStorage(rootCfg, "repo-avatars", storageType, repoAvatarSec) RepoAvatar.Fallback = sec.Key("REPOSITORY_AVATAR_FALLBACK").MustString("none") RepoAvatar.FallbackImage = sec.Key("REPOSITORY_AVATAR_FALLBACK_IMAGE").MustString("/assets/img/repo_default.png") diff --git a/modules/setting/project.go b/modules/setting/project.go index 4cc415df0dad..7e8ab454c6c7 100644 --- a/modules/setting/project.go +++ b/modules/setting/project.go @@ -13,3 +13,7 @@ var ( ProjectBoardBugTriageType: []string{"Needs Triage", "High Priority", "Low Priority", "Closed"}, } ) + +func parseProjectSetting(rootCfg Config) { + mustMapSetting(rootCfg, "project", &Project) +} diff --git a/modules/setting/repository.go b/modules/setting/repository.go index 531ed11fb2a4..a44f7f937294 100644 --- a/modules/setting/repository.go +++ b/modules/setting/repository.go @@ -352,5 +352,5 @@ func parseRepositorySetting(rootCfg Config) { Repository.Upload.TempPath = path.Join(AppWorkPath, Repository.Upload.TempPath) } - RepoArchive.Storage = getStorage("repo-archive", "", nil) + RepoArchive.Storage = getStorage(rootCfg, "repo-archive", "", nil) } diff --git a/modules/setting/security.go b/modules/setting/security.go index aeb7b6b935f3..30deb004060c 100644 --- a/modules/setting/security.go +++ b/modules/setting/security.go @@ -18,6 +18,7 @@ var ( // Security settings InstallLock bool SecretKey string + InternalToken string // internal access token LogInRememberDays int CookieUserName string CookieRememberName string @@ -35,6 +36,8 @@ var ( PasswordHashAlgo string PasswordCheckPwn bool SuccessfulTokensCacheSize int + CSRFCookieName = "_csrf" + CSRFCookieHTTPOnly = true ) // loadSecret load the secret from ini by uriKey or verbatimKey, only one of them could be set diff --git a/modules/setting/server.go b/modules/setting/server.go index 9620f0bc9053..703774f60b27 100644 --- a/modules/setting/server.go +++ b/modules/setting/server.go @@ -7,7 +7,6 @@ import ( "encoding/base64" "net" "net/url" - "os" "path" "path/filepath" "strconv" @@ -16,7 +15,6 @@ import ( "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/user" "code.gitea.io/gitea/modules/util" ) @@ -81,14 +79,102 @@ func MakeAbsoluteAssetURL(appURL, staticURLPrefix string) string { return strings.TrimSuffix(staticURLPrefix, "/") } +// Scheme describes protocol types +type Scheme string + +// enumerates all the scheme types +const ( + HTTP Scheme = "http" + HTTPS Scheme = "https" + FCGI Scheme = "fcgi" + FCGIUnix Scheme = "fcgi+unix" + HTTPUnix Scheme = "http+unix" +) + +// LandingPage describes the default page +type LandingPage string + +// enumerates all the landing page types +const ( + LandingPageHome LandingPage = "/" + LandingPageExplore LandingPage = "/explore" + LandingPageOrganizations LandingPage = "/explore/organizations" + LandingPageLogin LandingPage = "/user/login" +) + +var ( + // AppName is the Application name, used in the page title. + // It maps to ini:"APP_NAME" + AppName string + // AppURL is the Application ROOT_URL. It always has a '/' suffix + // It maps to ini:"ROOT_URL" + AppURL string + // AppSubURL represents the sub-url mounting point for gitea. It is either "" or starts with '/' and ends without '/', such as '/{subpath}'. + // This value is empty if site does not have sub-url. + AppSubURL string + // AppDataPath is the default path for storing data. + // It maps to ini:"APP_DATA_PATH" in [server] and defaults to AppWorkPath + "/data" + AppDataPath string + // LocalURL is the url for locally running applications to contact Gitea. It always has a '/' suffix + // It maps to ini:"LOCAL_ROOT_URL" in [server] + LocalURL string + // AssetVersion holds a opaque value that is used for cache-busting assets + AssetVersion string + + // Server settings + Protocol Scheme + UseProxyProtocol bool // `ini:"USE_PROXY_PROTOCOL"` + ProxyProtocolTLSBridging bool //`ini:"PROXY_PROTOCOL_TLS_BRIDGING"` + ProxyProtocolHeaderTimeout time.Duration + ProxyProtocolAcceptUnknown bool + Domain string + HTTPAddr string + HTTPPort string + LocalUseProxyProtocol bool + RedirectOtherPort bool + RedirectorUseProxyProtocol bool + PortToRedirect string + OfflineMode bool + CertFile string + KeyFile string + StaticRootPath string + StaticCacheTime time.Duration + EnableGzip bool + LandingPageURL LandingPage + LandingPageCustom string + UnixSocketPermission uint32 + EnablePprof bool + PprofDataPath string + EnableAcme bool + AcmeTOS bool + AcmeLiveDirectory string + AcmeEmail string + AcmeURL string + AcmeCARoot string + SSLMinimumVersion string + SSLMaximumVersion string + SSLCurvePreferences []string + SSLCipherSuites []string + GracefulRestartable bool + GracefulHammerTime time.Duration + StartupTimeout time.Duration + PerWriteTimeout = 30 * time.Second + PerWritePerKbTimeout = 10 * time.Second + StaticURLPrefix string + AbsoluteAssetURL string + + HasRobotsTxt bool +) + func parseServerSetting(rootCfg Config) { - LogLevel = getLogLevel(Cfg.Section("log"), "LEVEL", log.INFO) - StacktraceLogLevel = getStacktraceLogLevel(Cfg.Section("log"), "STACKTRACE_LEVEL", "None") - LogRootPath = Cfg.Section("log").Key("ROOT_PATH").MustString(path.Join(AppWorkPath, "log")) + logSec := rootCfg.Section("log") + LogLevel = getLogLevel(logSec, "LEVEL", log.INFO) + StacktraceLogLevel = getStacktraceLogLevel(logSec, "STACKTRACE_LEVEL", "None") + LogRootPath = logSec.Key("ROOT_PATH").MustString(path.Join(AppWorkPath, "log")) forcePathSeparator(LogRootPath) - sec := Cfg.Section("server") - AppName = Cfg.Section("").Key("APP_NAME").MustString("Gitea: Git with a cup of tea") + sec := rootCfg.Section("server") + AppName = rootCfg.Section("").Key("APP_NAME").MustString("Gitea: Git with a cup of tea") Domain = sec.Key("DOMAIN").MustString("localhost") HTTPAddr = sec.Key("HTTP_ADDR").MustString("0.0.0.0") @@ -270,49 +356,8 @@ func parseServerSetting(rootCfg Config) { LandingPageURL = LandingPage(landingPage) } - parseRunModeSetting(rootCfg) -} - -// IsRunUserMatchCurrentUser returns false if configured run user does not match -// actual user that runs the app. The first return value is the actual user name. -// This check is ignored under Windows since SSH remote login is not the main -// method to login on Windows. -func IsRunUserMatchCurrentUser(runUser string) (string, bool) { - if IsWindows || SSH.StartBuiltinServer { - return "", true - } - - currentUser := user.CurrentUsername() - return currentUser, runUser == currentUser -} - -func parseRunModeSetting(rootCfg Config) { - RunUser = Cfg.Section("").Key("RUN_USER").MustString(user.CurrentUsername()) - // The following is a purposefully undocumented option. Please do not run Gitea as root. It will only cause future headaches. - // Please don't use root as a bandaid to "fix" something that is broken, instead the broken thing should instead be fixed properly. - unsafeAllowRunAsRoot := Cfg.Section("").Key("I_AM_BEING_UNSAFE_RUNNING_AS_ROOT").MustBool(false) - RunMode = os.Getenv("GITEA_RUN_MODE") - if RunMode == "" { - RunMode = Cfg.Section("").Key("RUN_MODE").MustString("prod") - } - IsProd = strings.EqualFold(RunMode, "prod") - // Does not check run user when the install lock is off. - if InstallLock { - currentUser, match := IsRunUserMatchCurrentUser(RunUser) - if !match { - log.Fatal("Expect user '%s' but current user is: %s", RunUser, currentUser) - } - } - - // check if we run as root - if os.Getuid() == 0 { - if !unsafeAllowRunAsRoot { - // Special thanks to VLC which inspired the wording of this messaging. - log.Fatal("Gitea is not supposed to be run as root. Sorry. If you need to use privileged TCP ports please instead use setcap and the `cap_net_bind_service` permission") - } - log.Critical("You are running Gitea using the root user, and have purposely chosen to skip built-in protections around this. You have been warned against this.") + HasRobotsTxt, err = util.IsFile(path.Join(CustomPath, "robots.txt")) + if err != nil { + log.Error("Unable to check if %s is a file. Error: %v", path.Join(CustomPath, "robots.txt"), err) } - - SSH.BuiltinServerUser = Cfg.Section("server").Key("BUILTIN_SSH_SERVER_USER").MustString(RunUser) - SSH.User = Cfg.Section("server").Key("SSH_USER").MustString(SSH.BuiltinServerUser) } diff --git a/modules/setting/setting.go b/modules/setting/setting.go index fd1fd0921c62..d9303dcc2135 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -16,34 +16,12 @@ import ( "time" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/user" "code.gitea.io/gitea/modules/util" ini "gopkg.in/ini.v1" ) -// Scheme describes protocol types -type Scheme string - -// enumerates all the scheme types -const ( - HTTP Scheme = "http" - HTTPS Scheme = "https" - FCGI Scheme = "fcgi" - FCGIUnix Scheme = "fcgi+unix" - HTTPUnix Scheme = "http+unix" -) - -// LandingPage describes the default page -type LandingPage string - -// enumerates all the landing page types -const ( - LandingPageHome LandingPage = "/" - LandingPageExplore LandingPage = "/explore" - LandingPageOrganizations LandingPage = "/explore/organizations" - LandingPageLogin LandingPage = "/user/login" -) - // settings var ( // AppVer is the version of the current build of Gitea. It is set in main.go from main.Version. @@ -52,15 +30,7 @@ var ( AppBuiltWith string // AppStartTime store time gitea has started AppStartTime time.Time - // AppName is the Application name, used in the page title. - // It maps to ini:"APP_NAME" - AppName string - // AppURL is the Application ROOT_URL. It always has a '/' suffix - // It maps to ini:"ROOT_URL" - AppURL string - // AppSubURL represents the sub-url mounting point for gitea. It is either "" or starts with '/' and ends without '/', such as '/{subpath}'. - // This value is empty if site does not have sub-url. - AppSubURL string + // AppPath represents the path to the gitea binary AppPath string // AppWorkPath is the "working directory" of Gitea. It maps to the environment variable GITEA_WORK_DIR. @@ -68,75 +38,17 @@ var ( // // AppWorkPath is used as the base path for several other paths. AppWorkPath string - // AppDataPath is the default path for storing data. - // It maps to ini:"APP_DATA_PATH" in [server] and defaults to AppWorkPath + "/data" - AppDataPath string - // LocalURL is the url for locally running applications to contact Gitea. It always has a '/' suffix - // It maps to ini:"LOCAL_ROOT_URL" in [server] - LocalURL string - // AssetVersion holds a opaque value that is used for cache-busting assets - AssetVersion string - - // Server settings - Protocol Scheme - UseProxyProtocol bool // `ini:"USE_PROXY_PROTOCOL"` - ProxyProtocolTLSBridging bool //`ini:"PROXY_PROTOCOL_TLS_BRIDGING"` - ProxyProtocolHeaderTimeout time.Duration - ProxyProtocolAcceptUnknown bool - Domain string - HTTPAddr string - HTTPPort string - LocalUseProxyProtocol bool - RedirectOtherPort bool - RedirectorUseProxyProtocol bool - PortToRedirect string - OfflineMode bool - CertFile string - KeyFile string - StaticRootPath string - StaticCacheTime time.Duration - EnableGzip bool - LandingPageURL LandingPage - LandingPageCustom string - UnixSocketPermission uint32 - EnablePprof bool - PprofDataPath string - EnableAcme bool - AcmeTOS bool - AcmeLiveDirectory string - AcmeEmail string - AcmeURL string - AcmeCARoot string - SSLMinimumVersion string - SSLMaximumVersion string - SSLCurvePreferences []string - SSLCipherSuites []string - GracefulRestartable bool - GracefulHammerTime time.Duration - StartupTimeout time.Duration - PerWriteTimeout = 30 * time.Second - PerWritePerKbTimeout = 10 * time.Second - StaticURLPrefix string - AbsoluteAssetURL string - - CSRFCookieName = "_csrf" - CSRFCookieHTTPOnly = true - - // Highlight settings are loaded in modules/template/highlight.go // Global setting objects - Cfg *ini.File - CustomPath string // Custom directory path - CustomConf string - PIDFile = "/run/gitea.pid" - WritePIDFile bool - RunMode string - IsProd bool - RunUser string - IsWindows bool - HasRobotsTxt bool - EnableSitemap bool - InternalToken string // internal access token + Cfg *ini.File + CustomPath string // Custom directory path + CustomConf string + PIDFile = "/run/gitea.pid" + WritePIDFile bool + RunMode string + IsProd bool + RunUser string + IsWindows bool ) func getAppPath() (string, error) { @@ -321,6 +233,7 @@ func loadFromConf(allowEmpty bool, extraConfig string) { Cfg.NameMapper = ini.SnackCase + parseRunModeSetting(Cfg) parseServerSetting(Cfg) parseSSHSetting(Cfg) parseOAuth2Setting(Cfg) @@ -335,12 +248,54 @@ func loadFromConf(allowEmpty bool, extraConfig string) { parseAdminSetting(Cfg) parseAPISetting(Cfg) parseMetricsSetting(Cfg) + parseCamoSetting(Cfg) parseI18nSetting(Cfg) parseGitSetting(Cfg) parseMirrorSetting(Cfg) parseMarkupSetting(Cfg) parseOtherSetting(Cfg) - parseCamoSetting(Cfg) +} + +// IsRunUserMatchCurrentUser returns false if configured run user does not match +// actual user that runs the app. The first return value is the actual user name. +// This check is ignored under Windows since SSH remote login is not the main +// method to login on Windows. +func IsRunUserMatchCurrentUser(runUser string) (string, bool) { + if IsWindows || SSH.StartBuiltinServer { + return "", true + } + + currentUser := user.CurrentUsername() + return currentUser, runUser == currentUser +} + +func parseRunModeSetting(rootCfg Config) { + rootSec := rootCfg.Section("") + RunUser = rootSec.Key("RUN_USER").MustString(user.CurrentUsername()) + // The following is a purposefully undocumented option. Please do not run Gitea as root. It will only cause future headaches. + // Please don't use root as a bandaid to "fix" something that is broken, instead the broken thing should instead be fixed properly. + unsafeAllowRunAsRoot := rootSec.Key("I_AM_BEING_UNSAFE_RUNNING_AS_ROOT").MustBool(false) + RunMode = os.Getenv("GITEA_RUN_MODE") + if RunMode == "" { + RunMode = rootSec.Key("RUN_MODE").MustString("prod") + } + IsProd = strings.EqualFold(RunMode, "prod") + // Does not check run user when the install lock is off. + if InstallLock { + currentUser, match := IsRunUserMatchCurrentUser(RunUser) + if !match { + log.Fatal("Expect user '%s' but current user is: %s", RunUser, currentUser) + } + } + + // check if we run as root + if os.Getuid() == 0 { + if !unsafeAllowRunAsRoot { + // Special thanks to VLC which inspired the wording of this messaging. + log.Fatal("Gitea is not supposed to be run as root. Sorry. If you need to use privileged TCP ports please instead use setcap and the `cap_net_bind_service` permission") + } + log.Critical("You are running Gitea using the root user, and have purposely chosen to skip built-in protections around this. You have been warned against this.") + } } // CreateOrAppendToCustomConf creates or updates the custom config. @@ -396,11 +351,7 @@ func ParseSettings() { ParseLogSettings(false) parseCacheSetting(Cfg) parseSessionSetting(Cfg) - mustMapSetting(Cfg, "cors", &CORSConfig) - if CORSConfig.Enabled { - log.Info("CORS Service Enabled") - } - + parseCorsSetting(Cfg) parseMailSettings(Cfg) parseProxySetting(Cfg) parseWebhookSetting(Cfg) @@ -408,7 +359,7 @@ func ParseSettings() { parseIndexerSetting(Cfg) parseTaskSetting(Cfg) ParseQueueSettings() - mustMapSetting(Cfg, "project", &Project) + parseProjectSetting(Cfg) parseMimeTypeMap(Cfg) parseFederationSetting(Cfg) } diff --git a/modules/setting/ssh.go b/modules/setting/ssh.go index 1121c91e2f01..2e8b81828bd0 100644 --- a/modules/setting/ssh.go +++ b/modules/setting/ssh.go @@ -125,7 +125,7 @@ func parseSSHSetting(rootCfg Config) { SSH.ServerMACs = serverMACs } SSH.KeyTestPath = os.TempDir() - if err = Cfg.Section("server").MapTo(&SSH); err != nil { + if err = sec.MapTo(&SSH); err != nil { log.Fatal("Failed to map SSH settings: %v", err) } for i, key := range SSH.ServerHostKeys { @@ -164,7 +164,7 @@ func parseSSHSetting(rootCfg Config) { SSH.AuthorizedPrincipalsAllow, SSH.AuthorizedPrincipalsEnabled = parseAuthorizedPrincipalsAllow(sec.Key("SSH_AUTHORIZED_PRINCIPALS_ALLOW").Strings(",")) SSH.MinimumKeySizeCheck = sec.Key("MINIMUM_KEY_SIZE_CHECK").MustBool(SSH.MinimumKeySizeCheck) - minimumKeySizes := Cfg.Section("ssh.minimum_key_sizes").Keys() + minimumKeySizes := rootCfg.Section("ssh.minimum_key_sizes").Keys() for _, key := range minimumKeySizes { if key.MustInt() != -1 { SSH.MinimumKeySizes[strings.ToLower(key.Name())] = key.MustInt() @@ -190,4 +190,8 @@ func parseSSHSetting(rootCfg Config) { SSH.PerWriteTimeout = sec.Key("SSH_PER_WRITE_TIMEOUT").MustDuration(PerWriteTimeout) SSH.PerWritePerKbTimeout = sec.Key("SSH_PER_WRITE_PER_KB_TIMEOUT").MustDuration(PerWritePerKbTimeout) + + // ensure parseRunModeSetting has been executed before this + SSH.BuiltinServerUser = rootCfg.Section("server").Key("BUILTIN_SSH_SERVER_USER").MustString(RunUser) + SSH.User = rootCfg.Section("server").Key("SSH_USER").MustString(SSH.BuiltinServerUser) } diff --git a/modules/setting/storage.go b/modules/setting/storage.go index 32f74aa072cb..3661a7a478a0 100644 --- a/modules/setting/storage.go +++ b/modules/setting/storage.go @@ -30,9 +30,9 @@ func (s *Storage) MapTo(v interface{}) error { return nil } -func getStorage(name, typ string, targetSec *ini.Section) Storage { +func getStorage(rootCfg Config, name, typ string, targetSec *ini.Section) Storage { const sectionName = "storage" - sec := Cfg.Section(sectionName) + sec := rootCfg.Section(sectionName) // Global Defaults sec.Key("MINIO_ENDPOINT").MustString("localhost:9000") @@ -43,7 +43,7 @@ func getStorage(name, typ string, targetSec *ini.Section) Storage { sec.Key("MINIO_USE_SSL").MustBool(false) if targetSec == nil { - targetSec, _ = Cfg.NewSection(name) + targetSec, _ = rootCfg.NewSection(name) } var storage Storage @@ -51,12 +51,12 @@ func getStorage(name, typ string, targetSec *ini.Section) Storage { storage.Type = typ overrides := make([]*ini.Section, 0, 3) - nameSec, err := Cfg.GetSection(sectionName + "." + name) + nameSec, err := rootCfg.GetSection(sectionName + "." + name) if err == nil { overrides = append(overrides, nameSec) } - typeSec, err := Cfg.GetSection(sectionName + "." + typ) + typeSec, err := rootCfg.GetSection(sectionName + "." + typ) if err == nil { overrides = append(overrides, typeSec) nextType := typeSec.Key("STORAGE_TYPE").String() diff --git a/modules/setting/storage_test.go b/modules/setting/storage_test.go index 256bbb7a5281..2f8710336f2a 100644 --- a/modules/setting/storage_test.go +++ b/modules/setting/storage_test.go @@ -24,7 +24,7 @@ MINIO_ENDPOINT = my_minio:9000 sec := Cfg.Section("attachment") storageType := sec.Key("STORAGE_TYPE").MustString("") - storage := getStorage("attachments", storageType, sec) + storage := getStorage(Cfg, "attachments", storageType, sec) assert.EqualValues(t, "minio", storage.Type) assert.EqualValues(t, "my_minio:9000", storage.Section.Key("MINIO_ENDPOINT").String()) @@ -46,7 +46,7 @@ MINIO_BUCKET = gitea sec := Cfg.Section("attachment") storageType := sec.Key("STORAGE_TYPE").MustString("") - storage := getStorage("attachments", storageType, sec) + storage := getStorage(Cfg, "attachments", storageType, sec) assert.EqualValues(t, "minio", storage.Type) assert.EqualValues(t, "gitea-attachment", storage.Section.Key("MINIO_BUCKET").String()) @@ -67,7 +67,7 @@ MINIO_BUCKET = gitea sec := Cfg.Section("attachment") storageType := sec.Key("STORAGE_TYPE").MustString("") - storage := getStorage("attachments", storageType, sec) + storage := getStorage(Cfg, "attachments", storageType, sec) assert.EqualValues(t, "minio", storage.Type) assert.EqualValues(t, "gitea-minio", storage.Section.Key("MINIO_BUCKET").String()) @@ -89,7 +89,7 @@ STORAGE_TYPE = local sec := Cfg.Section("attachment") storageType := sec.Key("STORAGE_TYPE").MustString("") - storage := getStorage("attachments", storageType, sec) + storage := getStorage(Cfg, "attachments", storageType, sec) assert.EqualValues(t, "minio", storage.Type) assert.EqualValues(t, "gitea-attachment", storage.Section.Key("MINIO_BUCKET").String()) @@ -100,7 +100,7 @@ func Test_getStorageGetDefaults(t *testing.T) { sec := Cfg.Section("attachment") storageType := sec.Key("STORAGE_TYPE").MustString("") - storage := getStorage("attachments", storageType, sec) + storage := getStorage(Cfg, "attachments", storageType, sec) assert.EqualValues(t, "gitea", storage.Section.Key("MINIO_BUCKET").String()) } @@ -121,21 +121,21 @@ MINIO_BUCKET = gitea-storage { sec := Cfg.Section("attachment") storageType := sec.Key("STORAGE_TYPE").MustString("") - storage := getStorage("attachments", storageType, sec) + storage := getStorage(Cfg, "attachments", storageType, sec) assert.EqualValues(t, "gitea-attachment", storage.Section.Key("MINIO_BUCKET").String()) } { sec := Cfg.Section("lfs") storageType := sec.Key("STORAGE_TYPE").MustString("") - storage := getStorage("lfs", storageType, sec) + storage := getStorage(Cfg, "lfs", storageType, sec) assert.EqualValues(t, "gitea-lfs", storage.Section.Key("MINIO_BUCKET").String()) } { sec := Cfg.Section("avatar") storageType := sec.Key("STORAGE_TYPE").MustString("") - storage := getStorage("avatars", storageType, sec) + storage := getStorage(Cfg, "avatars", storageType, sec) assert.EqualValues(t, "gitea-storage", storage.Section.Key("MINIO_BUCKET").String()) } @@ -154,14 +154,14 @@ MINIO_BUCKET = gitea-storage { sec := Cfg.Section("attachment") storageType := sec.Key("STORAGE_TYPE").MustString("") - storage := getStorage("attachments", storageType, sec) + storage := getStorage(Cfg, "attachments", storageType, sec) assert.EqualValues(t, "gitea-storage", storage.Section.Key("MINIO_BUCKET").String()) } { sec := Cfg.Section("lfs") storageType := sec.Key("STORAGE_TYPE").MustString("") - storage := getStorage("lfs", storageType, sec) + storage := getStorage(Cfg, "lfs", storageType, sec) assert.EqualValues(t, "gitea-storage", storage.Section.Key("MINIO_BUCKET").String()) } @@ -176,7 +176,7 @@ STORAGE_TYPE = minio sec := Cfg.Section("attachment") storageType := sec.Key("STORAGE_TYPE").MustString("") - storage := getStorage("attachments", storageType, sec) + storage := getStorage(Cfg, "attachments", storageType, sec) assert.EqualValues(t, "minio", storage.Type) } @@ -190,7 +190,7 @@ STORAGE_TYPE = minio sec := Cfg.Section("attachment") storageType := sec.Key("STORAGE_TYPE").MustString("") - storage := getStorage("attachments", storageType, sec) + storage := getStorage(Cfg, "attachments", storageType, sec) assert.EqualValues(t, "minio", storage.Type) } diff --git a/modules/setting/ui.go b/modules/setting/ui.go index 3c2d1cd529b6..3b0355bc9993 100644 --- a/modules/setting/ui.go +++ b/modules/setting/ui.go @@ -4,12 +4,9 @@ package setting import ( - "path" "time" "code.gitea.io/gitea/modules/container" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/util" ) // UI settings @@ -152,10 +149,4 @@ func parseUISetting(rootCfg Config) { for _, emoji := range UI.CustomEmojis { UI.CustomEmojisMap[emoji] = ":" + emoji + ":" } - - var err error - HasRobotsTxt, err = util.IsFile(path.Join(CustomPath, "robots.txt")) - if err != nil { - log.Error("Unable to check if %s is a file. Error: %v", path.Join(CustomPath, "robots.txt"), err) - } } From e908a539a08f17ba79b941b3a1e408cc9513315a Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 12 Jan 2023 17:19:14 +0800 Subject: [PATCH 05/20] Fix copyright year --- modules/setting/admin.go | 2 +- modules/setting/api.go | 2 +- modules/setting/camo.go | 2 +- modules/setting/config.go | 2 +- modules/setting/metrics.go | 2 +- modules/setting/other.go | 2 +- modules/setting/security.go | 2 +- modules/setting/server.go | 2 +- modules/setting/ssh.go | 2 +- modules/setting/time.go | 2 +- modules/setting/ui.go | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/modules/setting/admin.go b/modules/setting/admin.go index 5bbb7e283501..84aa5831f6ed 100644 --- a/modules/setting/admin.go +++ b/modules/setting/admin.go @@ -1,4 +1,4 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. +// Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package setting diff --git a/modules/setting/api.go b/modules/setting/api.go index 7a888e77bdf5..e13c1396f471 100644 --- a/modules/setting/api.go +++ b/modules/setting/api.go @@ -1,4 +1,4 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. +// Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package setting diff --git a/modules/setting/camo.go b/modules/setting/camo.go index f385cbcca0c0..7fa5bb40eea3 100644 --- a/modules/setting/camo.go +++ b/modules/setting/camo.go @@ -1,4 +1,4 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. +// Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package setting diff --git a/modules/setting/config.go b/modules/setting/config.go index 30fb40c418da..1c98315c4975 100644 --- a/modules/setting/config.go +++ b/modules/setting/config.go @@ -1,4 +1,4 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. +// Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package setting diff --git a/modules/setting/metrics.go b/modules/setting/metrics.go index 767c3136bd9f..2e536502b439 100644 --- a/modules/setting/metrics.go +++ b/modules/setting/metrics.go @@ -1,4 +1,4 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. +// Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package setting diff --git a/modules/setting/other.go b/modules/setting/other.go index 81a3db994d81..39e2d42adac0 100644 --- a/modules/setting/other.go +++ b/modules/setting/other.go @@ -1,4 +1,4 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. +// Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package setting diff --git a/modules/setting/security.go b/modules/setting/security.go index 30deb004060c..2c53d8b8684d 100644 --- a/modules/setting/security.go +++ b/modules/setting/security.go @@ -1,4 +1,4 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. +// Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package setting diff --git a/modules/setting/server.go b/modules/setting/server.go index 703774f60b27..a9e29690e446 100644 --- a/modules/setting/server.go +++ b/modules/setting/server.go @@ -1,4 +1,4 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. +// Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package setting diff --git a/modules/setting/ssh.go b/modules/setting/ssh.go index 2e8b81828bd0..c5d3f4958ab6 100644 --- a/modules/setting/ssh.go +++ b/modules/setting/ssh.go @@ -1,4 +1,4 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. +// Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package setting diff --git a/modules/setting/time.go b/modules/setting/time.go index 864aa1c65904..07b346480f66 100644 --- a/modules/setting/time.go +++ b/modules/setting/time.go @@ -1,4 +1,4 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. +// Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package setting diff --git a/modules/setting/ui.go b/modules/setting/ui.go index 3b0355bc9993..fccdc8b1c489 100644 --- a/modules/setting/ui.go +++ b/modules/setting/ui.go @@ -1,4 +1,4 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. +// Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package setting From 434a6dad56f873ed5181f0e3467d906738f6ec7d Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 12 Jan 2023 17:31:36 +0800 Subject: [PATCH 06/20] improvement --- modules/setting/server.go | 121 ++++++++++++++++++------------------- modules/setting/setting.go | 28 ++++----- 2 files changed, 74 insertions(+), 75 deletions(-) diff --git a/modules/setting/server.go b/modules/setting/server.go index a9e29690e446..cb0b426e1a04 100644 --- a/modules/setting/server.go +++ b/modules/setting/server.go @@ -18,67 +18,6 @@ import ( "code.gitea.io/gitea/modules/util" ) -var ManifestData string - -// MakeManifestData generates web app manifest JSON -func MakeManifestData(appName, appURL, absoluteAssetURL string) []byte { - type manifestIcon struct { - Src string `json:"src"` - Type string `json:"type"` - Sizes string `json:"sizes"` - } - - type manifestJSON struct { - Name string `json:"name"` - ShortName string `json:"short_name"` - StartURL string `json:"start_url"` - Icons []manifestIcon `json:"icons"` - } - - bytes, err := json.Marshal(&manifestJSON{ - Name: appName, - ShortName: appName, - StartURL: appURL, - Icons: []manifestIcon{ - { - Src: absoluteAssetURL + "/assets/img/logo.png", - Type: "image/png", - Sizes: "512x512", - }, - { - Src: absoluteAssetURL + "/assets/img/logo.svg", - Type: "image/svg+xml", - Sizes: "512x512", - }, - }, - }) - if err != nil { - log.Error("unable to marshal manifest JSON. Error: %v", err) - return make([]byte, 0) - } - - return bytes -} - -// MakeAbsoluteAssetURL returns the absolute asset url prefix without a trailing slash -func MakeAbsoluteAssetURL(appURL, staticURLPrefix string) string { - parsedPrefix, err := url.Parse(strings.TrimSuffix(staticURLPrefix, "/")) - if err != nil { - log.Fatal("Unable to parse STATIC_URL_PREFIX: %v", err) - } - - if err == nil && parsedPrefix.Hostname() == "" { - if staticURLPrefix == "" { - return strings.TrimSuffix(appURL, "/") - } - - // StaticURLPrefix is just a path - return util.URLJoin(appURL, strings.TrimSuffix(staticURLPrefix, "/")) - } - - return strings.TrimSuffix(staticURLPrefix, "/") -} - // Scheme describes protocol types type Scheme string @@ -164,8 +103,68 @@ var ( AbsoluteAssetURL string HasRobotsTxt bool + ManifestData string ) +// MakeManifestData generates web app manifest JSON +func MakeManifestData(appName, appURL, absoluteAssetURL string) []byte { + type manifestIcon struct { + Src string `json:"src"` + Type string `json:"type"` + Sizes string `json:"sizes"` + } + + type manifestJSON struct { + Name string `json:"name"` + ShortName string `json:"short_name"` + StartURL string `json:"start_url"` + Icons []manifestIcon `json:"icons"` + } + + bytes, err := json.Marshal(&manifestJSON{ + Name: appName, + ShortName: appName, + StartURL: appURL, + Icons: []manifestIcon{ + { + Src: absoluteAssetURL + "/assets/img/logo.png", + Type: "image/png", + Sizes: "512x512", + }, + { + Src: absoluteAssetURL + "/assets/img/logo.svg", + Type: "image/svg+xml", + Sizes: "512x512", + }, + }, + }) + if err != nil { + log.Error("unable to marshal manifest JSON. Error: %v", err) + return make([]byte, 0) + } + + return bytes +} + +// MakeAbsoluteAssetURL returns the absolute asset url prefix without a trailing slash +func MakeAbsoluteAssetURL(appURL, staticURLPrefix string) string { + parsedPrefix, err := url.Parse(strings.TrimSuffix(staticURLPrefix, "/")) + if err != nil { + log.Fatal("Unable to parse STATIC_URL_PREFIX: %v", err) + } + + if err == nil && parsedPrefix.Hostname() == "" { + if staticURLPrefix == "" { + return strings.TrimSuffix(appURL, "/") + } + + // StaticURLPrefix is just a path + return util.URLJoin(appURL, strings.TrimSuffix(staticURLPrefix, "/")) + } + + return strings.TrimSuffix(staticURLPrefix, "/") +} + func parseServerSetting(rootCfg Config) { logSec := rootCfg.Section("log") LogLevel = getLogLevel(logSec, "LEVEL", log.INFO) diff --git a/modules/setting/setting.go b/modules/setting/setting.go index d9303dcc2135..6af509010ffb 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -46,8 +46,8 @@ var ( PIDFile = "/run/gitea.pid" WritePIDFile bool RunMode string - IsProd bool RunUser string + IsProd bool IsWindows bool ) @@ -127,6 +127,19 @@ func forcePathSeparator(path string) { } } +// IsRunUserMatchCurrentUser returns false if configured run user does not match +// actual user that runs the app. The first return value is the actual user name. +// This check is ignored under Windows since SSH remote login is not the main +// method to login on Windows. +func IsRunUserMatchCurrentUser(runUser string) (string, bool) { + if IsWindows || SSH.StartBuiltinServer { + return "", true + } + + currentUser := user.CurrentUsername() + return currentUser, runUser == currentUser +} + func createPIDFile(pidPath string) { currentPid := os.Getpid() if err := os.MkdirAll(filepath.Dir(pidPath), os.ModePerm); err != nil { @@ -256,19 +269,6 @@ func loadFromConf(allowEmpty bool, extraConfig string) { parseOtherSetting(Cfg) } -// IsRunUserMatchCurrentUser returns false if configured run user does not match -// actual user that runs the app. The first return value is the actual user name. -// This check is ignored under Windows since SSH remote login is not the main -// method to login on Windows. -func IsRunUserMatchCurrentUser(runUser string) (string, bool) { - if IsWindows || SSH.StartBuiltinServer { - return "", true - } - - currentUser := user.CurrentUsername() - return currentUser, runUser == currentUser -} - func parseRunModeSetting(rootCfg Config) { rootSec := rootCfg.Section("") RunUser = rootSec.Key("RUN_USER").MustString(user.CurrentUsername()) From ce140fa9681cc4d364483a691161ff5da86da361 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 12 Jan 2023 17:41:02 +0800 Subject: [PATCH 07/20] Fix bug --- modules/setting/setting.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 6af509010ffb..1ed5435c588a 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -246,6 +246,7 @@ func loadFromConf(allowEmpty bool, extraConfig string) { Cfg.NameMapper = ini.SnackCase + // WARNNING: don't change the sequence except you know what you are doing. parseRunModeSetting(Cfg) parseServerSetting(Cfg) parseSSHSetting(Cfg) @@ -281,7 +282,8 @@ func parseRunModeSetting(rootCfg Config) { } IsProd = strings.EqualFold(RunMode, "prod") // Does not check run user when the install lock is off. - if InstallLock { + installLock := rootCfg.Section("security").Key("INSTALL_LOCK").MustBool(false) + if installLock { currentUser, match := IsRunUserMatchCurrentUser(RunUser) if !match { log.Fatal("Expect user '%s' but current user is: %s", RunUser, currentUser) From 14a8a0e63f518d2424ec1271fa09b5995b175a4c Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 12 Jan 2023 22:26:24 +0800 Subject: [PATCH 08/20] move function --- modules/setting/directory.go | 39 ------------------------------------ modules/setting/setting.go | 30 +++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 39 deletions(-) delete mode 100644 modules/setting/directory.go diff --git a/modules/setting/directory.go b/modules/setting/directory.go deleted file mode 100644 index a80df47ab486..000000000000 --- a/modules/setting/directory.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2021 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package setting - -import ( - "fmt" - "os" -) - -// PrepareAppDataPath creates app data directory if necessary -func PrepareAppDataPath() error { - // FIXME: There are too many calls to MkdirAll in old code. It is incorrect. - // For example, if someDir=/mnt/vol1/gitea-home/data, if the mount point /mnt/vol1 is not mounted when Gitea runs, - // then gitea will make new empty directories in /mnt/vol1, all are stored in the root filesystem. - // The correct behavior should be: creating parent directories is end users' duty. We only create sub-directories in existing parent directories. - // For quickstart, the parent directories should be created automatically for first startup (eg: a flag or a check of INSTALL_LOCK). - // Now we can take the first step to do correctly (using Mkdir) in other packages, and prepare the AppDataPath here, then make a refactor in future. - - st, err := os.Stat(AppDataPath) - - if os.IsNotExist(err) { - err = os.MkdirAll(AppDataPath, os.ModePerm) - if err != nil { - return fmt.Errorf("unable to create the APP_DATA_PATH directory: %q, Error: %w", AppDataPath, err) - } - return nil - } - - if err != nil { - return fmt.Errorf("unable to use APP_DATA_PATH %q. Error: %w", AppDataPath, err) - } - - if !st.IsDir() /* also works for symlink */ { - return fmt.Errorf("the APP_DATA_PATH %q is not a directory (or symlink to a directory) and can't be used", AppDataPath) - } - - return nil -} diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 1ed5435c588a..0bd0f927a811 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -186,6 +186,36 @@ func SetCustomPathAndConf(providedCustom, providedConf, providedWorkPath string) } } +// PrepareAppDataPath creates app data directory if necessary +func PrepareAppDataPath() error { + // FIXME: There are too many calls to MkdirAll in old code. It is incorrect. + // For example, if someDir=/mnt/vol1/gitea-home/data, if the mount point /mnt/vol1 is not mounted when Gitea runs, + // then gitea will make new empty directories in /mnt/vol1, all are stored in the root filesystem. + // The correct behavior should be: creating parent directories is end users' duty. We only create sub-directories in existing parent directories. + // For quickstart, the parent directories should be created automatically for first startup (eg: a flag or a check of INSTALL_LOCK). + // Now we can take the first step to do correctly (using Mkdir) in other packages, and prepare the AppDataPath here, then make a refactor in future. + + st, err := os.Stat(AppDataPath) + + if os.IsNotExist(err) { + err = os.MkdirAll(AppDataPath, os.ModePerm) + if err != nil { + return fmt.Errorf("unable to create the APP_DATA_PATH directory: %q, Error: %w", AppDataPath, err) + } + return nil + } + + if err != nil { + return fmt.Errorf("unable to use APP_DATA_PATH %q. Error: %w", AppDataPath, err) + } + + if !st.IsDir() /* also works for symlink */ { + return fmt.Errorf("the APP_DATA_PATH %q is not a directory (or symlink to a directory) and can't be used", AppDataPath) + } + + return nil +} + // LoadFromExisting initializes setting options from an existing config file (app.ini) func LoadFromExisting() { loadFromConf(false, "") From d4e51e250d3fc0437ccd5aa2b185e906f71635b1 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 14 Jan 2023 17:41:20 +0800 Subject: [PATCH 09/20] More refactor --- modules/setting/cron.go | 8 +++- modules/setting/cron_test.go | 8 ++-- modules/setting/indexer.go | 10 ++--- modules/setting/lfs.go | 2 +- modules/setting/log.go | 12 ++++-- modules/setting/mailer.go | 18 ++++---- modules/setting/mirror.go | 2 +- modules/setting/picture.go | 4 +- modules/setting/queue.go | 38 ++++++++++------- modules/setting/server.go | 8 ++-- modules/setting/setting.go | 68 +++++++++++++++--------------- modules/setting/storage_test.go | 75 ++++++++++++++++++--------------- modules/setting/task.go | 6 +-- 13 files changed, 143 insertions(+), 116 deletions(-) diff --git a/modules/setting/cron.go b/modules/setting/cron.go index a76de2797ffc..a275bf3a0732 100644 --- a/modules/setting/cron.go +++ b/modules/setting/cron.go @@ -7,7 +7,11 @@ import "reflect" // GetCronSettings maps the cron subsection to the provided config func GetCronSettings(name string, config interface{}) (interface{}, error) { - if err := Cfg.Section("cron." + name).MapTo(config); err != nil { + return getCronSettings(Cfg, name, config) +} + +func getCronSettings(rootCfg Config, name string, config interface{}) (interface{}, error) { + if err := rootCfg.Section("cron." + name).MapTo(config); err != nil { return config, err } @@ -18,7 +22,7 @@ func GetCronSettings(name string, config interface{}) (interface{}, error) { field := val.Field(i) tpField := typ.Field(i) if tpField.Type.Kind() == reflect.Struct && tpField.Anonymous { - if err := Cfg.Section("cron." + name).MapTo(field.Addr().Interface()); err != nil { + if err := rootCfg.Section("cron." + name).MapTo(field.Addr().Interface()); err != nil { return config, err } } diff --git a/modules/setting/cron_test.go b/modules/setting/cron_test.go index 29cdca8fbfda..be97e59bd9a7 100644 --- a/modules/setting/cron_test.go +++ b/modules/setting/cron_test.go @@ -10,7 +10,7 @@ import ( ini "gopkg.in/ini.v1" ) -func Test_GetCronSettings(t *testing.T) { +func Test_getCronSettings(t *testing.T) { type BaseStruct struct { Base bool Second string @@ -27,7 +27,8 @@ Base = true Second = white rabbit Extend = true ` - Cfg, _ = ini.Load([]byte(iniStr)) + cfg, err := ini.Load([]byte(iniStr)) + assert.NoError(t, err) extended := &Extended{ BaseStruct: BaseStruct{ @@ -35,8 +36,7 @@ Extend = true }, } - _, err := GetCronSettings("test", extended) - + _, err = getCronSettings(cfg, "test", extended) assert.NoError(t, err) assert.True(t, extended.Base) assert.EqualValues(t, extended.Second, "white rabbit") diff --git a/modules/setting/indexer.go b/modules/setting/indexer.go index 0761fe4e4862..f3d2611d788d 100644 --- a/modules/setting/indexer.go +++ b/modules/setting/indexer.go @@ -57,11 +57,11 @@ func parseIndexerSetting(rootCfg Config) { // The following settings are deprecated and can be overridden by settings in [queue] or [queue.issue_indexer] // FIXME: DEPRECATED to be removed in v1.18.0 - deprecatedSetting("indexer", "ISSUE_INDEXER_QUEUE_TYPE", "queue.issue_indexer", "TYPE") - deprecatedSetting("indexer", "ISSUE_INDEXER_QUEUE_DIR", "queue.issue_indexer", "DATADIR") - deprecatedSetting("indexer", "ISSUE_INDEXER_QUEUE_CONN_STR", "queue.issue_indexer", "CONN_STR") - deprecatedSetting("indexer", "ISSUE_INDEXER_QUEUE_BATCH_NUMBER", "queue.issue_indexer", "BATCH_LENGTH") - deprecatedSetting("indexer", "UPDATE_BUFFER_LEN", "queue.issue_indexer", "LENGTH") + deprecatedSetting(rootCfg, "indexer", "ISSUE_INDEXER_QUEUE_TYPE", "queue.issue_indexer", "TYPE") + deprecatedSetting(rootCfg, "indexer", "ISSUE_INDEXER_QUEUE_DIR", "queue.issue_indexer", "DATADIR") + deprecatedSetting(rootCfg, "indexer", "ISSUE_INDEXER_QUEUE_CONN_STR", "queue.issue_indexer", "CONN_STR") + deprecatedSetting(rootCfg, "indexer", "ISSUE_INDEXER_QUEUE_BATCH_NUMBER", "queue.issue_indexer", "BATCH_LENGTH") + deprecatedSetting(rootCfg, "indexer", "UPDATE_BUFFER_LEN", "queue.issue_indexer", "LENGTH") Indexer.RepoIndexerEnabled = sec.Key("REPO_INDEXER_ENABLED").MustBool(false) Indexer.RepoType = sec.Key("REPO_INDEXER_TYPE").MustString("bleve") diff --git a/modules/setting/lfs.go b/modules/setting/lfs.go index 865454844ba7..fbd05bfa6ac8 100644 --- a/modules/setting/lfs.go +++ b/modules/setting/lfs.go @@ -36,7 +36,7 @@ func parseLFSSetting(rootCfg Config) { // Specifically default PATH to LFS_CONTENT_PATH // FIXME: DEPRECATED to be removed in v1.18.0 - deprecatedSetting("server", "LFS_CONTENT_PATH", "lfs", "PATH") + deprecatedSetting(rootCfg, "server", "LFS_CONTENT_PATH", "lfs", "PATH") lfsSec.Key("PATH").MustString( sec.Key("LFS_CONTENT_PATH").String()) diff --git a/modules/setting/log.go b/modules/setting/log.go index 0e4c7d0b3a1c..641e5275363a 100644 --- a/modules/setting/log.go +++ b/modules/setting/log.go @@ -370,14 +370,18 @@ func ParseLogSettings(disableConsole bool) { // ParseXORMLogSetting initializes xorm logger setting func ParseXORMLogSetting(disableConsole bool) { - EnableXORMLog = Cfg.Section("log").Key("ENABLE_XORM_LOG").MustBool(true) + parseXORMLogSetting(Cfg, disableConsole) +} + +func parseXORMLogSetting(rootCfg Config, disableConsole bool) { + EnableXORMLog = rootCfg.Section("log").Key("ENABLE_XORM_LOG").MustBool(true) if EnableXORMLog { options := newDefaultLogOptions() options.filename = filepath.Join(LogRootPath, "xorm.log") - options.bufferLength = Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000) + options.bufferLength = rootCfg.Section("log").Key("BUFFER_LEN").MustInt64(10000) options.disableConsole = disableConsole - Cfg.Section("log").Key("XORM").MustString(",") - generateNamedLogger(Cfg, "xorm", options) + rootCfg.Section("log").Key("XORM").MustString(",") + generateNamedLogger(rootCfg, "xorm", options) } } diff --git a/modules/setting/mailer.go b/modules/setting/mailer.go index 42a28c57a6d6..90860dcf96ab 100644 --- a/modules/setting/mailer.go +++ b/modules/setting/mailer.go @@ -64,7 +64,7 @@ func parseMailerSetting(rootCfg Config) { // Handle Deprecations and map on to new configuration // FIXME: DEPRECATED to be removed in v1.19.0 - deprecatedSetting("mailer", "MAILER_TYPE", "mailer", "PROTOCOL") + deprecatedSetting(rootCfg, "mailer", "MAILER_TYPE", "mailer", "PROTOCOL") if sec.HasKey("MAILER_TYPE") && !sec.HasKey("PROTOCOL") { if sec.Key("MAILER_TYPE").String() == "sendmail" { sec.Key("PROTOCOL").MustString("sendmail") @@ -72,7 +72,7 @@ func parseMailerSetting(rootCfg Config) { } // FIXME: DEPRECATED to be removed in v1.19.0 - deprecatedSetting("mailer", "HOST", "mailer", "SMTP_ADDR") + deprecatedSetting(rootCfg, "mailer", "HOST", "mailer", "SMTP_ADDR") if sec.HasKey("HOST") && !sec.HasKey("SMTP_ADDR") { givenHost := sec.Key("HOST").String() addr, port, err := net.SplitHostPort(givenHost) @@ -89,7 +89,7 @@ func parseMailerSetting(rootCfg Config) { } // FIXME: DEPRECATED to be removed in v1.19.0 - deprecatedSetting("mailer", "IS_TLS_ENABLED", "mailer", "PROTOCOL") + deprecatedSetting(rootCfg, "mailer", "IS_TLS_ENABLED", "mailer", "PROTOCOL") if sec.HasKey("IS_TLS_ENABLED") && !sec.HasKey("PROTOCOL") { if sec.Key("IS_TLS_ENABLED").MustBool() { sec.Key("PROTOCOL").MustString("smtps") @@ -99,37 +99,37 @@ func parseMailerSetting(rootCfg Config) { } // FIXME: DEPRECATED to be removed in v1.19.0 - deprecatedSetting("mailer", "DISABLE_HELO", "mailer", "ENABLE_HELO") + deprecatedSetting(rootCfg, "mailer", "DISABLE_HELO", "mailer", "ENABLE_HELO") if sec.HasKey("DISABLE_HELO") && !sec.HasKey("ENABLE_HELO") { sec.Key("ENABLE_HELO").MustBool(!sec.Key("DISABLE_HELO").MustBool()) } // FIXME: DEPRECATED to be removed in v1.19.0 - deprecatedSetting("mailer", "SKIP_VERIFY", "mailer", "FORCE_TRUST_SERVER_CERT") + deprecatedSetting(rootCfg, "mailer", "SKIP_VERIFY", "mailer", "FORCE_TRUST_SERVER_CERT") if sec.HasKey("SKIP_VERIFY") && !sec.HasKey("FORCE_TRUST_SERVER_CERT") { sec.Key("FORCE_TRUST_SERVER_CERT").MustBool(sec.Key("SKIP_VERIFY").MustBool()) } // FIXME: DEPRECATED to be removed in v1.19.0 - deprecatedSetting("mailer", "USE_CERTIFICATE", "mailer", "USE_CLIENT_CERT") + deprecatedSetting(rootCfg, "mailer", "USE_CERTIFICATE", "mailer", "USE_CLIENT_CERT") if sec.HasKey("USE_CERTIFICATE") && !sec.HasKey("USE_CLIENT_CERT") { sec.Key("USE_CLIENT_CERT").MustBool(sec.Key("USE_CERTIFICATE").MustBool()) } // FIXME: DEPRECATED to be removed in v1.19.0 - deprecatedSetting("mailer", "CERT_FILE", "mailer", "CLIENT_CERT_FILE") + deprecatedSetting(rootCfg, "mailer", "CERT_FILE", "mailer", "CLIENT_CERT_FILE") if sec.HasKey("CERT_FILE") && !sec.HasKey("CLIENT_CERT_FILE") { sec.Key("CERT_FILE").MustString(sec.Key("CERT_FILE").String()) } // FIXME: DEPRECATED to be removed in v1.19.0 - deprecatedSetting("mailer", "KEY_FILE", "mailer", "CLIENT_KEY_FILE") + deprecatedSetting(rootCfg, "mailer", "KEY_FILE", "mailer", "CLIENT_KEY_FILE") if sec.HasKey("KEY_FILE") && !sec.HasKey("CLIENT_KEY_FILE") { sec.Key("KEY_FILE").MustString(sec.Key("KEY_FILE").String()) } // FIXME: DEPRECATED to be removed in v1.19.0 - deprecatedSetting("mailer", "ENABLE_HTML_ALTERNATIVE", "mailer", "SEND_AS_PLAIN_TEXT") + deprecatedSetting(rootCfg, "mailer", "ENABLE_HTML_ALTERNATIVE", "mailer", "SEND_AS_PLAIN_TEXT") if sec.HasKey("ENABLE_HTML_ALTERNATIVE") && !sec.HasKey("SEND_AS_PLAIN_TEXT") { sec.Key("SEND_AS_PLAIN_TEXT").MustBool(!sec.Key("ENABLE_HTML_ALTERNATIVE").MustBool(false)) } diff --git a/modules/setting/mirror.go b/modules/setting/mirror.go index 7a0ab516f2f6..99a417c50443 100644 --- a/modules/setting/mirror.go +++ b/modules/setting/mirror.go @@ -28,7 +28,7 @@ func parseMirrorSetting(rootCfg Config) { // Handle old configuration through `[repository]` `DISABLE_MIRRORS` // - please note this was badly named and only disabled the creation of new pull mirrors // FIXME: DEPRECATED to be removed in v1.18.0 - deprecatedSetting("repository", "DISABLE_MIRRORS", "mirror", "ENABLED") + deprecatedSetting(rootCfg, "repository", "DISABLE_MIRRORS", "mirror", "ENABLED") if rootCfg.Section("repository").Key("DISABLE_MIRRORS").MustBool(false) { Mirror.DisableNewPull = true } diff --git a/modules/setting/picture.go b/modules/setting/picture.go index 79118011a9b3..cae8a99ef16b 100644 --- a/modules/setting/picture.go +++ b/modules/setting/picture.go @@ -60,9 +60,9 @@ func parsePictureSetting(rootCfg Config) { } DisableGravatar = sec.Key("DISABLE_GRAVATAR").MustBool(GetDefaultDisableGravatar()) - deprecatedSettingDB("", "DISABLE_GRAVATAR") + deprecatedSettingDB(rootCfg, "", "DISABLE_GRAVATAR") EnableFederatedAvatar = sec.Key("ENABLE_FEDERATED_AVATAR").MustBool(GetDefaultEnableFederatedAvatar(DisableGravatar)) - deprecatedSettingDB("", "ENABLE_FEDERATED_AVATAR") + deprecatedSettingDB(rootCfg, "", "ENABLE_FEDERATED_AVATAR") parseRepoAvatarSetting(rootCfg) } diff --git a/modules/setting/queue.go b/modules/setting/queue.go index 2bfc64e59da2..c0f7592ca021 100644 --- a/modules/setting/queue.go +++ b/modules/setting/queue.go @@ -39,8 +39,12 @@ var Queue = QueueSettings{} // GetQueueSettings returns the queue settings for the appropriately named queue func GetQueueSettings(name string) QueueSettings { + return getQueueSettings(Cfg, name) +} + +func getQueueSettings(rootCfg Config, name string) QueueSettings { q := QueueSettings{} - sec := Cfg.Section("queue." + name) + sec := rootCfg.Section("queue." + name) q.Name = name // DataDir is not directly inheritable @@ -85,7 +89,11 @@ func GetQueueSettings(name string) QueueSettings { // ParseQueueSettings sets up the default settings for Queues // This is exported for tests to be able to use the queue func ParseQueueSettings() { - sec := Cfg.Section("queue") + parseQueueSettings(Cfg) +} + +func parseQueueSettings(rootCfg Config) { + sec := rootCfg.Section("queue") Queue.DataDir = filepath.ToSlash(sec.Key("DATADIR").MustString("queues/")) if !filepath.IsAbs(Queue.DataDir) { Queue.DataDir = filepath.ToSlash(filepath.Join(AppDataPath, Queue.DataDir)) @@ -108,10 +116,10 @@ func ParseQueueSettings() { // Now handle the old issue_indexer configuration // FIXME: DEPRECATED to be removed in v1.18.0 - section := Cfg.Section("queue.issue_indexer") + section := rootCfg.Section("queue.issue_indexer") directlySet := toDirectlySetKeysSet(section) if !directlySet.Contains("TYPE") && defaultType == "" { - switch typ := Cfg.Section("indexer").Key("ISSUE_INDEXER_QUEUE_TYPE").MustString(""); typ { + switch typ := rootCfg.Section("indexer").Key("ISSUE_INDEXER_QUEUE_TYPE").MustString(""); typ { case "levelqueue": _, _ = section.NewKey("TYPE", "level") case "channel": @@ -125,25 +133,25 @@ func ParseQueueSettings() { } } if !directlySet.Contains("LENGTH") { - length := Cfg.Section("indexer").Key("UPDATE_BUFFER_LEN").MustInt(0) + length := rootCfg.Section("indexer").Key("UPDATE_BUFFER_LEN").MustInt(0) if length != 0 { _, _ = section.NewKey("LENGTH", strconv.Itoa(length)) } } if !directlySet.Contains("BATCH_LENGTH") { - fallback := Cfg.Section("indexer").Key("ISSUE_INDEXER_QUEUE_BATCH_NUMBER").MustInt(0) + fallback := rootCfg.Section("indexer").Key("ISSUE_INDEXER_QUEUE_BATCH_NUMBER").MustInt(0) if fallback != 0 { _, _ = section.NewKey("BATCH_LENGTH", strconv.Itoa(fallback)) } } if !directlySet.Contains("DATADIR") { - queueDir := filepath.ToSlash(Cfg.Section("indexer").Key("ISSUE_INDEXER_QUEUE_DIR").MustString("")) + queueDir := filepath.ToSlash(rootCfg.Section("indexer").Key("ISSUE_INDEXER_QUEUE_DIR").MustString("")) if queueDir != "" { _, _ = section.NewKey("DATADIR", queueDir) } } if !directlySet.Contains("CONN_STR") { - connStr := Cfg.Section("indexer").Key("ISSUE_INDEXER_QUEUE_CONN_STR").MustString("") + connStr := rootCfg.Section("indexer").Key("ISSUE_INDEXER_QUEUE_CONN_STR").MustString("") if connStr != "" { _, _ = section.NewKey("CONN_STR", connStr) } @@ -153,31 +161,31 @@ func ParseQueueSettings() { // - will need to set default for [queue.*)] LENGTH appropriately though though // Handle the old mailer configuration - handleOldLengthConfiguration("mailer", "mailer", "SEND_BUFFER_LEN", 100) + handleOldLengthConfiguration(rootCfg, "mailer", "mailer", "SEND_BUFFER_LEN", 100) // Handle the old test pull requests configuration // Please note this will be a unique queue - handleOldLengthConfiguration("pr_patch_checker", "repository", "PULL_REQUEST_QUEUE_LENGTH", 1000) + handleOldLengthConfiguration(rootCfg, "pr_patch_checker", "repository", "PULL_REQUEST_QUEUE_LENGTH", 1000) // Handle the old mirror queue configuration // Please note this will be a unique queue - handleOldLengthConfiguration("mirror", "repository", "MIRROR_QUEUE_LENGTH", 1000) + handleOldLengthConfiguration(rootCfg, "mirror", "repository", "MIRROR_QUEUE_LENGTH", 1000) } // handleOldLengthConfiguration allows fallback to older configuration. `[queue.name]` `LENGTH` will override this configuration, but // if that is left unset then we should fallback to the older configuration. (Except where the new length woul be <=0) -func handleOldLengthConfiguration(queueName, oldSection, oldKey string, defaultValue int) { - if Cfg.Section(oldSection).HasKey(oldKey) { +func handleOldLengthConfiguration(rootCfg Config, queueName, oldSection, oldKey string, defaultValue int) { + if rootCfg.Section(oldSection).HasKey(oldKey) { log.Error("Deprecated fallback for %s queue length `[%s]` `%s` present. Use `[queue.%s]` `LENGTH`. This will be removed in v1.18.0", queueName, queueName, oldSection, oldKey) } - value := Cfg.Section(oldSection).Key(oldKey).MustInt(defaultValue) + value := rootCfg.Section(oldSection).Key(oldKey).MustInt(defaultValue) // Don't override with 0 if value <= 0 { return } - section := Cfg.Section("queue." + queueName) + section := rootCfg.Section("queue." + queueName) directlySet := toDirectlySetKeysSet(section) if !directlySet.Contains("LENGTH") { _, _ = section.NewKey("LENGTH", strconv.Itoa(value)) diff --git a/modules/setting/server.go b/modules/setting/server.go index cb0b426e1a04..bc9c882db836 100644 --- a/modules/setting/server.go +++ b/modules/setting/server.go @@ -188,7 +188,7 @@ func parseServerSetting(rootCfg Config) { if sec.HasKey("ENABLE_ACME") { EnableAcme = sec.Key("ENABLE_ACME").MustBool(false) } else { - deprecatedSetting("server", "ENABLE_LETSENCRYPT", "server", "ENABLE_ACME") + deprecatedSetting(rootCfg, "server", "ENABLE_LETSENCRYPT", "server", "ENABLE_ACME") EnableAcme = sec.Key("ENABLE_LETSENCRYPT").MustBool(false) } if EnableAcme { @@ -198,7 +198,7 @@ func parseServerSetting(rootCfg Config) { if sec.HasKey("ACME_ACCEPTTOS") { AcmeTOS = sec.Key("ACME_ACCEPTTOS").MustBool(false) } else { - deprecatedSetting("server", "LETSENCRYPT_ACCEPTTOS", "server", "ACME_ACCEPTTOS") + deprecatedSetting(rootCfg, "server", "LETSENCRYPT_ACCEPTTOS", "server", "ACME_ACCEPTTOS") AcmeTOS = sec.Key("LETSENCRYPT_ACCEPTTOS").MustBool(false) } if !AcmeTOS { @@ -208,14 +208,14 @@ func parseServerSetting(rootCfg Config) { if sec.HasKey("ACME_DIRECTORY") { AcmeLiveDirectory = sec.Key("ACME_DIRECTORY").MustString("https") } else { - deprecatedSetting("server", "LETSENCRYPT_DIRECTORY", "server", "ACME_DIRECTORY") + deprecatedSetting(rootCfg, "server", "LETSENCRYPT_DIRECTORY", "server", "ACME_DIRECTORY") AcmeLiveDirectory = sec.Key("LETSENCRYPT_DIRECTORY").MustString("https") } // FIXME: DEPRECATED to be removed in v1.18.0 if sec.HasKey("ACME_EMAIL") { AcmeEmail = sec.Key("ACME_EMAIL").MustString("") } else { - deprecatedSetting("server", "LETSENCRYPT_EMAIL", "server", "ACME_EMAIL") + deprecatedSetting(rootCfg, "server", "LETSENCRYPT_EMAIL", "server", "ACME_EMAIL") AcmeEmail = sec.Key("LETSENCRYPT_EMAIL").MustString("") } } else { diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 0bd0f927a811..7adfd6c12355 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -218,39 +218,39 @@ func PrepareAppDataPath() error { // LoadFromExisting initializes setting options from an existing config file (app.ini) func LoadFromExisting() { - loadFromConf(false, "") + Cfg = loadFromConf(false, "") } // LoadAllowEmpty initializes setting options, it's also fine that if the config file (app.ini) doesn't exist func LoadAllowEmpty() { - loadFromConf(true, "") + Cfg = loadFromConf(true, "") } // LoadForTest initializes setting options for tests func LoadForTest(extraConfigs ...string) { - loadFromConf(true, strings.Join(extraConfigs, "\n")) + Cfg = loadFromConf(true, strings.Join(extraConfigs, "\n")) if err := PrepareAppDataPath(); err != nil { log.Fatal("Can not prepare APP_DATA_PATH: %v", err) } } -func deprecatedSetting(oldSection, oldKey, newSection, newKey string) { - if Cfg.Section(oldSection).HasKey(oldKey) { +func deprecatedSetting(rootCfg Config, oldSection, oldKey, newSection, newKey string) { + if rootCfg.Section(oldSection).HasKey(oldKey) { log.Error("Deprecated fallback `[%s]` `%s` present. Use `[%s]` `%s` instead. This fallback will be removed in v1.19.0", oldSection, oldKey, newSection, newKey) } } // deprecatedSettingDB add a hint that the configuration has been moved to database but still kept in app.ini -func deprecatedSettingDB(oldSection, oldKey string) { - if Cfg.Section(oldSection).HasKey(oldKey) { +func deprecatedSettingDB(rootCfg Config, oldSection, oldKey string) { + if rootCfg.Section(oldSection).HasKey(oldKey) { log.Error("Deprecated `[%s]` `%s` present which has been copied to database table sys_setting", oldSection, oldKey) } } // loadFromConf initializes configuration context. // NOTE: do not print any log except error. -func loadFromConf(allowEmpty bool, extraConfig string) { - Cfg = ini.Empty() +func loadFromConf(allowEmpty bool, extraConfig string) *ini.File { + cfg := ini.Empty() if WritePIDFile && len(PIDFile) > 0 { createPIDFile(PIDFile) @@ -261,7 +261,7 @@ func loadFromConf(allowEmpty bool, extraConfig string) { log.Error("Unable to check if %s is a file. Error: %v", CustomConf, err) } if isFile { - if err := Cfg.Append(CustomConf); err != nil { + if err := cfg.Append(CustomConf); err != nil { log.Fatal("Failed to load custom conf '%s': %v", CustomConf, err) } } else if !allowEmpty { @@ -269,35 +269,37 @@ func loadFromConf(allowEmpty bool, extraConfig string) { } // else: no config file, a config file might be created at CustomConf later (might not) if extraConfig != "" { - if err = Cfg.Append([]byte(extraConfig)); err != nil { + if err = cfg.Append([]byte(extraConfig)); err != nil { log.Fatal("Unable to append more config: %v", err) } } - Cfg.NameMapper = ini.SnackCase + cfg.NameMapper = ini.SnackCase // WARNNING: don't change the sequence except you know what you are doing. - parseRunModeSetting(Cfg) - parseServerSetting(Cfg) - parseSSHSetting(Cfg) - parseOAuth2Setting(Cfg) - parseSecuritySetting(Cfg) - parseAttachmentSetting(Cfg) - parseLFSSetting(Cfg) - parseTimeSetting(Cfg) - parseRepositorySetting(Cfg) - parsePictureSetting(Cfg) - parsePackagesSetting(Cfg) - parseUISetting(Cfg) - parseAdminSetting(Cfg) - parseAPISetting(Cfg) - parseMetricsSetting(Cfg) - parseCamoSetting(Cfg) - parseI18nSetting(Cfg) - parseGitSetting(Cfg) - parseMirrorSetting(Cfg) - parseMarkupSetting(Cfg) - parseOtherSetting(Cfg) + parseRunModeSetting(cfg) + parseServerSetting(cfg) + parseSSHSetting(cfg) + parseOAuth2Setting(cfg) + parseSecuritySetting(cfg) + parseAttachmentSetting(cfg) + parseLFSSetting(cfg) + parseTimeSetting(cfg) + parseRepositorySetting(cfg) + parsePictureSetting(cfg) + parsePackagesSetting(cfg) + parseUISetting(cfg) + parseAdminSetting(cfg) + parseAPISetting(cfg) + parseMetricsSetting(cfg) + parseCamoSetting(cfg) + parseI18nSetting(cfg) + parseGitSetting(cfg) + parseMirrorSetting(cfg) + parseMarkupSetting(cfg) + parseOtherSetting(cfg) + + return cfg } func parseRunModeSetting(rootCfg Config) { diff --git a/modules/setting/storage_test.go b/modules/setting/storage_test.go index 2f8710336f2a..7737d233b9b0 100644 --- a/modules/setting/storage_test.go +++ b/modules/setting/storage_test.go @@ -20,11 +20,12 @@ MINIO_BUCKET = gitea-attachment STORAGE_TYPE = minio MINIO_ENDPOINT = my_minio:9000 ` - Cfg, _ = ini.Load([]byte(iniStr)) + cfg, err := ini.Load([]byte(iniStr)) + assert.NoError(t, err) - sec := Cfg.Section("attachment") + sec := cfg.Section("attachment") storageType := sec.Key("STORAGE_TYPE").MustString("") - storage := getStorage(Cfg, "attachments", storageType, sec) + storage := getStorage(cfg, "attachments", storageType, sec) assert.EqualValues(t, "minio", storage.Type) assert.EqualValues(t, "my_minio:9000", storage.Section.Key("MINIO_ENDPOINT").String()) @@ -42,11 +43,12 @@ MINIO_BUCKET = gitea-attachment [storage.minio] MINIO_BUCKET = gitea ` - Cfg, _ = ini.Load([]byte(iniStr)) + cfg, err := ini.Load([]byte(iniStr)) + assert.NoError(t, err) - sec := Cfg.Section("attachment") + sec := cfg.Section("attachment") storageType := sec.Key("STORAGE_TYPE").MustString("") - storage := getStorage(Cfg, "attachments", storageType, sec) + storage := getStorage(cfg, "attachments", storageType, sec) assert.EqualValues(t, "minio", storage.Type) assert.EqualValues(t, "gitea-attachment", storage.Section.Key("MINIO_BUCKET").String()) @@ -63,11 +65,12 @@ MINIO_BUCKET = gitea-minio [storage] MINIO_BUCKET = gitea ` - Cfg, _ = ini.Load([]byte(iniStr)) + cfg, err := ini.Load([]byte(iniStr)) + assert.NoError(t, err) - sec := Cfg.Section("attachment") + sec := cfg.Section("attachment") storageType := sec.Key("STORAGE_TYPE").MustString("") - storage := getStorage(Cfg, "attachments", storageType, sec) + storage := getStorage(cfg, "attachments", storageType, sec) assert.EqualValues(t, "minio", storage.Type) assert.EqualValues(t, "gitea-minio", storage.Section.Key("MINIO_BUCKET").String()) @@ -85,22 +88,24 @@ MINIO_BUCKET = gitea [storage] STORAGE_TYPE = local ` - Cfg, _ = ini.Load([]byte(iniStr)) + cfg, err := ini.Load([]byte(iniStr)) + assert.NoError(t, err) - sec := Cfg.Section("attachment") + sec := cfg.Section("attachment") storageType := sec.Key("STORAGE_TYPE").MustString("") - storage := getStorage(Cfg, "attachments", storageType, sec) + storage := getStorage(cfg, "attachments", storageType, sec) assert.EqualValues(t, "minio", storage.Type) assert.EqualValues(t, "gitea-attachment", storage.Section.Key("MINIO_BUCKET").String()) } func Test_getStorageGetDefaults(t *testing.T) { - Cfg, _ = ini.Load([]byte("")) + cfg, err := ini.Load([]byte("")) + assert.NoError(t, err) - sec := Cfg.Section("attachment") + sec := cfg.Section("attachment") storageType := sec.Key("STORAGE_TYPE").MustString("") - storage := getStorage(Cfg, "attachments", storageType, sec) + storage := getStorage(cfg, "attachments", storageType, sec) assert.EqualValues(t, "gitea", storage.Section.Key("MINIO_BUCKET").String()) } @@ -116,26 +121,27 @@ MINIO_BUCKET = gitea-attachment [storage] MINIO_BUCKET = gitea-storage ` - Cfg, _ = ini.Load([]byte(iniStr)) + cfg, err := ini.Load([]byte(iniStr)) + assert.NoError(t, err) { - sec := Cfg.Section("attachment") + sec := cfg.Section("attachment") storageType := sec.Key("STORAGE_TYPE").MustString("") - storage := getStorage(Cfg, "attachments", storageType, sec) + storage := getStorage(cfg, "attachments", storageType, sec) assert.EqualValues(t, "gitea-attachment", storage.Section.Key("MINIO_BUCKET").String()) } { - sec := Cfg.Section("lfs") + sec := cfg.Section("lfs") storageType := sec.Key("STORAGE_TYPE").MustString("") - storage := getStorage(Cfg, "lfs", storageType, sec) + storage := getStorage(cfg, "lfs", storageType, sec) assert.EqualValues(t, "gitea-lfs", storage.Section.Key("MINIO_BUCKET").String()) } { - sec := Cfg.Section("avatar") + sec := cfg.Section("avatar") storageType := sec.Key("STORAGE_TYPE").MustString("") - storage := getStorage(Cfg, "avatars", storageType, sec) + storage := getStorage(cfg, "avatars", storageType, sec) assert.EqualValues(t, "gitea-storage", storage.Section.Key("MINIO_BUCKET").String()) } @@ -149,19 +155,20 @@ STORAGE_TYPE = lfs [storage.lfs] MINIO_BUCKET = gitea-storage ` - Cfg, _ = ini.Load([]byte(iniStr)) + cfg, err := ini.Load([]byte(iniStr)) + assert.NoError(t, err) { - sec := Cfg.Section("attachment") + sec := cfg.Section("attachment") storageType := sec.Key("STORAGE_TYPE").MustString("") - storage := getStorage(Cfg, "attachments", storageType, sec) + storage := getStorage(cfg, "attachments", storageType, sec) assert.EqualValues(t, "gitea-storage", storage.Section.Key("MINIO_BUCKET").String()) } { - sec := Cfg.Section("lfs") + sec := cfg.Section("lfs") storageType := sec.Key("STORAGE_TYPE").MustString("") - storage := getStorage(Cfg, "lfs", storageType, sec) + storage := getStorage(cfg, "lfs", storageType, sec) assert.EqualValues(t, "gitea-storage", storage.Section.Key("MINIO_BUCKET").String()) } @@ -172,11 +179,12 @@ func Test_getStorageInheritStorageType(t *testing.T) { [storage] STORAGE_TYPE = minio ` - Cfg, _ = ini.Load([]byte(iniStr)) + cfg, err := ini.Load([]byte(iniStr)) + assert.NoError(t, err) - sec := Cfg.Section("attachment") + sec := cfg.Section("attachment") storageType := sec.Key("STORAGE_TYPE").MustString("") - storage := getStorage(Cfg, "attachments", storageType, sec) + storage := getStorage(cfg, "attachments", storageType, sec) assert.EqualValues(t, "minio", storage.Type) } @@ -186,11 +194,12 @@ func Test_getStorageInheritNameSectionType(t *testing.T) { [storage.attachments] STORAGE_TYPE = minio ` - Cfg, _ = ini.Load([]byte(iniStr)) + cfg, err := ini.Load([]byte(iniStr)) + assert.NoError(t, err) - sec := Cfg.Section("attachment") + sec := cfg.Section("attachment") storageType := sec.Key("STORAGE_TYPE").MustString("") - storage := getStorage(Cfg, "attachments", storageType, sec) + storage := getStorage(cfg, "attachments", storageType, sec) assert.EqualValues(t, "minio", storage.Type) } diff --git a/modules/setting/task.go b/modules/setting/task.go index 35dac48c4fc8..5680dc4ac6bb 100644 --- a/modules/setting/task.go +++ b/modules/setting/task.go @@ -9,9 +9,9 @@ func parseTaskSetting(rootCfg Config) { taskSec := rootCfg.Section("task") queueTaskSec := rootCfg.Section("queue.task") - deprecatedSetting("task", "QUEUE_TYPE", "queue.task", "TYPE") - deprecatedSetting("task", "QUEUE_CONN_STR", "queue.task", "CONN_STR") - deprecatedSetting("task", "QUEUE_LENGTH", "queue.task", "LENGTH") + deprecatedSetting(rootCfg, "task", "QUEUE_TYPE", "queue.task", "TYPE") + deprecatedSetting(rootCfg, "task", "QUEUE_CONN_STR", "queue.task", "CONN_STR") + deprecatedSetting(rootCfg, "task", "QUEUE_LENGTH", "queue.task", "LENGTH") switch taskSec.Key("QUEUE_TYPE").MustString("channel") { case "channel": From e2d63dec3133ff5881366dc959ff1344b9f6fad4 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 14 Jan 2023 17:48:17 +0800 Subject: [PATCH 10/20] some improvement --- modules/setting/setting.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 7adfd6c12355..2bdf9c1cdd0f 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -218,17 +218,17 @@ func PrepareAppDataPath() error { // LoadFromExisting initializes setting options from an existing config file (app.ini) func LoadFromExisting() { - Cfg = loadFromConf(false, "") + Cfg = loadFromConf(CustomConf, WritePIDFile, false, PIDFile, "") } // LoadAllowEmpty initializes setting options, it's also fine that if the config file (app.ini) doesn't exist func LoadAllowEmpty() { - Cfg = loadFromConf(true, "") + Cfg = loadFromConf(CustomConf, WritePIDFile, true, PIDFile,"") } // LoadForTest initializes setting options for tests func LoadForTest(extraConfigs ...string) { - Cfg = loadFromConf(true, strings.Join(extraConfigs, "\n")) + Cfg = loadFromConf(CustomConf, WritePIDFile, true, PIDFile,strings.Join(extraConfigs, "\n")) if err := PrepareAppDataPath(); err != nil { log.Fatal("Can not prepare APP_DATA_PATH: %v", err) } @@ -249,20 +249,20 @@ func deprecatedSettingDB(rootCfg Config, oldSection, oldKey string) { // loadFromConf initializes configuration context. // NOTE: do not print any log except error. -func loadFromConf(allowEmpty bool, extraConfig string) *ini.File { +func loadFromConf(customConf string, writePIDFile, allowEmpty bool, pidFile, extraConfig string) *ini.File { cfg := ini.Empty() - if WritePIDFile && len(PIDFile) > 0 { - createPIDFile(PIDFile) + if writePIDFile && len(pidFile) > 0 { + createPIDFile(pidFile) } - isFile, err := util.IsFile(CustomConf) + isFile, err := util.IsFile(customConf) if err != nil { - log.Error("Unable to check if %s is a file. Error: %v", CustomConf, err) + log.Error("Unable to check if %s is a file. Error: %v", customConf, err) } if isFile { - if err := cfg.Append(CustomConf); err != nil { - log.Fatal("Failed to load custom conf '%s': %v", CustomConf, err) + if err := cfg.Append(customConf); err != nil { + log.Fatal("Failed to load custom conf '%s': %v", customConf, err) } } else if !allowEmpty { log.Fatal("Unable to find configuration file: %q.\nEnsure you are running in the correct environment or set the correct configuration file with -c.", CustomConf) From 5afb136586cadee5388fddb1cf5f6ba0ffd275f0 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 14 Jan 2023 18:02:10 +0800 Subject: [PATCH 11/20] fix lint --- modules/setting/setting.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 2bdf9c1cdd0f..c18971186ebd 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -223,12 +223,12 @@ func LoadFromExisting() { // LoadAllowEmpty initializes setting options, it's also fine that if the config file (app.ini) doesn't exist func LoadAllowEmpty() { - Cfg = loadFromConf(CustomConf, WritePIDFile, true, PIDFile,"") + Cfg = loadFromConf(CustomConf, WritePIDFile, true, PIDFile, "") } // LoadForTest initializes setting options for tests func LoadForTest(extraConfigs ...string) { - Cfg = loadFromConf(CustomConf, WritePIDFile, true, PIDFile,strings.Join(extraConfigs, "\n")) + Cfg = loadFromConf(CustomConf, WritePIDFile, true, PIDFile, strings.Join(extraConfigs, "\n")) if err := PrepareAppDataPath(); err != nil { log.Fatal("Can not prepare APP_DATA_PATH: %v", err) } From ab0d264a0fd8dbc77296cd5eafc86860f6b6c4a2 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 15 Jan 2023 23:30:17 +0800 Subject: [PATCH 12/20] Rename --- cmd/cmd.go | 4 +- cmd/doctor.go | 4 +- cmd/dump.go | 2 +- models/migrations/base/tests.go | 4 +- modules/doctor/doctor.go | 4 +- modules/indexer/issues/indexer_test.go | 2 +- modules/indexer/stats/indexer_test.go | 2 +- modules/setting/admin.go | 2 +- modules/setting/api.go | 2 +- modules/setting/attachment.go | 2 +- modules/setting/cache.go | 2 +- modules/setting/camo.go | 2 +- modules/setting/cors.go | 2 +- modules/setting/database.go | 4 +- modules/setting/federation.go | 2 +- modules/setting/git.go | 2 +- modules/setting/i18n.go | 2 +- modules/setting/indexer.go | 2 +- modules/setting/lfs.go | 2 +- modules/setting/log.go | 28 +++--- modules/setting/mailer.go | 14 +-- modules/setting/mailer_test.go | 4 +- modules/setting/markup.go | 2 +- modules/setting/metrics.go | 2 +- modules/setting/migrations.go | 2 +- modules/setting/mime_type_map.go | 2 +- modules/setting/mirror.go | 2 +- modules/setting/oauth2.go | 4 +- modules/setting/other.go | 2 +- modules/setting/packages.go | 2 +- modules/setting/picture.go | 6 +- modules/setting/project.go | 2 +- modules/setting/proxy.go | 2 +- modules/setting/queue.go | 8 +- modules/setting/repository.go | 2 +- modules/setting/security.go | 2 +- modules/setting/server.go | 2 +- modules/setting/service.go | 2 +- modules/setting/session.go | 2 +- modules/setting/setting.go | 92 +++++++++---------- modules/setting/ssh.go | 2 +- modules/setting/task.go | 2 +- modules/setting/time.go | 2 +- modules/setting/ui.go | 2 +- modules/setting/webhook.go | 2 +- routers/api/v1/repo/main_test.go | 2 +- routers/init.go | 4 +- routers/install/setting.go | 4 +- services/webhook/main_test.go | 2 +- .../migration-test/migration_test.go | 6 +- tests/test_utils.go | 2 +- 51 files changed, 131 insertions(+), 131 deletions(-) diff --git a/cmd/cmd.go b/cmd/cmd.go index 849f3b7dc3c0..e93a6b33df55 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -58,8 +58,8 @@ func confirm() (bool, error) { func initDB(ctx context.Context) error { setting.LoadFromExisting() - setting.ParseDBSetting() - setting.ParseXORMLogSetting(false) + setting.LoadDBSetting() + setting.LoadSQLLogSetting(false) if setting.Database.Type == "" { log.Fatal(`Database settings are missing from the configuration file: %q. diff --git a/cmd/doctor.go b/cmd/doctor.go index 316cd095fece..61e4e7da6610 100644 --- a/cmd/doctor.go +++ b/cmd/doctor.go @@ -88,13 +88,13 @@ func runRecreateTable(ctx *cli.Context) error { golog.SetOutput(log.NewLoggerAsWriter("INFO", log.GetLogger(log.DEFAULT))) setting.LoadFromExisting() - setting.ParseDBSetting() + setting.LoadDBSetting() setting.EnableXORMLog = ctx.Bool("debug") setting.Database.LogSQL = ctx.Bool("debug") setting.Cfg.Section("log").Key("XORM").SetValue(",") - setting.ParseXORMLogSetting(!ctx.Bool("debug")) + setting.LoadSQLLogSetting(!ctx.Bool("debug")) stdCtx, cancel := installSignals() defer cancel() diff --git a/cmd/dump.go b/cmd/dump.go index 332e317871bd..909ab6d44fe7 100644 --- a/cmd/dump.go +++ b/cmd/dump.go @@ -194,7 +194,7 @@ func runDump(ctx *cli.Context) error { log.Error("Is '%s' really the right config path?\n", setting.CustomConf) return fmt.Errorf("gitea is not initialized") } - setting.ParseSettings() // cannot access session settings otherwise + setting.LoadSettings() // cannot access session settings otherwise stdCtx, cancel := installSignals() defer cancel() diff --git a/models/migrations/base/tests.go b/models/migrations/base/tests.go index 7086bf1fd65b..9c02338b6d72 100644 --- a/models/migrations/base/tests.go +++ b/models/migrations/base/tests.go @@ -154,8 +154,8 @@ func MainTest(m *testing.M) { fmt.Printf("Unable to InitFull: %v\n", err) os.Exit(1) } - setting.ParseDBSetting() - setting.ParseLogSettings(true) + setting.LoadDBSetting() + setting.LoadLogSettings(true) exitStatus := m.Run() diff --git a/modules/doctor/doctor.go b/modules/doctor/doctor.go index 5b3d27f4c9c4..4930ca2b42a5 100644 --- a/modules/doctor/doctor.go +++ b/modules/doctor/doctor.go @@ -45,8 +45,8 @@ func (w *wrappedLevelLogger) Log(skip int, level log.Level, format string, v ... func initDBDisableConsole(ctx context.Context, disableConsole bool) error { setting.LoadFromExisting() - setting.ParseDBSetting() - setting.ParseXORMLogSetting(disableConsole) + setting.LoadDBSetting() + setting.LoadSQLLogSetting(disableConsole) if err := db.InitEngine(ctx); err != nil { return fmt.Errorf("db.InitEngine: %w", err) } diff --git a/modules/indexer/issues/indexer_test.go b/modules/indexer/issues/indexer_test.go index f06994a57089..b7f70b72fb2e 100644 --- a/modules/indexer/issues/indexer_test.go +++ b/modules/indexer/issues/indexer_test.go @@ -40,7 +40,7 @@ func TestBleveSearchIssues(t *testing.T) { }() setting.Indexer.IssueType = "bleve" - setting.ParseQueueSettings() + setting.LoadQueueSettings() InitIssueIndexer(true) defer func() { indexer := holder.get() diff --git a/modules/indexer/stats/indexer_test.go b/modules/indexer/stats/indexer_test.go index 5dc031f20da3..7319fc9fa30f 100644 --- a/modules/indexer/stats/indexer_test.go +++ b/modules/indexer/stats/indexer_test.go @@ -31,7 +31,7 @@ func TestRepoStatsIndex(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) setting.Cfg = ini.Empty() - setting.ParseQueueSettings() + setting.LoadQueueSettings() err := Init() assert.NoError(t, err) diff --git a/modules/setting/admin.go b/modules/setting/admin.go index 84aa5831f6ed..2dbf83907982 100644 --- a/modules/setting/admin.go +++ b/modules/setting/admin.go @@ -9,7 +9,7 @@ var Admin struct { DefaultEmailNotification string } -func parseAdminSetting(rootCfg Config) { +func loadAdminFrom(rootCfg Config) { mustMapSetting(rootCfg, "admin", &Admin) sec := rootCfg.Section("admin") Admin.DefaultEmailNotification = sec.Key("DEFAULT_EMAIL_NOTIFICATIONS").MustString("enabled") diff --git a/modules/setting/api.go b/modules/setting/api.go index e13c1396f471..909982481a54 100644 --- a/modules/setting/api.go +++ b/modules/setting/api.go @@ -27,7 +27,7 @@ var API = struct { DefaultMaxBlobSize: 10485760, } -func parseAPISetting(rootCfg Config) { +func loadAPIFrom(rootCfg Config) { mustMapSetting(rootCfg, "api", &API) defaultAppURL := string(Protocol) + "://" + Domain + ":" + HTTPPort diff --git a/modules/setting/attachment.go b/modules/setting/attachment.go index 48452a11a85e..316e1506751f 100644 --- a/modules/setting/attachment.go +++ b/modules/setting/attachment.go @@ -20,7 +20,7 @@ var Attachment = struct { Enabled: true, } -func parseAttachmentSetting(rootCfg Config) { +func loadAttachmentFrom(rootCfg Config) { sec := rootCfg.Section("attachment") storageType := sec.Key("STORAGE_TYPE").MustString("") diff --git a/modules/setting/cache.go b/modules/setting/cache.go index 59678b6f5486..d7a030a97df1 100644 --- a/modules/setting/cache.go +++ b/modules/setting/cache.go @@ -49,7 +49,7 @@ var CacheService = struct { // MemcacheMaxTTL represents the maximum memcache TTL const MemcacheMaxTTL = 30 * 24 * time.Hour -func parseCacheSetting(rootCfg Config) { +func loadCacheFrom(rootCfg Config) { sec := rootCfg.Section("cache") if err := sec.MapTo(&CacheService); err != nil { log.Fatal("Failed to map Cache settings: %v", err) diff --git a/modules/setting/camo.go b/modules/setting/camo.go index 7fa5bb40eea3..b6ac87445ed5 100644 --- a/modules/setting/camo.go +++ b/modules/setting/camo.go @@ -12,7 +12,7 @@ var Camo = struct { Allways bool }{} -func parseCamoSetting(rootCfg Config) { +func loadCamoFrom(rootCfg Config) { mustMapSetting(rootCfg, "camo", &Camo) if Camo.Enabled { if Camo.ServerURL == "" || Camo.HMACKey == "" { diff --git a/modules/setting/cors.go b/modules/setting/cors.go index 04acb13f3493..f112a81fcf41 100644 --- a/modules/setting/cors.go +++ b/modules/setting/cors.go @@ -27,7 +27,7 @@ var CORSConfig = struct { XFrameOptions: "SAMEORIGIN", } -func parseCorsSetting(rootCfg Config) { +func loadCorsFrom(rootCfg Config) { mustMapSetting(rootCfg, "cors", &CORSConfig) if CORSConfig.Enabled { log.Info("CORS Service Enabled") diff --git a/modules/setting/database.go b/modules/setting/database.go index ca2bfade888b..f522d52fea00 100644 --- a/modules/setting/database.go +++ b/modules/setting/database.go @@ -56,8 +56,8 @@ var ( } ) -// InitDBConfig loads the database settings -func ParseDBSetting() { +// LoadDBSetting loads the database settings +func LoadDBSetting() { sec := Cfg.Section("database") Database.Type = sec.Key("DB_TYPE").String() defaultCharset := "utf8" diff --git a/modules/setting/federation.go b/modules/setting/federation.go index 5220e6cd81ef..fa706137f9ac 100644 --- a/modules/setting/federation.go +++ b/modules/setting/federation.go @@ -33,7 +33,7 @@ var ( // HttpsigAlgs is a constant slice of httpsig algorithm objects var HttpsigAlgs []httpsig.Algorithm -func parseFederationSetting(rootCfg Config) { +func loadFederationFrom(rootCfg Config) { if err := rootCfg.Section("federation").MapTo(&Federation); err != nil { log.Fatal("Failed to map Federation settings: %v", err) } else if !httpsig.IsSupportedDigestAlgorithm(Federation.DigestAlgorithm) { diff --git a/modules/setting/git.go b/modules/setting/git.go index 04fe9bbb1061..40b63e068eae 100644 --- a/modules/setting/git.go +++ b/modules/setting/git.go @@ -67,7 +67,7 @@ var Git = struct { }, } -func parseGitSetting(rootCfg Config) { +func loadGitFrom(rootCfg Config) { sec := rootCfg.Section("git") if err := sec.MapTo(&Git); err != nil { log.Fatal("Failed to map Git settings: %v", err) diff --git a/modules/setting/i18n.go b/modules/setting/i18n.go index 067154a1be13..1f458911d418 100644 --- a/modules/setting/i18n.go +++ b/modules/setting/i18n.go @@ -54,7 +54,7 @@ var ( Names []string ) -func parseI18nSetting(rootCfg Config) { +func loadI18nFrom(rootCfg Config) { Langs = rootCfg.Section("i18n").Key("LANGS").Strings(",") if len(Langs) == 0 { Langs = defaultI18nLangs() diff --git a/modules/setting/indexer.go b/modules/setting/indexer.go index f3d2611d788d..bcd90a53f15e 100644 --- a/modules/setting/indexer.go +++ b/modules/setting/indexer.go @@ -45,7 +45,7 @@ var Indexer = struct { ExcludeVendored: true, } -func parseIndexerSetting(rootCfg Config) { +func loadIndexerFrom(rootCfg Config) { sec := rootCfg.Section("indexer") Indexer.IssueType = sec.Key("ISSUE_INDEXER_TYPE").MustString("bleve") Indexer.IssuePath = filepath.ToSlash(sec.Key("ISSUE_INDEXER_PATH").MustString(filepath.ToSlash(filepath.Join(AppDataPath, "indexers/issues.bleve")))) diff --git a/modules/setting/lfs.go b/modules/setting/lfs.go index fbd05bfa6ac8..312fed6f4dcf 100644 --- a/modules/setting/lfs.go +++ b/modules/setting/lfs.go @@ -25,7 +25,7 @@ var LFS = struct { Storage }{} -func parseLFSSetting(rootCfg Config) { +func loadLFSFrom(rootCfg Config) { sec := rootCfg.Section("server") if err := sec.MapTo(&LFS); err != nil { log.Fatal("Failed to map LFS settings: %v", err) diff --git a/modules/setting/log.go b/modules/setting/log.go index 641e5275363a..553494476f18 100644 --- a/modules/setting/log.go +++ b/modules/setting/log.go @@ -267,7 +267,7 @@ func generateNamedLogger(rootCfg Config, key string, options defaultLogOptions) return &description } -func parseAccessLogSetting(rootCfg Config) { +func loadAccessLogFrom(rootCfg Config) { sec := rootCfg.Section("log") EnableAccessLog = sec.Key("ENABLE_ACCESS_LOG").MustBool(false) AccessLogTemplate = sec.Key("ACCESS_LOG_TEMPLATE").MustString( @@ -284,7 +284,7 @@ func parseAccessLogSetting(rootCfg Config) { } } -func parseRouterLogSetting(rootCfg Config) { +func loadRouterLogFrom(rootCfg Config) { sec := rootCfg.Section("log") sec.Key("ROUTER").MustString("console") // Allow [log] DISABLE_ROUTER_LOG to override [server] DISABLE_ROUTER_LOG @@ -299,7 +299,7 @@ func parseRouterLogSetting(rootCfg Config) { } } -func parseLogSetting(rootCfg Config) { +func loadLogFrom(rootCfg Config) { sec := rootCfg.Section("log") options := newDefaultLogOptions() options.bufferLength = sec.Key("BUFFER_LEN").MustInt64(10000) @@ -357,23 +357,23 @@ func parseLogSetting(rootCfg Config) { // RestartLogsWithPIDSuffix restarts the logs with a PID suffix on files func RestartLogsWithPIDSuffix() { filenameSuffix = fmt.Sprintf(".%d", os.Getpid()) - ParseLogSettings(false) + LoadLogSettings(false) } -// ParseLogSettings creates all the log services -func ParseLogSettings(disableConsole bool) { - parseLogSetting(Cfg) - parseRouterLogSetting(Cfg) - parseAccessLogSetting(Cfg) - ParseXORMLogSetting(disableConsole) +// LoadLogSettings creates all the log services +func LoadLogSettings(disableConsole bool) { + loadLogFrom(Cfg) + loadRouterLogFrom(Cfg) + loadAccessLogFrom(Cfg) + LoadSQLLogSetting(disableConsole) } -// ParseXORMLogSetting initializes xorm logger setting -func ParseXORMLogSetting(disableConsole bool) { - parseXORMLogSetting(Cfg, disableConsole) +// LoadSQLLogSetting initializes xorm logger setting +func LoadSQLLogSetting(disableConsole bool) { + loadSQLLogFrom(Cfg, disableConsole) } -func parseXORMLogSetting(rootCfg Config, disableConsole bool) { +func loadSQLLogFrom(rootCfg Config, disableConsole bool) { EnableXORMLog = rootCfg.Section("log").Key("ENABLE_XORM_LOG").MustBool(true) if EnableXORMLog { options := newDefaultLogOptions() diff --git a/modules/setting/mailer.go b/modules/setting/mailer.go index 90860dcf96ab..975e39afedc7 100644 --- a/modules/setting/mailer.go +++ b/modules/setting/mailer.go @@ -49,13 +49,13 @@ type Mailer struct { // MailService the global mailer var MailService *Mailer -func parseMailSettings(rootCfg Config) { - parseMailerSetting(rootCfg) - parseRegisterMailSetting(rootCfg) - parseNotifyMailSetting(rootCfg) +func loadMailsFrom(rootCfg Config) { + loadMailerFrom(rootCfg) + loadRegisterMailFrom(rootCfg) + loadNotifyMailFrom(rootCfg) } -func parseMailerSetting(rootCfg Config) { +func loadMailerFrom(rootCfg Config) { sec := rootCfg.Section("mailer") // Check mailer setting. if !sec.Key("ENABLED").MustBool() { @@ -242,7 +242,7 @@ func parseMailerSetting(rootCfg Config) { log.Info("Mail Service Enabled") } -func parseRegisterMailSetting(rootCfg Config) { +func loadRegisterMailFrom(rootCfg Config) { if !rootCfg.Section("service").Key("REGISTER_EMAIL_CONFIRM").MustBool() { return } else if MailService == nil { @@ -253,7 +253,7 @@ func parseRegisterMailSetting(rootCfg Config) { log.Info("Register Mail Service Enabled") } -func parseNotifyMailSetting(rootCfg Config) { +func loadNotifyMailFrom(rootCfg Config) { if !rootCfg.Section("service").Key("ENABLE_NOTIFY_MAIL").MustBool() { return } else if MailService == nil { diff --git a/modules/setting/mailer_test.go b/modules/setting/mailer_test.go index 480914b9b2b9..4cfd6142be73 100644 --- a/modules/setting/mailer_test.go +++ b/modules/setting/mailer_test.go @@ -10,7 +10,7 @@ import ( ini "gopkg.in/ini.v1" ) -func TestParseMailerConfig(t *testing.T) { +func Test_loadMailerFrom(t *testing.T) { iniFile := ini.Empty() kases := map[string]*Mailer{ "smtp.mydomain.com": { @@ -34,7 +34,7 @@ func TestParseMailerConfig(t *testing.T) { sec.NewKey("HOST", host) // Check mailer setting - parseMailerSetting(iniFile) + loadMailerFrom(iniFile) assert.EqualValues(t, kase.SMTPAddr, MailService.SMTPAddr) assert.EqualValues(t, kase.SMTPPort, MailService.SMTPPort) diff --git a/modules/setting/markup.go b/modules/setting/markup.go index b08c338c5763..1cfe9d24ed48 100644 --- a/modules/setting/markup.go +++ b/modules/setting/markup.go @@ -60,7 +60,7 @@ type MarkupSanitizerRule struct { AllowDataURIImages bool } -func parseMarkupSetting(rootCfg Config) { +func loadMarkupFrom(rootCfg Config) { mustMapSetting(rootCfg, "markdown", &Markdown) MermaidMaxSourceCharacters = rootCfg.Section("markup").Key("MERMAID_MAX_SOURCE_CHARACTERS").MustInt(5000) diff --git a/modules/setting/metrics.go b/modules/setting/metrics.go index 2e536502b439..1482610f3902 100644 --- a/modules/setting/metrics.go +++ b/modules/setting/metrics.go @@ -16,6 +16,6 @@ var Metrics = struct { EnabledIssueByRepository: false, } -func parseMetricsSetting(rootCfg Config) { +func loadMetricsFrom(rootCfg Config) { mustMapSetting(rootCfg, "metrics", &Metrics) } diff --git a/modules/setting/migrations.go b/modules/setting/migrations.go index aa8b429fa365..5c0f193035b5 100644 --- a/modules/setting/migrations.go +++ b/modules/setting/migrations.go @@ -16,7 +16,7 @@ var Migrations = struct { RetryBackoff: 3, } -func parseMigrationsSetting(rootCfg Config) { +func loadMigrationsFrom(rootCfg Config) { sec := rootCfg.Section("migrations") Migrations.MaxAttempts = sec.Key("MAX_ATTEMPTS").MustInt(Migrations.MaxAttempts) Migrations.RetryBackoff = sec.Key("RETRY_BACKOFF").MustInt(Migrations.RetryBackoff) diff --git a/modules/setting/mime_type_map.go b/modules/setting/mime_type_map.go index 41a1b5e7e58c..9315ba05a9bc 100644 --- a/modules/setting/mime_type_map.go +++ b/modules/setting/mime_type_map.go @@ -14,7 +14,7 @@ var MimeTypeMap = struct { Map: map[string]string{}, } -func parseMimeTypeMap(rootCfg Config) { +func loadMimeTypeMapFrom(rootCfg Config) { sec := rootCfg.Section("repository.mimetype_mapping") keys := sec.Keys() m := make(map[string]string, len(keys)) diff --git a/modules/setting/mirror.go b/modules/setting/mirror.go index 99a417c50443..3f273668aecf 100644 --- a/modules/setting/mirror.go +++ b/modules/setting/mirror.go @@ -24,7 +24,7 @@ var Mirror = struct { DefaultInterval: 8 * time.Hour, } -func parseMirrorSetting(rootCfg Config) { +func loadMirrorFrom(rootCfg Config) { // Handle old configuration through `[repository]` `DISABLE_MIRRORS` // - please note this was badly named and only disabled the creation of new pull mirrors // FIXME: DEPRECATED to be removed in v1.18.0 diff --git a/modules/setting/oauth2.go b/modules/setting/oauth2.go index 186b268d831a..e1d0d092f99c 100644 --- a/modules/setting/oauth2.go +++ b/modules/setting/oauth2.go @@ -62,7 +62,7 @@ var OAuth2Client struct { AccountLinking OAuth2AccountLinkingType } -func parseOAuth2ClientSetting(rootCfg Config) { +func loadOAuth2ClientFrom(rootCfg Config) { sec := rootCfg.Section("oauth2_client") OAuth2Client.RegisterEmailConfirm = sec.Key("REGISTER_EMAIL_CONFIRM").MustBool(Service.RegisterEmailConfirm) OAuth2Client.OpenIDConnectScopes = parseScopes(sec, "OPENID_CONNECT_SCOPES") @@ -110,7 +110,7 @@ var OAuth2 = struct { MaxTokenLength: math.MaxInt16, } -func parseOAuth2Setting(rootCfg Config) { +func loadOAuth2From(rootCfg Config) { if err := rootCfg.Section("oauth2").MapTo(&OAuth2); err != nil { log.Fatal("Failed to OAuth2 settings: %v", err) return diff --git a/modules/setting/other.go b/modules/setting/other.go index 39e2d42adac0..e384678ef568 100644 --- a/modules/setting/other.go +++ b/modules/setting/other.go @@ -12,7 +12,7 @@ var ( EnableSitemap bool ) -func parseOtherSetting(rootCfg Config) { +func loadOtherFrom(rootCfg Config) { sec := rootCfg.Section("other") ShowFooterBranding = sec.Key("SHOW_FOOTER_BRANDING").MustBool(false) ShowFooterVersion = sec.Key("SHOW_FOOTER_VERSION").MustBool(true) diff --git a/modules/setting/packages.go b/modules/setting/packages.go index 7fa214e9aaf9..4caaebffe4fd 100644 --- a/modules/setting/packages.go +++ b/modules/setting/packages.go @@ -43,7 +43,7 @@ var ( } ) -func parsePackagesSetting(rootCfg Config) { +func loadPackagesFrom(rootCfg Config) { sec := rootCfg.Section("packages") if err := sec.MapTo(&Packages); err != nil { log.Fatal("Failed to map Packages settings: %v", err) diff --git a/modules/setting/picture.go b/modules/setting/picture.go index cae8a99ef16b..fbda34c901d9 100644 --- a/modules/setting/picture.go +++ b/modules/setting/picture.go @@ -32,7 +32,7 @@ var ( }{} ) -func parsePictureSetting(rootCfg Config) { +func loadPictureFrom(rootCfg Config) { sec := rootCfg.Section("picture") avatarSec := rootCfg.Section("avatar") @@ -64,7 +64,7 @@ func parsePictureSetting(rootCfg Config) { EnableFederatedAvatar = sec.Key("ENABLE_FEDERATED_AVATAR").MustBool(GetDefaultEnableFederatedAvatar(DisableGravatar)) deprecatedSettingDB(rootCfg, "", "ENABLE_FEDERATED_AVATAR") - parseRepoAvatarSetting(rootCfg) + loadRepoAvatarFrom(rootCfg) } func GetDefaultDisableGravatar() bool { @@ -82,7 +82,7 @@ func GetDefaultEnableFederatedAvatar(disableGravatar bool) bool { return v } -func parseRepoAvatarSetting(rootCfg Config) { +func loadRepoAvatarFrom(rootCfg Config) { sec := rootCfg.Section("picture") repoAvatarSec := rootCfg.Section("repo-avatar") diff --git a/modules/setting/project.go b/modules/setting/project.go index 7e8ab454c6c7..b4b198f19c33 100644 --- a/modules/setting/project.go +++ b/modules/setting/project.go @@ -14,6 +14,6 @@ var ( } ) -func parseProjectSetting(rootCfg Config) { +func loadProjectFrom(rootCfg Config) { mustMapSetting(rootCfg, "project", &Project) } diff --git a/modules/setting/proxy.go b/modules/setting/proxy.go index 6a036d600672..d96ec4a0e8cf 100644 --- a/modules/setting/proxy.go +++ b/modules/setting/proxy.go @@ -21,7 +21,7 @@ var Proxy = struct { ProxyHosts: []string{}, } -func parseProxySetting(rootCfg Config) { +func loadProxyFrom(rootCfg Config) { sec := rootCfg.Section("proxy") Proxy.Enabled = sec.Key("PROXY_ENABLED").MustBool(false) Proxy.ProxyURL = sec.Key("PROXY_URL").MustString("") diff --git a/modules/setting/queue.go b/modules/setting/queue.go index c0f7592ca021..5fca82397192 100644 --- a/modules/setting/queue.go +++ b/modules/setting/queue.go @@ -86,13 +86,13 @@ func getQueueSettings(rootCfg Config, name string) QueueSettings { return q } -// ParseQueueSettings sets up the default settings for Queues +// LoadQueueSettings sets up the default settings for Queues // This is exported for tests to be able to use the queue -func ParseQueueSettings() { - parseQueueSettings(Cfg) +func LoadQueueSettings() { + loadQueueFrom(Cfg) } -func parseQueueSettings(rootCfg Config) { +func loadQueueFrom(rootCfg Config) { sec := rootCfg.Section("queue") Queue.DataDir = filepath.ToSlash(sec.Key("DATADIR").MustString("queues/")) if !filepath.IsAbs(Queue.DataDir) { diff --git a/modules/setting/repository.go b/modules/setting/repository.go index a44f7f937294..9044c4a339ab 100644 --- a/modules/setting/repository.go +++ b/modules/setting/repository.go @@ -268,7 +268,7 @@ var ( }{} ) -func parseRepositorySetting(rootCfg Config) { +func loadRepositoryFrom(rootCfg Config) { var err error // Determine and create root git repository path. sec := rootCfg.Section("repository") diff --git a/modules/setting/security.go b/modules/setting/security.go index 2c53d8b8684d..98b83ee3dd4d 100644 --- a/modules/setting/security.go +++ b/modules/setting/security.go @@ -95,7 +95,7 @@ func generateSaveInternalToken() { }) } -func parseSecuritySetting(rootCfg Config) { +func loadSecurityFrom(rootCfg Config) { sec := rootCfg.Section("security") InstallLock = sec.Key("INSTALL_LOCK").MustBool(false) LogInRememberDays = sec.Key("LOGIN_REMEMBER_DAYS").MustInt(7) diff --git a/modules/setting/server.go b/modules/setting/server.go index bc9c882db836..b62b6a18cb28 100644 --- a/modules/setting/server.go +++ b/modules/setting/server.go @@ -165,7 +165,7 @@ func MakeAbsoluteAssetURL(appURL, staticURLPrefix string) string { return strings.TrimSuffix(staticURLPrefix, "/") } -func parseServerSetting(rootCfg Config) { +func loadServerFrom(rootCfg Config) { logSec := rootCfg.Section("log") LogLevel = getLogLevel(logSec, "LEVEL", log.INFO) StacktraceLogLevel = getStacktraceLogLevel(logSec, "STACKTRACE_LEVEL", "None") diff --git a/modules/setting/service.go b/modules/setting/service.go index 75e525ec4a79..e7069c70dfe8 100644 --- a/modules/setting/service.go +++ b/modules/setting/service.go @@ -111,7 +111,7 @@ func (a AllowedVisibility) ToVisibleTypeSlice() (result []structs.VisibleType) { return result } -func parseServiceSetting(rootCfg Config) { +func loadServiceFrom(rootCfg Config) { sec := rootCfg.Section("service") Service.ActiveCodeLives = sec.Key("ACTIVE_CODE_LIVE_MINUTES").MustInt(180) Service.ResetPwdCodeLives = sec.Key("RESET_PASSWD_CODE_LIVE_MINUTES").MustInt(180) diff --git a/modules/setting/session.go b/modules/setting/session.go index e0db309cbc39..6145fa4f8ef9 100644 --- a/modules/setting/session.go +++ b/modules/setting/session.go @@ -39,7 +39,7 @@ var SessionConfig = struct { SameSite: http.SameSiteLaxMode, } -func parseSessionSetting(rootCfg Config) { +func loadSessionFrom(rootCfg Config) { sec := rootCfg.Section("session") SessionConfig.Provider = sec.Key("PROVIDER").In("memory", []string{"memory", "file", "redis", "mysql", "postgres", "couchbase", "memcache", "db"}) diff --git a/modules/setting/setting.go b/modules/setting/setting.go index c18971186ebd..98accd5410d6 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -277,32 +277,32 @@ func loadFromConf(customConf string, writePIDFile, allowEmpty bool, pidFile, ext cfg.NameMapper = ini.SnackCase // WARNNING: don't change the sequence except you know what you are doing. - parseRunModeSetting(cfg) - parseServerSetting(cfg) - parseSSHSetting(cfg) - parseOAuth2Setting(cfg) - parseSecuritySetting(cfg) - parseAttachmentSetting(cfg) - parseLFSSetting(cfg) - parseTimeSetting(cfg) - parseRepositorySetting(cfg) - parsePictureSetting(cfg) - parsePackagesSetting(cfg) - parseUISetting(cfg) - parseAdminSetting(cfg) - parseAPISetting(cfg) - parseMetricsSetting(cfg) - parseCamoSetting(cfg) - parseI18nSetting(cfg) - parseGitSetting(cfg) - parseMirrorSetting(cfg) - parseMarkupSetting(cfg) - parseOtherSetting(cfg) + loadRunModeFrom(cfg) + loadServerFrom(cfg) + loadSSHFrom(cfg) + loadOAuth2From(cfg) + loadSecurityFrom(cfg) + loadAttachmentFrom(cfg) + loadLFSFrom(cfg) + loadTimeFrom(cfg) + loadRepositoryFrom(cfg) + loadPictureFrom(cfg) + loadPackagesFrom(cfg) + loadUIFrom(cfg) + loadAdminFrom(cfg) + loadAPIFrom(cfg) + loadMetricsFrom(cfg) + loadCamoFrom(cfg) + loadI18nFrom(cfg) + loadGitFrom(cfg) + loadMirrorFrom(cfg) + loadMarkupFrom(cfg) + loadOtherFrom(cfg) return cfg } -func parseRunModeSetting(rootCfg Config) { +func loadRunModeFrom(rootCfg Config) { rootSec := rootCfg.Section("") RunUser = rootSec.Key("RUN_USER").MustString(user.CurrentUsername()) // The following is a purposefully undocumented option. Please do not run Gitea as root. It will only cause future headaches. @@ -377,30 +377,30 @@ func CreateOrAppendToCustomConf(purpose string, callback func(cfg *ini.File)) { } } -// ParseSettings initializes the settings for normal start up -func ParseSettings() { - ParseDBSetting() - parseServiceSetting(Cfg) - parseOAuth2ClientSetting(Cfg) - ParseLogSettings(false) - parseCacheSetting(Cfg) - parseSessionSetting(Cfg) - parseCorsSetting(Cfg) - parseMailSettings(Cfg) - parseProxySetting(Cfg) - parseWebhookSetting(Cfg) - parseMigrationsSetting(Cfg) - parseIndexerSetting(Cfg) - parseTaskSetting(Cfg) - ParseQueueSettings() - parseProjectSetting(Cfg) - parseMimeTypeMap(Cfg) - parseFederationSetting(Cfg) +// LoadSettings initializes the settings for normal start up +func LoadSettings() { + LoadDBSetting() + loadServiceFrom(Cfg) + loadOAuth2ClientFrom(Cfg) + LoadLogSettings(false) + loadCacheFrom(Cfg) + loadSessionFrom(Cfg) + loadCorsFrom(Cfg) + loadMailsFrom(Cfg) + loadProxyFrom(Cfg) + loadWebhookFrom(Cfg) + loadMigrationsFrom(Cfg) + loadIndexerFrom(Cfg) + loadTaskFrom(Cfg) + LoadQueueSettings() + loadProjectFrom(Cfg) + loadMimeTypeMapFrom(Cfg) + loadFederationFrom(Cfg) } -// ParseSettingsForInstall initializes the settings for install -func ParseSettingsForInstall() { - ParseDBSetting() - parseServiceSetting(Cfg) - parseMailerSetting(Cfg) +// LoadSettingsForInstall initializes the settings for install +func LoadSettingsForInstall() { + LoadDBSetting() + loadServiceFrom(Cfg) + loadMailerFrom(Cfg) } diff --git a/modules/setting/ssh.go b/modules/setting/ssh.go index c5d3f4958ab6..512909c5547e 100644 --- a/modules/setting/ssh.go +++ b/modules/setting/ssh.go @@ -99,7 +99,7 @@ func parseAuthorizedPrincipalsAllow(values []string) ([]string, bool) { return authorizedPrincipalsAllow, true } -func parseSSHSetting(rootCfg Config) { +func loadSSHFrom(rootCfg Config) { sec := rootCfg.Section("server") if len(SSH.Domain) == 0 { SSH.Domain = Domain diff --git a/modules/setting/task.go b/modules/setting/task.go index 5680dc4ac6bb..00ecd194e923 100644 --- a/modules/setting/task.go +++ b/modules/setting/task.go @@ -5,7 +5,7 @@ package setting // FIXME: DEPRECATED to be removed in v1.18.0 // - will need to set default for [queue.task] LENGTH to 1000 though -func parseTaskSetting(rootCfg Config) { +func loadTaskFrom(rootCfg Config) { taskSec := rootCfg.Section("task") queueTaskSec := rootCfg.Section("queue.task") diff --git a/modules/setting/time.go b/modules/setting/time.go index 07b346480f66..9e9aaa9a6c65 100644 --- a/modules/setting/time.go +++ b/modules/setting/time.go @@ -16,7 +16,7 @@ var ( DefaultUILocation = time.Local ) -func parseTimeSetting(rootCfg Config) { +func loadTimeFrom(rootCfg Config) { timeFormatKey := rootCfg.Section("time").Key("FORMAT").MustString("") if timeFormatKey != "" { TimeFormat = map[string]string{ diff --git a/modules/setting/ui.go b/modules/setting/ui.go index fccdc8b1c489..e9979f8b7da7 100644 --- a/modules/setting/ui.go +++ b/modules/setting/ui.go @@ -132,7 +132,7 @@ var UI = struct { }, } -func parseUISetting(rootCfg Config) { +func loadUIFrom(rootCfg Config) { mustMapSetting(rootCfg, "ui", &UI) sec := rootCfg.Section("ui") UI.ShowUserEmail = sec.Key("SHOW_USER_EMAIL").MustBool(true) diff --git a/modules/setting/webhook.go b/modules/setting/webhook.go index e9a1714ee9ba..fe2564ab3e0d 100644 --- a/modules/setting/webhook.go +++ b/modules/setting/webhook.go @@ -29,7 +29,7 @@ var Webhook = struct { ProxyHosts: []string{}, } -func parseWebhookSetting(rootCfg Config) { +func loadWebhookFrom(rootCfg Config) { sec := rootCfg.Section("webhook") Webhook.QueueLength = sec.Key("QUEUE_LENGTH").MustInt(1000) Webhook.DeliverTimeout = sec.Key("DELIVER_TIMEOUT").MustInt(5) diff --git a/routers/api/v1/repo/main_test.go b/routers/api/v1/repo/main_test.go index f16d0f209611..1af155910679 100644 --- a/routers/api/v1/repo/main_test.go +++ b/routers/api/v1/repo/main_test.go @@ -14,7 +14,7 @@ import ( func TestMain(m *testing.M) { setting.LoadForTest() - setting.ParseQueueSettings() + setting.LoadQueueSettings() unittest.MainTest(m, &unittest.TestOptions{ GiteaRootPath: filepath.Join("..", "..", "..", ".."), SetUp: webhook_service.Init, diff --git a/routers/init.go b/routers/init.go index f205c727cb86..f5181aa83481 100644 --- a/routers/init.go +++ b/routers/init.go @@ -70,7 +70,7 @@ func mustInitCtx(ctx context.Context, fn func(ctx context.Context) error) { // InitGitServices init new services for git, this is also called in `contrib/pr/checkout.go` func InitGitServices() { - setting.ParseSettings() + setting.LoadSettings() mustInit(storage.Init) mustInit(repo_service.Init) } @@ -124,7 +124,7 @@ func GlobalInitInstalled(ctx context.Context) { // Setup i18n translation.InitLocales(ctx) - setting.ParseSettings() + setting.LoadSettings() mustInit(storage.Init) mailer.NewContext(ctx) diff --git a/routers/install/setting.go b/routers/install/setting.go index ae6135e32f32..8119ef305821 100644 --- a/routers/install/setting.go +++ b/routers/install/setting.go @@ -28,7 +28,7 @@ func PreloadSettings(ctx context.Context) bool { log.Info("SQLite3 is supported") } - setting.ParseSettingsForInstall() + setting.LoadSettingsForInstall() svg.Init() } @@ -38,7 +38,7 @@ func PreloadSettings(ctx context.Context) bool { // reloadSettings reloads the existing settings and starts up the database func reloadSettings(ctx context.Context) { setting.LoadFromExisting() - setting.ParseDBSetting() + setting.LoadDBSetting() if setting.InstallLock { if err := common.InitDBEngine(ctx); err == nil { log.Info("ORM engine initialization successful!") diff --git a/services/webhook/main_test.go b/services/webhook/main_test.go index b5b3b1f99c82..a7f7c0bd9915 100644 --- a/services/webhook/main_test.go +++ b/services/webhook/main_test.go @@ -16,7 +16,7 @@ import ( func TestMain(m *testing.M) { setting.LoadForTest() - setting.ParseQueueSettings() + setting.LoadQueueSettings() // for tests, allow only loopback IPs setting.Webhook.AllowedHostList = hostmatcher.MatchBuiltinLoopback diff --git a/tests/integration/migration-test/migration_test.go b/tests/integration/migration-test/migration_test.go index 4ddc3313d7bd..7161f9de459a 100644 --- a/tests/integration/migration-test/migration_test.go +++ b/tests/integration/migration-test/migration_test.go @@ -83,8 +83,8 @@ func initMigrationTest(t *testing.T) func() { } assert.NoError(t, git.InitFull(context.Background())) - setting.ParseDBSetting() - setting.ParseLogSettings(true) + setting.LoadDBSetting() + setting.LoadLogSettings(true) return deferFn } @@ -292,7 +292,7 @@ func doMigrationTest(t *testing.T, version string) { return } - setting.ParseXORMLogSetting(false) + setting.LoadSQLLogSetting(false) err := db.InitEngineWithMigration(context.Background(), wrappedMigrate) assert.NoError(t, err) diff --git a/tests/test_utils.go b/tests/test_utils.go index f78842834d8f..72718aeb464b 100644 --- a/tests/test_utils.go +++ b/tests/test_utils.go @@ -65,7 +65,7 @@ func InitTest(requireGitea bool) { log.Fatal("git.InitOnceWithSync: %v", err) } - setting.ParseDBSetting() + setting.LoadDBSetting() if err := storage.Init(); err != nil { fmt.Printf("Init storage failed: %v", err) os.Exit(1) From 709196e91b881c4ff1c86ffa08f4d3aad5bd591b Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 30 Jan 2023 13:48:15 +0800 Subject: [PATCH 13/20] Rename Config -> ConfigProvider --- cmd/convert.go | 2 +- cmd/doctor.go | 5 +- cmd/dump.go | 15 +++--- cmd/dump_repo.go | 2 +- cmd/migrate.go | 2 +- cmd/migrate_storage.go | 2 +- contrib/pr/checkout.go | 2 +- models/migrations/base/tests.go | 2 +- modules/context/access_log.go | 2 +- modules/doctor/doctor.go | 2 +- modules/doctor/paths.go | 2 +- modules/highlight/highlight.go | 8 +-- modules/indexer/issues/indexer_test.go | 4 +- modules/indexer/stats/indexer_test.go | 2 +- modules/setting/admin.go | 2 +- modules/setting/api.go | 2 +- modules/setting/attachment.go | 2 +- modules/setting/cache.go | 2 +- modules/setting/camo.go | 2 +- modules/setting/config.go | 22 -------- modules/setting/config_provider.go | 39 ++++++++++++++ modules/setting/cors.go | 2 +- modules/setting/cron.go | 4 +- modules/setting/database.go | 2 +- modules/setting/federation.go | 2 +- modules/setting/git.go | 2 +- modules/setting/highlight.go | 17 ++++++ modules/setting/i18n.go | 2 +- modules/setting/incoming_email.go | 2 +- modules/setting/indexer.go | 2 +- modules/setting/lfs.go | 2 +- modules/setting/log.go | 73 ++++++++++++++------------ modules/setting/mailer.go | 8 +-- modules/setting/markup.go | 2 +- modules/setting/metrics.go | 2 +- modules/setting/migrations.go | 2 +- modules/setting/mime_type_map.go | 2 +- modules/setting/mirror.go | 2 +- modules/setting/oauth2.go | 4 +- modules/setting/other.go | 2 +- modules/setting/packages.go | 2 +- modules/setting/picture.go | 4 +- modules/setting/project.go | 2 +- modules/setting/proxy.go | 2 +- modules/setting/queue.go | 10 ++-- modules/setting/repository.go | 2 +- modules/setting/security.go | 2 +- modules/setting/server.go | 12 ++--- modules/setting/service.go | 4 +- modules/setting/session.go | 6 ++- modules/setting/setting.go | 71 +++++++++++-------------- modules/setting/ssh.go | 2 +- modules/setting/storage.go | 2 +- modules/setting/task.go | 2 +- modules/setting/time.go | 2 +- modules/setting/ui.go | 2 +- modules/setting/webhook.go | 2 +- routers/common/middleware.go | 4 +- routers/init.go | 2 +- routers/install/install.go | 4 +- routers/install/setting.go | 2 +- routers/private/manager.go | 6 +-- routers/private/ssh_log.go | 2 +- routers/web/admin/config.go | 12 ++--- 64 files changed, 223 insertions(+), 195 deletions(-) delete mode 100644 modules/setting/config.go create mode 100644 modules/setting/config_provider.go create mode 100644 modules/setting/highlight.go diff --git a/cmd/convert.go b/cmd/convert.go index b9ed9f162742..30e7d01e11a9 100644 --- a/cmd/convert.go +++ b/cmd/convert.go @@ -32,7 +32,7 @@ func runConvert(ctx *cli.Context) error { log.Info("AppPath: %s", setting.AppPath) log.Info("AppWorkPath: %s", setting.AppWorkPath) log.Info("Custom path: %s", setting.CustomPath) - log.Info("Log path: %s", setting.LogRootPath) + log.Info("Log path: %s", setting.Log.RootPath) log.Info("Configuration file: %s", setting.CustomConf) if !setting.Database.UseMySQL { diff --git a/cmd/doctor.go b/cmd/doctor.go index 61e4e7da6610..44d418c260b9 100644 --- a/cmd/doctor.go +++ b/cmd/doctor.go @@ -90,9 +90,10 @@ func runRecreateTable(ctx *cli.Context) error { setting.LoadFromExisting() setting.LoadDBSetting() - setting.EnableXORMLog = ctx.Bool("debug") + setting.Log.EnableXORMLog = ctx.Bool("debug") setting.Database.LogSQL = ctx.Bool("debug") - setting.Cfg.Section("log").Key("XORM").SetValue(",") + // FIXME: don't use CfgProvider directly + setting.CfgProvider.Section("log").Key("XORM").SetValue(",") setting.LoadSQLLogSetting(!ctx.Bool("debug")) stdCtx, cancel := installSignals() diff --git a/cmd/dump.go b/cmd/dump.go index 909ab6d44fe7..5afabb450f7c 100644 --- a/cmd/dump.go +++ b/cmd/dump.go @@ -184,10 +184,11 @@ func runDump(ctx *cli.Context) error { setting.LoadFromExisting() // make sure we are logging to the console no matter what the configuration tells us do to - if _, err := setting.Cfg.Section("log").NewKey("MODE", "console"); err != nil { + // FIXME: don't use CfgProvider directly + if _, err := setting.CfgProvider.Section("log").NewKey("MODE", "console"); err != nil { fatal("Setting logging mode to console failed: %v", err) } - if _, err := setting.Cfg.Section("log.console").NewKey("STDERR", "true"); err != nil { + if _, err := setting.CfgProvider.Section("log.console").NewKey("STDERR", "true"); err != nil { fatal("Setting console logger to stderr failed: %v", err) } if !setting.InstallLock { @@ -322,7 +323,7 @@ func runDump(ctx *cli.Context) error { log.Info("Packing data directory...%s", setting.AppDataPath) var excludes []string - if setting.Cfg.Section("session").Key("PROVIDER").Value() == "file" { + if setting.SessionConfig.OriginalProvider == "file" { var opts session.Options if err = json.Unmarshal([]byte(setting.SessionConfig.ProviderConfig), &opts); err != nil { return err @@ -339,7 +340,7 @@ func runDump(ctx *cli.Context) error { excludes = append(excludes, setting.LFS.Path) excludes = append(excludes, setting.Attachment.Path) excludes = append(excludes, setting.Packages.Path) - excludes = append(excludes, setting.LogRootPath) + excludes = append(excludes, setting.Log.RootPath) excludes = append(excludes, absFileName) if err := addRecursiveExclude(w, "data", setting.AppDataPath, excludes, verbose); err != nil { fatal("Failed to include data directory: %v", err) @@ -378,12 +379,12 @@ func runDump(ctx *cli.Context) error { if ctx.IsSet("skip-log") && ctx.Bool("skip-log") { log.Info("Skip dumping log files") } else { - isExist, err := util.IsExist(setting.LogRootPath) + isExist, err := util.IsExist(setting.Log.RootPath) if err != nil { - log.Error("Unable to check if %s exists. Error: %v", setting.LogRootPath, err) + log.Error("Unable to check if %s exists. Error: %v", setting.Log.RootPath, err) } if isExist { - if err := addRecursiveExclude(w, "log", setting.LogRootPath, []string{absFileName}, verbose); err != nil { + if err := addRecursiveExclude(w, "log", setting.Log.RootPath, []string{absFileName}, verbose); err != nil { fatal("Failed to include log: %v", err) } } diff --git a/cmd/dump_repo.go b/cmd/dump_repo.go index b7b9b3ccc734..0d3970466cd0 100644 --- a/cmd/dump_repo.go +++ b/cmd/dump_repo.go @@ -94,7 +94,7 @@ func runDumpRepository(ctx *cli.Context) error { log.Info("AppPath: %s", setting.AppPath) log.Info("AppWorkPath: %s", setting.AppWorkPath) log.Info("Custom path: %s", setting.CustomPath) - log.Info("Log path: %s", setting.LogRootPath) + log.Info("Log path: %s", setting.Log.RootPath) log.Info("Configuration file: %s", setting.CustomConf) var ( diff --git a/cmd/migrate.go b/cmd/migrate.go index 2546fca21d0a..efa791bc65a0 100644 --- a/cmd/migrate.go +++ b/cmd/migrate.go @@ -33,7 +33,7 @@ func runMigrate(ctx *cli.Context) error { log.Info("AppPath: %s", setting.AppPath) log.Info("AppWorkPath: %s", setting.AppWorkPath) log.Info("Custom path: %s", setting.CustomPath) - log.Info("Log path: %s", setting.LogRootPath) + log.Info("Log path: %s", setting.Log.RootPath) log.Info("Configuration file: %s", setting.CustomConf) if err := db.InitEngineWithMigration(context.Background(), migrations.Migrate); err != nil { diff --git a/cmd/migrate_storage.go b/cmd/migrate_storage.go index 0b8ebe7c8dcd..dfa7212e5b0c 100644 --- a/cmd/migrate_storage.go +++ b/cmd/migrate_storage.go @@ -136,7 +136,7 @@ func runMigrateStorage(ctx *cli.Context) error { log.Info("AppPath: %s", setting.AppPath) log.Info("AppWorkPath: %s", setting.AppWorkPath) log.Info("Custom path: %s", setting.CustomPath) - log.Info("Log path: %s", setting.LogRootPath) + log.Info("Log path: %s", setting.Log.RootPath) log.Info("Configuration file: %s", setting.CustomConf) if err := db.InitEngineWithMigration(context.Background(), migrations.Migrate); err != nil { diff --git a/contrib/pr/checkout.go b/contrib/pr/checkout.go index b31a4a8c689e..9df63225d2a5 100644 --- a/contrib/pr/checkout.go +++ b/contrib/pr/checkout.go @@ -82,7 +82,7 @@ func runPR() { setting.Database.Path = ":memory:" setting.Database.Timeout = 500 */ - dbCfg := setting.Cfg.Section("database") + dbCfg := setting.CfgProvider.Section("database") dbCfg.NewKey("DB_TYPE", "sqlite3") dbCfg.NewKey("PATH", ":memory:") diff --git a/models/migrations/base/tests.go b/models/migrations/base/tests.go index 9c02338b6d72..361dfc9a9ed8 100644 --- a/models/migrations/base/tests.go +++ b/models/migrations/base/tests.go @@ -155,7 +155,7 @@ func MainTest(m *testing.M) { os.Exit(1) } setting.LoadDBSetting() - setting.LoadLogSettings(true) + setting.InitLogs(true) exitStatus := m.Run() diff --git a/modules/context/access_log.go b/modules/context/access_log.go index 05c0f86218c9..84663ee8d3b0 100644 --- a/modules/context/access_log.go +++ b/modules/context/access_log.go @@ -27,7 +27,7 @@ var signedUserNameStringPointerKey interface{} = "signedUserNameStringPointerKey // AccessLogger returns a middleware to log access logger func AccessLogger() func(http.Handler) http.Handler { logger := log.GetLogger("access") - logTemplate, _ := template.New("log").Parse(setting.AccessLogTemplate) + logTemplate, _ := template.New("log").Parse(setting.Log.AccessLogTemplate) return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { start := time.Now() diff --git a/modules/doctor/doctor.go b/modules/doctor/doctor.go index 4930ca2b42a5..044e5bff9b77 100644 --- a/modules/doctor/doctor.go +++ b/modules/doctor/doctor.go @@ -70,7 +70,7 @@ func RunChecks(ctx context.Context, logger log.Logger, autofix bool, checks []*C for i, check := range checks { if !dbIsInit && !check.SkipDatabaseInitialization { // Only open database after the most basic configuration check - setting.EnableXORMLog = false + setting.Log.EnableXORMLog = false if err := initDBDisableConsole(ctx, true); err != nil { logger.Error("Error whilst initializing the database: %v", err) logger.Error("Check if you are using the right config file. You can use a --config directive to specify one.") diff --git a/modules/doctor/paths.go b/modules/doctor/paths.go index ad50078d3ea9..3d0b2cd5e0dc 100644 --- a/modules/doctor/paths.go +++ b/modules/doctor/paths.go @@ -75,7 +75,7 @@ func checkConfigurationFiles(ctx context.Context, logger log.Logger, autofix boo {"Data Root Path", setting.AppDataPath, true, true, true}, {"Custom File Root Path", setting.CustomPath, true, false, false}, {"Work directory", setting.AppWorkPath, true, true, false}, - {"Log Root Path", setting.LogRootPath, true, true, true}, + {"Log Root Path", setting.Log.RootPath, true, true, true}, } if options.IsDynamic() { diff --git a/modules/highlight/highlight.go b/modules/highlight/highlight.go index 05e472c0833e..a5c38940a7be 100644 --- a/modules/highlight/highlight.go +++ b/modules/highlight/highlight.go @@ -41,12 +41,8 @@ var ( // NewContext loads custom highlight map from local config func NewContext() { once.Do(func() { - if setting.Cfg != nil { - keys := setting.Cfg.Section("highlight.mapping").Keys() - for i := range keys { - highlightMapping[keys[i].Name()] = keys[i].Value() - } - } + highlightMapping = setting.GetHighlightMapping() + // The size 512 is simply a conservative rule of thumb c, err := lru.New2Q(512) if err != nil { diff --git a/modules/indexer/issues/indexer_test.go b/modules/indexer/issues/indexer_test.go index b7f70b72fb2e..bf9d6d0d1641 100644 --- a/modules/indexer/issues/indexer_test.go +++ b/modules/indexer/issues/indexer_test.go @@ -27,11 +27,11 @@ func TestMain(m *testing.M) { func TestBleveSearchIssues(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - setting.Cfg = ini.Empty() + setting.CfgProvider = ini.Empty() tmpIndexerDir := t.TempDir() - setting.Cfg.Section("queue.issue_indexer").Key("DATADIR").MustString(path.Join(tmpIndexerDir, "issues.queue")) + setting.CfgProvider.Section("queue.issue_indexer").Key("DATADIR").MustString(path.Join(tmpIndexerDir, "issues.queue")) oldIssuePath := setting.Indexer.IssuePath setting.Indexer.IssuePath = path.Join(tmpIndexerDir, "issues.queue") diff --git a/modules/indexer/stats/indexer_test.go b/modules/indexer/stats/indexer_test.go index 7319fc9fa30f..50a5fade789a 100644 --- a/modules/indexer/stats/indexer_test.go +++ b/modules/indexer/stats/indexer_test.go @@ -29,7 +29,7 @@ func TestMain(m *testing.M) { func TestRepoStatsIndex(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - setting.Cfg = ini.Empty() + setting.CfgProvider = ini.Empty() setting.LoadQueueSettings() diff --git a/modules/setting/admin.go b/modules/setting/admin.go index 2dbf83907982..2d2dd26de94a 100644 --- a/modules/setting/admin.go +++ b/modules/setting/admin.go @@ -9,7 +9,7 @@ var Admin struct { DefaultEmailNotification string } -func loadAdminFrom(rootCfg Config) { +func loadAdminFrom(rootCfg ConfigProvider) { mustMapSetting(rootCfg, "admin", &Admin) sec := rootCfg.Section("admin") Admin.DefaultEmailNotification = sec.Key("DEFAULT_EMAIL_NOTIFICATIONS").MustString("enabled") diff --git a/modules/setting/api.go b/modules/setting/api.go index 909982481a54..c36f05cfd1c2 100644 --- a/modules/setting/api.go +++ b/modules/setting/api.go @@ -27,7 +27,7 @@ var API = struct { DefaultMaxBlobSize: 10485760, } -func loadAPIFrom(rootCfg Config) { +func loadAPIFrom(rootCfg ConfigProvider) { mustMapSetting(rootCfg, "api", &API) defaultAppURL := string(Protocol) + "://" + Domain + ":" + HTTPPort diff --git a/modules/setting/attachment.go b/modules/setting/attachment.go index 316e1506751f..8b6eb9fd7a1e 100644 --- a/modules/setting/attachment.go +++ b/modules/setting/attachment.go @@ -20,7 +20,7 @@ var Attachment = struct { Enabled: true, } -func loadAttachmentFrom(rootCfg Config) { +func loadAttachmentFrom(rootCfg ConfigProvider) { sec := rootCfg.Section("attachment") storageType := sec.Key("STORAGE_TYPE").MustString("") diff --git a/modules/setting/cache.go b/modules/setting/cache.go index d7a030a97df1..783246077d90 100644 --- a/modules/setting/cache.go +++ b/modules/setting/cache.go @@ -49,7 +49,7 @@ var CacheService = struct { // MemcacheMaxTTL represents the maximum memcache TTL const MemcacheMaxTTL = 30 * 24 * time.Hour -func loadCacheFrom(rootCfg Config) { +func loadCacheFrom(rootCfg ConfigProvider) { sec := rootCfg.Section("cache") if err := sec.MapTo(&CacheService); err != nil { log.Fatal("Failed to map Cache settings: %v", err) diff --git a/modules/setting/camo.go b/modules/setting/camo.go index b6ac87445ed5..366e9a116cd5 100644 --- a/modules/setting/camo.go +++ b/modules/setting/camo.go @@ -12,7 +12,7 @@ var Camo = struct { Allways bool }{} -func loadCamoFrom(rootCfg Config) { +func loadCamoFrom(rootCfg ConfigProvider) { mustMapSetting(rootCfg, "camo", &Camo) if Camo.Enabled { if Camo.ServerURL == "" || Camo.HMACKey == "" { diff --git a/modules/setting/config.go b/modules/setting/config.go deleted file mode 100644 index 1c98315c4975..000000000000 --- a/modules/setting/config.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package setting - -import ( - "code.gitea.io/gitea/modules/log" - - ini "gopkg.in/ini.v1" -) - -type Config interface { - Section(section string) *ini.Section - NewSection(name string) (*ini.Section, error) - GetSection(name string) (*ini.Section, error) -} - -func mustMapSetting(rootCfg Config, sectionName string, setting interface{}) { - if err := rootCfg.Section(sectionName).MapTo(setting); err != nil { - log.Fatal("Failed to map %s settings: %v", sectionName, err) - } -} diff --git a/modules/setting/config_provider.go b/modules/setting/config_provider.go new file mode 100644 index 000000000000..ec91533c55ad --- /dev/null +++ b/modules/setting/config_provider.go @@ -0,0 +1,39 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package setting + +import ( + "code.gitea.io/gitea/modules/log" + + ini "gopkg.in/ini.v1" +) + +// ConfigProvider represents a config provider +type ConfigProvider interface { + Section(section string) *ini.Section + NewSection(name string) (*ini.Section, error) + GetSection(name string) (*ini.Section, error) +} + +// a file is an implementation ConfigProvider and others implementation are possible, i.e. from docker/k8s and etc. +var _ ConfigProvider = &ini.File{} + +func mustMapSetting(rootCfg ConfigProvider, sectionName string, setting interface{}) { + if err := rootCfg.Section(sectionName).MapTo(setting); err != nil { + log.Fatal("Failed to map %s settings: %v", sectionName, err) + } +} + +func deprecatedSetting(rootCfg ConfigProvider, oldSection, oldKey, newSection, newKey string) { + if rootCfg.Section(oldSection).HasKey(oldKey) { + log.Error("Deprecated fallback `[%s]` `%s` present. Use `[%s]` `%s` instead. This fallback will be removed in v1.19.0", oldSection, oldKey, newSection, newKey) + } +} + +// deprecatedSettingDB add a hint that the configuration has been moved to database but still kept in app.ini +func deprecatedSettingDB(rootCfg ConfigProvider, oldSection, oldKey string) { + if rootCfg.Section(oldSection).HasKey(oldKey) { + log.Error("Deprecated `[%s]` `%s` present which has been copied to database table sys_setting", oldSection, oldKey) + } +} diff --git a/modules/setting/cors.go b/modules/setting/cors.go index f112a81fcf41..260848b5df33 100644 --- a/modules/setting/cors.go +++ b/modules/setting/cors.go @@ -27,7 +27,7 @@ var CORSConfig = struct { XFrameOptions: "SAMEORIGIN", } -func loadCorsFrom(rootCfg Config) { +func loadCorsFrom(rootCfg ConfigProvider) { mustMapSetting(rootCfg, "cors", &CORSConfig) if CORSConfig.Enabled { log.Info("CORS Service Enabled") diff --git a/modules/setting/cron.go b/modules/setting/cron.go index a275bf3a0732..45bae4dde37a 100644 --- a/modules/setting/cron.go +++ b/modules/setting/cron.go @@ -7,10 +7,10 @@ import "reflect" // GetCronSettings maps the cron subsection to the provided config func GetCronSettings(name string, config interface{}) (interface{}, error) { - return getCronSettings(Cfg, name, config) + return getCronSettings(CfgProvider, name, config) } -func getCronSettings(rootCfg Config, name string, config interface{}) (interface{}, error) { +func getCronSettings(rootCfg ConfigProvider, name string, config interface{}) (interface{}, error) { if err := rootCfg.Section("cron." + name).MapTo(config); err != nil { return config, err } diff --git a/modules/setting/database.go b/modules/setting/database.go index f522d52fea00..49865a38a284 100644 --- a/modules/setting/database.go +++ b/modules/setting/database.go @@ -58,7 +58,7 @@ var ( // LoadDBSetting loads the database settings func LoadDBSetting() { - sec := Cfg.Section("database") + sec := CfgProvider.Section("database") Database.Type = sec.Key("DB_TYPE").String() defaultCharset := "utf8" Database.UseMySQL = false diff --git a/modules/setting/federation.go b/modules/setting/federation.go index fa706137f9ac..2bea900633fd 100644 --- a/modules/setting/federation.go +++ b/modules/setting/federation.go @@ -33,7 +33,7 @@ var ( // HttpsigAlgs is a constant slice of httpsig algorithm objects var HttpsigAlgs []httpsig.Algorithm -func loadFederationFrom(rootCfg Config) { +func loadFederationFrom(rootCfg ConfigProvider) { if err := rootCfg.Section("federation").MapTo(&Federation); err != nil { log.Fatal("Failed to map Federation settings: %v", err) } else if !httpsig.IsSupportedDigestAlgorithm(Federation.DigestAlgorithm) { diff --git a/modules/setting/git.go b/modules/setting/git.go index 40b63e068eae..457b35936e9f 100644 --- a/modules/setting/git.go +++ b/modules/setting/git.go @@ -67,7 +67,7 @@ var Git = struct { }, } -func loadGitFrom(rootCfg Config) { +func loadGitFrom(rootCfg ConfigProvider) { sec := rootCfg.Section("git") if err := sec.MapTo(&Git); err != nil { log.Fatal("Failed to map Git settings: %v", err) diff --git a/modules/setting/highlight.go b/modules/setting/highlight.go new file mode 100644 index 000000000000..538d844c916a --- /dev/null +++ b/modules/setting/highlight.go @@ -0,0 +1,17 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package setting + +func GetHighlightMapping() map[string]string { + highlightMapping := map[string]string{} + if CfgProvider == nil { + return highlightMapping + } + + keys := CfgProvider.Section("highlight.mapping").Keys() + for i := range keys { + highlightMapping[keys[i].Name()] = keys[i].Value() + } + return highlightMapping +} diff --git a/modules/setting/i18n.go b/modules/setting/i18n.go index 1f458911d418..c3076c0ab70b 100644 --- a/modules/setting/i18n.go +++ b/modules/setting/i18n.go @@ -54,7 +54,7 @@ var ( Names []string ) -func loadI18nFrom(rootCfg Config) { +func loadI18nFrom(rootCfg ConfigProvider) { Langs = rootCfg.Section("i18n").Key("LANGS").Strings(",") if len(Langs) == 0 { Langs = defaultI18nLangs() diff --git a/modules/setting/incoming_email.go b/modules/setting/incoming_email.go index 9821ef5f2fa0..75337a312ff6 100644 --- a/modules/setting/incoming_email.go +++ b/modules/setting/incoming_email.go @@ -31,7 +31,7 @@ var IncomingEmail = struct { MaximumMessageSize: 10485760, } -func loadIncomingEmailFrom(rootCfg Config) { +func loadIncomingEmailFrom(rootCfg ConfigProvider) { mustMapSetting(rootCfg, "email.incoming", &IncomingEmail) if !IncomingEmail.Enabled { diff --git a/modules/setting/indexer.go b/modules/setting/indexer.go index bcd90a53f15e..528a9eb65561 100644 --- a/modules/setting/indexer.go +++ b/modules/setting/indexer.go @@ -45,7 +45,7 @@ var Indexer = struct { ExcludeVendored: true, } -func loadIndexerFrom(rootCfg Config) { +func loadIndexerFrom(rootCfg ConfigProvider) { sec := rootCfg.Section("indexer") Indexer.IssueType = sec.Key("ISSUE_INDEXER_TYPE").MustString("bleve") Indexer.IssuePath = filepath.ToSlash(sec.Key("ISSUE_INDEXER_PATH").MustString(filepath.ToSlash(filepath.Join(AppDataPath, "indexers/issues.bleve")))) diff --git a/modules/setting/lfs.go b/modules/setting/lfs.go index 312fed6f4dcf..e6c9e42f2cfb 100644 --- a/modules/setting/lfs.go +++ b/modules/setting/lfs.go @@ -25,7 +25,7 @@ var LFS = struct { Storage }{} -func loadLFSFrom(rootCfg Config) { +func loadLFSFrom(rootCfg ConfigProvider) { sec := rootCfg.Section("server") if err := sec.MapTo(&LFS); err != nil { log.Fatal("Failed to map LFS settings: %v", err) diff --git a/modules/setting/log.go b/modules/setting/log.go index 553494476f18..2138a0587c97 100644 --- a/modules/setting/log.go +++ b/modules/setting/log.go @@ -25,11 +25,11 @@ var ( logDescriptions = make(map[string]*LogDescription) ) -var ( - // Log settings - LogLevel log.Level +// Log settings +var Log struct { + Level log.Level StacktraceLogLevel string - LogRootPath string + RootPath string EnableSSHLog bool EnableXORMLog bool @@ -37,7 +37,8 @@ var ( EnableAccessLog bool AccessLogTemplate string -) + BufferLength int64 +} // GetLogDescriptions returns a race safe set of descriptions func GetLogDescriptions() map[string]*LogDescription { @@ -108,9 +109,9 @@ type defaultLogOptions struct { func newDefaultLogOptions() defaultLogOptions { return defaultLogOptions{ - levelName: LogLevel.String(), + levelName: Log.Level.String(), flags: "stdflags", - filename: filepath.Join(LogRootPath, "gitea.log"), + filename: filepath.Join(Log.RootPath, "gitea.log"), bufferLength: 10000, disableConsole: false, } @@ -140,9 +141,9 @@ func getStacktraceLogLevel(section *ini.Section, key, defaultValue string) strin } func generateLogConfig(sec *ini.Section, name string, defaults defaultLogOptions) (mode, jsonConfig, levelName string) { - level := getLogLevel(sec, "LEVEL", LogLevel) + level := getLogLevel(sec, "LEVEL", Log.Level) levelName = level.String() - stacktraceLevelName := getStacktraceLogLevel(sec, "STACKTRACE_LEVEL", StacktraceLogLevel) + stacktraceLevelName := getStacktraceLogLevel(sec, "STACKTRACE_LEVEL", Log.StacktraceLogLevel) stacktraceLevel := log.FromString(stacktraceLevelName) mode = name keys := sec.Keys() @@ -158,7 +159,7 @@ func generateLogConfig(sec *ini.Section, name string, defaults defaultLogOptions logPath = key.MustString(defaults.filename) forcePathSeparator(logPath) if !filepath.IsAbs(logPath) { - logPath = path.Join(LogRootPath, logPath) + logPath = path.Join(Log.RootPath, logPath) } case "FLAGS": flags = log.FlagsFromString(key.MustString(defaults.flags)) @@ -227,7 +228,7 @@ func generateLogConfig(sec *ini.Section, name string, defaults defaultLogOptions return mode, jsonConfig, levelName } -func generateNamedLogger(rootCfg Config, key string, options defaultLogOptions) *LogDescription { +func generateNamedLogger(rootCfg ConfigProvider, key string, options defaultLogOptions) *LogDescription { description := LogDescription{ Name: key, } @@ -267,43 +268,45 @@ func generateNamedLogger(rootCfg Config, key string, options defaultLogOptions) return &description } -func loadAccessLogFrom(rootCfg Config) { +func initAccessLogFrom(rootCfg ConfigProvider) { sec := rootCfg.Section("log") - EnableAccessLog = sec.Key("ENABLE_ACCESS_LOG").MustBool(false) - AccessLogTemplate = sec.Key("ACCESS_LOG_TEMPLATE").MustString( + Log.EnableAccessLog = sec.Key("ENABLE_ACCESS_LOG").MustBool(false) + Log.BufferLength = sec.Key("BUFFER_LEN").MustInt64(10000) + Log.AccessLogTemplate = sec.Key("ACCESS_LOG_TEMPLATE").MustString( `{{.Ctx.RemoteAddr}} - {{.Identity}} {{.Start.Format "[02/Jan/2006:15:04:05 -0700]" }} "{{.Ctx.Req.Method}} {{.Ctx.Req.URL.RequestURI}} {{.Ctx.Req.Proto}}" {{.ResponseWriter.Status}} {{.ResponseWriter.Size}} "{{.Ctx.Req.Referer}}\" \"{{.Ctx.Req.UserAgent}}"`, ) // the `MustString` updates the default value, and `log.ACCESS` is used by `generateNamedLogger("access")` later _ = sec.Key("ACCESS").MustString("file") - if EnableAccessLog { + if Log.EnableAccessLog { options := newDefaultLogOptions() - options.filename = filepath.Join(LogRootPath, "access.log") + options.filename = filepath.Join(Log.RootPath, "access.log") options.flags = "" // For the router we don't want any prefixed flags - options.bufferLength = sec.Key("BUFFER_LEN").MustInt64(10000) + options.bufferLength = Log.BufferLength generateNamedLogger(rootCfg, "access", options) } } -func loadRouterLogFrom(rootCfg Config) { +func initRouterLogFrom(rootCfg ConfigProvider) { sec := rootCfg.Section("log") sec.Key("ROUTER").MustString("console") // Allow [log] DISABLE_ROUTER_LOG to override [server] DISABLE_ROUTER_LOG - DisableRouterLog = sec.Key("DISABLE_ROUTER_LOG").MustBool(DisableRouterLog) + Log.DisableRouterLog = sec.Key("DISABLE_ROUTER_LOG").MustBool(Log.DisableRouterLog) - if !DisableRouterLog { + if !Log.DisableRouterLog { options := newDefaultLogOptions() - options.filename = filepath.Join(LogRootPath, "router.log") + options.filename = filepath.Join(Log.RootPath, "router.log") options.flags = "date,time" // For the router we don't want any prefixed flags options.bufferLength = sec.Key("BUFFER_LEN").MustInt64(10000) generateNamedLogger(rootCfg, "router", options) } } -func loadLogFrom(rootCfg Config) { +// initLogFrom initializes logging with settings from configuration provider +func initLogFrom(rootCfg ConfigProvider) { sec := rootCfg.Section("log") options := newDefaultLogOptions() options.bufferLength = sec.Key("BUFFER_LEN").MustInt64(10000) - EnableSSHLog = sec.Key("ENABLE_SSH_LOG").MustBool(false) + Log.EnableSSHLog = sec.Key("ENABLE_SSH_LOG").MustBool(false) description := LogDescription{ Name: log.DEFAULT, @@ -357,27 +360,27 @@ func loadLogFrom(rootCfg Config) { // RestartLogsWithPIDSuffix restarts the logs with a PID suffix on files func RestartLogsWithPIDSuffix() { filenameSuffix = fmt.Sprintf(".%d", os.Getpid()) - LoadLogSettings(false) + InitLogs(false) } -// LoadLogSettings creates all the log services -func LoadLogSettings(disableConsole bool) { - loadLogFrom(Cfg) - loadRouterLogFrom(Cfg) - loadAccessLogFrom(Cfg) - LoadSQLLogSetting(disableConsole) +// InitLogs creates all the log services +func InitLogs(disableConsole bool) { + initLogFrom(CfgProvider) + initRouterLogFrom(CfgProvider) + initAccessLogFrom(CfgProvider) + initSQLLogFrom(CfgProvider, disableConsole) } // LoadSQLLogSetting initializes xorm logger setting func LoadSQLLogSetting(disableConsole bool) { - loadSQLLogFrom(Cfg, disableConsole) + initSQLLogFrom(CfgProvider, disableConsole) } -func loadSQLLogFrom(rootCfg Config, disableConsole bool) { - EnableXORMLog = rootCfg.Section("log").Key("ENABLE_XORM_LOG").MustBool(true) - if EnableXORMLog { +func initSQLLogFrom(rootCfg ConfigProvider, disableConsole bool) { + Log.EnableXORMLog = rootCfg.Section("log").Key("ENABLE_XORM_LOG").MustBool(true) + if Log.EnableXORMLog { options := newDefaultLogOptions() - options.filename = filepath.Join(LogRootPath, "xorm.log") + options.filename = filepath.Join(Log.RootPath, "xorm.log") options.bufferLength = rootCfg.Section("log").Key("BUFFER_LEN").MustInt64(10000) options.disableConsole = disableConsole diff --git a/modules/setting/mailer.go b/modules/setting/mailer.go index c59b2c6e2bd3..62a73cb2f348 100644 --- a/modules/setting/mailer.go +++ b/modules/setting/mailer.go @@ -49,14 +49,14 @@ type Mailer struct { // MailService the global mailer var MailService *Mailer -func loadMailsFrom(rootCfg Config) { +func loadMailsFrom(rootCfg ConfigProvider) { loadMailerFrom(rootCfg) loadRegisterMailFrom(rootCfg) loadNotifyMailFrom(rootCfg) loadIncomingEmailFrom(rootCfg) } -func loadMailerFrom(rootCfg Config) { +func loadMailerFrom(rootCfg ConfigProvider) { sec := rootCfg.Section("mailer") // Check mailer setting. if !sec.Key("ENABLED").MustBool() { @@ -243,7 +243,7 @@ func loadMailerFrom(rootCfg Config) { log.Info("Mail Service Enabled") } -func loadRegisterMailFrom(rootCfg Config) { +func loadRegisterMailFrom(rootCfg ConfigProvider) { if !rootCfg.Section("service").Key("REGISTER_EMAIL_CONFIRM").MustBool() { return } else if MailService == nil { @@ -254,7 +254,7 @@ func loadRegisterMailFrom(rootCfg Config) { log.Info("Register Mail Service Enabled") } -func loadNotifyMailFrom(rootCfg Config) { +func loadNotifyMailFrom(rootCfg ConfigProvider) { if !rootCfg.Section("service").Key("ENABLE_NOTIFY_MAIL").MustBool() { return } else if MailService == nil { diff --git a/modules/setting/markup.go b/modules/setting/markup.go index 1cfe9d24ed48..b71a902be65f 100644 --- a/modules/setting/markup.go +++ b/modules/setting/markup.go @@ -60,7 +60,7 @@ type MarkupSanitizerRule struct { AllowDataURIImages bool } -func loadMarkupFrom(rootCfg Config) { +func loadMarkupFrom(rootCfg ConfigProvider) { mustMapSetting(rootCfg, "markdown", &Markdown) MermaidMaxSourceCharacters = rootCfg.Section("markup").Key("MERMAID_MAX_SOURCE_CHARACTERS").MustInt(5000) diff --git a/modules/setting/metrics.go b/modules/setting/metrics.go index 1482610f3902..daa0e3b70b2d 100644 --- a/modules/setting/metrics.go +++ b/modules/setting/metrics.go @@ -16,6 +16,6 @@ var Metrics = struct { EnabledIssueByRepository: false, } -func loadMetricsFrom(rootCfg Config) { +func loadMetricsFrom(rootCfg ConfigProvider) { mustMapSetting(rootCfg, "metrics", &Metrics) } diff --git a/modules/setting/migrations.go b/modules/setting/migrations.go index 5c0f193035b5..5a6079b6e2db 100644 --- a/modules/setting/migrations.go +++ b/modules/setting/migrations.go @@ -16,7 +16,7 @@ var Migrations = struct { RetryBackoff: 3, } -func loadMigrationsFrom(rootCfg Config) { +func loadMigrationsFrom(rootCfg ConfigProvider) { sec := rootCfg.Section("migrations") Migrations.MaxAttempts = sec.Key("MAX_ATTEMPTS").MustInt(Migrations.MaxAttempts) Migrations.RetryBackoff = sec.Key("RETRY_BACKOFF").MustInt(Migrations.RetryBackoff) diff --git a/modules/setting/mime_type_map.go b/modules/setting/mime_type_map.go index 9315ba05a9bc..55cb2c028dbf 100644 --- a/modules/setting/mime_type_map.go +++ b/modules/setting/mime_type_map.go @@ -14,7 +14,7 @@ var MimeTypeMap = struct { Map: map[string]string{}, } -func loadMimeTypeMapFrom(rootCfg Config) { +func loadMimeTypeMapFrom(rootCfg ConfigProvider) { sec := rootCfg.Section("repository.mimetype_mapping") keys := sec.Keys() m := make(map[string]string, len(keys)) diff --git a/modules/setting/mirror.go b/modules/setting/mirror.go index 3f273668aecf..875062f52252 100644 --- a/modules/setting/mirror.go +++ b/modules/setting/mirror.go @@ -24,7 +24,7 @@ var Mirror = struct { DefaultInterval: 8 * time.Hour, } -func loadMirrorFrom(rootCfg Config) { +func loadMirrorFrom(rootCfg ConfigProvider) { // Handle old configuration through `[repository]` `DISABLE_MIRRORS` // - please note this was badly named and only disabled the creation of new pull mirrors // FIXME: DEPRECATED to be removed in v1.18.0 diff --git a/modules/setting/oauth2.go b/modules/setting/oauth2.go index e1d0d092f99c..44f5568ef4b1 100644 --- a/modules/setting/oauth2.go +++ b/modules/setting/oauth2.go @@ -62,7 +62,7 @@ var OAuth2Client struct { AccountLinking OAuth2AccountLinkingType } -func loadOAuth2ClientFrom(rootCfg Config) { +func loadOAuth2ClientFrom(rootCfg ConfigProvider) { sec := rootCfg.Section("oauth2_client") OAuth2Client.RegisterEmailConfirm = sec.Key("REGISTER_EMAIL_CONFIRM").MustBool(Service.RegisterEmailConfirm) OAuth2Client.OpenIDConnectScopes = parseScopes(sec, "OPENID_CONNECT_SCOPES") @@ -110,7 +110,7 @@ var OAuth2 = struct { MaxTokenLength: math.MaxInt16, } -func loadOAuth2From(rootCfg Config) { +func loadOAuth2From(rootCfg ConfigProvider) { if err := rootCfg.Section("oauth2").MapTo(&OAuth2); err != nil { log.Fatal("Failed to OAuth2 settings: %v", err) return diff --git a/modules/setting/other.go b/modules/setting/other.go index e384678ef568..4fba754a0848 100644 --- a/modules/setting/other.go +++ b/modules/setting/other.go @@ -12,7 +12,7 @@ var ( EnableSitemap bool ) -func loadOtherFrom(rootCfg Config) { +func loadOtherFrom(rootCfg ConfigProvider) { sec := rootCfg.Section("other") ShowFooterBranding = sec.Key("SHOW_FOOTER_BRANDING").MustBool(false) ShowFooterVersion = sec.Key("SHOW_FOOTER_VERSION").MustBool(true) diff --git a/modules/setting/packages.go b/modules/setting/packages.go index 4caaebffe4fd..db9cabfb297a 100644 --- a/modules/setting/packages.go +++ b/modules/setting/packages.go @@ -43,7 +43,7 @@ var ( } ) -func loadPackagesFrom(rootCfg Config) { +func loadPackagesFrom(rootCfg ConfigProvider) { sec := rootCfg.Section("packages") if err := sec.MapTo(&Packages); err != nil { log.Fatal("Failed to map Packages settings: %v", err) diff --git a/modules/setting/picture.go b/modules/setting/picture.go index fbda34c901d9..6d7c8b33ce46 100644 --- a/modules/setting/picture.go +++ b/modules/setting/picture.go @@ -32,7 +32,7 @@ var ( }{} ) -func loadPictureFrom(rootCfg Config) { +func loadPictureFrom(rootCfg ConfigProvider) { sec := rootCfg.Section("picture") avatarSec := rootCfg.Section("avatar") @@ -82,7 +82,7 @@ func GetDefaultEnableFederatedAvatar(disableGravatar bool) bool { return v } -func loadRepoAvatarFrom(rootCfg Config) { +func loadRepoAvatarFrom(rootCfg ConfigProvider) { sec := rootCfg.Section("picture") repoAvatarSec := rootCfg.Section("repo-avatar") diff --git a/modules/setting/project.go b/modules/setting/project.go index b4b198f19c33..803e933b887e 100644 --- a/modules/setting/project.go +++ b/modules/setting/project.go @@ -14,6 +14,6 @@ var ( } ) -func loadProjectFrom(rootCfg Config) { +func loadProjectFrom(rootCfg ConfigProvider) { mustMapSetting(rootCfg, "project", &Project) } diff --git a/modules/setting/proxy.go b/modules/setting/proxy.go index d96ec4a0e8cf..4ff420d0900d 100644 --- a/modules/setting/proxy.go +++ b/modules/setting/proxy.go @@ -21,7 +21,7 @@ var Proxy = struct { ProxyHosts: []string{}, } -func loadProxyFrom(rootCfg Config) { +func loadProxyFrom(rootCfg ConfigProvider) { sec := rootCfg.Section("proxy") Proxy.Enabled = sec.Key("PROXY_ENABLED").MustBool(false) Proxy.ProxyURL = sec.Key("PROXY_URL").MustString("") diff --git a/modules/setting/queue.go b/modules/setting/queue.go index 5fca82397192..bd4bf48e3309 100644 --- a/modules/setting/queue.go +++ b/modules/setting/queue.go @@ -39,10 +39,10 @@ var Queue = QueueSettings{} // GetQueueSettings returns the queue settings for the appropriately named queue func GetQueueSettings(name string) QueueSettings { - return getQueueSettings(Cfg, name) + return getQueueSettings(CfgProvider, name) } -func getQueueSettings(rootCfg Config, name string) QueueSettings { +func getQueueSettings(rootCfg ConfigProvider, name string) QueueSettings { q := QueueSettings{} sec := rootCfg.Section("queue." + name) q.Name = name @@ -89,10 +89,10 @@ func getQueueSettings(rootCfg Config, name string) QueueSettings { // LoadQueueSettings sets up the default settings for Queues // This is exported for tests to be able to use the queue func LoadQueueSettings() { - loadQueueFrom(Cfg) + loadQueueFrom(CfgProvider) } -func loadQueueFrom(rootCfg Config) { +func loadQueueFrom(rootCfg ConfigProvider) { sec := rootCfg.Section("queue") Queue.DataDir = filepath.ToSlash(sec.Key("DATADIR").MustString("queues/")) if !filepath.IsAbs(Queue.DataDir) { @@ -174,7 +174,7 @@ func loadQueueFrom(rootCfg Config) { // handleOldLengthConfiguration allows fallback to older configuration. `[queue.name]` `LENGTH` will override this configuration, but // if that is left unset then we should fallback to the older configuration. (Except where the new length woul be <=0) -func handleOldLengthConfiguration(rootCfg Config, queueName, oldSection, oldKey string, defaultValue int) { +func handleOldLengthConfiguration(rootCfg ConfigProvider, queueName, oldSection, oldKey string, defaultValue int) { if rootCfg.Section(oldSection).HasKey(oldKey) { log.Error("Deprecated fallback for %s queue length `[%s]` `%s` present. Use `[queue.%s]` `LENGTH`. This will be removed in v1.18.0", queueName, queueName, oldSection, oldKey) } diff --git a/modules/setting/repository.go b/modules/setting/repository.go index 9044c4a339ab..e897abda1819 100644 --- a/modules/setting/repository.go +++ b/modules/setting/repository.go @@ -268,7 +268,7 @@ var ( }{} ) -func loadRepositoryFrom(rootCfg Config) { +func loadRepositoryFrom(rootCfg ConfigProvider) { var err error // Determine and create root git repository path. sec := rootCfg.Section("repository") diff --git a/modules/setting/security.go b/modules/setting/security.go index 98b83ee3dd4d..147483f1127d 100644 --- a/modules/setting/security.go +++ b/modules/setting/security.go @@ -95,7 +95,7 @@ func generateSaveInternalToken() { }) } -func loadSecurityFrom(rootCfg Config) { +func loadSecurityFrom(rootCfg ConfigProvider) { sec := rootCfg.Section("security") InstallLock = sec.Key("INSTALL_LOCK").MustBool(false) LogInRememberDays = sec.Key("LOGIN_REMEMBER_DAYS").MustInt(7) diff --git a/modules/setting/server.go b/modules/setting/server.go index b62b6a18cb28..f3d3d534c72b 100644 --- a/modules/setting/server.go +++ b/modules/setting/server.go @@ -165,12 +165,12 @@ func MakeAbsoluteAssetURL(appURL, staticURLPrefix string) string { return strings.TrimSuffix(staticURLPrefix, "/") } -func loadServerFrom(rootCfg Config) { +func loadServerFrom(rootCfg ConfigProvider) { logSec := rootCfg.Section("log") - LogLevel = getLogLevel(logSec, "LEVEL", log.INFO) - StacktraceLogLevel = getStacktraceLogLevel(logSec, "STACKTRACE_LEVEL", "None") - LogRootPath = logSec.Key("ROOT_PATH").MustString(path.Join(AppWorkPath, "log")) - forcePathSeparator(LogRootPath) + Log.Level = getLogLevel(logSec, "LEVEL", log.INFO) + Log.StacktraceLogLevel = getStacktraceLogLevel(logSec, "STACKTRACE_LEVEL", "None") + Log.RootPath = logSec.Key("ROOT_PATH").MustString(path.Join(AppWorkPath, "log")) + forcePathSeparator(Log.RootPath) sec := rootCfg.Section("server") AppName = rootCfg.Section("").Key("APP_NAME").MustString("Gitea: Git with a cup of tea") @@ -321,7 +321,7 @@ func loadServerFrom(rootCfg Config) { PortToRedirect = sec.Key("PORT_TO_REDIRECT").MustString("80") RedirectorUseProxyProtocol = sec.Key("REDIRECTOR_USE_PROXY_PROTOCOL").MustBool(UseProxyProtocol) OfflineMode = sec.Key("OFFLINE_MODE").MustBool() - DisableRouterLog = sec.Key("DISABLE_ROUTER_LOG").MustBool() + Log.DisableRouterLog = sec.Key("DISABLE_ROUTER_LOG").MustBool() if len(StaticRootPath) == 0 { StaticRootPath = AppWorkPath } diff --git a/modules/setting/service.go b/modules/setting/service.go index e7069c70dfe8..2237f02fb201 100644 --- a/modules/setting/service.go +++ b/modules/setting/service.go @@ -111,7 +111,7 @@ func (a AllowedVisibility) ToVisibleTypeSlice() (result []structs.VisibleType) { return result } -func loadServiceFrom(rootCfg Config) { +func loadServiceFrom(rootCfg ConfigProvider) { sec := rootCfg.Section("service") Service.ActiveCodeLives = sec.Key("ACTIVE_CODE_LIVE_MINUTES").MustInt(180) Service.ResetPwdCodeLives = sec.Key("RESET_PASSWD_CODE_LIVE_MINUTES").MustInt(180) @@ -193,7 +193,7 @@ func loadServiceFrom(rootCfg Config) { loadOpenIDSetting(rootCfg) } -func loadOpenIDSetting(rootCfg Config) { +func loadOpenIDSetting(rootCfg ConfigProvider) { sec := rootCfg.Section("openid") Service.EnableOpenIDSignIn = sec.Key("ENABLE_OPENID_SIGNIN").MustBool(!InstallLock) Service.EnableOpenIDSignUp = sec.Key("ENABLE_OPENID_SIGNUP").MustBool(!Service.DisableRegistration && Service.EnableOpenIDSignIn) diff --git a/modules/setting/session.go b/modules/setting/session.go index 6145fa4f8ef9..b8498335d986 100644 --- a/modules/setting/session.go +++ b/modules/setting/session.go @@ -15,7 +15,8 @@ import ( // SessionConfig defines Session settings var SessionConfig = struct { - Provider string + OriginalProvider string + Provider string // Provider configuration, it's corresponding to provider. ProviderConfig string // Cookie name to save session ID. Default is "MacaronSession". @@ -39,7 +40,7 @@ var SessionConfig = struct { SameSite: http.SameSiteLaxMode, } -func loadSessionFrom(rootCfg Config) { +func loadSessionFrom(rootCfg ConfigProvider) { sec := rootCfg.Section("session") SessionConfig.Provider = sec.Key("PROVIDER").In("memory", []string{"memory", "file", "redis", "mysql", "postgres", "couchbase", "memcache", "db"}) @@ -67,6 +68,7 @@ func loadSessionFrom(rootCfg Config) { log.Fatal("Can't shadow session config: %v", err) } SessionConfig.ProviderConfig = string(shadowConfig) + SessionConfig.OriginalProvider = SessionConfig.Provider SessionConfig.Provider = "VirtualSession" log.Info("Session Service Enabled") diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 98accd5410d6..6c89dc529228 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -40,7 +40,7 @@ var ( AppWorkPath string // Global setting objects - Cfg *ini.File + CfgProvider ConfigProvider CustomPath string // Custom directory path CustomConf string PIDFile = "/run/gitea.pid" @@ -196,7 +196,6 @@ func PrepareAppDataPath() error { // Now we can take the first step to do correctly (using Mkdir) in other packages, and prepare the AppDataPath here, then make a refactor in future. st, err := os.Stat(AppDataPath) - if os.IsNotExist(err) { err = os.MkdirAll(AppDataPath, os.ModePerm) if err != nil { @@ -218,38 +217,28 @@ func PrepareAppDataPath() error { // LoadFromExisting initializes setting options from an existing config file (app.ini) func LoadFromExisting() { - Cfg = loadFromConf(CustomConf, WritePIDFile, false, PIDFile, "") + CfgProvider = newFileProviderFromConf(CustomConf, WritePIDFile, false, PIDFile, "") + loadCommonConfigsFrom(CfgProvider) } // LoadAllowEmpty initializes setting options, it's also fine that if the config file (app.ini) doesn't exist func LoadAllowEmpty() { - Cfg = loadFromConf(CustomConf, WritePIDFile, true, PIDFile, "") + CfgProvider = newFileProviderFromConf(CustomConf, WritePIDFile, true, PIDFile, "") + loadCommonConfigsFrom(CfgProvider) } // LoadForTest initializes setting options for tests func LoadForTest(extraConfigs ...string) { - Cfg = loadFromConf(CustomConf, WritePIDFile, true, PIDFile, strings.Join(extraConfigs, "\n")) + CfgProvider = newFileProviderFromConf(CustomConf, WritePIDFile, true, PIDFile, strings.Join(extraConfigs, "\n")) + loadCommonConfigsFrom(CfgProvider) if err := PrepareAppDataPath(); err != nil { log.Fatal("Can not prepare APP_DATA_PATH: %v", err) } } -func deprecatedSetting(rootCfg Config, oldSection, oldKey, newSection, newKey string) { - if rootCfg.Section(oldSection).HasKey(oldKey) { - log.Error("Deprecated fallback `[%s]` `%s` present. Use `[%s]` `%s` instead. This fallback will be removed in v1.19.0", oldSection, oldKey, newSection, newKey) - } -} - -// deprecatedSettingDB add a hint that the configuration has been moved to database but still kept in app.ini -func deprecatedSettingDB(rootCfg Config, oldSection, oldKey string) { - if rootCfg.Section(oldSection).HasKey(oldKey) { - log.Error("Deprecated `[%s]` `%s` present which has been copied to database table sys_setting", oldSection, oldKey) - } -} - -// loadFromConf initializes configuration context. +// newFileProviderFromConf initializes configuration context. // NOTE: do not print any log except error. -func loadFromConf(customConf string, writePIDFile, allowEmpty bool, pidFile, extraConfig string) *ini.File { +func newFileProviderFromConf(customConf string, writePIDFile, allowEmpty bool, pidFile, extraConfig string) *ini.File { cfg := ini.Empty() if writePIDFile && len(pidFile) > 0 { @@ -275,7 +264,11 @@ func loadFromConf(customConf string, writePIDFile, allowEmpty bool, pidFile, ext } cfg.NameMapper = ini.SnackCase + return cfg +} +// loadCommonConfigsFrom loads common configurations from a configuration provider. +func loadCommonConfigsFrom(cfg ConfigProvider) { // WARNNING: don't change the sequence except you know what you are doing. loadRunModeFrom(cfg) loadServerFrom(cfg) @@ -298,11 +291,9 @@ func loadFromConf(customConf string, writePIDFile, allowEmpty bool, pidFile, ext loadMirrorFrom(cfg) loadMarkupFrom(cfg) loadOtherFrom(cfg) - - return cfg } -func loadRunModeFrom(rootCfg Config) { +func loadRunModeFrom(rootCfg ConfigProvider) { rootSec := rootCfg.Section("") RunUser = rootSec.Key("RUN_USER").MustString(user.CurrentUsername()) // The following is a purposefully undocumented option. Please do not run Gitea as root. It will only cause future headaches. @@ -380,27 +371,27 @@ func CreateOrAppendToCustomConf(purpose string, callback func(cfg *ini.File)) { // LoadSettings initializes the settings for normal start up func LoadSettings() { LoadDBSetting() - loadServiceFrom(Cfg) - loadOAuth2ClientFrom(Cfg) - LoadLogSettings(false) - loadCacheFrom(Cfg) - loadSessionFrom(Cfg) - loadCorsFrom(Cfg) - loadMailsFrom(Cfg) - loadProxyFrom(Cfg) - loadWebhookFrom(Cfg) - loadMigrationsFrom(Cfg) - loadIndexerFrom(Cfg) - loadTaskFrom(Cfg) + loadServiceFrom(CfgProvider) + loadOAuth2ClientFrom(CfgProvider) + InitLogs(false) + loadCacheFrom(CfgProvider) + loadSessionFrom(CfgProvider) + loadCorsFrom(CfgProvider) + loadMailsFrom(CfgProvider) + loadProxyFrom(CfgProvider) + loadWebhookFrom(CfgProvider) + loadMigrationsFrom(CfgProvider) + loadIndexerFrom(CfgProvider) + loadTaskFrom(CfgProvider) LoadQueueSettings() - loadProjectFrom(Cfg) - loadMimeTypeMapFrom(Cfg) - loadFederationFrom(Cfg) + loadProjectFrom(CfgProvider) + loadMimeTypeMapFrom(CfgProvider) + loadFederationFrom(CfgProvider) } // LoadSettingsForInstall initializes the settings for install func LoadSettingsForInstall() { LoadDBSetting() - loadServiceFrom(Cfg) - loadMailerFrom(Cfg) + loadServiceFrom(CfgProvider) + loadMailerFrom(CfgProvider) } diff --git a/modules/setting/ssh.go b/modules/setting/ssh.go index 512909c5547e..e8796f98d6f1 100644 --- a/modules/setting/ssh.go +++ b/modules/setting/ssh.go @@ -99,7 +99,7 @@ func parseAuthorizedPrincipalsAllow(values []string) ([]string, bool) { return authorizedPrincipalsAllow, true } -func loadSSHFrom(rootCfg Config) { +func loadSSHFrom(rootCfg ConfigProvider) { sec := rootCfg.Section("server") if len(SSH.Domain) == 0 { SSH.Domain = Domain diff --git a/modules/setting/storage.go b/modules/setting/storage.go index 3661a7a478a0..9197c5f8bb37 100644 --- a/modules/setting/storage.go +++ b/modules/setting/storage.go @@ -30,7 +30,7 @@ func (s *Storage) MapTo(v interface{}) error { return nil } -func getStorage(rootCfg Config, name, typ string, targetSec *ini.Section) Storage { +func getStorage(rootCfg ConfigProvider, name, typ string, targetSec *ini.Section) Storage { const sectionName = "storage" sec := rootCfg.Section(sectionName) diff --git a/modules/setting/task.go b/modules/setting/task.go index 00ecd194e923..81732deeb64f 100644 --- a/modules/setting/task.go +++ b/modules/setting/task.go @@ -5,7 +5,7 @@ package setting // FIXME: DEPRECATED to be removed in v1.18.0 // - will need to set default for [queue.task] LENGTH to 1000 though -func loadTaskFrom(rootCfg Config) { +func loadTaskFrom(rootCfg ConfigProvider) { taskSec := rootCfg.Section("task") queueTaskSec := rootCfg.Section("queue.task") diff --git a/modules/setting/time.go b/modules/setting/time.go index 9e9aaa9a6c65..5fd0fdb92f47 100644 --- a/modules/setting/time.go +++ b/modules/setting/time.go @@ -16,7 +16,7 @@ var ( DefaultUILocation = time.Local ) -func loadTimeFrom(rootCfg Config) { +func loadTimeFrom(rootCfg ConfigProvider) { timeFormatKey := rootCfg.Section("time").Key("FORMAT").MustString("") if timeFormatKey != "" { TimeFormat = map[string]string{ diff --git a/modules/setting/ui.go b/modules/setting/ui.go index e9979f8b7da7..2df3c35c76ee 100644 --- a/modules/setting/ui.go +++ b/modules/setting/ui.go @@ -132,7 +132,7 @@ var UI = struct { }, } -func loadUIFrom(rootCfg Config) { +func loadUIFrom(rootCfg ConfigProvider) { mustMapSetting(rootCfg, "ui", &UI) sec := rootCfg.Section("ui") UI.ShowUserEmail = sec.Key("SHOW_USER_EMAIL").MustBool(true) diff --git a/modules/setting/webhook.go b/modules/setting/webhook.go index fe2564ab3e0d..c01261dbbd6e 100644 --- a/modules/setting/webhook.go +++ b/modules/setting/webhook.go @@ -29,7 +29,7 @@ var Webhook = struct { ProxyHosts: []string{}, } -func loadWebhookFrom(rootCfg Config) { +func loadWebhookFrom(rootCfg ConfigProvider) { sec := rootCfg.Section("webhook") Webhook.QueueLength = sec.Key("QUEUE_LENGTH").MustInt(1000) Webhook.DeliverTimeout = sec.Key("DELIVER_TIMEOUT").MustInt(5) diff --git a/routers/common/middleware.go b/routers/common/middleware.go index 0c7838b0ef5b..bceca30d3bcf 100644 --- a/routers/common/middleware.go +++ b/routers/common/middleware.go @@ -49,11 +49,11 @@ func Middlewares() []func(http.Handler) http.Handler { handlers = append(handlers, middleware.StripSlashes) - if !setting.DisableRouterLog { + if !setting.Log.DisableRouterLog { handlers = append(handlers, routing.NewLoggerHandler()) } - if setting.EnableAccessLog { + if setting.Log.EnableAccessLog { handlers = append(handlers, context.AccessLogger()) } diff --git a/routers/init.go b/routers/init.go index 5a3bb789edbe..e970ad3ae587 100644 --- a/routers/init.go +++ b/routers/init.go @@ -117,7 +117,7 @@ func GlobalInitInstalled(ctx context.Context) { log.Info("AppPath: %s", setting.AppPath) log.Info("AppWorkPath: %s", setting.AppWorkPath) log.Info("Custom path: %s", setting.CustomPath) - log.Info("Log path: %s", setting.LogRootPath) + log.Info("Log path: %s", setting.Log.RootPath) log.Info("Configuration file: %s", setting.CustomConf) log.Info("Run Mode: %s", util.ToTitleCase(setting.RunMode)) log.Info("Gitea v%s%s", setting.AppVer, setting.AppBuiltWith) diff --git a/routers/install/install.go b/routers/install/install.go index e9fa844a0956..d0c34cbe146f 100644 --- a/routers/install/install.go +++ b/routers/install/install.go @@ -133,7 +133,7 @@ func Install(ctx *context.Context) { form.SSHPort = setting.SSH.Port form.HTTPPort = setting.HTTPPort form.AppURL = setting.AppURL - form.LogRootPath = setting.LogRootPath + form.LogRootPath = setting.Log.RootPath // E-mail service settings if setting.MailService != nil { @@ -466,7 +466,7 @@ func SubmitInstall(ctx *context.Context) { cfg.Section("session").Key("PROVIDER").SetValue("file") cfg.Section("log").Key("MODE").SetValue("console") - cfg.Section("log").Key("LEVEL").SetValue(setting.LogLevel.String()) + cfg.Section("log").Key("LEVEL").SetValue(setting.Log.Level.String()) cfg.Section("log").Key("ROOT_PATH").SetValue(form.LogRootPath) cfg.Section("log").Key("ROUTER").SetValue("console") diff --git a/routers/install/setting.go b/routers/install/setting.go index 8119ef305821..059a51f3e35d 100644 --- a/routers/install/setting.go +++ b/routers/install/setting.go @@ -20,7 +20,7 @@ func PreloadSettings(ctx context.Context) bool { log.Info("AppPath: %s", setting.AppPath) log.Info("AppWorkPath: %s", setting.AppWorkPath) log.Info("Custom path: %s", setting.CustomPath) - log.Info("Log path: %s", setting.LogRootPath) + log.Info("Log path: %s", setting.Log.RootPath) log.Info("Configuration file: %s", setting.CustomConf) log.Info("Prepare to run install page") translation.InitLocales(ctx) diff --git a/routers/private/manager.go b/routers/private/manager.go index f15da298d6a0..a56fe9d12349 100644 --- a/routers/private/manager.go +++ b/routers/private/manager.go @@ -116,11 +116,11 @@ func AddLogger(ctx *context.PrivateContext) { } if _, ok := opts.Config["level"]; !ok { - opts.Config["level"] = setting.LogLevel + opts.Config["level"] = setting.Log.Level } if _, ok := opts.Config["stacktraceLevel"]; !ok { - opts.Config["stacktraceLevel"] = setting.StacktraceLogLevel + opts.Config["stacktraceLevel"] = setting.Log.StacktraceLogLevel } if opts.Mode == "file" { @@ -135,7 +135,7 @@ func AddLogger(ctx *context.PrivateContext) { } } - bufferLen := setting.Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000) + bufferLen := setting.Log.BufferLength byteConfig, err := json.Marshal(opts.Config) if err != nil { log.Error("Failed to marshal log configuration: %v %v", opts.Config, err) diff --git a/routers/private/ssh_log.go b/routers/private/ssh_log.go index 54604ad55466..eacfa18f058b 100644 --- a/routers/private/ssh_log.go +++ b/routers/private/ssh_log.go @@ -15,7 +15,7 @@ import ( // SSHLog hook to response ssh log func SSHLog(ctx *context.PrivateContext) { - if !setting.EnableSSHLog { + if !setting.Log.EnableSSHLog { ctx.Status(http.StatusOK) return } diff --git a/routers/web/admin/config.go b/routers/web/admin/config.go index eaa02588ca5c..e2e1759c1fbc 100644 --- a/routers/web/admin/config.go +++ b/routers/web/admin/config.go @@ -115,7 +115,7 @@ func Config(ctx *context.Context) { ctx.Data["AppUrl"] = setting.AppURL ctx.Data["Domain"] = setting.Domain ctx.Data["OfflineMode"] = setting.OfflineMode - ctx.Data["DisableRouterLog"] = setting.DisableRouterLog + ctx.Data["DisableRouterLog"] = setting.Log.DisableRouterLog ctx.Data["RunUser"] = setting.RunUser ctx.Data["RunMode"] = util.ToTitleCase(setting.RunMode) ctx.Data["GitVersion"] = git.VersionInfo() @@ -123,7 +123,7 @@ func Config(ctx *context.Context) { ctx.Data["RepoRootPath"] = setting.RepoRootPath ctx.Data["CustomRootPath"] = setting.CustomPath ctx.Data["StaticRootPath"] = setting.StaticRootPath - ctx.Data["LogRootPath"] = setting.LogRootPath + ctx.Data["LogRootPath"] = setting.Log.RootPath ctx.Data["ScriptType"] = setting.ScriptType ctx.Data["ReverseProxyAuthUser"] = setting.ReverseProxyAuthUser ctx.Data["ReverseProxyAuthEmail"] = setting.ReverseProxyAuthEmail @@ -181,10 +181,10 @@ func Config(ctx *context.Context) { ctx.Data["EnvVars"] = envVars ctx.Data["Loggers"] = setting.GetLogDescriptions() - ctx.Data["EnableAccessLog"] = setting.EnableAccessLog - ctx.Data["AccessLogTemplate"] = setting.AccessLogTemplate - ctx.Data["DisableRouterLog"] = setting.DisableRouterLog - ctx.Data["EnableXORMLog"] = setting.EnableXORMLog + ctx.Data["EnableAccessLog"] = setting.Log.EnableAccessLog + ctx.Data["AccessLogTemplate"] = setting.Log.AccessLogTemplate + ctx.Data["DisableRouterLog"] = setting.Log.DisableRouterLog + ctx.Data["EnableXORMLog"] = setting.Log.EnableXORMLog ctx.Data["LogSQL"] = setting.Database.LogSQL ctx.HTML(http.StatusOK, tplConfig) From 52ed1ed4c6e3cfbf2d9371f69094b981a9e0832b Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 30 Jan 2023 14:16:48 +0800 Subject: [PATCH 14/20] Rename LoadFromExisting and related functions --- cmd/cmd.go | 4 ++-- cmd/doctor.go | 4 ++-- cmd/dump.go | 2 +- cmd/embedded.go | 2 +- cmd/mailer.go | 2 +- cmd/main_test.go | 2 +- cmd/restore_repo.go | 2 +- cmd/serv.go | 2 +- cmd/web.go | 2 +- contrib/pr/checkout.go | 2 +- models/asymkey/main_test.go | 2 +- models/issues/main_test.go | 2 +- models/main_test.go | 2 +- models/migrations/base/tests.go | 2 +- modules/doctor/doctor.go | 4 ++-- modules/doctor/paths.go | 2 +- modules/markup/html_test.go | 2 +- modules/markup/markdown/markdown_test.go | 2 +- modules/setting/log.go | 16 ++++++++++++---- modules/setting/server.go | 6 ------ modules/setting/setting.go | 13 +++++++------ routers/api/v1/repo/main_test.go | 2 +- routers/install/setting.go | 4 ++-- services/webhook/main_test.go | 2 +- .../integration/migration-test/migration_test.go | 2 +- tests/test_utils.go | 2 +- 26 files changed, 46 insertions(+), 43 deletions(-) diff --git a/cmd/cmd.go b/cmd/cmd.go index e93a6b33df55..87218ecaa236 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -57,9 +57,9 @@ func confirm() (bool, error) { } func initDB(ctx context.Context) error { - setting.LoadFromExisting() + setting.LoadAllFromExistingFile() setting.LoadDBSetting() - setting.LoadSQLLogSetting(false) + setting.InitSQLLog(false) if setting.Database.Type == "" { log.Fatal(`Database settings are missing from the configuration file: %q. diff --git a/cmd/doctor.go b/cmd/doctor.go index 44d418c260b9..16d1e11207de 100644 --- a/cmd/doctor.go +++ b/cmd/doctor.go @@ -87,7 +87,7 @@ func runRecreateTable(ctx *cli.Context) error { golog.SetPrefix("") golog.SetOutput(log.NewLoggerAsWriter("INFO", log.GetLogger(log.DEFAULT))) - setting.LoadFromExisting() + setting.LoadAllFromExistingFile() setting.LoadDBSetting() setting.Log.EnableXORMLog = ctx.Bool("debug") @@ -95,7 +95,7 @@ func runRecreateTable(ctx *cli.Context) error { // FIXME: don't use CfgProvider directly setting.CfgProvider.Section("log").Key("XORM").SetValue(",") - setting.LoadSQLLogSetting(!ctx.Bool("debug")) + setting.InitSQLLog(!ctx.Bool("debug")) stdCtx, cancel := installSignals() defer cancel() diff --git a/cmd/dump.go b/cmd/dump.go index 5afabb450f7c..c733b94c884a 100644 --- a/cmd/dump.go +++ b/cmd/dump.go @@ -181,7 +181,7 @@ func runDump(ctx *cli.Context) error { } fileName += "." + outType } - setting.LoadFromExisting() + setting.LoadAllFromExistingFile() // make sure we are logging to the console no matter what the configuration tells us do to // FIXME: don't use CfgProvider directly diff --git a/cmd/embedded.go b/cmd/embedded.go index 118781895eca..5e1daa0cce73 100644 --- a/cmd/embedded.go +++ b/cmd/embedded.go @@ -112,7 +112,7 @@ func initEmbeddedExtractor(c *cli.Context) error { log.DelNamedLogger(log.DEFAULT) // Read configuration file - setting.LoadAllowEmpty() + setting.LoadAllAllowEmpty() pats, err := getPatterns(c.Args()) if err != nil { diff --git a/cmd/mailer.go b/cmd/mailer.go index af6613f15960..6c4fa9043717 100644 --- a/cmd/mailer.go +++ b/cmd/mailer.go @@ -17,7 +17,7 @@ func runSendMail(c *cli.Context) error { ctx, cancel := installSignals() defer cancel() - setting.LoadFromExisting() + setting.LoadAllFromExistingFile() if err := argsSet(c, "title"); err != nil { return err diff --git a/cmd/main_test.go b/cmd/main_test.go index 9aacdf7bbae1..e2ff72f52cdc 100644 --- a/cmd/main_test.go +++ b/cmd/main_test.go @@ -12,7 +12,7 @@ import ( func init() { setting.SetCustomPathAndConf("", "", "") - setting.LoadForTest() + setting.LoadAllForTest() } func TestMain(m *testing.M) { diff --git a/cmd/restore_repo.go b/cmd/restore_repo.go index 23932f821c28..702ac3f7d8a2 100644 --- a/cmd/restore_repo.go +++ b/cmd/restore_repo.go @@ -54,7 +54,7 @@ func runRestoreRepository(c *cli.Context) error { ctx, cancel := installSignals() defer cancel() - setting.LoadFromExisting() + setting.LoadAllFromExistingFile() var units []string if s := c.String("units"); s != "" { units = strings.Split(s, ",") diff --git a/cmd/serv.go b/cmd/serv.go index 346c918b184d..3bebf981c6a6 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -61,7 +61,7 @@ func setup(logPath string, debug bool) { } else { _ = log.NewLogger(1000, "console", "console", `{"level":"fatal","stacktracelevel":"NONE","stderr":true}`) } - setting.LoadFromExisting() + setting.LoadAllFromExistingFile() if debug { setting.RunMode = "dev" } diff --git a/cmd/web.go b/cmd/web.go index 49a03356158e..7b7a007055f1 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -158,7 +158,7 @@ func runWeb(ctx *cli.Context) error { log.Info("Global init") // Perform global initialization - setting.LoadFromExisting() + setting.LoadAllFromExistingFile() routers.GlobalInitInstalled(graceful.GetManager().HammerContext()) // We check that AppDataPath exists here (it should have been created during installation) diff --git a/contrib/pr/checkout.go b/contrib/pr/checkout.go index 9df63225d2a5..b55f5873195a 100644 --- a/contrib/pr/checkout.go +++ b/contrib/pr/checkout.go @@ -49,7 +49,7 @@ func runPR() { log.Fatal(err) } setting.SetCustomPathAndConf("", "", "") - setting.LoadAllowEmpty() + setting.LoadAllAllowEmpty() setting.RepoRootPath, err = os.MkdirTemp(os.TempDir(), "repos") if err != nil { diff --git a/models/asymkey/main_test.go b/models/asymkey/main_test.go index 82a408ece08b..70144bef97e2 100644 --- a/models/asymkey/main_test.go +++ b/models/asymkey/main_test.go @@ -13,7 +13,7 @@ import ( func init() { setting.SetCustomPathAndConf("", "", "") - setting.LoadForTest() + setting.LoadAllForTest() } func TestMain(m *testing.M) { diff --git a/models/issues/main_test.go b/models/issues/main_test.go index 93e05f33f664..ba31d391ac4b 100644 --- a/models/issues/main_test.go +++ b/models/issues/main_test.go @@ -20,7 +20,7 @@ import ( func init() { setting.SetCustomPathAndConf("", "", "") - setting.LoadForTest() + setting.LoadAllForTest() } func TestFixturesAreConsistent(t *testing.T) { diff --git a/models/main_test.go b/models/main_test.go index cc4eebfe7644..f859e56fc51f 100644 --- a/models/main_test.go +++ b/models/main_test.go @@ -20,7 +20,7 @@ import ( func init() { setting.SetCustomPathAndConf("", "", "") - setting.LoadForTest() + setting.LoadAllForTest() } // TestFixturesAreConsistent assert that test fixtures are consistent diff --git a/models/migrations/base/tests.go b/models/migrations/base/tests.go index 361dfc9a9ed8..c16696546697 100644 --- a/models/migrations/base/tests.go +++ b/models/migrations/base/tests.go @@ -149,7 +149,7 @@ func MainTest(m *testing.M) { setting.AppDataPath = tmpDataPath setting.SetCustomPathAndConf("", "", "") - setting.LoadForTest() + setting.LoadAllForTest() if err = git.InitFull(context.Background()); err != nil { fmt.Printf("Unable to InitFull: %v\n", err) os.Exit(1) diff --git a/modules/doctor/doctor.go b/modules/doctor/doctor.go index 044e5bff9b77..50c445a160fe 100644 --- a/modules/doctor/doctor.go +++ b/modules/doctor/doctor.go @@ -44,9 +44,9 @@ func (w *wrappedLevelLogger) Log(skip int, level log.Level, format string, v ... } func initDBDisableConsole(ctx context.Context, disableConsole bool) error { - setting.LoadFromExisting() + setting.LoadAllFromExistingFile() setting.LoadDBSetting() - setting.LoadSQLLogSetting(disableConsole) + setting.InitSQLLog(disableConsole) if err := db.InitEngine(ctx); err != nil { return fmt.Errorf("db.InitEngine: %w", err) } diff --git a/modules/doctor/paths.go b/modules/doctor/paths.go index 3d0b2cd5e0dc..6b0f1c16d555 100644 --- a/modules/doctor/paths.go +++ b/modules/doctor/paths.go @@ -67,7 +67,7 @@ func checkConfigurationFiles(ctx context.Context, logger log.Logger, autofix boo return err } - setting.LoadFromExisting() + setting.LoadAllFromExistingFile() configurationFiles := []configurationFile{ {"Configuration File Path", setting.CustomConf, false, true, false}, diff --git a/modules/markup/html_test.go b/modules/markup/html_test.go index 32f26bffabb0..5b6a8796e8ed 100644 --- a/modules/markup/html_test.go +++ b/modules/markup/html_test.go @@ -28,7 +28,7 @@ var localMetas = map[string]string{ } func TestMain(m *testing.M) { - setting.LoadAllowEmpty() + setting.LoadAllAllowEmpty() if err := git.InitSimple(context.Background()); err != nil { log.Fatal("git init failed, err: %v", err) } diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go index cc683dc5b7c7..8e1f56f9dd9a 100644 --- a/modules/markup/markdown/markdown_test.go +++ b/modules/markup/markdown/markdown_test.go @@ -33,7 +33,7 @@ var localMetas = map[string]string{ } func TestMain(m *testing.M) { - setting.LoadAllowEmpty() + setting.LoadAllAllowEmpty() if err := git.InitSimple(context.Background()); err != nil { log.Fatal("git init failed, err: %v", err) } diff --git a/modules/setting/log.go b/modules/setting/log.go index 2138a0587c97..c59e1fe304b2 100644 --- a/modules/setting/log.go +++ b/modules/setting/log.go @@ -140,6 +140,15 @@ func getStacktraceLogLevel(section *ini.Section, key, defaultValue string) strin return log.FromString(value).String() } +func loadLogFrom(rootCfg ConfigProvider) { + sec := rootCfg.Section("log") + Log.Level = getLogLevel(sec, "LEVEL", log.INFO) + Log.StacktraceLogLevel = getStacktraceLogLevel(sec, "STACKTRACE_LEVEL", "None") + Log.RootPath = sec.Key("ROOT_PATH").MustString(path.Join(AppWorkPath, "log")) + Log.EnableSSHLog = sec.Key("ENABLE_SSH_LOG").MustBool(false) + forcePathSeparator(Log.RootPath) +} + func generateLogConfig(sec *ini.Section, name string, defaults defaultLogOptions) (mode, jsonConfig, levelName string) { level := getLogLevel(sec, "LEVEL", Log.Level) levelName = level.String() @@ -305,8 +314,7 @@ func initRouterLogFrom(rootCfg ConfigProvider) { func initLogFrom(rootCfg ConfigProvider) { sec := rootCfg.Section("log") options := newDefaultLogOptions() - options.bufferLength = sec.Key("BUFFER_LEN").MustInt64(10000) - Log.EnableSSHLog = sec.Key("ENABLE_SSH_LOG").MustBool(false) + options.bufferLength = Log.BufferLength description := LogDescription{ Name: log.DEFAULT, @@ -371,8 +379,8 @@ func InitLogs(disableConsole bool) { initSQLLogFrom(CfgProvider, disableConsole) } -// LoadSQLLogSetting initializes xorm logger setting -func LoadSQLLogSetting(disableConsole bool) { +// InitSQLLog initializes xorm logger setting +func InitSQLLog(disableConsole bool) { initSQLLogFrom(CfgProvider, disableConsole) } diff --git a/modules/setting/server.go b/modules/setting/server.go index f3d3d534c72b..6b0f3752e142 100644 --- a/modules/setting/server.go +++ b/modules/setting/server.go @@ -166,12 +166,6 @@ func MakeAbsoluteAssetURL(appURL, staticURLPrefix string) string { } func loadServerFrom(rootCfg ConfigProvider) { - logSec := rootCfg.Section("log") - Log.Level = getLogLevel(logSec, "LEVEL", log.INFO) - Log.StacktraceLogLevel = getStacktraceLogLevel(logSec, "STACKTRACE_LEVEL", "None") - Log.RootPath = logSec.Key("ROOT_PATH").MustString(path.Join(AppWorkPath, "log")) - forcePathSeparator(Log.RootPath) - sec := rootCfg.Section("server") AppName = rootCfg.Section("").Key("APP_NAME").MustString("Gitea: Git with a cup of tea") diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 6c89dc529228..c2f58cf4c9cc 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -215,20 +215,20 @@ func PrepareAppDataPath() error { return nil } -// LoadFromExisting initializes setting options from an existing config file (app.ini) -func LoadFromExisting() { +// LoadAllFromExistingFile initializes setting options from an existing config file (app.ini) +func LoadAllFromExistingFile() { CfgProvider = newFileProviderFromConf(CustomConf, WritePIDFile, false, PIDFile, "") loadCommonConfigsFrom(CfgProvider) } -// LoadAllowEmpty initializes setting options, it's also fine that if the config file (app.ini) doesn't exist -func LoadAllowEmpty() { +// LoadAllAllowEmpty initializes setting options, it's also fine that if the config file (app.ini) doesn't exist +func LoadAllAllowEmpty() { CfgProvider = newFileProviderFromConf(CustomConf, WritePIDFile, true, PIDFile, "") loadCommonConfigsFrom(CfgProvider) } -// LoadForTest initializes setting options for tests -func LoadForTest(extraConfigs ...string) { +// LoadAllForTest initializes setting options for tests +func LoadAllForTest(extraConfigs ...string) { CfgProvider = newFileProviderFromConf(CustomConf, WritePIDFile, true, PIDFile, strings.Join(extraConfigs, "\n")) loadCommonConfigsFrom(CfgProvider) if err := PrepareAppDataPath(); err != nil { @@ -271,6 +271,7 @@ func newFileProviderFromConf(customConf string, writePIDFile, allowEmpty bool, p func loadCommonConfigsFrom(cfg ConfigProvider) { // WARNNING: don't change the sequence except you know what you are doing. loadRunModeFrom(cfg) + loadLogFrom(cfg) loadServerFrom(cfg) loadSSHFrom(cfg) loadOAuth2From(cfg) diff --git a/routers/api/v1/repo/main_test.go b/routers/api/v1/repo/main_test.go index 1af155910679..22269ae9bda1 100644 --- a/routers/api/v1/repo/main_test.go +++ b/routers/api/v1/repo/main_test.go @@ -13,7 +13,7 @@ import ( ) func TestMain(m *testing.M) { - setting.LoadForTest() + setting.LoadAllForTest() setting.LoadQueueSettings() unittest.MainTest(m, &unittest.TestOptions{ GiteaRootPath: filepath.Join("..", "..", "..", ".."), diff --git a/routers/install/setting.go b/routers/install/setting.go index 059a51f3e35d..e185ffc3cb7c 100644 --- a/routers/install/setting.go +++ b/routers/install/setting.go @@ -15,7 +15,7 @@ import ( // PreloadSettings preloads the configuration to check if we need to run install func PreloadSettings(ctx context.Context) bool { - setting.LoadAllowEmpty() + setting.LoadAllAllowEmpty() if !setting.InstallLock { log.Info("AppPath: %s", setting.AppPath) log.Info("AppWorkPath: %s", setting.AppWorkPath) @@ -37,7 +37,7 @@ func PreloadSettings(ctx context.Context) bool { // reloadSettings reloads the existing settings and starts up the database func reloadSettings(ctx context.Context) { - setting.LoadFromExisting() + setting.LoadAllFromExistingFile() setting.LoadDBSetting() if setting.InstallLock { if err := common.InitDBEngine(ctx); err == nil { diff --git a/services/webhook/main_test.go b/services/webhook/main_test.go index a7f7c0bd9915..047a3d76c81c 100644 --- a/services/webhook/main_test.go +++ b/services/webhook/main_test.go @@ -15,7 +15,7 @@ import ( ) func TestMain(m *testing.M) { - setting.LoadForTest() + setting.LoadAllForTest() setting.LoadQueueSettings() // for tests, allow only loopback IPs diff --git a/tests/integration/migration-test/migration_test.go b/tests/integration/migration-test/migration_test.go index 7161f9de459a..9bab3ecb6ebd 100644 --- a/tests/integration/migration-test/migration_test.go +++ b/tests/integration/migration-test/migration_test.go @@ -57,7 +57,7 @@ func initMigrationTest(t *testing.T) func() { setting.CustomConf = giteaConf } - setting.LoadForTest() + setting.LoadAllForTest() assert.True(t, len(setting.RepoRootPath) != 0) assert.NoError(t, util.RemoveAll(setting.RepoRootPath)) diff --git a/tests/test_utils.go b/tests/test_utils.go index 72718aeb464b..c2e440e24fd9 100644 --- a/tests/test_utils.go +++ b/tests/test_utils.go @@ -57,7 +57,7 @@ func InitTest(requireGitea bool) { } setting.SetCustomPathAndConf("", "", "") - setting.LoadForTest() + setting.LoadAllForTest() setting.Repository.DefaultBranch = "master" // many test code still assume that default branch is called "master" _ = util.RemoveAll(repo_module.LocalCopyPath()) From 2b2c9a38dfe87dfeb362fb00d17631afa981a276 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 30 Jan 2023 14:38:26 +0800 Subject: [PATCH 15/20] Improvement --- modules/setting/log.go | 71 ++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 38 deletions(-) diff --git a/modules/setting/log.go b/modules/setting/log.go index c59e1fe304b2..5448650aadb9 100644 --- a/modules/setting/log.go +++ b/modules/setting/log.go @@ -145,8 +145,22 @@ func loadLogFrom(rootCfg ConfigProvider) { Log.Level = getLogLevel(sec, "LEVEL", log.INFO) Log.StacktraceLogLevel = getStacktraceLogLevel(sec, "STACKTRACE_LEVEL", "None") Log.RootPath = sec.Key("ROOT_PATH").MustString(path.Join(AppWorkPath, "log")) - Log.EnableSSHLog = sec.Key("ENABLE_SSH_LOG").MustBool(false) forcePathSeparator(Log.RootPath) + Log.BufferLength = sec.Key("BUFFER_LEN").MustInt64(10000) + + Log.EnableSSHLog = sec.Key("ENABLE_SSH_LOG").MustBool(false) + Log.EnableAccessLog = sec.Key("ENABLE_ACCESS_LOG").MustBool(false) + Log.AccessLogTemplate = sec.Key("ACCESS_LOG_TEMPLATE").MustString( + `{{.Ctx.RemoteAddr}} - {{.Identity}} {{.Start.Format "[02/Jan/2006:15:04:05 -0700]" }} "{{.Ctx.Req.Method}} {{.Ctx.Req.URL.RequestURI}} {{.Ctx.Req.Proto}}" {{.ResponseWriter.Status}} {{.ResponseWriter.Size}} "{{.Ctx.Req.Referer}}\" \"{{.Ctx.Req.UserAgent}}"`, + ) + // the `MustString` updates the default value, and `log.ACCESS` is used by `generateNamedLogger("access")` later + _ = rootCfg.Section("log").Key("ACCESS").MustString("file") + + sec.Key("ROUTER").MustString("console") + // Allow [log] DISABLE_ROUTER_LOG to override [server] DISABLE_ROUTER_LOG + Log.DisableRouterLog = sec.Key("DISABLE_ROUTER_LOG").MustBool(Log.DisableRouterLog) + + Log.EnableXORMLog = rootCfg.Section("log").Key("ENABLE_XORM_LOG").MustBool(true) } func generateLogConfig(sec *ini.Section, name string, defaults defaultLogOptions) (mode, jsonConfig, levelName string) { @@ -277,39 +291,6 @@ func generateNamedLogger(rootCfg ConfigProvider, key string, options defaultLogO return &description } -func initAccessLogFrom(rootCfg ConfigProvider) { - sec := rootCfg.Section("log") - Log.EnableAccessLog = sec.Key("ENABLE_ACCESS_LOG").MustBool(false) - Log.BufferLength = sec.Key("BUFFER_LEN").MustInt64(10000) - Log.AccessLogTemplate = sec.Key("ACCESS_LOG_TEMPLATE").MustString( - `{{.Ctx.RemoteAddr}} - {{.Identity}} {{.Start.Format "[02/Jan/2006:15:04:05 -0700]" }} "{{.Ctx.Req.Method}} {{.Ctx.Req.URL.RequestURI}} {{.Ctx.Req.Proto}}" {{.ResponseWriter.Status}} {{.ResponseWriter.Size}} "{{.Ctx.Req.Referer}}\" \"{{.Ctx.Req.UserAgent}}"`, - ) - // the `MustString` updates the default value, and `log.ACCESS` is used by `generateNamedLogger("access")` later - _ = sec.Key("ACCESS").MustString("file") - if Log.EnableAccessLog { - options := newDefaultLogOptions() - options.filename = filepath.Join(Log.RootPath, "access.log") - options.flags = "" // For the router we don't want any prefixed flags - options.bufferLength = Log.BufferLength - generateNamedLogger(rootCfg, "access", options) - } -} - -func initRouterLogFrom(rootCfg ConfigProvider) { - sec := rootCfg.Section("log") - sec.Key("ROUTER").MustString("console") - // Allow [log] DISABLE_ROUTER_LOG to override [server] DISABLE_ROUTER_LOG - Log.DisableRouterLog = sec.Key("DISABLE_ROUTER_LOG").MustBool(Log.DisableRouterLog) - - if !Log.DisableRouterLog { - options := newDefaultLogOptions() - options.filename = filepath.Join(Log.RootPath, "router.log") - options.flags = "date,time" // For the router we don't want any prefixed flags - options.bufferLength = sec.Key("BUFFER_LEN").MustInt64(10000) - generateNamedLogger(rootCfg, "router", options) - } -} - // initLogFrom initializes logging with settings from configuration provider func initLogFrom(rootCfg ConfigProvider) { sec := rootCfg.Section("log") @@ -374,8 +355,23 @@ func RestartLogsWithPIDSuffix() { // InitLogs creates all the log services func InitLogs(disableConsole bool) { initLogFrom(CfgProvider) - initRouterLogFrom(CfgProvider) - initAccessLogFrom(CfgProvider) + + if !Log.DisableRouterLog { + options := newDefaultLogOptions() + options.filename = filepath.Join(Log.RootPath, "router.log") + options.flags = "date,time" // For the router we don't want any prefixed flags + options.bufferLength = Log.BufferLength + generateNamedLogger(CfgProvider, "router", options) + } + + if Log.EnableAccessLog { + options := newDefaultLogOptions() + options.filename = filepath.Join(Log.RootPath, "access.log") + options.flags = "" // For the router we don't want any prefixed flags + options.bufferLength = Log.BufferLength + generateNamedLogger(CfgProvider, "access", options) + } + initSQLLogFrom(CfgProvider, disableConsole) } @@ -385,11 +381,10 @@ func InitSQLLog(disableConsole bool) { } func initSQLLogFrom(rootCfg ConfigProvider, disableConsole bool) { - Log.EnableXORMLog = rootCfg.Section("log").Key("ENABLE_XORM_LOG").MustBool(true) if Log.EnableXORMLog { options := newDefaultLogOptions() options.filename = filepath.Join(Log.RootPath, "xorm.log") - options.bufferLength = rootCfg.Section("log").Key("BUFFER_LEN").MustInt64(10000) + options.bufferLength = Log.BufferLength options.disableConsole = disableConsole rootCfg.Section("log").Key("XORM").MustString(",") From e19b2caa5ea71c1cfca8751ccbc569e34b7e7224 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 31 Jan 2023 00:04:58 +0800 Subject: [PATCH 16/20] Fix lint --- tests/integration/integration_test.go | 4 ++-- tests/integration/migration-test/migration_test.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/integration/integration_test.go b/tests/integration/integration_test.go index fbb6322785af..716f6d44ab34 100644 --- a/tests/integration/integration_test.go +++ b/tests/integration/integration_test.go @@ -87,8 +87,8 @@ func TestMain(m *testing.M) { c = routers.NormalRoutes(context.TODO()) // integration test settings... - if setting.Cfg != nil { - testingCfg := setting.Cfg.Section("integration-tests") + if setting.CfgProvider != nil { + testingCfg := setting.CfgProvider.Section("integration-tests") tests.SlowTest = testingCfg.Key("SLOW_TEST").MustDuration(tests.SlowTest) tests.SlowFlush = testingCfg.Key("SLOW_FLUSH").MustDuration(tests.SlowFlush) } diff --git a/tests/integration/migration-test/migration_test.go b/tests/integration/migration-test/migration_test.go index 9bab3ecb6ebd..65eb11ae1180 100644 --- a/tests/integration/migration-test/migration_test.go +++ b/tests/integration/migration-test/migration_test.go @@ -84,7 +84,7 @@ func initMigrationTest(t *testing.T) func() { assert.NoError(t, git.InitFull(context.Background())) setting.LoadDBSetting() - setting.LoadLogSettings(true) + setting.InitLogs(true) return deferFn } @@ -292,7 +292,7 @@ func doMigrationTest(t *testing.T, version string) { return } - setting.LoadSQLLogSetting(false) + setting.InitSQLLog(false) err := db.InitEngineWithMigration(context.Background(), wrappedMigrate) assert.NoError(t, err) From 11d867e7f19ce71d12367193dd1311620ce99b1a Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 3 Feb 2023 14:01:49 +0800 Subject: [PATCH 17/20] Fix lint --- models/dbfs/main_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/dbfs/main_test.go b/models/dbfs/main_test.go index 7a820b2d83e1..63ddb092bdde 100644 --- a/models/dbfs/main_test.go +++ b/models/dbfs/main_test.go @@ -13,7 +13,7 @@ import ( func init() { setting.SetCustomPathAndConf("", "", "") - setting.LoadForTest() + setting.LoadAllForTest() } func TestMain(m *testing.M) { From 3d4935590f9b8710a40c71fd533c107905fa6cf4 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 4 Feb 2023 22:36:09 +0800 Subject: [PATCH 18/20] Rename LoadAllXXX to InitProviderXXX --- cmd/cmd.go | 3 ++- cmd/doctor.go | 3 ++- cmd/dump.go | 3 ++- cmd/embedded.go | 3 ++- cmd/mailer.go | 3 ++- cmd/main_test.go | 3 ++- cmd/restore_repo.go | 3 ++- cmd/serv.go | 3 ++- cmd/web.go | 3 ++- contrib/pr/checkout.go | 3 ++- models/asymkey/main_test.go | 3 ++- models/dbfs/main_test.go | 3 ++- models/issues/main_test.go | 3 ++- models/main_test.go | 3 ++- models/migrations/base/tests.go | 3 ++- modules/doctor/doctor.go | 3 ++- modules/doctor/paths.go | 3 ++- modules/markup/html_test.go | 3 ++- modules/markup/markdown/markdown_test.go | 3 ++- modules/setting/setting.go | 24 ++++++++++--------- routers/api/v1/repo/main_test.go | 3 ++- routers/install/setting.go | 6 +++-- services/webhook/main_test.go | 3 ++- .../migration-test/migration_test.go | 3 ++- tests/test_utils.go | 3 ++- 25 files changed, 63 insertions(+), 36 deletions(-) diff --git a/cmd/cmd.go b/cmd/cmd.go index 87218ecaa236..18d5db3987bd 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -57,7 +57,8 @@ func confirm() (bool, error) { } func initDB(ctx context.Context) error { - setting.LoadAllFromExistingFile() + setting.InitProviderFromExistingFile() + setting.LoadCommonSettings() setting.LoadDBSetting() setting.InitSQLLog(false) diff --git a/cmd/doctor.go b/cmd/doctor.go index 16d1e11207de..e7baad60c1f9 100644 --- a/cmd/doctor.go +++ b/cmd/doctor.go @@ -87,7 +87,8 @@ func runRecreateTable(ctx *cli.Context) error { golog.SetPrefix("") golog.SetOutput(log.NewLoggerAsWriter("INFO", log.GetLogger(log.DEFAULT))) - setting.LoadAllFromExistingFile() + setting.InitProviderFromExistingFile() + setting.LoadCommonSettings() setting.LoadDBSetting() setting.Log.EnableXORMLog = ctx.Bool("debug") diff --git a/cmd/dump.go b/cmd/dump.go index c733b94c884a..c879d2fbee07 100644 --- a/cmd/dump.go +++ b/cmd/dump.go @@ -181,7 +181,8 @@ func runDump(ctx *cli.Context) error { } fileName += "." + outType } - setting.LoadAllFromExistingFile() + setting.InitProviderFromExistingFile() + setting.LoadCommonSettings() // make sure we are logging to the console no matter what the configuration tells us do to // FIXME: don't use CfgProvider directly diff --git a/cmd/embedded.go b/cmd/embedded.go index 5e1daa0cce73..d87fc0187c70 100644 --- a/cmd/embedded.go +++ b/cmd/embedded.go @@ -112,7 +112,8 @@ func initEmbeddedExtractor(c *cli.Context) error { log.DelNamedLogger(log.DEFAULT) // Read configuration file - setting.LoadAllAllowEmpty() + setting.InitProviderAllowEmpty() + setting.LoadCommonSettings() pats, err := getPatterns(c.Args()) if err != nil { diff --git a/cmd/mailer.go b/cmd/mailer.go index 6c4fa9043717..d05fee12bca7 100644 --- a/cmd/mailer.go +++ b/cmd/mailer.go @@ -17,7 +17,8 @@ func runSendMail(c *cli.Context) error { ctx, cancel := installSignals() defer cancel() - setting.LoadAllFromExistingFile() + setting.InitProviderFromExistingFile() + setting.LoadCommonSettings() if err := argsSet(c, "title"); err != nil { return err diff --git a/cmd/main_test.go b/cmd/main_test.go index e2ff72f52cdc..e29c21a65862 100644 --- a/cmd/main_test.go +++ b/cmd/main_test.go @@ -12,7 +12,8 @@ import ( func init() { setting.SetCustomPathAndConf("", "", "") - setting.LoadAllForTest() + setting.InitProviderForTest() + setting.LoadCommonSettings() } func TestMain(m *testing.M) { diff --git a/cmd/restore_repo.go b/cmd/restore_repo.go index 702ac3f7d8a2..c7dff4196689 100644 --- a/cmd/restore_repo.go +++ b/cmd/restore_repo.go @@ -54,7 +54,8 @@ func runRestoreRepository(c *cli.Context) error { ctx, cancel := installSignals() defer cancel() - setting.LoadAllFromExistingFile() + setting.InitProviderFromExistingFile() + setting.LoadCommonSettings() var units []string if s := c.String("units"); s != "" { units = strings.Split(s, ",") diff --git a/cmd/serv.go b/cmd/serv.go index 3bebf981c6a6..145d1b9e935f 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -61,7 +61,8 @@ func setup(logPath string, debug bool) { } else { _ = log.NewLogger(1000, "console", "console", `{"level":"fatal","stacktracelevel":"NONE","stderr":true}`) } - setting.LoadAllFromExistingFile() + setting.InitProviderFromExistingFile() + setting.LoadCommonSettings() if debug { setting.RunMode = "dev" } diff --git a/cmd/web.go b/cmd/web.go index 7b7a007055f1..8722ddb609e5 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -158,7 +158,8 @@ func runWeb(ctx *cli.Context) error { log.Info("Global init") // Perform global initialization - setting.LoadAllFromExistingFile() + setting.InitProviderFromExistingFile() + setting.LoadCommonSettings() routers.GlobalInitInstalled(graceful.GetManager().HammerContext()) // We check that AppDataPath exists here (it should have been created during installation) diff --git a/contrib/pr/checkout.go b/contrib/pr/checkout.go index b55f5873195a..f12d8a94199b 100644 --- a/contrib/pr/checkout.go +++ b/contrib/pr/checkout.go @@ -49,7 +49,8 @@ func runPR() { log.Fatal(err) } setting.SetCustomPathAndConf("", "", "") - setting.LoadAllAllowEmpty() + setting.InitProviderAllowEmpty() + setting.LoadCommonSettings() setting.RepoRootPath, err = os.MkdirTemp(os.TempDir(), "repos") if err != nil { diff --git a/models/asymkey/main_test.go b/models/asymkey/main_test.go index 70144bef97e2..9b277a52993f 100644 --- a/models/asymkey/main_test.go +++ b/models/asymkey/main_test.go @@ -13,7 +13,8 @@ import ( func init() { setting.SetCustomPathAndConf("", "", "") - setting.LoadAllForTest() + setting.InitProviderForTest() + setting.LoadCommonSettings() } func TestMain(m *testing.M) { diff --git a/models/dbfs/main_test.go b/models/dbfs/main_test.go index 63ddb092bdde..3d5bdd50458b 100644 --- a/models/dbfs/main_test.go +++ b/models/dbfs/main_test.go @@ -13,7 +13,8 @@ import ( func init() { setting.SetCustomPathAndConf("", "", "") - setting.LoadAllForTest() + setting.InitProviderForTest() + setting.LoadCommonSettings() } func TestMain(m *testing.M) { diff --git a/models/issues/main_test.go b/models/issues/main_test.go index ba31d391ac4b..350e4cae0607 100644 --- a/models/issues/main_test.go +++ b/models/issues/main_test.go @@ -20,7 +20,8 @@ import ( func init() { setting.SetCustomPathAndConf("", "", "") - setting.LoadAllForTest() + setting.InitProviderForTest() + setting.LoadCommonSettings() } func TestFixturesAreConsistent(t *testing.T) { diff --git a/models/main_test.go b/models/main_test.go index f859e56fc51f..ef9202671f0a 100644 --- a/models/main_test.go +++ b/models/main_test.go @@ -20,7 +20,8 @@ import ( func init() { setting.SetCustomPathAndConf("", "", "") - setting.LoadAllForTest() + setting.InitProviderForTest() + setting.LoadCommonSettings() } // TestFixturesAreConsistent assert that test fixtures are consistent diff --git a/models/migrations/base/tests.go b/models/migrations/base/tests.go index c16696546697..67fe159e0bc9 100644 --- a/models/migrations/base/tests.go +++ b/models/migrations/base/tests.go @@ -149,7 +149,8 @@ func MainTest(m *testing.M) { setting.AppDataPath = tmpDataPath setting.SetCustomPathAndConf("", "", "") - setting.LoadAllForTest() + setting.InitProviderForTest() + setting.LoadCommonSettings() if err = git.InitFull(context.Background()); err != nil { fmt.Printf("Unable to InitFull: %v\n", err) os.Exit(1) diff --git a/modules/doctor/doctor.go b/modules/doctor/doctor.go index 50c445a160fe..b23805bc4c96 100644 --- a/modules/doctor/doctor.go +++ b/modules/doctor/doctor.go @@ -44,7 +44,8 @@ func (w *wrappedLevelLogger) Log(skip int, level log.Level, format string, v ... } func initDBDisableConsole(ctx context.Context, disableConsole bool) error { - setting.LoadAllFromExistingFile() + setting.InitProviderFromExistingFile() + setting.LoadCommonSettings() setting.LoadDBSetting() setting.InitSQLLog(disableConsole) if err := db.InitEngine(ctx); err != nil { diff --git a/modules/doctor/paths.go b/modules/doctor/paths.go index 6b0f1c16d555..7b1c6ce9ad1c 100644 --- a/modules/doctor/paths.go +++ b/modules/doctor/paths.go @@ -67,7 +67,8 @@ func checkConfigurationFiles(ctx context.Context, logger log.Logger, autofix boo return err } - setting.LoadAllFromExistingFile() + setting.InitProviderFromExistingFile() + setting.LoadCommonSettings() configurationFiles := []configurationFile{ {"Configuration File Path", setting.CustomConf, false, true, false}, diff --git a/modules/markup/html_test.go b/modules/markup/html_test.go index 5b6a8796e8ed..aea1d9267682 100644 --- a/modules/markup/html_test.go +++ b/modules/markup/html_test.go @@ -28,7 +28,8 @@ var localMetas = map[string]string{ } func TestMain(m *testing.M) { - setting.LoadAllAllowEmpty() + setting.InitProviderAllowEmpty() + setting.LoadCommonSettings() if err := git.InitSimple(context.Background()); err != nil { log.Fatal("git init failed, err: %v", err) } diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go index 8e1f56f9dd9a..bb458a65c1c2 100644 --- a/modules/markup/markdown/markdown_test.go +++ b/modules/markup/markdown/markdown_test.go @@ -33,7 +33,8 @@ var localMetas = map[string]string{ } func TestMain(m *testing.M) { - setting.LoadAllAllowEmpty() + setting.InitProviderAllowEmpty() + setting.LoadCommonSettings() if err := git.InitSimple(context.Background()); err != nil { log.Fatal("git init failed, err: %v", err) } diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 0ce04f5ba0e8..e6e922cfabf4 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -215,22 +215,19 @@ func PrepareAppDataPath() error { return nil } -// LoadAllFromExistingFile initializes setting options from an existing config file (app.ini) -func LoadAllFromExistingFile() { +// InitProviderFromExistingFile initializes config provider from an existing config file (app.ini) +func InitProviderFromExistingFile() { CfgProvider = newFileProviderFromConf(CustomConf, WritePIDFile, false, PIDFile, "") - loadCommonConfigsFrom(CfgProvider) } -// LoadAllAllowEmpty initializes setting options, it's also fine that if the config file (app.ini) doesn't exist -func LoadAllAllowEmpty() { +// InitProviderAllowEmpty initializes config provider from file, it's also fine that if the config file (app.ini) doesn't exist +func InitProviderAllowEmpty() { CfgProvider = newFileProviderFromConf(CustomConf, WritePIDFile, true, PIDFile, "") - loadCommonConfigsFrom(CfgProvider) } -// LoadAllForTest initializes setting options for tests -func LoadAllForTest(extraConfigs ...string) { +// InitProviderForTest initializes config provider for tests +func InitProviderForTest(extraConfigs ...string) { CfgProvider = newFileProviderFromConf(CustomConf, WritePIDFile, true, PIDFile, strings.Join(extraConfigs, "\n")) - loadCommonConfigsFrom(CfgProvider) if err := PrepareAppDataPath(); err != nil { log.Fatal("Can not prepare APP_DATA_PATH: %v", err) } @@ -267,8 +264,13 @@ func newFileProviderFromConf(customConf string, writePIDFile, allowEmpty bool, p return cfg } -// loadCommonConfigsFrom loads common configurations from a configuration provider. -func loadCommonConfigsFrom(cfg ConfigProvider) { +// LoadCommonSettings loads common configurations from a configuration provider. +func LoadCommonSettings() { + loadCommonSettingsFrom(CfgProvider) +} + +// loadCommonSettingsFrom loads common configurations from a configuration provider. +func loadCommonSettingsFrom(cfg ConfigProvider) { // WARNNING: don't change the sequence except you know what you are doing. loadRunModeFrom(cfg) loadLogFrom(cfg) diff --git a/routers/api/v1/repo/main_test.go b/routers/api/v1/repo/main_test.go index 22269ae9bda1..0d83aa98927a 100644 --- a/routers/api/v1/repo/main_test.go +++ b/routers/api/v1/repo/main_test.go @@ -13,7 +13,8 @@ import ( ) func TestMain(m *testing.M) { - setting.LoadAllForTest() + setting.InitProviderForTest() + setting.LoadCommonSettings() setting.LoadQueueSettings() unittest.MainTest(m, &unittest.TestOptions{ GiteaRootPath: filepath.Join("..", "..", "..", ".."), diff --git a/routers/install/setting.go b/routers/install/setting.go index e185ffc3cb7c..68984f1e7837 100644 --- a/routers/install/setting.go +++ b/routers/install/setting.go @@ -15,7 +15,8 @@ import ( // PreloadSettings preloads the configuration to check if we need to run install func PreloadSettings(ctx context.Context) bool { - setting.LoadAllAllowEmpty() + setting.InitProviderAllowEmpty() + setting.LoadCommonSettings() if !setting.InstallLock { log.Info("AppPath: %s", setting.AppPath) log.Info("AppWorkPath: %s", setting.AppWorkPath) @@ -37,7 +38,8 @@ func PreloadSettings(ctx context.Context) bool { // reloadSettings reloads the existing settings and starts up the database func reloadSettings(ctx context.Context) { - setting.LoadAllFromExistingFile() + setting.InitProviderFromExistingFile() + setting.LoadCommonSettings() setting.LoadDBSetting() if setting.InstallLock { if err := common.InitDBEngine(ctx); err == nil { diff --git a/services/webhook/main_test.go b/services/webhook/main_test.go index 047a3d76c81c..1d7daa769c61 100644 --- a/services/webhook/main_test.go +++ b/services/webhook/main_test.go @@ -15,7 +15,8 @@ import ( ) func TestMain(m *testing.M) { - setting.LoadAllForTest() + setting.InitProviderForTest() + setting.LoadCommonSettings() setting.LoadQueueSettings() // for tests, allow only loopback IPs diff --git a/tests/integration/migration-test/migration_test.go b/tests/integration/migration-test/migration_test.go index 65eb11ae1180..c9a72246ccfa 100644 --- a/tests/integration/migration-test/migration_test.go +++ b/tests/integration/migration-test/migration_test.go @@ -57,7 +57,8 @@ func initMigrationTest(t *testing.T) func() { setting.CustomConf = giteaConf } - setting.LoadAllForTest() + setting.InitProviderForTest() + setting.LoadCommonSettings() assert.True(t, len(setting.RepoRootPath) != 0) assert.NoError(t, util.RemoveAll(setting.RepoRootPath)) diff --git a/tests/test_utils.go b/tests/test_utils.go index c2e440e24fd9..9f8eb36da250 100644 --- a/tests/test_utils.go +++ b/tests/test_utils.go @@ -57,7 +57,8 @@ func InitTest(requireGitea bool) { } setting.SetCustomPathAndConf("", "", "") - setting.LoadAllForTest() + setting.InitProviderForTest() + setting.LoadCommonSettings() setting.Repository.DefaultBranch = "master" // many test code still assume that default branch is called "master" _ = util.RemoveAll(repo_module.LocalCopyPath()) From 7950a0d575ad74a8eabe885a925333a84c1e4000 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 5 Feb 2023 18:55:21 +0800 Subject: [PATCH 19/20] Fix bug --- cmd/main_test.go | 3 +-- models/asymkey/main_test.go | 3 +-- models/dbfs/main_test.go | 3 +-- models/issues/main_test.go | 3 +-- models/main_test.go | 3 +-- models/migrations/base/tests.go | 3 +-- modules/setting/setting.go | 5 +++-- routers/api/v1/repo/main_test.go | 3 +-- services/webhook/main_test.go | 3 +-- tests/integration/migration-test/migration_test.go | 3 +-- tests/test_utils.go | 3 +-- 11 files changed, 13 insertions(+), 22 deletions(-) diff --git a/cmd/main_test.go b/cmd/main_test.go index e29c21a65862..ba323af47217 100644 --- a/cmd/main_test.go +++ b/cmd/main_test.go @@ -12,8 +12,7 @@ import ( func init() { setting.SetCustomPathAndConf("", "", "") - setting.InitProviderForTest() - setting.LoadCommonSettings() + setting.InitProviderAndLoadCommonSettingsForTest() } func TestMain(m *testing.M) { diff --git a/models/asymkey/main_test.go b/models/asymkey/main_test.go index 9b277a52993f..7f8657189fd1 100644 --- a/models/asymkey/main_test.go +++ b/models/asymkey/main_test.go @@ -13,8 +13,7 @@ import ( func init() { setting.SetCustomPathAndConf("", "", "") - setting.InitProviderForTest() - setting.LoadCommonSettings() + setting.InitProviderAndLoadCommonSettingsForTest() } func TestMain(m *testing.M) { diff --git a/models/dbfs/main_test.go b/models/dbfs/main_test.go index 3d5bdd50458b..9dce663eeab9 100644 --- a/models/dbfs/main_test.go +++ b/models/dbfs/main_test.go @@ -13,8 +13,7 @@ import ( func init() { setting.SetCustomPathAndConf("", "", "") - setting.InitProviderForTest() - setting.LoadCommonSettings() + setting.InitProviderAndLoadCommonSettingsForTest() } func TestMain(m *testing.M) { diff --git a/models/issues/main_test.go b/models/issues/main_test.go index 350e4cae0607..de84da30ecc0 100644 --- a/models/issues/main_test.go +++ b/models/issues/main_test.go @@ -20,8 +20,7 @@ import ( func init() { setting.SetCustomPathAndConf("", "", "") - setting.InitProviderForTest() - setting.LoadCommonSettings() + setting.InitProviderAndLoadCommonSettingsForTest() } func TestFixturesAreConsistent(t *testing.T) { diff --git a/models/main_test.go b/models/main_test.go index ef9202671f0a..b5919bb28615 100644 --- a/models/main_test.go +++ b/models/main_test.go @@ -20,8 +20,7 @@ import ( func init() { setting.SetCustomPathAndConf("", "", "") - setting.InitProviderForTest() - setting.LoadCommonSettings() + setting.InitProviderAndLoadCommonSettingsForTest() } // TestFixturesAreConsistent assert that test fixtures are consistent diff --git a/models/migrations/base/tests.go b/models/migrations/base/tests.go index 67fe159e0bc9..2f1b24664831 100644 --- a/models/migrations/base/tests.go +++ b/models/migrations/base/tests.go @@ -149,8 +149,7 @@ func MainTest(m *testing.M) { setting.AppDataPath = tmpDataPath setting.SetCustomPathAndConf("", "", "") - setting.InitProviderForTest() - setting.LoadCommonSettings() + setting.InitProviderAndLoadCommonSettingsForTest() if err = git.InitFull(context.Background()); err != nil { fmt.Printf("Unable to InitFull: %v\n", err) os.Exit(1) diff --git a/modules/setting/setting.go b/modules/setting/setting.go index e6e922cfabf4..83ebde947882 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -225,9 +225,10 @@ func InitProviderAllowEmpty() { CfgProvider = newFileProviderFromConf(CustomConf, WritePIDFile, true, PIDFile, "") } -// InitProviderForTest initializes config provider for tests -func InitProviderForTest(extraConfigs ...string) { +// InitProviderAndLoadCommonSettingsForTest initializes config provider and load common setttings for tests +func InitProviderAndLoadCommonSettingsForTest(extraConfigs ...string) { CfgProvider = newFileProviderFromConf(CustomConf, WritePIDFile, true, PIDFile, strings.Join(extraConfigs, "\n")) + loadCommonSettingsFrom(CfgProvider) if err := PrepareAppDataPath(); err != nil { log.Fatal("Can not prepare APP_DATA_PATH: %v", err) } diff --git a/routers/api/v1/repo/main_test.go b/routers/api/v1/repo/main_test.go index 0d83aa98927a..c7466c493f01 100644 --- a/routers/api/v1/repo/main_test.go +++ b/routers/api/v1/repo/main_test.go @@ -13,8 +13,7 @@ import ( ) func TestMain(m *testing.M) { - setting.InitProviderForTest() - setting.LoadCommonSettings() + setting.InitProviderAndLoadCommonSettingsForTest() setting.LoadQueueSettings() unittest.MainTest(m, &unittest.TestOptions{ GiteaRootPath: filepath.Join("..", "..", "..", ".."), diff --git a/services/webhook/main_test.go b/services/webhook/main_test.go index 1d7daa769c61..210221b12041 100644 --- a/services/webhook/main_test.go +++ b/services/webhook/main_test.go @@ -15,8 +15,7 @@ import ( ) func TestMain(m *testing.M) { - setting.InitProviderForTest() - setting.LoadCommonSettings() + setting.InitProviderAndLoadCommonSettingsForTest() setting.LoadQueueSettings() // for tests, allow only loopback IPs diff --git a/tests/integration/migration-test/migration_test.go b/tests/integration/migration-test/migration_test.go index c9a72246ccfa..f030f566ce44 100644 --- a/tests/integration/migration-test/migration_test.go +++ b/tests/integration/migration-test/migration_test.go @@ -57,8 +57,7 @@ func initMigrationTest(t *testing.T) func() { setting.CustomConf = giteaConf } - setting.InitProviderForTest() - setting.LoadCommonSettings() + setting.InitProviderAndLoadCommonSettingsForTest() assert.True(t, len(setting.RepoRootPath) != 0) assert.NoError(t, util.RemoveAll(setting.RepoRootPath)) diff --git a/tests/test_utils.go b/tests/test_utils.go index 9f8eb36da250..9e9f97a5f5d1 100644 --- a/tests/test_utils.go +++ b/tests/test_utils.go @@ -57,8 +57,7 @@ func InitTest(requireGitea bool) { } setting.SetCustomPathAndConf("", "", "") - setting.InitProviderForTest() - setting.LoadCommonSettings() + setting.InitProviderAndLoadCommonSettingsForTest() setting.Repository.DefaultBranch = "master" // many test code still assume that default branch is called "master" _ = util.RemoveAll(repo_module.LocalCopyPath()) From 3d31d6d617a52d1effc98db7641b102c03e9114a Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 19 Feb 2023 10:28:59 +0800 Subject: [PATCH 20/20] Apply suggestions from code review Co-authored-by: delvh --- modules/setting/config_provider.go | 2 +- modules/setting/highlight.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/setting/config_provider.go b/modules/setting/config_provider.go index ec91533c55ad..67a4e4ded1a1 100644 --- a/modules/setting/config_provider.go +++ b/modules/setting/config_provider.go @@ -16,7 +16,7 @@ type ConfigProvider interface { GetSection(name string) (*ini.Section, error) } -// a file is an implementation ConfigProvider and others implementation are possible, i.e. from docker/k8s and etc. +// a file is an implementation ConfigProvider and other implementations are possible, i.e. from docker, k8s, … var _ ConfigProvider = &ini.File{} func mustMapSetting(rootCfg ConfigProvider, sectionName string, setting interface{}) { diff --git a/modules/setting/highlight.go b/modules/setting/highlight.go index 538d844c916a..6291b08a4519 100644 --- a/modules/setting/highlight.go +++ b/modules/setting/highlight.go @@ -10,8 +10,8 @@ func GetHighlightMapping() map[string]string { } keys := CfgProvider.Section("highlight.mapping").Keys() - for i := range keys { - highlightMapping[keys[i].Name()] = keys[i].Value() + for _, key := range keys { + highlightMapping[key.Name()] = key.Value() } return highlightMapping }