gitea

Зеркало из https://github.com/go-gitea/gitea
Форк
0
/
doctor.go 
219 строк · 6.2 Кб
1
// Copyright 2019 The Gitea Authors. All rights reserved.
2
// SPDX-License-Identifier: MIT
3

4
package cmd
5

6
import (
7
	"fmt"
8
	golog "log"
9
	"os"
10
	"path/filepath"
11
	"strings"
12
	"text/tabwriter"
13

14
	"code.gitea.io/gitea/models/db"
15
	"code.gitea.io/gitea/models/migrations"
16
	migrate_base "code.gitea.io/gitea/models/migrations/base"
17
	"code.gitea.io/gitea/modules/container"
18
	"code.gitea.io/gitea/modules/log"
19
	"code.gitea.io/gitea/modules/setting"
20
	"code.gitea.io/gitea/services/doctor"
21

22
	"github.com/urfave/cli/v2"
23
	"xorm.io/xorm"
24
)
25

26
// CmdDoctor represents the available doctor sub-command.
27
var CmdDoctor = &cli.Command{
28
	Name:        "doctor",
29
	Usage:       "Diagnose and optionally fix problems, convert or re-create database tables",
30
	Description: "A command to diagnose problems with the current Gitea instance according to the given configuration. Some problems can optionally be fixed by modifying the database or data storage.",
31

32
	Subcommands: []*cli.Command{
33
		cmdDoctorCheck,
34
		cmdRecreateTable,
35
		cmdDoctorConvert,
36
	},
37
}
38

39
var cmdDoctorCheck = &cli.Command{
40
	Name:        "check",
41
	Usage:       "Diagnose and optionally fix problems",
42
	Description: "A command to diagnose problems with the current Gitea instance according to the given configuration. Some problems can optionally be fixed by modifying the database or data storage.",
43
	Action:      runDoctorCheck,
44
	Flags: []cli.Flag{
45
		&cli.BoolFlag{
46
			Name:  "list",
47
			Usage: "List the available checks",
48
		},
49
		&cli.BoolFlag{
50
			Name:  "default",
51
			Usage: "Run the default checks (if neither --run or --all is set, this is the default behaviour)",
52
		},
53
		&cli.StringSliceFlag{
54
			Name:  "run",
55
			Usage: "Run the provided checks - (if --default is set, the default checks will also run)",
56
		},
57
		&cli.BoolFlag{
58
			Name:  "all",
59
			Usage: "Run all the available checks",
60
		},
61
		&cli.BoolFlag{
62
			Name:  "fix",
63
			Usage: "Automatically fix what we can",
64
		},
65
		&cli.StringFlag{
66
			Name:  "log-file",
67
			Usage: `Name of the log file (no verbose log output by default). Set to "-" to output to stdout`,
68
		},
69
		&cli.BoolFlag{
70
			Name:    "color",
71
			Aliases: []string{"H"},
72
			Usage:   "Use color for outputted information",
73
		},
74
	},
75
}
76

77
var cmdRecreateTable = &cli.Command{
78
	Name:      "recreate-table",
79
	Usage:     "Recreate tables from XORM definitions and copy the data.",
80
	ArgsUsage: "[TABLE]... : (TABLEs to recreate - leave blank for all)",
81
	Flags: []cli.Flag{
82
		&cli.BoolFlag{
83
			Name:  "debug",
84
			Usage: "Print SQL commands sent",
85
		},
86
	},
87
	Description: `The database definitions Gitea uses change across versions, sometimes changing default values and leaving old unused columns.
88

89
This command will cause Xorm to recreate tables, copying over the data and deleting the old table.
90

91
You should back-up your database before doing this and ensure that your database is up-to-date first.`,
92
	Action: runRecreateTable,
93
}
94

