Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

main.go 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. // Copyright 2023 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package cmd
  4. import (
  5. "fmt"
  6. "os"
  7. "strings"
  8. "code.gitea.io/gitea/modules/log"
  9. "code.gitea.io/gitea/modules/setting"
  10. "github.com/urfave/cli/v2"
  11. )
  12. // cmdHelp is our own help subcommand with more information
  13. // Keep in mind that the "./gitea help"(subcommand) is different from "./gitea --help"(flag), the flag doesn't parse the config or output "DEFAULT CONFIGURATION:" information
  14. func cmdHelp() *cli.Command {
  15. c := &cli.Command{
  16. Name: "help",
  17. Aliases: []string{"h"},
  18. Usage: "Shows a list of commands or help for one command",
  19. ArgsUsage: "[command]",
  20. Action: func(c *cli.Context) (err error) {
  21. lineage := c.Lineage() // The order is from child to parent: help, doctor, Gitea, {Command:nil}
  22. targetCmdIdx := 0
  23. if c.Command.Name == "help" {
  24. targetCmdIdx = 1
  25. }
  26. if lineage[targetCmdIdx+1].Command != nil {
  27. err = cli.ShowCommandHelp(lineage[targetCmdIdx+1], lineage[targetCmdIdx].Command.Name)
  28. } else {
  29. err = cli.ShowAppHelp(c)
  30. }
  31. _, _ = fmt.Fprintf(c.App.Writer, `
  32. DEFAULT CONFIGURATION:
  33. AppPath: %s
  34. WorkPath: %s
  35. CustomPath: %s
  36. ConfigFile: %s
  37. `, setting.AppPath, setting.AppWorkPath, setting.CustomPath, setting.CustomConf)
  38. return err
  39. },
  40. }
  41. return c
  42. }
  43. func appGlobalFlags() []cli.Flag {
  44. return []cli.Flag{
  45. // make the builtin flags at the top
  46. cli.HelpFlag,
  47. // shared configuration flags, they are for global and for each sub-command at the same time
  48. // eg: such command is valid: "./gitea --config /tmp/app.ini web --config /tmp/app.ini", while it's discouraged indeed
  49. // keep in mind that the short flags like "-C", "-c" and "-w" are globally polluted, they can't be used for sub-commands anymore.
  50. &cli.StringFlag{
  51. Name: "custom-path",
  52. Aliases: []string{"C"},
  53. Usage: "Set custom path (defaults to '{WorkPath}/custom')",
  54. },
  55. &cli.StringFlag{
  56. Name: "config",
  57. Aliases: []string{"c"},
  58. Value: setting.CustomConf,
  59. Usage: "Set custom config file (defaults to '{WorkPath}/custom/conf/app.ini')",
  60. },
  61. &cli.StringFlag{
  62. Name: "work-path",
  63. Aliases: []string{"w"},
  64. Usage: "Set Gitea's working path (defaults to the Gitea's binary directory)",
  65. },
  66. }
  67. }
  68. func prepareSubcommandWithConfig(command *cli.Command, globalFlags []cli.Flag) {
  69. command.Flags = append(append([]cli.Flag{}, globalFlags...), command.Flags...)
  70. command.Action = prepareWorkPathAndCustomConf(command.Action)
  71. command.HideHelp = true
  72. if command.Name != "help" {
  73. command.Subcommands = append(command.Subcommands, cmdHelp())
  74. }
  75. for i := range command.Subcommands {
  76. prepareSubcommandWithConfig(command.Subcommands[i], globalFlags)
  77. }
  78. }
  79. // prepareWorkPathAndCustomConf wraps the Action to prepare the work path and custom config
  80. // It can't use "Before", because each level's sub-command's Before will be called one by one, so the "init" would be done multiple times
  81. func prepareWorkPathAndCustomConf(action cli.ActionFunc) func(ctx *cli.Context) error {
  82. return func(ctx *cli.Context) error {
  83. var args setting.ArgWorkPathAndCustomConf
  84. // from children to parent, check the global flags
  85. for _, curCtx := range ctx.Lineage() {
  86. if curCtx.IsSet("work-path") && args.WorkPath == "" {
  87. args.WorkPath = curCtx.String("work-path")
  88. }
  89. if curCtx.IsSet("custom-path") && args.CustomPath == "" {
  90. args.CustomPath = curCtx.String("custom-path")
  91. }
  92. if curCtx.IsSet("config") && args.CustomConf == "" {
  93. args.CustomConf = curCtx.String("config")
  94. }
  95. }
  96. setting.InitWorkPathAndCommonConfig(os.Getenv, args)
  97. if ctx.Bool("help") || action == nil {
  98. // the default behavior of "urfave/cli": "nil action" means "show help"
  99. return cmdHelp().Action(ctx)
  100. }
  101. return action(ctx)
  102. }
  103. }
  104. func NewMainApp(version, versionExtra string) *cli.App {
  105. app := cli.NewApp()
  106. app.Name = "Gitea"
  107. app.HelpName = "gitea"
  108. app.Usage = "A painless self-hosted Git service"
  109. app.Description = `Gitea program contains "web" and other subcommands. If no subcommand is given, it starts the web server by default. Use "web" subcommand for more web server arguments, use other subcommands for other purposes.`
  110. app.Version = version + versionExtra
  111. app.EnableBashCompletion = true
  112. // these sub-commands need to use config file
  113. subCmdWithConfig := []*cli.Command{
  114. cmdHelp(), // the "help" sub-command was used to show the more information for "work path" and "custom config"
  115. CmdWeb,
  116. CmdServ,
  117. CmdHook,
  118. CmdKeys,
  119. CmdDump,
  120. CmdAdmin,
  121. CmdMigrate,
  122. CmdDoctor,
  123. CmdManager,
  124. CmdEmbedded,
  125. CmdMigrateStorage,
  126. CmdDumpRepository,
  127. CmdRestoreRepository,
  128. CmdActions,
  129. }
  130. // these sub-commands do not need the config file, and they do not depend on any path or environment variable.
  131. subCmdStandalone := []*cli.Command{
  132. CmdCert,
  133. CmdGenerate,
  134. CmdDocs,
  135. }
  136. app.DefaultCommand = CmdWeb.Name
  137. globalFlags := appGlobalFlags()
  138. app.Flags = append(app.Flags, cli.VersionFlag)
  139. app.Flags = append(app.Flags, globalFlags...)
  140. app.HideHelp = true // use our own help action to show helps (with more information like default config)
  141. app.Before = PrepareConsoleLoggerLevel(log.INFO)
  142. for i := range subCmdWithConfig {
  143. prepareSubcommandWithConfig(subCmdWithConfig[i], globalFlags)
  144. }
  145. app.Commands = append(app.Commands, subCmdWithConfig...)
  146. app.Commands = append(app.Commands, subCmdStandalone...)
  147. return app
  148. }
  149. func RunMainApp(app *cli.App, args ...string) error {
  150. err := app.Run(args)
  151. if err == nil {
  152. return nil
  153. }
  154. if strings.HasPrefix(err.Error(), "flag provided but not defined:") {
  155. // the cli package should already have output the error message, so just exit
  156. cli.OsExiter(1)
  157. return err
  158. }
  159. _, _ = fmt.Fprintf(app.ErrWriter, "Command error: %v\n", err)
  160. cli.OsExiter(1)
  161. return err
  162. }