mirror of
https://codeberg.org/forgejo/forgejo
synced 2024-11-30 22:06:11 +01:00
b4460cf541
Backport #25648 Replace #25580 Fix #19453 The problem was: when users set "GITEA__XXX__YYY" , the "install page" doesn't respect it. So, to make the result consistent and avoid surprising end users, now the "install page" also writes the environment variables to the config file. And, to make things clear, there are enough messages on the UI to tell users what will happen. There are some necessary/related changes to `environment-to-ini.go`: * The "--clear" flag is removed and it was incorrectly written there. The "clear" operation should be done if INSTALL_LOCK=true * The "--prefix" flag is removed because it's never used, never documented and it only causes inconsistent behavior. The only conflict during backport is "ui divider" in templates/install.tmpl
199 lines
5.5 KiB
Go
199 lines
5.5 KiB
Go
// 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)
|
|
if HasInstallLock(CfgProvider) {
|
|
ClearEnvConfigKeys() // if the instance has been installed, do not pass the environment variables to sub-processes
|
|
}
|
|
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
|
|
}
|