mirror of
https://github.com/go-gitea/gitea.git
synced 2026-07-28 23:01:50 +02:00
Merge remote-tracking branch 'upstream/main' into limit-repo-size
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
package setting
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -51,12 +52,18 @@ type ConfigProvider interface {
|
||||
GetSection(name string) (ConfigSection, error)
|
||||
Save() error
|
||||
SaveTo(filename string) error
|
||||
|
||||
DisableSaving()
|
||||
PrepareSaving() (ConfigProvider, error)
|
||||
IsLoadedFromEmpty() bool
|
||||
}
|
||||
|
||||
type iniConfigProvider struct {
|
||||
opts *Options
|
||||
ini *ini.File
|
||||
newFile bool // whether the file has not existed previously
|
||||
file string
|
||||
ini *ini.File
|
||||
|
||||
disableSaving bool // disable the "Save" method because the config options could be polluted
|
||||
loadedFromEmpty bool // whether the file has not existed previously
|
||||
}
|
||||
|
||||
type iniConfigSection struct {
|
||||
@@ -175,53 +182,43 @@ func NewConfigProviderFromData(configContent string) (ConfigProvider, error) {
|
||||
}
|
||||
cfg.NameMapper = ini.SnackCase
|
||||
return &iniConfigProvider{
|
||||
ini: cfg,
|
||||
newFile: true,
|
||||
ini: cfg,
|
||||
loadedFromEmpty: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type Options struct {
|
||||
CustomConf string // the ini file path
|
||||
AllowEmpty bool // whether not finding configuration files is allowed
|
||||
ExtraConfig string
|
||||
|
||||
DisableLoadCommonSettings bool // only used by "Init()", not used by "NewConfigProvider()"
|
||||
}
|
||||
|
||||
// NewConfigProviderFromFile load configuration from file.
|
||||
// NOTE: do not print any log except error.
|
||||
func NewConfigProviderFromFile(opts *Options) (ConfigProvider, error) {
|
||||
cfg := ini.Empty()
|
||||
newFile := true
|
||||
func NewConfigProviderFromFile(file string, extraConfigs ...string) (ConfigProvider, error) {
|
||||
cfg := ini.Empty(ini.LoadOptions{KeyValueDelimiterOnWrite: " = "})
|
||||
loadedFromEmpty := true
|
||||
|
||||
if opts.CustomConf != "" {
|
||||
isFile, err := util.IsFile(opts.CustomConf)
|
||||
if file != "" {
|
||||
isFile, err := util.IsFile(file)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to check if %s is a file. Error: %v", opts.CustomConf, err)
|
||||
return nil, fmt.Errorf("unable to check if %q is a file. Error: %v", file, err)
|
||||
}
|
||||
if isFile {
|
||||
if err := cfg.Append(opts.CustomConf); err != nil {
|
||||
return nil, fmt.Errorf("failed to load custom conf '%s': %v", opts.CustomConf, err)
|
||||
if err = cfg.Append(file); err != nil {
|
||||
return nil, fmt.Errorf("failed to load config file %q: %v", file, err)
|
||||
}
|
||||
newFile = false
|
||||
loadedFromEmpty = false
|
||||
}
|
||||
}
|
||||
|
||||
if newFile && !opts.AllowEmpty {
|
||||
return nil, fmt.Errorf("unable to find configuration file: %q, please ensure you are running in the correct environment or set the correct configuration file with -c", CustomConf)
|
||||
}
|
||||
|
||||
if opts.ExtraConfig != "" {
|
||||
if err := cfg.Append([]byte(opts.ExtraConfig)); err != nil {
|
||||
return nil, fmt.Errorf("unable to append more config: %v", err)
|
||||
if len(extraConfigs) > 0 {
|
||||
for _, s := range extraConfigs {
|
||||
if err := cfg.Append([]byte(s)); err != nil {
|
||||
return nil, fmt.Errorf("unable to append more config: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cfg.NameMapper = ini.SnackCase
|
||||
return &iniConfigProvider{
|
||||
opts: opts,
|
||||
ini: cfg,
|
||||
newFile: newFile,
|
||||
file: file,
|
||||
ini: cfg,
|
||||
loadedFromEmpty: loadedFromEmpty,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -252,22 +249,24 @@ func (p *iniConfigProvider) GetSection(name string) (ConfigSection, error) {
|
||||
return &iniConfigSection{sec: sec}, nil
|
||||
}
|
||||
|
||||
var errDisableSaving = errors.New("this config can't be saved, developers should prepare a new config to save")
|
||||
|
||||
// Save saves the content into file
|
||||
func (p *iniConfigProvider) Save() error {
|
||||
filename := p.opts.CustomConf
|
||||
if filename == "" {
|
||||
if !p.opts.AllowEmpty {
|
||||
return fmt.Errorf("custom config path must not be empty")
|
||||
}
|
||||
return nil
|
||||
if p.disableSaving {
|
||||
return errDisableSaving
|
||||
}
|
||||
if p.newFile {
|
||||
filename := p.file
|
||||
if filename == "" {
|
||||
return fmt.Errorf("config file path must not be empty")
|
||||
}
|
||||
if p.loadedFromEmpty {
|
||||
if err := os.MkdirAll(filepath.Dir(filename), os.ModePerm); err != nil {
|
||||
return fmt.Errorf("failed to create '%s': %v", filename, err)
|
||||
return fmt.Errorf("failed to create %q: %v", filename, err)
|
||||
}
|
||||
}
|
||||
if err := p.ini.SaveTo(filename); err != nil {
|
||||
return fmt.Errorf("failed to save '%s': %v", filename, err)
|
||||
return fmt.Errorf("failed to save %q: %v", filename, err)
|
||||
}
|
||||
|
||||
// Change permissions to be more restrictive
|
||||
@@ -285,9 +284,32 @@ func (p *iniConfigProvider) Save() error {
|
||||
}
|
||||
|
||||
func (p *iniConfigProvider) SaveTo(filename string) error {
|
||||
if p.disableSaving {
|
||||
return errDisableSaving
|
||||
}
|
||||
return p.ini.SaveTo(filename)
|
||||
}
|
||||
|
||||
// DisableSaving disables the saving function, use PrepareSaving to get clear config options.
|
||||
func (p *iniConfigProvider) DisableSaving() {
|
||||
p.disableSaving = true
|
||||
}
|
||||
|
||||
// PrepareSaving loads the ini from file again to get clear config options.
|
||||
// Otherwise, the "MustXxx" calls would have polluted the current config provider,
|
||||
// it makes the "Save" outputs a lot of garbage options
|
||||
// After the INI package gets refactored, no "MustXxx" pollution, this workaround can be dropped.
|
||||
func (p *iniConfigProvider) PrepareSaving() (ConfigProvider, error) {
|
||||
if p.file == "" {
|
||||
return nil, errors.New("no config file to save")
|
||||
}
|
||||
return NewConfigProviderFromFile(p.file)
|
||||
}
|
||||
|
||||
func (p *iniConfigProvider) IsLoadedFromEmpty() bool {
|
||||
return p.loadedFromEmpty
|
||||
}
|
||||
|
||||
func mustMapSetting(rootCfg ConfigProvider, sectionName string, setting any) {
|
||||
if err := rootCfg.Section(sectionName).MapTo(setting); err != nil {
|
||||
log.Fatal("Failed to map %s settings: %v", sectionName, err)
|
||||
@@ -324,8 +346,8 @@ func NewConfigProviderForLocale(source any, others ...any) (ConfigProvider, erro
|
||||
}
|
||||
iniFile.BlockMode = false
|
||||
return &iniConfigProvider{
|
||||
ini: iniFile,
|
||||
newFile: true,
|
||||
ini: iniFile,
|
||||
loadedFromEmpty: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -67,13 +67,14 @@ key = 123
|
||||
}
|
||||
|
||||
func TestNewConfigProviderFromFile(t *testing.T) {
|
||||
_, err := NewConfigProviderFromFile(&Options{CustomConf: "no-such.ini", AllowEmpty: false})
|
||||
assert.ErrorContains(t, err, "unable to find configuration file")
|
||||
cfg, err := NewConfigProviderFromFile("no-such.ini")
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, cfg.IsLoadedFromEmpty())
|
||||
|
||||
// load non-existing file and save
|
||||
testFile := t.TempDir() + "/test.ini"
|
||||
testFile1 := t.TempDir() + "/test1.ini"
|
||||
cfg, err := NewConfigProviderFromFile(&Options{CustomConf: testFile, AllowEmpty: true})
|
||||
cfg, err = NewConfigProviderFromFile(testFile)
|
||||
assert.NoError(t, err)
|
||||
|
||||
sec, _ := cfg.NewSection("foo")
|
||||
@@ -84,14 +85,14 @@ func TestNewConfigProviderFromFile(t *testing.T) {
|
||||
|
||||
bs, err := os.ReadFile(testFile)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "[foo]\nk1=a\n", string(bs))
|
||||
assert.Equal(t, "[foo]\nk1 = a\n", string(bs))
|
||||
|
||||
bs, err = os.ReadFile(testFile1)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "[foo]\nk1=a\nk2=b\n", string(bs))
|
||||
assert.Equal(t, "[foo]\nk1 = a\nk2 = b\n", string(bs))
|
||||
|
||||
// load existing file and save
|
||||
cfg, err = NewConfigProviderFromFile(&Options{CustomConf: testFile, AllowEmpty: true})
|
||||
cfg, err = NewConfigProviderFromFile(testFile)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "a", cfg.Section("foo").Key("k1").String())
|
||||
sec, _ = cfg.NewSection("bar")
|
||||
@@ -99,7 +100,7 @@ func TestNewConfigProviderFromFile(t *testing.T) {
|
||||
assert.NoError(t, cfg.Save())
|
||||
bs, err = os.ReadFile(testFile)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "[foo]\nk1=a\n\n[bar]\nk1=b\n", string(bs))
|
||||
assert.Equal(t, "[foo]\nk1 = a\n\n[bar]\nk1 = b\n", string(bs))
|
||||
}
|
||||
|
||||
func TestNewConfigProviderForLocale(t *testing.T) {
|
||||
@@ -119,3 +120,27 @@ func TestNewConfigProviderForLocale(t *testing.T) {
|
||||
assert.Equal(t, "foo", cfg.Section("").Key("k1").String())
|
||||
assert.Equal(t, "xxx", cfg.Section("").Key("k2").String())
|
||||
}
|
||||
|
||||
func TestDisableSaving(t *testing.T) {
|
||||
testFile := t.TempDir() + "/test.ini"
|
||||
_ = os.WriteFile(testFile, []byte("k1=a\nk2=b"), 0o644)
|
||||
cfg, err := NewConfigProviderFromFile(testFile)
|
||||
assert.NoError(t, err)
|
||||
|
||||
cfg.DisableSaving()
|
||||
err = cfg.Save()
|
||||
assert.ErrorIs(t, err, errDisableSaving)
|
||||
|
||||
saveCfg, err := cfg.PrepareSaving()
|
||||
assert.NoError(t, err)
|
||||
|
||||
saveCfg.Section("").Key("k1").MustString("x")
|
||||
saveCfg.Section("").Key("k2").SetValue("y")
|
||||
saveCfg.Section("").Key("k3").SetValue("z")
|
||||
err = saveCfg.Save()
|
||||
assert.NoError(t, err)
|
||||
|
||||
bs, err := os.ReadFile(testFile)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "k1 = a\nk2 = y\nk3 = z\n", string(bs))
|
||||
}
|
||||
|
||||
@@ -12,8 +12,6 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -36,7 +34,7 @@ var (
|
||||
SSLMode string
|
||||
Path string
|
||||
LogSQL bool
|
||||
Charset string
|
||||
MysqlCharset string
|
||||
Timeout int // seconds
|
||||
SQLiteJournalMode string
|
||||
DBConnectRetries int
|
||||
@@ -60,11 +58,6 @@ func LoadDBSetting() {
|
||||
func loadDBSetting(rootCfg ConfigProvider) {
|
||||
sec := rootCfg.Section("database")
|
||||
Database.Type = DatabaseType(sec.Key("DB_TYPE").String())
|
||||
defaultCharset := "utf8"
|
||||
|
||||
if Database.Type.IsMySQL() {
|
||||
defaultCharset = "utf8mb4"
|
||||
}
|
||||
|
||||
Database.Host = sec.Key("HOST").String()
|
||||
Database.Name = sec.Key("NAME").String()
|
||||
@@ -74,10 +67,7 @@ func loadDBSetting(rootCfg ConfigProvider) {
|
||||
}
|
||||
Database.Schema = sec.Key("SCHEMA").String()
|
||||
Database.SSLMode = sec.Key("SSL_MODE").MustString("disable")
|
||||
Database.Charset = sec.Key("CHARSET").In(defaultCharset, []string{"utf8", "utf8mb4"})
|
||||
if Database.Type.IsMySQL() && defaultCharset != "utf8mb4" {
|
||||
log.Error("Deprecated database mysql charset utf8 support, please use utf8mb4 or convert utf8 to utf8mb4.")
|
||||
}
|
||||
Database.MysqlCharset = sec.Key("MYSQL_CHARSET").MustString("utf8mb4") // do not document it, end users won't need it.
|
||||
|
||||
Database.Path = sec.Key("PATH").MustString(filepath.Join(AppDataPath, "gitea.db"))
|
||||
Database.Timeout = sec.Key("SQLITE_TIMEOUT").MustInt(500)
|
||||
@@ -101,9 +91,9 @@ func loadDBSetting(rootCfg ConfigProvider) {
|
||||
// DBConnStr returns database connection string
|
||||
func DBConnStr() (string, error) {
|
||||
var connStr string
|
||||
Param := "?"
|
||||
if strings.Contains(Database.Name, Param) {
|
||||
Param = "&"
|
||||
paramSep := "?"
|
||||
if strings.Contains(Database.Name, paramSep) {
|
||||
paramSep = "&"
|
||||
}
|
||||
switch Database.Type {
|
||||
case "mysql":
|
||||
@@ -116,15 +106,15 @@ func DBConnStr() (string, error) {
|
||||
tls = "false"
|
||||
}
|
||||
connStr = fmt.Sprintf("%s:%s@%s(%s)/%s%scharset=%s&parseTime=true&tls=%s",
|
||||
Database.User, Database.Passwd, connType, Database.Host, Database.Name, Param, Database.Charset, tls)
|
||||
Database.User, Database.Passwd, connType, Database.Host, Database.Name, paramSep, Database.MysqlCharset, tls)
|
||||
case "postgres":
|
||||
connStr = getPostgreSQLConnectionString(Database.Host, Database.User, Database.Passwd, Database.Name, Param, Database.SSLMode)
|
||||
connStr = getPostgreSQLConnectionString(Database.Host, Database.User, Database.Passwd, Database.Name, paramSep, Database.SSLMode)
|
||||
case "mssql":
|
||||
host, port := ParseMSSQLHostPort(Database.Host)
|
||||
connStr = fmt.Sprintf("server=%s; port=%s; database=%s; user id=%s; password=%s;", host, port, Database.Name, Database.User, Database.Passwd)
|
||||
case "sqlite3":
|
||||
if !EnableSQLite3 {
|
||||
return "", errors.New("this binary version does not build support for SQLite3")
|
||||
return "", errors.New("this Gitea binary was not built with SQLite3 support")
|
||||
}
|
||||
if err := os.MkdirAll(path.Dir(Database.Path), os.ModePerm); err != nil {
|
||||
return "", fmt.Errorf("Failed to create directories: %w", err)
|
||||
@@ -136,7 +126,7 @@ func DBConnStr() (string, error) {
|
||||
connStr = fmt.Sprintf("file:%s?cache=shared&mode=rwc&_busy_timeout=%d&_txlock=immediate%s",
|
||||
Database.Path, Database.Timeout, journalMode)
|
||||
default:
|
||||
return "", fmt.Errorf("Unknown database type: %s", Database.Type)
|
||||
return "", fmt.Errorf("unknown database type: %s", Database.Type)
|
||||
}
|
||||
|
||||
return connStr, nil
|
||||
|
||||
+11
-4
@@ -53,19 +53,26 @@ func loadLFSFrom(rootCfg ConfigProvider) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
LFS.JWTSecretBase64 = loadSecret(rootCfg.Section("lfs"), "LFS_JWT_SECRET_URI", "LFS_JWT_SECRET")
|
||||
|
||||
LFS.JWTSecretBytes = make([]byte, 32)
|
||||
n, err := base64.RawURLEncoding.Decode(LFS.JWTSecretBytes, []byte(LFS.JWTSecretBase64))
|
||||
|
||||
if err != nil || n != 32 {
|
||||
LFS.JWTSecretBase64, err = generate.NewJwtSecretBase64()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error generating JWT Secret for custom config: %v", err)
|
||||
return fmt.Errorf("error generating JWT Secret for custom config: %v", err)
|
||||
}
|
||||
|
||||
// Save secret
|
||||
sec.Key("LFS_JWT_SECRET").SetValue(LFS.JWTSecretBase64)
|
||||
if err := rootCfg.Save(); err != nil {
|
||||
return fmt.Errorf("Error saving JWT Secret for custom config: %v", err)
|
||||
saveCfg, err := rootCfg.PrepareSaving()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error saving JWT Secret for custom config: %v", err)
|
||||
}
|
||||
rootCfg.Section("server").Key("LFS_JWT_SECRET").SetValue(LFS.JWTSecretBase64)
|
||||
saveCfg.Section("server").Key("LFS_JWT_SECRET").SetValue(LFS.JWTSecretBase64)
|
||||
if err := saveCfg.Save(); err != nil {
|
||||
return fmt.Errorf("error saving JWT Secret for custom config: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -244,7 +244,7 @@ func initLoggerByName(manager *log.LoggerManager, rootCfg ConfigProvider, logger
|
||||
eventWriters = append(eventWriters, eventWriter)
|
||||
}
|
||||
|
||||
manager.GetLogger(loggerName).RemoveAllWriters().AddWriters(eventWriters...)
|
||||
manager.GetLogger(loggerName).ReplaceAllWriters(eventWriters...)
|
||||
}
|
||||
|
||||
func InitSQLLoggersForCli(level log.Level) {
|
||||
|
||||
@@ -116,6 +116,12 @@ func loadOAuth2From(rootCfg ConfigProvider) {
|
||||
return
|
||||
}
|
||||
|
||||
if !OAuth2.Enable {
|
||||
return
|
||||
}
|
||||
|
||||
OAuth2.JWTSecretBase64 = loadSecret(rootCfg.Section("oauth2"), "JWT_SECRET_URI", "JWT_SECRET")
|
||||
|
||||
if !filepath.IsAbs(OAuth2.JWTSigningPrivateKeyFile) {
|
||||
OAuth2.JWTSigningPrivateKeyFile = filepath.Join(AppDataPath, OAuth2.JWTSigningPrivateKeyFile)
|
||||
}
|
||||
@@ -130,8 +136,13 @@ func loadOAuth2From(rootCfg ConfigProvider) {
|
||||
}
|
||||
|
||||
secretBase64 := base64.RawURLEncoding.EncodeToString(key)
|
||||
saveCfg, err := rootCfg.PrepareSaving()
|
||||
if err != nil {
|
||||
log.Fatal("save oauth2.JWT_SECRET failed: %v", err)
|
||||
}
|
||||
rootCfg.Section("oauth2").Key("JWT_SECRET").SetValue(secretBase64)
|
||||
if err := rootCfg.Save(); err != nil {
|
||||
saveCfg.Section("oauth2").Key("JWT_SECRET").SetValue(secretBase64)
|
||||
if err := saveCfg.Save(); err != nil {
|
||||
log.Fatal("save oauth2.JWT_SECRET failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package setting
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
)
|
||||
|
||||
var (
|
||||
// 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.
|
||||
// If that is not set it is the default set here by the linker or failing that the directory of AppPath.
|
||||
// It is used as the base path for several other paths.
|
||||
AppWorkPath string
|
||||
CustomPath string // Custom directory path. Env: GITEA_CUSTOM
|
||||
CustomConf string
|
||||
|
||||
appWorkPathBuiltin string
|
||||
customPathBuiltin string
|
||||
customConfBuiltin string
|
||||
|
||||
AppWorkPathMismatch bool
|
||||
)
|
||||
|
||||
func getAppPath() (string, error) {
|
||||
var appPath string
|
||||
var err error
|
||||
if IsWindows && filepath.IsAbs(os.Args[0]) {
|
||||
appPath = filepath.Clean(os.Args[0])
|
||||
} else {
|
||||
appPath, err = exec.LookPath(os.Args[0])
|
||||
}
|
||||
if err != nil {
|
||||
if !errors.Is(err, exec.ErrDot) {
|
||||
return "", err
|
||||
}
|
||||
appPath, err = filepath.Abs(os.Args[0])
|
||||
}
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
appPath, err = filepath.Abs(appPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// Note: (legacy code) we don't use path.Dir here because it does not handle case which path starts with two "/" in Windows: "//psf/Home/..."
|
||||
return strings.ReplaceAll(appPath, "\\", "/"), err
|
||||
}
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
if AppPath, err = getAppPath(); err != nil {
|
||||
log.Fatal("Failed to get app path: %v", err)
|
||||
}
|
||||
|
||||
if AppWorkPath == "" {
|
||||
AppWorkPath = filepath.Dir(AppPath)
|
||||
}
|
||||
|
||||
appWorkPathBuiltin = AppWorkPath
|
||||
customPathBuiltin = CustomPath
|
||||
customConfBuiltin = CustomConf
|
||||
}
|
||||
|
||||
type ArgWorkPathAndCustomConf struct {
|
||||
WorkPath string
|
||||
CustomPath string
|
||||
CustomConf string
|
||||
}
|
||||
|
||||
type stringWithDefault struct {
|
||||
Value string
|
||||
IsSet bool
|
||||
}
|
||||
|
||||
func (s *stringWithDefault) Set(v string) {
|
||||
s.Value = v
|
||||
s.IsSet = true
|
||||
}
|
||||
|
||||
// InitWorkPathAndCommonConfig will set AppWorkPath, CustomPath and CustomConf, init default config provider by CustomConf and load common settings,
|
||||
func InitWorkPathAndCommonConfig(getEnvFn func(name string) string, args ArgWorkPathAndCustomConf) {
|
||||
InitWorkPathAndCfgProvider(getEnvFn, args)
|
||||
LoadCommonSettings()
|
||||
}
|
||||
|
||||
// InitWorkPathAndCfgProvider will set AppWorkPath, CustomPath and CustomConf, init default config provider by CustomConf
|
||||
func InitWorkPathAndCfgProvider(getEnvFn func(name string) string, args ArgWorkPathAndCustomConf) {
|
||||
tryAbsPath := func(paths ...string) string {
|
||||
s := paths[len(paths)-1]
|
||||
for i := len(paths) - 2; i >= 0; i-- {
|
||||
if filepath.IsAbs(s) {
|
||||
break
|
||||
}
|
||||
s = filepath.Join(paths[i], s)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
var err error
|
||||
tmpWorkPath := stringWithDefault{Value: appWorkPathBuiltin}
|
||||
if tmpWorkPath.Value == "" {
|
||||
tmpWorkPath.Value = filepath.Dir(AppPath)
|
||||
}
|
||||
tmpCustomPath := stringWithDefault{Value: customPathBuiltin}
|
||||
if tmpCustomPath.Value == "" {
|
||||
tmpCustomPath.Value = "custom"
|
||||
}
|
||||
tmpCustomConf := stringWithDefault{Value: customConfBuiltin}
|
||||
if tmpCustomConf.Value == "" {
|
||||
tmpCustomConf.Value = "conf/app.ini"
|
||||
}
|
||||
|
||||
readFromEnv := func() {
|
||||
envWorkPath := getEnvFn("GITEA_WORK_DIR")
|
||||
if envWorkPath != "" {
|
||||
tmpWorkPath.Set(envWorkPath)
|
||||
if !filepath.IsAbs(tmpWorkPath.Value) {
|
||||
log.Fatal("GITEA_WORK_DIR (work path) must be absolute path")
|
||||
}
|
||||
}
|
||||
|
||||
envCustomPath := getEnvFn("GITEA_CUSTOM")
|
||||
if envCustomPath != "" {
|
||||
tmpCustomPath.Set(envCustomPath)
|
||||
if !filepath.IsAbs(tmpCustomPath.Value) {
|
||||
log.Fatal("GITEA_CUSTOM (custom path) must be absolute path")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
readFromArgs := func() {
|
||||
if args.WorkPath != "" {
|
||||
tmpWorkPath.Set(args.WorkPath)
|
||||
if !filepath.IsAbs(tmpWorkPath.Value) {
|
||||
log.Fatal("--work-path must be absolute path")
|
||||
}
|
||||
}
|
||||
if args.CustomPath != "" {
|
||||
tmpCustomPath.Set(args.CustomPath) // if it is not abs, it will be based on work-path, it shouldn't happen
|
||||
if !filepath.IsAbs(tmpCustomPath.Value) {
|
||||
log.Error("--custom-path must be absolute path")
|
||||
}
|
||||
}
|
||||
if args.CustomConf != "" {
|
||||
tmpCustomConf.Set(args.CustomConf)
|
||||
if !filepath.IsAbs(tmpCustomConf.Value) {
|
||||
// the config path can be relative to the real current working path
|
||||
if tmpCustomConf.Value, err = filepath.Abs(tmpCustomConf.Value); err != nil {
|
||||
log.Fatal("Failed to get absolute path of config %q: %v", tmpCustomConf.Value, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
readFromEnv()
|
||||
readFromArgs()
|
||||
|
||||
if !tmpCustomConf.IsSet {
|
||||
tmpCustomConf.Set(tryAbsPath(tmpWorkPath.Value, tmpCustomPath.Value, tmpCustomConf.Value))
|
||||
}
|
||||
|
||||
// only read the config but do not load/init anything more, because the AppWorkPath and CustomPath are not ready
|
||||
InitCfgProvider(tmpCustomConf.Value)
|
||||
configWorkPath := ConfigSectionKeyString(CfgProvider.Section(""), "WORK_PATH")
|
||||
if configWorkPath != "" {
|
||||
if !filepath.IsAbs(configWorkPath) {
|
||||
log.Fatal("WORK_PATH in %q must be absolute path", configWorkPath)
|
||||
}
|
||||
configWorkPath = filepath.Clean(configWorkPath)
|
||||
if tmpWorkPath.Value != "" && (getEnvFn("GITEA_WORK_DIR") != "" || args.WorkPath != "") {
|
||||
fi1, err1 := os.Stat(tmpWorkPath.Value)
|
||||
fi2, err2 := os.Stat(configWorkPath)
|
||||
if err1 != nil || err2 != nil || !os.SameFile(fi1, fi2) {
|
||||
AppWorkPathMismatch = true
|
||||
}
|
||||
}
|
||||
tmpWorkPath.Set(configWorkPath)
|
||||
}
|
||||
|
||||
tmpCustomPath.Set(tryAbsPath(tmpWorkPath.Value, tmpCustomPath.Value))
|
||||
|
||||
AppWorkPath = tmpWorkPath.Value
|
||||
CustomPath = tmpCustomPath.Value
|
||||
CustomConf = tmpCustomConf.Value
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package setting
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type envVars map[string]string
|
||||
|
||||
func (e envVars) Getenv(key string) string {
|
||||
return e[key]
|
||||
}
|
||||
|
||||
func TestInitWorkPathAndCommonConfig(t *testing.T) {
|
||||
testInit := func(defaultWorkPath, defaultCustomPath, defaultCustomConf string) {
|
||||
AppWorkPathMismatch = false
|
||||
AppWorkPath = defaultWorkPath
|
||||
appWorkPathBuiltin = defaultWorkPath
|
||||
CustomPath = defaultCustomPath
|
||||
customPathBuiltin = defaultCustomPath
|
||||
CustomConf = defaultCustomConf
|
||||
customConfBuiltin = defaultCustomConf
|
||||
}
|
||||
|
||||
fp := filepath.Join
|
||||
|
||||
tmpDir := t.TempDir()
|
||||
dirFoo := fp(tmpDir, "foo")
|
||||
dirBar := fp(tmpDir, "bar")
|
||||
dirXxx := fp(tmpDir, "xxx")
|
||||
dirYyy := fp(tmpDir, "yyy")
|
||||
|
||||
t.Run("Default", func(t *testing.T) {
|
||||
testInit(dirFoo, "", "")
|
||||
InitWorkPathAndCommonConfig(envVars{}.Getenv, ArgWorkPathAndCustomConf{})
|
||||
assert.Equal(t, dirFoo, AppWorkPath)
|
||||
assert.Equal(t, fp(dirFoo, "custom"), CustomPath)
|
||||
assert.Equal(t, fp(dirFoo, "custom/conf/app.ini"), CustomConf)
|
||||
})
|
||||
|
||||
t.Run("WorkDir(env)", func(t *testing.T) {
|
||||
testInit(dirFoo, "", "")
|
||||
InitWorkPathAndCommonConfig(envVars{"GITEA_WORK_DIR": dirBar}.Getenv, ArgWorkPathAndCustomConf{})
|
||||
assert.Equal(t, dirBar, AppWorkPath)
|
||||
assert.Equal(t, fp(dirBar, "custom"), CustomPath)
|
||||
assert.Equal(t, fp(dirBar, "custom/conf/app.ini"), CustomConf)
|
||||
})
|
||||
|
||||
t.Run("WorkDir(env,arg)", func(t *testing.T) {
|
||||
testInit(dirFoo, "", "")
|
||||
InitWorkPathAndCommonConfig(envVars{"GITEA_WORK_DIR": dirBar}.Getenv, ArgWorkPathAndCustomConf{WorkPath: dirXxx})
|
||||
assert.Equal(t, dirXxx, AppWorkPath)
|
||||
assert.Equal(t, fp(dirXxx, "custom"), CustomPath)
|
||||
assert.Equal(t, fp(dirXxx, "custom/conf/app.ini"), CustomConf)
|
||||
})
|
||||
|
||||
t.Run("CustomPath(env)", func(t *testing.T) {
|
||||
testInit(dirFoo, "", "")
|
||||
InitWorkPathAndCommonConfig(envVars{"GITEA_CUSTOM": fp(dirBar, "custom1")}.Getenv, ArgWorkPathAndCustomConf{})
|
||||
assert.Equal(t, dirFoo, AppWorkPath)
|
||||
assert.Equal(t, fp(dirBar, "custom1"), CustomPath)
|
||||
assert.Equal(t, fp(dirBar, "custom1/conf/app.ini"), CustomConf)
|
||||
})
|
||||
|
||||
t.Run("CustomPath(env,arg)", func(t *testing.T) {
|
||||
testInit(dirFoo, "", "")
|
||||
InitWorkPathAndCommonConfig(envVars{"GITEA_CUSTOM": fp(dirBar, "custom1")}.Getenv, ArgWorkPathAndCustomConf{CustomPath: "custom2"})
|
||||
assert.Equal(t, dirFoo, AppWorkPath)
|
||||
assert.Equal(t, fp(dirFoo, "custom2"), CustomPath)
|
||||
assert.Equal(t, fp(dirFoo, "custom2/conf/app.ini"), CustomConf)
|
||||
})
|
||||
|
||||
t.Run("CustomConf", func(t *testing.T) {
|
||||
testInit(dirFoo, "", "")
|
||||
InitWorkPathAndCommonConfig(envVars{}.Getenv, ArgWorkPathAndCustomConf{CustomConf: "app1.ini"})
|
||||
assert.Equal(t, dirFoo, AppWorkPath)
|
||||
cwd, _ := os.Getwd()
|
||||
assert.Equal(t, fp(cwd, "app1.ini"), CustomConf)
|
||||
|
||||
testInit(dirFoo, "", "")
|
||||
InitWorkPathAndCommonConfig(envVars{}.Getenv, ArgWorkPathAndCustomConf{CustomConf: fp(dirBar, "app1.ini")})
|
||||
assert.Equal(t, dirFoo, AppWorkPath)
|
||||
assert.Equal(t, fp(dirBar, "app1.ini"), CustomConf)
|
||||
})
|
||||
|
||||
t.Run("CustomConfOverrideWorkPath", func(t *testing.T) {
|
||||
iniWorkPath := fp(tmpDir, "app-workpath.ini")
|
||||
_ = os.WriteFile(iniWorkPath, []byte("WORK_PATH="+dirXxx), 0o644)
|
||||
|
||||
testInit(dirFoo, "", "")
|
||||
InitWorkPathAndCommonConfig(envVars{}.Getenv, ArgWorkPathAndCustomConf{CustomConf: iniWorkPath})
|
||||
assert.Equal(t, dirXxx, AppWorkPath)
|
||||
assert.Equal(t, fp(dirXxx, "custom"), CustomPath)
|
||||
assert.Equal(t, iniWorkPath, CustomConf)
|
||||
assert.False(t, AppWorkPathMismatch)
|
||||
|
||||
testInit(dirFoo, "", "")
|
||||
InitWorkPathAndCommonConfig(envVars{"GITEA_WORK_DIR": dirBar}.Getenv, ArgWorkPathAndCustomConf{CustomConf: iniWorkPath})
|
||||
assert.Equal(t, dirXxx, AppWorkPath)
|
||||
assert.Equal(t, fp(dirXxx, "custom"), CustomPath)
|
||||
assert.Equal(t, iniWorkPath, CustomConf)
|
||||
assert.True(t, AppWorkPathMismatch)
|
||||
|
||||
testInit(dirFoo, "", "")
|
||||
InitWorkPathAndCommonConfig(envVars{}.Getenv, ArgWorkPathAndCustomConf{WorkPath: dirBar, CustomConf: iniWorkPath})
|
||||
assert.Equal(t, dirXxx, AppWorkPath)
|
||||
assert.Equal(t, fp(dirXxx, "custom"), CustomPath)
|
||||
assert.Equal(t, iniWorkPath, CustomConf)
|
||||
assert.True(t, AppWorkPathMismatch)
|
||||
})
|
||||
|
||||
t.Run("Builtin", func(t *testing.T) {
|
||||
testInit(dirFoo, dirBar, dirXxx)
|
||||
InitWorkPathAndCommonConfig(envVars{}.Getenv, ArgWorkPathAndCustomConf{})
|
||||
assert.Equal(t, dirFoo, AppWorkPath)
|
||||
assert.Equal(t, dirBar, CustomPath)
|
||||
assert.Equal(t, dirXxx, CustomConf)
|
||||
|
||||
testInit(dirFoo, "custom1", "cfg.ini")
|
||||
InitWorkPathAndCommonConfig(envVars{}.Getenv, ArgWorkPathAndCustomConf{})
|
||||
assert.Equal(t, dirFoo, AppWorkPath)
|
||||
assert.Equal(t, fp(dirFoo, "custom1"), CustomPath)
|
||||
assert.Equal(t, fp(dirFoo, "custom1/cfg.ini"), CustomConf)
|
||||
|
||||
testInit(dirFoo, "custom1", "cfg.ini")
|
||||
InitWorkPathAndCommonConfig(envVars{"GITEA_WORK_DIR": dirYyy}.Getenv, ArgWorkPathAndCustomConf{})
|
||||
assert.Equal(t, dirYyy, AppWorkPath)
|
||||
assert.Equal(t, fp(dirYyy, "custom1"), CustomPath)
|
||||
assert.Equal(t, fp(dirYyy, "custom1/cfg.ini"), CustomConf)
|
||||
|
||||
testInit(dirFoo, "custom1", "cfg.ini")
|
||||
InitWorkPathAndCommonConfig(envVars{"GITEA_CUSTOM": dirYyy}.Getenv, ArgWorkPathAndCustomConf{})
|
||||
assert.Equal(t, dirFoo, AppWorkPath)
|
||||
assert.Equal(t, dirYyy, CustomPath)
|
||||
assert.Equal(t, fp(dirYyy, "cfg.ini"), CustomConf)
|
||||
|
||||
iniWorkPath := fp(tmpDir, "app-workpath.ini")
|
||||
_ = os.WriteFile(iniWorkPath, []byte("WORK_PATH="+dirXxx), 0o644)
|
||||
testInit(dirFoo, "custom1", "cfg.ini")
|
||||
InitWorkPathAndCommonConfig(envVars{}.Getenv, ArgWorkPathAndCustomConf{CustomConf: iniWorkPath})
|
||||
assert.Equal(t, dirXxx, AppWorkPath)
|
||||
assert.Equal(t, fp(dirXxx, "custom1"), CustomPath)
|
||||
assert.Equal(t, iniWorkPath, CustomConf)
|
||||
})
|
||||
}
|
||||
@@ -76,7 +76,7 @@ func loadSecret(sec ConfigSection, uriKey, verbatimKey string) string {
|
||||
|
||||
// only file URIs are allowed
|
||||
default:
|
||||
log.Fatal("Unsupported URI-Scheme %q (INTERNAL_TOKEN_URI = %q)", tempURI.Scheme, uri)
|
||||
log.Fatal("Unsupported URI-Scheme %q (%q = %q)", tempURI.Scheme, uriKey, uri)
|
||||
return ""
|
||||
}
|
||||
}
|
||||
@@ -89,8 +89,13 @@ func generateSaveInternalToken(rootCfg ConfigProvider) {
|
||||
}
|
||||
|
||||
InternalToken = token
|
||||
saveCfg, err := rootCfg.PrepareSaving()
|
||||
if err != nil {
|
||||
log.Fatal("Error saving internal token: %v", err)
|
||||
}
|
||||
rootCfg.Section("security").Key("INTERNAL_TOKEN").SetValue(token)
|
||||
if err := rootCfg.Save(); err != nil {
|
||||
saveCfg.Section("security").Key("INTERNAL_TOKEN").SetValue(token)
|
||||
if err = saveCfg.Save(); err != nil {
|
||||
log.Fatal("Error saving internal token: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ var (
|
||||
AssetVersion string
|
||||
|
||||
// Server settings
|
||||
|
||||
Protocol Scheme
|
||||
UseProxyProtocol bool // `ini:"USE_PROXY_PROTOCOL"`
|
||||
ProxyProtocolTLSBridging bool //`ini:"PROXY_PROTOCOL_TLS_BRIDGING"`
|
||||
@@ -324,7 +325,6 @@ func loadServerFrom(rootCfg ConfigProvider) {
|
||||
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))
|
||||
}
|
||||
|
||||
|
||||
+16
-118
@@ -5,12 +5,8 @@
|
||||
package setting
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -28,19 +24,9 @@ var (
|
||||
// AppStartTime store time gitea has started
|
||||
AppStartTime time.Time
|
||||
|
||||
// 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.
|
||||
// If that is not set it is the default set here by the linker or failing that the directory of AppPath.
|
||||
//
|
||||
// AppWorkPath is used as the base path for several other paths.
|
||||
AppWorkPath string
|
||||
|
||||
// Other global setting objects
|
||||
|
||||
CfgProvider ConfigProvider
|
||||
CustomPath string // Custom directory path
|
||||
CustomConf string
|
||||
RunMode string
|
||||
RunUser string
|
||||
IsProd bool
|
||||
@@ -51,62 +37,6 @@ var (
|
||||
IsInTesting = false
|
||||
)
|
||||
|
||||
func getAppPath() (string, error) {
|
||||
var appPath string
|
||||
var err error
|
||||
if IsWindows && filepath.IsAbs(os.Args[0]) {
|
||||
appPath = filepath.Clean(os.Args[0])
|
||||
} else {
|
||||
appPath, err = exec.LookPath(os.Args[0])
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if !errors.Is(err, exec.ErrDot) {
|
||||
return "", err
|
||||
}
|
||||
appPath, err = filepath.Abs(os.Args[0])
|
||||
}
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
appPath, err = filepath.Abs(appPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// Note: we don't use path.Dir here because it does not handle case
|
||||
// which path starts with two "/" in Windows: "//psf/Home/..."
|
||||
return strings.ReplaceAll(appPath, "\\", "/"), err
|
||||
}
|
||||
|
||||
func getWorkPath(appPath string) string {
|
||||
workPath := AppWorkPath
|
||||
|
||||
if giteaWorkPath, ok := os.LookupEnv("GITEA_WORK_DIR"); ok {
|
||||
workPath = giteaWorkPath
|
||||
}
|
||||
if len(workPath) == 0 {
|
||||
i := strings.LastIndex(appPath, "/")
|
||||
if i == -1 {
|
||||
workPath = appPath
|
||||
} else {
|
||||
workPath = appPath[:i]
|
||||
}
|
||||
}
|
||||
workPath = strings.ReplaceAll(workPath, "\\", "/")
|
||||
if !filepath.IsAbs(workPath) {
|
||||
log.Info("Provided work path %s is not absolute - will be made absolute against the current working directory", workPath)
|
||||
|
||||
absPath, err := filepath.Abs(workPath)
|
||||
if err != nil {
|
||||
log.Error("Unable to absolute %s against the current working directory %v. Will absolute against the AppPath %s", workPath, err, appPath)
|
||||
workPath = filepath.Join(appPath, workPath)
|
||||
} else {
|
||||
workPath = absPath
|
||||
}
|
||||
}
|
||||
return strings.ReplaceAll(workPath, "\\", "/")
|
||||
}
|
||||
|
||||
func init() {
|
||||
IsWindows = runtime.GOOS == "windows"
|
||||
if AppVer == "" {
|
||||
@@ -116,12 +46,6 @@ func init() {
|
||||
// We can rely on log.CanColorStdout being set properly because modules/log/console_windows.go comes before modules/setting/setting.go lexicographically
|
||||
// By default set this logger at Info - we'll change it later, but we need to start with something.
|
||||
log.SetConsoleLogger(log.DEFAULT, "console", log.INFO)
|
||||
|
||||
var err error
|
||||
if AppPath, err = getAppPath(); err != nil {
|
||||
log.Fatal("Failed to get app path: %v", err)
|
||||
}
|
||||
AppWorkPath = getWorkPath(AppPath)
|
||||
}
|
||||
|
||||
// IsRunUserMatchCurrentUser returns false if configured run user does not match
|
||||
@@ -137,36 +61,6 @@ func IsRunUserMatchCurrentUser(runUser string) (string, bool) {
|
||||
return currentUser, runUser == currentUser
|
||||
}
|
||||
|
||||
// SetCustomPathAndConf will set CustomPath and CustomConf with reference to the
|
||||
// GITEA_CUSTOM environment variable and with provided overrides before stepping
|
||||
// back to the default
|
||||
func SetCustomPathAndConf(providedCustom, providedConf, providedWorkPath string) {
|
||||
if len(providedWorkPath) != 0 {
|
||||
AppWorkPath = filepath.ToSlash(providedWorkPath)
|
||||
}
|
||||
if giteaCustom, ok := os.LookupEnv("GITEA_CUSTOM"); ok {
|
||||
CustomPath = giteaCustom
|
||||
}
|
||||
if len(providedCustom) != 0 {
|
||||
CustomPath = providedCustom
|
||||
}
|
||||
if len(CustomPath) == 0 {
|
||||
CustomPath = path.Join(AppWorkPath, "custom")
|
||||
} else if !filepath.IsAbs(CustomPath) {
|
||||
CustomPath = path.Join(AppWorkPath, CustomPath)
|
||||
}
|
||||
|
||||
if len(providedConf) != 0 {
|
||||
CustomConf = providedConf
|
||||
}
|
||||
if len(CustomConf) == 0 {
|
||||
CustomConf = path.Join(CustomPath, "conf/app.ini")
|
||||
} else if !filepath.IsAbs(CustomConf) {
|
||||
CustomConf = path.Join(CustomPath, CustomConf)
|
||||
log.Warn("Using 'custom' directory as relative origin for configuration file: '%s'", CustomConf)
|
||||
}
|
||||
}
|
||||
|
||||
// PrepareAppDataPath creates app data directory if necessary
|
||||
func PrepareAppDataPath() error {
|
||||
// FIXME: There are too many calls to MkdirAll in old code. It is incorrect.
|
||||
@@ -196,25 +90,29 @@ func PrepareAppDataPath() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func Init(opts *Options) {
|
||||
if opts.CustomConf == "" {
|
||||
opts.CustomConf = CustomConf
|
||||
}
|
||||
func InitCfgProvider(file string, extraConfigs ...string) {
|
||||
var err error
|
||||
CfgProvider, err = NewConfigProviderFromFile(opts)
|
||||
if err != nil {
|
||||
log.Fatal("newConfigProviderFromFile[%v]: %v", opts, err)
|
||||
if CfgProvider, err = NewConfigProviderFromFile(file, extraConfigs...); err != nil {
|
||||
log.Fatal("Unable to init config provider from %q: %v", file, err)
|
||||
}
|
||||
if !opts.DisableLoadCommonSettings {
|
||||
if err := loadCommonSettingsFrom(CfgProvider); err != nil {
|
||||
log.Fatal("loadCommonSettingsFrom[%v]: %v", opts, err)
|
||||
}
|
||||
CfgProvider.DisableSaving() // do not allow saving the CfgProvider into file, it will be polluted by the "MustXxx" calls
|
||||
}
|
||||
|
||||
func MustInstalled() {
|
||||
if !InstallLock {
|
||||
log.Fatal(`Unable to load config file for a installed Gitea instance, you should either use "--config" to set your config file (app.ini), or run "gitea web" command to install Gitea.`)
|
||||
}
|
||||
}
|
||||
|
||||
func LoadCommonSettings() {
|
||||
if err := loadCommonSettingsFrom(CfgProvider); err != nil {
|
||||
log.Fatal("Unable to load settings from config: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// loadCommonSettingsFrom loads common configurations from a configuration provider.
|
||||
func loadCommonSettingsFrom(cfg ConfigProvider) error {
|
||||
// WARNNING: don't change the sequence except you know what you are doing.
|
||||
// WARNING: don't change the sequence except you know what you are doing.
|
||||
loadRunModeFrom(cfg)
|
||||
loadLogGlobalFrom(cfg)
|
||||
loadServerFrom(cfg)
|
||||
|
||||
Reference in New Issue
Block a user