mirror of https://github.com/go-gitea/gitea.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
214 lines
6.2 KiB
214 lines
6.2 KiB
// 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" |
|
"code.gitea.io/gitea/modules/tempdir" |
|
) |
|
|
|
var ( |
|
// AppPath represents the path to the gitea binary |
|
AppPath string |
|
|
|
// AppWorkPath is the "working directory" of Gitea. It maps to the: WORK_PATH in app.ini, "--work-path" flag, 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 |
|
} |
|
|
|
// AppDataTempDir returns a managed temporary directory for the application data. |
|
// Using empty sub will get the managed base temp directory, and it's safe to delete it. |
|
// Gitea only creates subdirectories under it, but not the APP_TEMP_PATH directory itself. |
|
// * When APP_TEMP_PATH="/tmp": the managed temp directory is "/tmp/gitea-tmp" |
|
// * When APP_TEMP_PATH is not set: the managed temp directory is "/{APP_DATA_PATH}/tmp" |
|
func AppDataTempDir(sub string) *tempdir.TempDir { |
|
if appTempPathInternal != "" { |
|
return tempdir.New(appTempPathInternal, "gitea-tmp/"+sub) |
|
} |
|
if AppDataPath == "" { |
|
panic("setting.AppDataPath is not set") |
|
} |
|
return tempdir.New(AppDataPath, "tmp/"+sub) |
|
}
|
|
|