From 64f2b8a17c1e1118fc1a98726bfdfc09a4b4b6c7 Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Sat, 12 Nov 2022 18:42:39 +0000 Subject: [PATCH 1/4] Adjust doctor command format and options The gitea doctor command is a little weird especially since the recreate-table subcommand. This PR changes the doctor command to be an empty subcommand and adds `gitea doctor check` subcommand. In this subcommand the requested checks are provided as an argument rather than as options. The logging is also changed so that the doctor.log is not provided by default - instead that will only be created if you set `--log-file` option. `--verbose` is provided to output this logging to stdout. `gitea convert` is also moved to be a subcommand as `gitea doctor convert`. Signed-off-by: Andrew Thornton --- cmd/convert.go | 11 + cmd/doctor.go | 267 +++++++++++-------- docs/content/doc/usage/command-line.en-us.md | 40 ++- 3 files changed, 179 insertions(+), 139 deletions(-) diff --git a/cmd/convert.go b/cmd/convert.go index 6d4d99a255040..0383fdbba7b52 100644 --- a/cmd/convert.go +++ b/cmd/convert.go @@ -15,11 +15,22 @@ import ( ) // CmdConvert represents the available convert sub-command. +// +// Deprecated: Remove in 1.20 var CmdConvert = cli.Command{ Name: "convert", Usage: "Convert the database", Description: "A command to convert an existing MySQL database from utf8 to utf8mb4", Action: runConvert, + Hidden: true, +} + +// CmdDoctorConvert represents the available convert sub-command. +var CmdDoctorConvert = cli.Command{ + Name: "convert", + Usage: "Convert the database", + Description: "A command to convert an existing MySQL database from utf8 to utf8mb4", + Action: runConvert, } func runConvert(ctx *cli.Context) error { diff --git a/cmd/doctor.go b/cmd/doctor.go index d05a0a98d7aeb..c8bcf9d4764cb 100644 --- a/cmd/doctor.go +++ b/cmd/doctor.go @@ -7,6 +7,7 @@ package cmd import ( "errors" "fmt" + "io" golog "log" "os" "strings" @@ -27,40 +28,11 @@ import ( var CmdDoctor = cli.Command{ Name: "doctor", Usage: "Diagnose and optionally fix problems", - 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.", - Action: runDoctor, - Flags: []cli.Flag{ - cli.BoolFlag{ - Name: "list", - Usage: "List the available checks", - }, - cli.BoolFlag{ - Name: "default", - Usage: "Run the default checks (if neither --run or --all is set, this is the default behaviour)", - }, - cli.StringSliceFlag{ - Name: "run", - Usage: "Run the provided checks - (if --default is set, the default checks will also run)", - }, - cli.BoolFlag{ - Name: "all", - Usage: "Run all the available checks", - }, - cli.BoolFlag{ - Name: "fix", - Usage: "Automatically fix what we can", - }, - cli.StringFlag{ - Name: "log-file", - Usage: `Name of the log file (default: "doctor.log"). Set to "-" to output to stdout, set to "" to disable`, - }, - cli.BoolFlag{ - Name: "color, H", - Usage: "Use color for outputted information", - }, - }, + Description: "Helper commands 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.", Subcommands: []cli.Command{ + cmdDoctorCheck, cmdRecreateTable, + CmdConvert, }, } @@ -82,6 +54,142 @@ You should back-up your database before doing this and ensure that your database Action: runRecreateTable, } +var cmdDoctorCheck = cli.Command{ + Name: "check", + Usage: "Runs doctor check(s)", + ArgsUsage: "[check-name]... : check(s) to run - leave blank to just run the default checks.\n\n", + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "fix", + Usage: "Automatically fix what we can", + }, + cli.StringFlag{ + Name: "log-file", + Usage: `Name of the log file (if empty defaults to: "doctor.log"). Set to "-" to output to stdout, leave unset to not run logs`, + }, + cli.BoolFlag{ + Name: "color, H", + Usage: "Use color for outputted information", + }, + cli.BoolFlag{ + Name: "verbose, V", + Usage: "log to stdout, (shorthand for --log-file=-", + }, + }, + Action: runDoctorCheck, +} + +func init() { + sb := new(strings.Builder) + writeChecks(sb) + + CmdDoctor.Subcommands[0].ArgsUsage += sb.String() +} + +func writeChecks(sb io.Writer) { + _, _ = sb.Write([]byte("CHECKS:\n")) + w := tabwriter.NewWriter(sb, 0, 8, 1, ' ', 0) + _, _ = w.Write([]byte(" \tlist\tPrints list of available checks\n")) + _, _ = w.Write([]byte(" \tall\tRuns all available checks\n")) + _, _ = w.Write([]byte(" \tdefault\tRuns checks marked with (*) below\n")) + for _, check := range doctor.Checks { + _, _ = w.Write([]byte(" \t")) + _, _ = w.Write([]byte(check.Name)) + _, _ = w.Write([]byte{'\t'}) + if check.IsDefault { + _, _ = w.Write([]byte("(*) ")) + } + _, _ = w.Write([]byte(check.Title)) + _, _ = w.Write([]byte{'\n'}) + } + _ = w.Flush() +} + +func runDoctorCheck(ctx *cli.Context) error { + stdCtx, cancel := installSignals() + defer cancel() + + // Silence the default loggers + log.DelNamedLogger("console") + log.DelNamedLogger(log.DEFAULT) + + // Now setup our logger + setDoctorLogger(ctx) + + colorize := log.CanColorStdout + if ctx.IsSet("color") { + colorize = ctx.Bool("color") + } + + // Finally redirect the default golog to here + golog.SetFlags(0) + golog.SetPrefix("") + golog.SetOutput(log.NewLoggerAsWriter("INFO", log.GetLogger(log.DEFAULT))) + + // Now we can set up our own logger to return information about what the doctor is doing + if err := log.NewNamedLogger("doctorouter", + 0, + "console", + "console", + fmt.Sprintf(`{"level":"INFO","stacktracelevel":"NONE","colorize":%t,"flags":-1}`, colorize)); err != nil { + fmt.Println(err) + return err + } + + logger := log.GetLogger("doctorouter") + defer logger.Close() + + var checks []*doctor.Check + if ctx.NArg() > 0 { + names := make([]string, 0, ctx.NArg()) + args := ctx.Args() + for i := 0; i < ctx.NArg(); i++ { + names = append(names, args.Get(i)) + } + + addDefault := false + all := false + for i, name := range names { + names[i] = strings.ToLower(strings.TrimSpace(name)) + switch names[i] { + case "default": + addDefault = true + case "list": + sb := new(strings.Builder) + writeChecks(sb) + logger.Info("%s", log.NewColoredValue(sb.String(), log.Reset)) + case "all": + all = true + } + } + + if all { + checks = doctor.Checks + } else { + for _, check := range doctor.Checks { + if addDefault && check.IsDefault { + checks = append(checks, check) + continue + } + for _, name := range names { + if name == check.Name { + checks = append(checks, check) + break + } + } + } + } + } else { + for _, check := range doctor.Checks { + if check.IsDefault { + checks = append(checks, check) + } + } + } + + return doctor.RunChecks(stdCtx, logger, ctx.Bool("fix"), checks) +} + func runRecreateTable(ctx *cli.Context) error { // Redirect the default golog to here golog.SetFlags(0) @@ -127,8 +235,17 @@ func runRecreateTable(ctx *cli.Context) error { func setDoctorLogger(ctx *cli.Context) { logFile := ctx.String("log-file") - if !ctx.IsSet("log-file") { - logFile = "doctor.log" + if ctx.IsSet("log-file") { + if logFile == "" { + // verbose is set and log-file="" then assume that we mean --log-file=- + if ctx.Bool("verbose") { + logFile = "-" + } else { + logFile = "doctor.log" + } + } + } else if ctx.Bool("verbose") { + logFile = "-" } colorize := log.CanColorStdout if ctx.IsSet("color") { @@ -165,85 +282,3 @@ func setDoctorLogger(ctx *cli.Context) { log.NewLogger(1000, "doctor", "file", fmt.Sprintf(`{"filename":%q,"level":"trace","stacktracelevel":"NONE"}`, logFile)) } } - -func runDoctor(ctx *cli.Context) error { - stdCtx, cancel := installSignals() - defer cancel() - - // Silence the default loggers - log.DelNamedLogger("console") - log.DelNamedLogger(log.DEFAULT) - - // Now setup our own - setDoctorLogger(ctx) - - colorize := log.CanColorStdout - if ctx.IsSet("color") { - colorize = ctx.Bool("color") - } - - // Finally redirect the default golog to here - golog.SetFlags(0) - golog.SetPrefix("") - golog.SetOutput(log.NewLoggerAsWriter("INFO", log.GetLogger(log.DEFAULT))) - - if ctx.IsSet("list") { - w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0) - _, _ = w.Write([]byte("Default\tName\tTitle\n")) - for _, check := range doctor.Checks { - if check.IsDefault { - _, _ = w.Write([]byte{'*'}) - } - _, _ = w.Write([]byte{'\t'}) - _, _ = w.Write([]byte(check.Name)) - _, _ = w.Write([]byte{'\t'}) - _, _ = w.Write([]byte(check.Title)) - _, _ = w.Write([]byte{'\n'}) - } - return w.Flush() - } - - var checks []*doctor.Check - if ctx.Bool("all") { - checks = doctor.Checks - } else if ctx.IsSet("run") { - addDefault := ctx.Bool("default") - names := ctx.StringSlice("run") - for i, name := range names { - names[i] = strings.ToLower(strings.TrimSpace(name)) - } - - for _, check := range doctor.Checks { - if addDefault && check.IsDefault { - checks = append(checks, check) - continue - } - for _, name := range names { - if name == check.Name { - checks = append(checks, check) - break - } - } - } - } else { - for _, check := range doctor.Checks { - if check.IsDefault { - checks = append(checks, check) - } - } - } - - // Now we can set up our own logger to return information about what the doctor is doing - if err := log.NewNamedLogger("doctorouter", - 0, - "console", - "console", - fmt.Sprintf(`{"level":"INFO","stacktracelevel":"NONE","colorize":%t,"flags":-1}`, colorize)); err != nil { - fmt.Println(err) - return err - } - - logger := log.GetLogger("doctorouter") - defer logger.Close() - return doctor.RunChecks(stdCtx, logger, ctx.Bool("fix"), checks) -} diff --git a/docs/content/doc/usage/command-line.en-us.md b/docs/content/doc/usage/command-line.en-us.md index 5f05bc4c3be3e..b80a880dc1fbf 100644 --- a/docs/content/doc/usage/command-line.en-us.md +++ b/docs/content/doc/usage/command-line.en-us.md @@ -369,33 +369,23 @@ This command is idempotent. ### convert -Converts an existing MySQL database from utf8 to utf8mb4. +(DEPRECATED: moved to doctor convert in 1.19) Converts an existing MySQL database from utf8 to utf8mb4. + ### doctor -Diagnose the problems of current Gitea instance according the given configuration. -Currently there are a check list below: - -- Check if OpenSSH authorized_keys file id correct - When your Gitea instance support OpenSSH, your Gitea instance binary path will be written to `authorized_keys` - when there is any public key added or changed on your Gitea instance. - Sometimes if you moved or renamed your Gitea binary when upgrade and you haven't run `Update the '.ssh/authorized_keys' file with Gitea SSH keys. (Not needed for the built-in SSH server.)` on your Admin Panel. Then all pull/push via SSH will not be work. - This check will help you to check if it works well. - -For contributors, if you want to add more checks, you can wrie ad new function like `func(ctx *cli.Context) ([]string, error)` and -append it to `doctor.go`. - -```go -var checklist = []check{ - { - title: "Check if OpenSSH authorized_keys file id correct", - f: runDoctorLocationMoved, - }, - // more checks please append here -} -``` +Provides sub-commands that can fix problems with the current Gitea instance. + +### doctor check + +Diagnose and potentially fix problems with the current Gitea instance. Several checks are run by default, but additional ones can be run: -This function will receive a command line context and return a list of details about the problems or error. +- `gitea doctor check list` - will list all the available checks +- `gitea doctor check all` - will run all available checks +- `gitea doctor check default` - will run the default checks +- `gitea doctor check [check(s)]...` - will run the named checks + +Some problems can be automatically fixed by passing the `--fix` option. Extra logging can be set with `--log-file=...` or `--verbose`. #### doctor recreate-table @@ -427,6 +417,10 @@ gitea doctor recreate-table It is highly recommended to back-up your database before running these commands. +### doctor convert + +Converts an existing MySQL database from utf8 to utf8mb4. + ### manager Manage running server operations: From 15c676bd37361c2b3460de464cad5b394b68ce65 Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Sat, 12 Nov 2022 18:57:10 +0000 Subject: [PATCH 2/4] placate the linter Signed-off-by: Andrew Thornton --- docs/content/doc/usage/command-line.en-us.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/content/doc/usage/command-line.en-us.md b/docs/content/doc/usage/command-line.en-us.md index b80a880dc1fbf..ed5fa06735cb1 100644 --- a/docs/content/doc/usage/command-line.en-us.md +++ b/docs/content/doc/usage/command-line.en-us.md @@ -371,7 +371,6 @@ This command is idempotent. (DEPRECATED: moved to doctor convert in 1.19) Converts an existing MySQL database from utf8 to utf8mb4. - ### doctor Provides sub-commands that can fix problems with the current Gitea instance. From 8c3b76159b753344acc9a677bca765a3b6f1a61c Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Wed, 16 Nov 2022 19:59:46 +0000 Subject: [PATCH 3/4] placate lint Signed-off-by: Andrew Thornton --- cmd/convert.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/convert.go b/cmd/convert.go index 0383fdbba7b52..42765f83a0f5a 100644 --- a/cmd/convert.go +++ b/cmd/convert.go @@ -16,7 +16,7 @@ import ( // CmdConvert represents the available convert sub-command. // -// Deprecated: Remove in 1.20 +// FIXME: DEPRECATED: Remove in 1.20 var CmdConvert = cli.Command{ Name: "convert", Usage: "Convert the database", From 18f2eb8e51a710b2b79b355ab80aea1c8a21be2f Mon Sep 17 00:00:00 2001 From: zeripath Date: Mon, 6 Feb 2023 09:28:14 +0000 Subject: [PATCH 4/4] Update docs/content/doc/usage/command-line.en-us.md --- docs/content/doc/usage/command-line.en-us.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/doc/usage/command-line.en-us.md b/docs/content/doc/usage/command-line.en-us.md index ed5fa06735cb1..414c2dd00f207 100644 --- a/docs/content/doc/usage/command-line.en-us.md +++ b/docs/content/doc/usage/command-line.en-us.md @@ -369,7 +369,7 @@ This command is idempotent. ### convert -(DEPRECATED: moved to doctor convert in 1.19) Converts an existing MySQL database from utf8 to utf8mb4. +(DEPRECATED: from 1.19 use `gitea doctor convert` instead.) Converts an existing MySQL database from utf8 to utf8mb4. ### doctor