mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-11-04 08:21:11 +00:00 
			
		
		
		
	urfave/cli v2 will eventually become unmaintained, switch over to v3 which is the latest supported version. Note: the `docs` command would be a lot of work to restore with v3 ([the package is still in alpha](https://github.com/urfave/cli-docs)) An alternative to avoid a breaking change would be to not upgrade from v2 to v3 for that reason alone. Note: these commits were cherry-picked from https://code.forgejo.org/forgefriends/forgefriends Note: it is best reviewed side by side with no display of whitespace changes (there are a lot of those when converting vars to func). - a few functional changes were necessary and are noted in context in the file changes tab - https://cli.urfave.org/migrate-v2-to-v3/ upgrade instructions were followed in the most minimal way possible - upgrade gof3 to v3.10.8 which includes and upgrade from urfave/cli v2 to urfave/cli v3 - upgrade gitlab.com/gitlab-org/api/client-go v0.129.0 because it is an indirect dependency of gof3 and requires a change because of a deprecated field that otherwise triggers a lint error but nothing else otherwise - verified that the [script](https://codeberg.org/forgejo/docs/src/branch/next/scripts/cli-docs.sh) that generates the [CLI documentation](https://codeberg.org/forgejo/docs/src/branch/next/scripts/cli-docs.sh) still works. There are cosmetic differences and the **help** subcommand is no longer advertised (although it is still supported) but the `--help` option is advertised as expected so it is fine. - end-to-end tests [passed](https://code.forgejo.org/forgejo/end-to-end/pulls/667) (they use the Forgejo CLI to some extent) ## Checklist The [contributor guide](https://forgejo.org/docs/next/contributor/) contains information that will be helpful to first time contributors. There also are a few [conditions for merging Pull Requests in Forgejo repositories](https://codeberg.org/forgejo/governance/src/branch/main/PullRequestsAgreement.md). You are also welcome to join the [Forgejo development chatroom](https://matrix.to/#/#forgejo-development:matrix.org). ### Tests - I added test coverage for Go changes... - [ ] in their respective `*_test.go` for unit tests. - [ ] in the `tests/integration` directory if it involves interactions with a live Forgejo server. - I added test coverage for JavaScript changes... - [ ] in `web_src/js/*.test.js` if it can be unit tested. - [ ] in `tests/e2e/*.test.e2e.js` if it requires interactions with a live Forgejo server (see also the [developer guide for JavaScript testing](https://codeberg.org/forgejo/forgejo/src/branch/forgejo/tests/e2e/README.md#end-to-end-tests)). ### Documentation - [ ] I created a pull request [to the documentation](https://codeberg.org/forgejo/docs) to explain to Forgejo users how to use this change. - [x] I did not document these changes and I do not expect someone else to do it. ### Release notes - [ ] I do not want this change to show in the release notes. - [ ] I want the title to show in the release notes with a link to this pull request. - [x] I want the content of the `release-notes/<pull request number>.md` to be be used for the release notes instead of the title. <!--start release-notes-assistant--> ## Release notes <!--URL:https://codeberg.org/forgejo/forgejo--> - Breaking features - [PR](https://codeberg.org/forgejo/forgejo/pulls/8035): <!--number 8035 --><!--line 0 --><!--description VGhlIGBmb3JnZWpvIGRvY3NgIGNvbW1hbmQgaXMgZGVwcmVjYXRlZCBhbmQgQ0xJIGVycm9ycyBhcmUgbm93IGRpc3BsYXllZCBvbiBzdGRlcnIgaW5zdGVhZCBvZiBzdGRvdXQuIFRoZXNlIGJyZWFraW5nIGNoYW5nZXMgaGFwcGVuZWQgYmVjYXVzZSB0aGUgcGFja2FnZSB1c2VkIHRvIHBhcnNlIHRoZSBjb21tYW5kIGxpbmUgYXJndW1lbnRzIHdhcyBbdXBncmFkZWQgZnJvbSB2MiB0byB2M10oaHR0cHM6Ly9jbGkudXJmYXZlLm9yZy9taWdyYXRlLXYyLXRvLXYzLykuIEEgW3NlcGFyYXRlIHByb2plY3Qgd2FzIGluaXRpYXRlZF0oaHR0cHM6Ly9naXRodWIuY29tL3VyZmF2ZS9jbGktZG9jcykgdG8gcmUtaW1wbGVtZW50IHRoZSBgZG9jc2AgY29tbWFuZCwgYnV0IGl0IGlzIG5vdCB5ZXQgcHJvZHVjdGlvbiByZWFkeS4=-->The `forgejo docs` command is deprecated and CLI errors are now displayed on stderr instead of stdout. These breaking changes happened because the package used to parse the command line arguments was [upgraded from v2 to v3](https://cli.urfave.org/migrate-v2-to-v3/). A [separate project was initiated](https://github.com/urfave/cli-docs) to re-implement the `docs` command, but it is not yet production ready.<!--description--> <!--end release-notes-assistant--> Co-authored-by: limiting-factor <limiting-factor@posteo.com> Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/8035 Reviewed-by: Gusted <gusted@noreply.codeberg.org>
		
			
				
	
	
		
			350 lines
		
	
	
	
		
			8.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			350 lines
		
	
	
	
		
			8.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2022 The Gitea Authors. All rights reserved.
 | 
						|
// SPDX-License-Identifier: MIT
 | 
						|
 | 
						|
package cmd
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"errors"
 | 
						|
	"fmt"
 | 
						|
	"os"
 | 
						|
 | 
						|
	"forgejo.org/modules/log"
 | 
						|
	"forgejo.org/modules/private"
 | 
						|
 | 
						|
	"github.com/urfave/cli/v3"
 | 
						|
)
 | 
						|
 | 
						|
func defaultLoggingFlags() []cli.Flag {
 | 
						|
	return []cli.Flag{
 | 
						|
		&cli.StringFlag{
 | 
						|
			Name:  "logger",
 | 
						|
			Usage: `Logger name - will default to "default"`,
 | 
						|
		},
 | 
						|
		&cli.StringFlag{
 | 
						|
			Name:  "writer",
 | 
						|
			Usage: "Name of the log writer - will default to mode",
 | 
						|
		},
 | 
						|
		&cli.StringFlag{
 | 
						|
			Name:  "level",
 | 
						|
			Usage: "Logging level for the new logger",
 | 
						|
		},
 | 
						|
		&cli.StringFlag{
 | 
						|
			Name:    "stacktrace-level",
 | 
						|
			Aliases: []string{"L"},
 | 
						|
			Usage:   "Stacktrace logging level",
 | 
						|
		},
 | 
						|
		&cli.StringFlag{
 | 
						|
			Name:    "flags",
 | 
						|
			Aliases: []string{"F"},
 | 
						|
			Usage:   "Flags for the logger",
 | 
						|
		},
 | 
						|
		&cli.StringFlag{
 | 
						|
			Name:    "expression",
 | 
						|
			Aliases: []string{"e"},
 | 
						|
			Usage:   "Matching expression for the logger",
 | 
						|
		},
 | 
						|
		&cli.StringFlag{
 | 
						|
			Name:    "prefix",
 | 
						|
			Aliases: []string{"p"},
 | 
						|
			Usage:   "Prefix for the logger",
 | 
						|
		},
 | 
						|
		&cli.BoolFlag{
 | 
						|
			Name:  "color",
 | 
						|
			Usage: "Use color in the logs",
 | 
						|
		},
 | 
						|
		&cli.BoolFlag{
 | 
						|
			Name: "debug",
 | 
						|
		},
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func subcmdLogging() *cli.Command {
 | 
						|
	return &cli.Command{
 | 
						|
		Name:  "logging",
 | 
						|
		Usage: "Adjust logging commands",
 | 
						|
		Commands: []*cli.Command{
 | 
						|
			{
 | 
						|
				Name:  "pause",
 | 
						|
				Usage: "Pause logging (Forgejo will buffer logs up to a certain point and will drop them after that point)",
 | 
						|
				Flags: []cli.Flag{
 | 
						|
					&cli.BoolFlag{
 | 
						|
						Name: "debug",
 | 
						|
					},
 | 
						|
				},
 | 
						|
				Action: runPauseLogging,
 | 
						|
			}, {
 | 
						|
				Name:  "resume",
 | 
						|
				Usage: "Resume logging",
 | 
						|
				Flags: []cli.Flag{
 | 
						|
					&cli.BoolFlag{
 | 
						|
						Name: "debug",
 | 
						|
					},
 | 
						|
				},
 | 
						|
				Action: runResumeLogging,
 | 
						|
			}, {
 | 
						|
				Name:  "release-and-reopen",
 | 
						|
				Usage: "Cause Forgejo to release and re-open files used for logging",
 | 
						|
				Flags: []cli.Flag{
 | 
						|
					&cli.BoolFlag{
 | 
						|
						Name: "debug",
 | 
						|
					},
 | 
						|
				},
 | 
						|
				Action: runReleaseReopenLogging,
 | 
						|
			}, {
 | 
						|
				Name:      "remove",
 | 
						|
				Usage:     "Remove a logger",
 | 
						|
				ArgsUsage: "[name] Name of logger to remove",
 | 
						|
				Flags: []cli.Flag{
 | 
						|
					&cli.BoolFlag{
 | 
						|
						Name: "debug",
 | 
						|
					}, &cli.StringFlag{
 | 
						|
						Name:  "logger",
 | 
						|
						Usage: `Logger name - will default to "default"`,
 | 
						|
					},
 | 
						|
				},
 | 
						|
				Action: runRemoveLogger,
 | 
						|
			}, {
 | 
						|
				Name:  "add",
 | 
						|
				Usage: "Add a logger",
 | 
						|
				Commands: []*cli.Command{
 | 
						|
					{
 | 
						|
						Name:  "file",
 | 
						|
						Usage: "Add a file logger",
 | 
						|
						Flags: append(defaultLoggingFlags(), []cli.Flag{
 | 
						|
							&cli.StringFlag{
 | 
						|
								Name:    "filename",
 | 
						|
								Aliases: []string{"f"},
 | 
						|
								Usage:   "Filename for the logger - this must be set.",
 | 
						|
							},
 | 
						|
							&cli.BoolFlag{
 | 
						|
								Name:    "rotate",
 | 
						|
								Aliases: []string{"r"},
 | 
						|
								Usage:   "Rotate logs",
 | 
						|
								Value:   true,
 | 
						|
							},
 | 
						|
							&cli.Int64Flag{
 | 
						|
								Name:    "max-size",
 | 
						|
								Aliases: []string{"s"},
 | 
						|
								Usage:   "Maximum size in bytes before rotation",
 | 
						|
							},
 | 
						|
							&cli.BoolFlag{
 | 
						|
								Name:    "daily",
 | 
						|
								Aliases: []string{"d"},
 | 
						|
								Usage:   "Rotate logs daily",
 | 
						|
								Value:   true,
 | 
						|
							},
 | 
						|
							&cli.IntFlag{
 | 
						|
								Name:    "max-days",
 | 
						|
								Aliases: []string{"D"},
 | 
						|
								Usage:   "Maximum number of daily logs to keep",
 | 
						|
							},
 | 
						|
							&cli.BoolFlag{
 | 
						|
								Name:    "compress",
 | 
						|
								Aliases: []string{"z"},
 | 
						|
								Usage:   "Compress rotated logs",
 | 
						|
								Value:   true,
 | 
						|
							},
 | 
						|
							&cli.IntFlag{
 | 
						|
								Name:    "compression-level",
 | 
						|
								Aliases: []string{"Z"},
 | 
						|
								Usage:   "Compression level to use",
 | 
						|
							},
 | 
						|
						}...),
 | 
						|
						Action: runAddFileLogger,
 | 
						|
					}, {
 | 
						|
						Name:  "conn",
 | 
						|
						Usage: "Add a net conn logger",
 | 
						|
						Flags: append(defaultLoggingFlags(), []cli.Flag{
 | 
						|
							&cli.BoolFlag{
 | 
						|
								Name:    "reconnect-on-message",
 | 
						|
								Aliases: []string{"R"},
 | 
						|
								Usage:   "Reconnect to host for every message",
 | 
						|
							},
 | 
						|
							&cli.BoolFlag{
 | 
						|
								Name:    "reconnect",
 | 
						|
								Aliases: []string{"r"},
 | 
						|
								Usage:   "Reconnect to host when connection is dropped",
 | 
						|
							},
 | 
						|
							&cli.StringFlag{
 | 
						|
								Name:    "protocol",
 | 
						|
								Aliases: []string{"P"},
 | 
						|
								Usage:   "Set protocol to use: tcp, unix, or udp (defaults to tcp)",
 | 
						|
							},
 | 
						|
							&cli.StringFlag{
 | 
						|
								Name:    "address",
 | 
						|
								Aliases: []string{"a"},
 | 
						|
								Usage:   "Host address and port to connect to (defaults to :7020)",
 | 
						|
							},
 | 
						|
						}...),
 | 
						|
						Action: runAddConnLogger,
 | 
						|
					},
 | 
						|
				},
 | 
						|
			}, {
 | 
						|
				Name:  "log-sql",
 | 
						|
				Usage: "Set LogSQL",
 | 
						|
				Flags: []cli.Flag{
 | 
						|
					&cli.BoolFlag{
 | 
						|
						Name: "debug",
 | 
						|
					},
 | 
						|
					&cli.BoolFlag{
 | 
						|
						Name:  "off",
 | 
						|
						Usage: "Switch off SQL logging",
 | 
						|
					},
 | 
						|
				},
 | 
						|
				Action: runSetLogSQL,
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func runRemoveLogger(ctx context.Context, c *cli.Command) error {
 | 
						|
	ctx, cancel := installSignals(ctx)
 | 
						|
	defer cancel()
 | 
						|
 | 
						|
	setup(ctx, c.Bool("debug"), false)
 | 
						|
	logger := c.String("logger")
 | 
						|
	if len(logger) == 0 {
 | 
						|
		logger = log.DEFAULT
 | 
						|
	}
 | 
						|
	writer := c.Args().First()
 | 
						|
 | 
						|
	extra := private.RemoveLogger(ctx, logger, writer)
 | 
						|
	return handleCliResponseExtra(extra)
 | 
						|
}
 | 
						|
 | 
						|
func runAddConnLogger(ctx context.Context, c *cli.Command) error {
 | 
						|
	ctx, cancel := installSignals(ctx)
 | 
						|
	defer cancel()
 | 
						|
 | 
						|
	setup(ctx, c.Bool("debug"), false)
 | 
						|
	vals := map[string]any{}
 | 
						|
	mode := "conn"
 | 
						|
	vals["net"] = "tcp"
 | 
						|
	if c.IsSet("protocol") {
 | 
						|
		switch c.String("protocol") {
 | 
						|
		case "udp":
 | 
						|
			vals["net"] = "udp"
 | 
						|
		case "unix":
 | 
						|
			vals["net"] = "unix"
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if c.IsSet("address") {
 | 
						|
		vals["address"] = c.String("address")
 | 
						|
	} else {
 | 
						|
		vals["address"] = ":7020"
 | 
						|
	}
 | 
						|
	if c.IsSet("reconnect") {
 | 
						|
		vals["reconnect"] = c.Bool("reconnect")
 | 
						|
	}
 | 
						|
	if c.IsSet("reconnect-on-message") {
 | 
						|
		vals["reconnectOnMsg"] = c.Bool("reconnect-on-message")
 | 
						|
	}
 | 
						|
	return commonAddLogger(ctx, c, mode, vals)
 | 
						|
}
 | 
						|
 | 
						|
func runAddFileLogger(ctx context.Context, c *cli.Command) error {
 | 
						|
	ctx, cancel := installSignals(ctx)
 | 
						|
	defer cancel()
 | 
						|
 | 
						|
	setup(ctx, c.Bool("debug"), false)
 | 
						|
	vals := map[string]any{}
 | 
						|
	mode := "file"
 | 
						|
	if c.IsSet("filename") {
 | 
						|
		vals["filename"] = c.String("filename")
 | 
						|
	} else {
 | 
						|
		return errors.New("filename must be set when creating a file logger")
 | 
						|
	}
 | 
						|
	if c.IsSet("rotate") {
 | 
						|
		vals["rotate"] = c.Bool("rotate")
 | 
						|
	}
 | 
						|
	if c.IsSet("max-size") {
 | 
						|
		vals["maxsize"] = c.Int64("max-size")
 | 
						|
	}
 | 
						|
	if c.IsSet("daily") {
 | 
						|
		vals["daily"] = c.Bool("daily")
 | 
						|
	}
 | 
						|
	if c.IsSet("max-days") {
 | 
						|
		vals["maxdays"] = c.Int("max-days")
 | 
						|
	}
 | 
						|
	if c.IsSet("compress") {
 | 
						|
		vals["compress"] = c.Bool("compress")
 | 
						|
	}
 | 
						|
	if c.IsSet("compression-level") {
 | 
						|
		vals["compressionLevel"] = c.Int("compression-level")
 | 
						|
	}
 | 
						|
	return commonAddLogger(ctx, c, mode, vals)
 | 
						|
}
 | 
						|
 | 
						|
func commonAddLogger(ctx context.Context, c *cli.Command, mode string, vals map[string]any) error {
 | 
						|
	if len(c.String("level")) > 0 {
 | 
						|
		vals["level"] = log.LevelFromString(c.String("level")).String()
 | 
						|
	}
 | 
						|
	if len(c.String("stacktrace-level")) > 0 {
 | 
						|
		vals["stacktraceLevel"] = log.LevelFromString(c.String("stacktrace-level")).String()
 | 
						|
	}
 | 
						|
	if len(c.String("expression")) > 0 {
 | 
						|
		vals["expression"] = c.String("expression")
 | 
						|
	}
 | 
						|
	if len(c.String("prefix")) > 0 {
 | 
						|
		vals["prefix"] = c.String("prefix")
 | 
						|
	}
 | 
						|
	if len(c.String("flags")) > 0 {
 | 
						|
		vals["flags"] = log.FlagsFromString(c.String("flags"))
 | 
						|
	}
 | 
						|
	if c.IsSet("color") {
 | 
						|
		vals["colorize"] = c.Bool("color")
 | 
						|
	}
 | 
						|
	logger := log.DEFAULT
 | 
						|
	if c.IsSet("logger") {
 | 
						|
		logger = c.String("logger")
 | 
						|
	}
 | 
						|
	writer := mode
 | 
						|
	if c.IsSet("writer") {
 | 
						|
		writer = c.String("writer")
 | 
						|
	}
 | 
						|
	ctx, cancel := installSignals(ctx)
 | 
						|
	defer cancel()
 | 
						|
 | 
						|
	extra := private.AddLogger(ctx, logger, writer, mode, vals)
 | 
						|
	return handleCliResponseExtra(extra)
 | 
						|
}
 | 
						|
 | 
						|
func runPauseLogging(ctx context.Context, c *cli.Command) error {
 | 
						|
	ctx, cancel := installSignals(ctx)
 | 
						|
	defer cancel()
 | 
						|
 | 
						|
	setup(ctx, c.Bool("debug"), false)
 | 
						|
	userMsg := private.PauseLogging(ctx)
 | 
						|
	_, _ = fmt.Fprintln(os.Stdout, userMsg)
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func runResumeLogging(ctx context.Context, c *cli.Command) error {
 | 
						|
	ctx, cancel := installSignals(ctx)
 | 
						|
	defer cancel()
 | 
						|
 | 
						|
	setup(ctx, c.Bool("debug"), false)
 | 
						|
	userMsg := private.ResumeLogging(ctx)
 | 
						|
	_, _ = fmt.Fprintln(os.Stdout, userMsg)
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func runReleaseReopenLogging(ctx context.Context, c *cli.Command) error {
 | 
						|
	ctx, cancel := installSignals(ctx)
 | 
						|
	defer cancel()
 | 
						|
 | 
						|
	setup(ctx, c.Bool("debug"), false)
 | 
						|
	userMsg := private.ReleaseReopenLogging(ctx)
 | 
						|
	_, _ = fmt.Fprintln(os.Stdout, userMsg)
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func runSetLogSQL(ctx context.Context, c *cli.Command) error {
 | 
						|
	ctx, cancel := installSignals(ctx)
 | 
						|
	defer cancel()
 | 
						|
	setup(ctx, c.Bool("debug"), false)
 | 
						|
 | 
						|
	extra := private.SetLogSQL(ctx, !c.Bool("off"))
 | 
						|
	return handleCliResponseExtra(extra)
 | 
						|
}
 |