summaryrefslogtreecommitdiffstats
path: root/modules/doctor/paths.go
diff options
context:
space:
mode:
authorzeripath <art27@cantab.net>2020-12-02 04:56:04 +0000
committerGitHub <noreply@github.com>2020-12-02 06:56:04 +0200
commit4569339a4b8ead2b9bb110f4b7fc393ef6b3b4ba (patch)
tree263a871fdaedcb45bc7fb29c59d83126c46fc563 /modules/doctor/paths.go
parent253add883d378ec706f09a44136bc20b4ece1bf5 (diff)
downloadgitea-4569339a4b8ead2b9bb110f4b7fc393ef6b3b4ba.tar.gz
gitea-4569339a4b8ead2b9bb110f4b7fc393ef6b3b4ba.zip
Refactor doctor (#12264)
* Refactor Logger Refactor Logger to make a logger interface and make it possible to wrap loggers for specific purposes. * Refactor Doctor Move the gitea doctor functions into its own module. Use a logger for its messages instead of returning a results string[] Signed-off-by: Andrew Thornton <art27@cantab.net> * Update modules/doctor/misc.go Co-authored-by: 6543 <6543@obermui.de> * Update modules/doctor/misc.go Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: techknowlogick <techknowlogick@gitea.io>
Diffstat (limited to 'modules/doctor/paths.go')
-rw-r--r--modules/doctor/paths.go126
1 files changed, 126 insertions, 0 deletions
diff --git a/modules/doctor/paths.go b/modules/doctor/paths.go
new file mode 100644
index 0000000000..53409b5fa4
--- /dev/null
+++ b/modules/doctor/paths.go
@@ -0,0 +1,126 @@
+// Copyright 2020 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package doctor
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+
+ "code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/options"
+ "code.gitea.io/gitea/modules/setting"
+)
+
+type configurationFile struct {
+ Name string
+ Path string
+ IsDirectory bool
+ Required bool
+ Writable bool
+}
+
+func checkConfigurationFile(logger log.Logger, autofix bool, fileOpts configurationFile) error {
+ logger.Info(`%-26s %q`, log.NewColoredValue(fileOpts.Name+":", log.Reset), fileOpts.Path)
+ fi, err := os.Stat(fileOpts.Path)
+ if err != nil {
+ if os.IsNotExist(err) && autofix && fileOpts.IsDirectory {
+ if err := os.MkdirAll(fileOpts.Path, 0777); err != nil {
+ logger.Error(" Directory does not exist and could not be created. ERROR: %v", err)
+ return fmt.Errorf("Configuration directory: \"%q\" does not exist and could not be created. ERROR: %v", fileOpts.Path, err)
+ }
+ fi, err = os.Stat(fileOpts.Path)
+ }
+ }
+ if err != nil {
+ if fileOpts.Required {
+ logger.Error(" Is REQUIRED but is not accessible. ERROR: %v", err)
+ return fmt.Errorf("Configuration file \"%q\" is not accessible but is required. Error: %v", fileOpts.Path, err)
+ }
+ logger.Warn(" NOTICE: is not accessible (Error: %v)", err)
+ // this is a non-critical error
+ return nil
+ }
+
+ if fileOpts.IsDirectory && !fi.IsDir() {
+ logger.Error(" ERROR: not a directory")
+ return fmt.Errorf("Configuration directory \"%q\" is not a directory. Error: %v", fileOpts.Path, err)
+ } else if !fileOpts.IsDirectory && !fi.Mode().IsRegular() {
+ logger.Error(" ERROR: not a regular file")
+ return fmt.Errorf("Configuration file \"%q\" is not a regular file. Error: %v", fileOpts.Path, err)
+ } else if fileOpts.Writable {
+ if err := isWritableDir(fileOpts.Path); err != nil {
+ logger.Error(" ERROR: is required to be writable but is not writable: %v", err)
+ return fmt.Errorf("Configuration file \"%q\" is required to be writable but is not. Error: %v", fileOpts.Path, err)
+ }
+ }
+ return nil
+}
+
+func checkConfigurationFiles(logger log.Logger, autofix bool) error {
+ if fi, err := os.Stat(setting.CustomConf); err != nil || !fi.Mode().IsRegular() {
+ logger.Error("Failed to find configuration file at '%s'.", setting.CustomConf)
+ logger.Error("If you've never ran Gitea yet, this is normal and '%s' will be created for you on first run.", setting.CustomConf)
+ logger.Error("Otherwise check that you are running this command from the correct path and/or provide a `--config` parameter.")
+ logger.Critical("Cannot proceed without a configuration file")
+ return err
+ }
+
+ setting.NewContext()
+
+ configurationFiles := []configurationFile{
+ {"Configuration File Path", setting.CustomConf, false, true, false},
+ {"Repository Root Path", setting.RepoRootPath, true, true, true},
+ {"Data Root Path", setting.AppDataPath, true, true, true},
+ {"Custom File Root Path", setting.CustomPath, true, false, false},
+ {"Work directory", setting.AppWorkPath, true, true, false},
+ {"Log Root Path", setting.LogRootPath, true, true, true},
+ }
+
+ if options.IsDynamic() {
+ configurationFiles = append(configurationFiles, configurationFile{"Static File Root Path", setting.StaticRootPath, true, true, false})
+ }
+
+ numberOfErrors := 0
+ for _, configurationFile := range configurationFiles {
+ if err := checkConfigurationFile(logger, autofix, configurationFile); err != nil {
+ numberOfErrors++
+ }
+ }
+
+ if numberOfErrors > 0 {
+ logger.Critical("Please check your configuration files and try again.")
+ return fmt.Errorf("%d configuration files with errors", numberOfErrors)
+ }
+
+ return nil
+}
+
+func isWritableDir(path string) error {
+ // There's no platform-independent way of checking if a directory is writable
+ // https://stackoverflow.com/questions/20026320/how-to-tell-if-folder-exists-and-is-writable
+
+ tmpFile, err := ioutil.TempFile(path, "doctors-order")
+ if err != nil {
+ return err
+ }
+ if err := os.Remove(tmpFile.Name()); err != nil {
+ fmt.Printf("Warning: can't remove temporary file: '%s'\n", tmpFile.Name())
+ }
+ tmpFile.Close()
+ return nil
+}
+
+func init() {
+ Register(&Check{
+ Title: "Check paths and basic configuration",
+ Name: "paths",
+ IsDefault: true,
+ Run: checkConfigurationFiles,
+ AbortIfFailed: true,
+ SkipDatabaseInitialization: true,
+ Priority: 1,
+ })
+}