summaryrefslogtreecommitdiffstats
path: root/modules/setting/path.go
diff options
context:
space:
mode:
Diffstat (limited to 'modules/setting/path.go')
-rw-r--r--modules/setting/path.go214
1 files changed, 214 insertions, 0 deletions
diff --git a/modules/setting/path.go b/modules/setting/path.go
new file mode 100644
index 00000000..85d0e063
--- /dev/null
+++ b/modules/setting/path.go
@@ -0,0 +1,214 @@
+// 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: 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")
+ }
+ }
+
+ envWorkPath = getEnvFn("FORGEJO_WORK_DIR")
+ if envWorkPath != "" {
+ tmpWorkPath.Set(envWorkPath)
+ if !filepath.IsAbs(tmpWorkPath.Value) {
+ log.Fatal("FORGEJO_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")
+ }
+ }
+
+ envCustomPath = getEnvFn("FORGEJO_CUSTOM")
+ if envCustomPath != "" {
+ tmpCustomPath.Set(envCustomPath)
+ if !filepath.IsAbs(tmpCustomPath.Value) {
+ log.Fatal("FORGEJO_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") != "" || getEnvFn("FORGEJO_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
+}