You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

main.go 6.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Copyright 2016 The Gitea Authors. All rights reserved.
  3. // SPDX-License-Identifier: MIT
  4. // Gitea (git with a cup of tea) is a painless self-hosted Git Service.
  5. package main // import "code.gitea.io/gitea"
  6. import (
  7. "fmt"
  8. "os"
  9. "runtime"
  10. "strings"
  11. "time"
  12. "code.gitea.io/gitea/cmd"
  13. "code.gitea.io/gitea/modules/log"
  14. "code.gitea.io/gitea/modules/setting"
  15. // register supported doc types
  16. _ "code.gitea.io/gitea/modules/markup/asciicast"
  17. _ "code.gitea.io/gitea/modules/markup/console"
  18. _ "code.gitea.io/gitea/modules/markup/csv"
  19. _ "code.gitea.io/gitea/modules/markup/markdown"
  20. _ "code.gitea.io/gitea/modules/markup/orgmode"
  21. "github.com/urfave/cli"
  22. )
  23. var (
  24. // Version holds the current Gitea version
  25. Version = "development"
  26. // Tags holds the build tags used
  27. Tags = ""
  28. // MakeVersion holds the current Make version if built with make
  29. MakeVersion = ""
  30. )
  31. func init() {
  32. setting.AppVer = Version
  33. setting.AppBuiltWith = formatBuiltWith()
  34. setting.AppStartTime = time.Now().UTC()
  35. }
  36. // cmdHelp is our own help subcommand with more information
  37. // test cases:
  38. // ./gitea help
  39. // ./gitea -h
  40. // ./gitea web help
  41. // ./gitea web -h (due to cli lib limitation, this won't call our cmdHelp, so no extra info)
  42. // ./gitea admin
  43. // ./gitea admin help
  44. // ./gitea admin auth help
  45. // ./gitea -c /tmp/app.ini -h
  46. // ./gitea -c /tmp/app.ini help
  47. // ./gitea help -c /tmp/app.ini
  48. // GITEA_WORK_DIR=/tmp ./gitea help
  49. // GITEA_WORK_DIR=/tmp ./gitea help --work-path /tmp/other
  50. // GITEA_WORK_DIR=/tmp ./gitea help --config /tmp/app-other.ini
  51. var cmdHelp = cli.Command{
  52. Name: "help",
  53. Aliases: []string{"h"},
  54. Usage: "Shows a list of commands or help for one command",
  55. ArgsUsage: "[command]",
  56. Action: func(c *cli.Context) (err error) {
  57. args := c.Args()
  58. if args.Present() {
  59. err = cli.ShowCommandHelp(c, args.First())
  60. } else {
  61. err = cli.ShowAppHelp(c)
  62. }
  63. _, _ = fmt.Fprintf(c.App.Writer, `
  64. DEFAULT CONFIGURATION:
  65. AppPath: %s
  66. WorkPath: %s
  67. CustomPath: %s
  68. ConfigFile: %s
  69. `, setting.AppPath, setting.AppWorkPath, setting.CustomPath, setting.CustomConf)
  70. return err
  71. },
  72. }
  73. func main() {
  74. app := cli.NewApp()
  75. app.Name = "Gitea"
  76. app.Usage = "A painless self-hosted Git service"
  77. app.Description = `By default, Gitea will start serving using the web-server with no argument, which can alternatively be run by running the subcommand "web".`
  78. app.Version = Version + formatBuiltWith()
  79. app.EnableBashCompletion = true
  80. // these sub-commands need to use config file
  81. subCmdWithIni := []cli.Command{
  82. cmd.CmdWeb,
  83. cmd.CmdServ,
  84. cmd.CmdHook,
  85. cmd.CmdDump,
  86. cmd.CmdAdmin,
  87. cmd.CmdMigrate,
  88. cmd.CmdKeys,
  89. cmd.CmdConvert,
  90. cmd.CmdDoctor,
  91. cmd.CmdManager,
  92. cmd.CmdEmbedded,
  93. cmd.CmdMigrateStorage,
  94. cmd.CmdDumpRepository,
  95. cmd.CmdRestoreRepository,
  96. cmd.CmdActions,
  97. cmdHelp, // TODO: the "help" sub-command was used to show the more information for "work path" and "custom config", in the future, it should avoid doing so
  98. }
  99. // these sub-commands do not need the config file, and they do not depend on any path or environment variable.
  100. subCmdStandalone := []cli.Command{
  101. cmd.CmdCert,
  102. cmd.CmdGenerate,
  103. cmd.CmdDocs,
  104. }
  105. // shared configuration flags, they are for global and for each sub-command at the same time
  106. // eg: such command is valid: "./gitea --config /tmp/app.ini web --config /tmp/app.ini", while it's discouraged indeed
  107. // keep in mind that the short flags like "-C", "-c" and "-w" are globally polluted, they can't be used for sub-commands anymore.
  108. globalFlags := []cli.Flag{
  109. cli.HelpFlag,
  110. cli.StringFlag{
  111. Name: "custom-path, C",
  112. Usage: "Set custom path (defaults to '{WorkPath}/custom')",
  113. },
  114. cli.StringFlag{
  115. Name: "config, c",
  116. Value: setting.CustomConf,
  117. Usage: "Set custom config file (defaults to '{WorkPath}/custom/conf/app.ini')",
  118. },
  119. cli.StringFlag{
  120. Name: "work-path, w",
  121. Usage: "Set Gitea's working path (defaults to the Gitea's binary directory)",
  122. },
  123. }
  124. // Set the default to be equivalent to cmdWeb and add the default flags
  125. app.Flags = append(app.Flags, globalFlags...)
  126. app.Flags = append(app.Flags, cmd.CmdWeb.Flags...) // TODO: the web flags polluted the global flags, they are not really global flags
  127. app.Action = prepareWorkPathAndCustomConf(cmd.CmdWeb.Action)
  128. app.HideHelp = true // use our own help action to show helps (with more information like default config)
  129. app.Before = cmd.PrepareConsoleLoggerLevel(log.INFO)
  130. for i := range subCmdWithIni {
  131. prepareSubcommands(&subCmdWithIni[i], globalFlags)
  132. }
  133. app.Commands = append(app.Commands, subCmdWithIni...)
  134. app.Commands = append(app.Commands, subCmdStandalone...)
  135. err := app.Run(os.Args)
  136. if err != nil {
  137. _, _ = fmt.Fprintf(app.Writer, "\nFailed to run with %s: %v\n", os.Args, err)
  138. }
  139. log.GetManager().Close()
  140. }
  141. func prepareSubcommands(command *cli.Command, defaultFlags []cli.Flag) {
  142. command.Flags = append(command.Flags, defaultFlags...)
  143. command.Action = prepareWorkPathAndCustomConf(command.Action)
  144. command.HideHelp = true
  145. if command.Name != "help" {
  146. command.Subcommands = append(command.Subcommands, cmdHelp)
  147. }
  148. for i := range command.Subcommands {
  149. prepareSubcommands(&command.Subcommands[i], defaultFlags)
  150. }
  151. }
  152. // prepareWorkPathAndCustomConf wraps the Action to prepare the work path and custom config
  153. // 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
  154. func prepareWorkPathAndCustomConf(action any) func(ctx *cli.Context) error {
  155. return func(ctx *cli.Context) error {
  156. var args setting.ArgWorkPathAndCustomConf
  157. curCtx := ctx
  158. for curCtx != nil {
  159. if curCtx.IsSet("work-path") && args.WorkPath == "" {
  160. args.WorkPath = curCtx.String("work-path")
  161. }
  162. if curCtx.IsSet("custom-path") && args.CustomPath == "" {
  163. args.CustomPath = curCtx.String("custom-path")
  164. }
  165. if curCtx.IsSet("config") && args.CustomConf == "" {
  166. args.CustomConf = curCtx.String("config")
  167. }
  168. curCtx = curCtx.Parent()
  169. }
  170. setting.InitWorkPathAndCommonConfig(os.Getenv, args)
  171. if ctx.Bool("help") || action == nil {
  172. // the default behavior of "urfave/cli": "nil action" means "show help"
  173. return cmdHelp.Action.(func(ctx *cli.Context) error)(ctx)
  174. }
  175. return action.(func(*cli.Context) error)(ctx)
  176. }
  177. }
  178. func formatBuiltWith() string {
  179. version := runtime.Version()
  180. if len(MakeVersion) > 0 {
  181. version = MakeVersion + ", " + runtime.Version()
  182. }
  183. if len(Tags) == 0 {
  184. return " built with " + version
  185. }
  186. return " built with " + version + " : " + strings.ReplaceAll(Tags, " ", ", ")
  187. }