210 lines · 5.9 KB · Go
RawDownload
// Copyright 2023 The Gitea Authors. All rights reserved.// SPDX-License-Identifier: MIT package setting import (	"errors"	"os"	"os/exec"	"path/filepath"	"strings" 	"forgejo.org/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	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 CustomConffunc 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}