95
func runRecreateTable(ctx *cli.Context) error {
96
	stdCtx, cancel := installSignals()
97
	defer cancel()
98

99
	// Redirect the default golog to here
100
	golog.SetFlags(0)
101
	golog.SetPrefix("")
102
	golog.SetOutput(log.LoggerToWriter(log.GetLogger(log.DEFAULT).Info))
103

104
	debug := ctx.Bool("debug")
105
	setting.MustInstalled()
106
	setting.LoadDBSetting()
107

108
	if debug {
109
		setting.InitSQLLoggersForCli(log.DEBUG)
110
	} else {
111
		setting.InitSQLLoggersForCli(log.INFO)
112
	}
113

114
	setting.Database.LogSQL = debug
115
	if err := db.InitEngine(stdCtx); err != nil {
116
		fmt.Println(err)
117
		fmt.Println("Check if you are using the right config file. You can use a --config directive to specify one.")
118
		return nil
119
	}
120

121
	args := ctx.Args()
122
	names := make([]string, 0, ctx.NArg())
123
	for i := 0; i < ctx.NArg(); i++ {
124
		names = append(names, args.Get(i))
125
	}
126

127
	beans, err := db.NamesToBean(names...)
128
	if err != nil {
129
		return err
130
	}
131
	recreateTables := migrate_base.RecreateTables(beans...)
132

133
	return db.InitEngineWithMigration(stdCtx, func(x *xorm.Engine) error {
134
		if err := migrations.EnsureUpToDate(x); err != nil {
135
			return err
136
		}
137
		return recreateTables(x)
138
	})
139
}
140

141
func setupDoctorDefaultLogger(ctx *cli.Context, colorize bool) {
142
	// Silence the default loggers
143
	setupConsoleLogger(log.FATAL, log.CanColorStderr, os.Stderr)
144

145
	logFile := ctx.String("log-file")
146
	if logFile == "" {
147
		return // if no doctor log-file is set, do not show any log from default logger
148
	} else if logFile == "-" {
149
		setupConsoleLogger(log.TRACE, colorize, os.Stdout)
150
	} else {
151
		logFile, _ = filepath.Abs(logFile)
152
		writeMode := log.WriterMode{Level: log.TRACE, WriterOption: log.WriterFileOption{FileName: logFile}}
153
		writer, err := log.NewEventWriter("console-to-file", "file", writeMode)
154
		if err != nil {
155
			log.FallbackErrorf("unable to create file log writer: %v", err)
156
			return
157
		}
158
		log.GetManager().GetLogger(log.DEFAULT).ReplaceAllWriters(writer)
159
	}
160
}
161

162
func runDoctorCheck(ctx *cli.Context) error {
163
	stdCtx, cancel := installSignals()
164
	defer cancel()
165

166
	colorize := log.CanColorStdout
167
	if ctx.IsSet("color") {
168
		colorize = ctx.Bool("color")
169
	}
170

171
	setupDoctorDefaultLogger(ctx, colorize)
172

173
	// Finally redirect the default golang's log to here
174
	golog.SetFlags(0)
175
	golog.SetPrefix("")
176
	golog.SetOutput(log.LoggerToWriter(log.GetLogger(log.DEFAULT).Info))
177

178
	if ctx.IsSet("list") {
179
		w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0)
180
		_, _ = w.Write([]byte("Default\tName\tTitle\n"))
181
		doctor.SortChecks(doctor.Checks)
182
		for _, check := range doctor.Checks {
183
			if check.IsDefault {
184
				_, _ = w.Write([]byte{'*'})
185
			}
186
			_, _ = w.Write([]byte{'\t'})
187
			_, _ = w.Write([]byte(check.Name))
188
			_, _ = w.Write([]byte{'\t'})
189
			_, _ = w.Write([]byte(check.Title))
190
			_, _ = w.Write([]byte{'\n'})
191
		}
192
		return w.Flush()
193
	}
194

195
	var checks []*doctor.Check
196
	if ctx.Bool("all") {
197
		checks = make([]*doctor.Check, len(doctor.Checks))
198
		copy(checks, doctor.Checks)
199
	} else if ctx.IsSet("run") {
200
		addDefault := ctx.Bool("default")
201
		runNamesSet := container.SetOf(ctx.StringSlice("run")...)
202
		for _, check := range doctor.Checks {
203
			if (addDefault && check.IsDefault) || runNamesSet.Contains(check.Name) {
204
				checks = append(checks, check)
205
				runNamesSet.Remove(check.Name)
206
			}
207
		}
208
		if len(runNamesSet) > 0 {
209
			return fmt.Errorf("unknown checks: %q", strings.Join(runNamesSet.Values(), ","))
210
		}
211
	} else {
212
		for _, check := range doctor.Checks {
213
			if check.IsDefault {
214
				checks = append(checks, check)
215
			}
216
		}
217
	}
218
	return doctor.RunChecks(stdCtx, colorize, ctx.Bool("fix"), checks)
219
}
220

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.