code.gitea.io/gitea@v1.19.3/modules/doctor/doctor.go (about)

     1  // Copyright 2020 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package doctor
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"sort"
    10  	"strings"
    11  
    12  	"code.gitea.io/gitea/models/db"
    13  	"code.gitea.io/gitea/modules/git"
    14  	"code.gitea.io/gitea/modules/log"
    15  	"code.gitea.io/gitea/modules/setting"
    16  )
    17  
    18  // Check represents a Doctor check
    19  type Check struct {
    20  	Title                      string
    21  	Name                       string
    22  	IsDefault                  bool
    23  	Run                        func(ctx context.Context, logger log.Logger, autofix bool) error
    24  	AbortIfFailed              bool
    25  	SkipDatabaseInitialization bool
    26  	Priority                   int
    27  }
    28  
    29  type wrappedLevelLogger struct {
    30  	log.LevelLogger
    31  }
    32  
    33  func (w *wrappedLevelLogger) Log(skip int, level log.Level, format string, v ...interface{}) error {
    34  	return w.LevelLogger.Log(
    35  		skip+1,
    36  		level,
    37  		" - %s "+format,
    38  		append(
    39  			[]interface{}{
    40  				log.NewColoredValueBytes(
    41  					fmt.Sprintf("[%s]", strings.ToUpper(level.String()[0:1])),
    42  					level.Color()),
    43  			}, v...)...)
    44  }
    45  
    46  func initDBDisableConsole(ctx context.Context, disableConsole bool) error {
    47  	setting.InitProviderFromExistingFile()
    48  	setting.LoadCommonSettings()
    49  	setting.LoadDBSetting()
    50  	setting.InitSQLLog(disableConsole)
    51  	if err := db.InitEngine(ctx); err != nil {
    52  		return fmt.Errorf("db.InitEngine: %w", err)
    53  	}
    54  	// some doctor sub-commands need to use git command
    55  	if err := git.InitFull(ctx); err != nil {
    56  		return fmt.Errorf("git.InitFull: %w", err)
    57  	}
    58  	return nil
    59  }
    60  
    61  // Checks is the list of available commands
    62  var Checks []*Check
    63  
    64  // RunChecks runs the doctor checks for the provided list
    65  func RunChecks(ctx context.Context, logger log.Logger, autofix bool, checks []*Check) error {
    66  	wrappedLogger := log.LevelLoggerLogger{
    67  		LevelLogger: &wrappedLevelLogger{logger},
    68  	}
    69  
    70  	dbIsInit := false
    71  	for i, check := range checks {
    72  		if !dbIsInit && !check.SkipDatabaseInitialization {
    73  			// Only open database after the most basic configuration check
    74  			setting.Log.EnableXORMLog = false
    75  			if err := initDBDisableConsole(ctx, true); err != nil {
    76  				logger.Error("Error whilst initializing the database: %v", err)
    77  				logger.Error("Check if you are using the right config file. You can use a --config directive to specify one.")
    78  				return nil
    79  			}
    80  			dbIsInit = true
    81  		}
    82  		logger.Info("[%d] %s", log.NewColoredIDValue(i+1), check.Title)
    83  		logger.Flush()
    84  		if err := check.Run(ctx, &wrappedLogger, autofix); err != nil {
    85  			if check.AbortIfFailed {
    86  				logger.Critical("FAIL")
    87  				return err
    88  			}
    89  			logger.Error("ERROR")
    90  		} else {
    91  			logger.Info("OK")
    92  			logger.Flush()
    93  		}
    94  	}
    95  	return nil
    96  }
    97  
    98  // Register registers a command with the list
    99  func Register(command *Check) {
   100  	Checks = append(Checks, command)
   101  	sort.SliceStable(Checks, func(i, j int) bool {
   102  		if Checks[i].Priority == Checks[j].Priority {
   103  			return Checks[i].Name < Checks[j].Name
   104  		}
   105  		if Checks[i].Priority == 0 {
   106  			return false
   107  		}
   108  		return Checks[i].Priority < Checks[j].Priority
   109  	})
   110  }