mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-11-02 15:31:03 +00:00
FORGEJO_* environment variables are set to the corresponding GITEA_* variable when the cli starts. This approach is intended to minimize the conflicts on rebase. All occurences of GITEA_* are left untouched in the codebase and they are only changed to FORGEJO_* if exposed to the user. (cherry picked from commite466f9d10e) (cherry picked from commite33e95931b) (cherry picked from commit2cfc6519b7) (cherry picked from commitaf8864373a) (cherry picked from commita0550ff339) (cherry picked from commit24dc0a5191) (cherry picked from commite255eea2b4) (cherry picked from commit0c4f5afa7a) (cherry picked from commit42fce708d0) (cherry picked from commite7278c3c22) (cherry picked from commit0fb9ed7e0e) (cherry picked from commita98308aa4d) (cherry picked from commitb8695fcbe0) (cherry picked from commit4aee8719f5) (cherry picked from commit1c503c1ba7) (cherry picked from commitcf1ed8551e) (cherry picked from commitc52459b088) (cherry picked from commit92cac277b2) (cherry picked from commit2c744f1118) (cherry picked from commit1482cfabe5)
252 lines
7.5 KiB
Go
252 lines
7.5 KiB
Go
// Copyright 2014 The Gogs Authors. All rights reserved.
|
|
// Copyright 2016 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
// Gitea (git with a cup of tea) is a painless self-hosted Git Service.
|
|
package main // import "code.gitea.io/gitea"
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
"time"
|
|
|
|
"code.gitea.io/gitea/cmd"
|
|
"code.gitea.io/gitea/cmd/forgejo"
|
|
"code.gitea.io/gitea/modules/log"
|
|
"code.gitea.io/gitea/modules/setting"
|
|
|
|
// register supported doc types
|
|
_ "code.gitea.io/gitea/modules/markup/asciicast"
|
|
_ "code.gitea.io/gitea/modules/markup/console"
|
|
_ "code.gitea.io/gitea/modules/markup/csv"
|
|
_ "code.gitea.io/gitea/modules/markup/markdown"
|
|
_ "code.gitea.io/gitea/modules/markup/orgmode"
|
|
|
|
"github.com/urfave/cli"
|
|
)
|
|
|
|
var (
|
|
// Version holds the current Gitea version
|
|
Version = "development"
|
|
// Tags holds the build tags used
|
|
Tags = ""
|
|
// MakeVersion holds the current Make version if built with make
|
|
MakeVersion = ""
|
|
)
|
|
|
|
func init() {
|
|
setting.AppVer = Version
|
|
setting.AppBuiltWith = formatBuiltWith()
|
|
setting.AppStartTime = time.Now().UTC()
|
|
}
|
|
|
|
// cmdHelp is our own help subcommand with more information
|
|
// test cases:
|
|
// ./gitea help
|
|
// ./gitea -h
|
|
// ./gitea web help
|
|
// ./gitea web -h (due to cli lib limitation, this won't call our cmdHelp, so no extra info)
|
|
// ./gitea admin
|
|
// ./gitea admin help
|
|
// ./gitea admin auth help
|
|
// ./gitea -c /tmp/app.ini -h
|
|
// ./gitea -c /tmp/app.ini help
|
|
// ./gitea help -c /tmp/app.ini
|
|
// GITEA_WORK_DIR=/tmp ./gitea help
|
|
// GITEA_WORK_DIR=/tmp ./gitea help --work-path /tmp/other
|
|
// GITEA_WORK_DIR=/tmp ./gitea help --config /tmp/app-other.ini
|
|
var cmdHelp = cli.Command{
|
|
Name: "help",
|
|
Aliases: []string{"h"},
|
|
Usage: "Shows a list of commands or help for one command",
|
|
ArgsUsage: "[command]",
|
|
Action: func(c *cli.Context) (err error) {
|
|
args := c.Args()
|
|
if args.Present() {
|
|
err = cli.ShowCommandHelp(c, args.First())
|
|
} else {
|
|
err = cli.ShowAppHelp(c)
|
|
}
|
|
_, _ = fmt.Fprintf(c.App.Writer, `
|
|
DEFAULT CONFIGURATION:
|
|
AppPath: %s
|
|
WorkPath: %s
|
|
CustomPath: %s
|
|
ConfigFile: %s
|
|
|
|
`, setting.AppPath, setting.AppWorkPath, setting.CustomPath, setting.CustomConf)
|
|
return err
|
|
},
|
|
}
|
|
|
|
func forgejoEnv() {
|
|
for _, k := range []string{"CUSTOM", "WORK_DIR"} {
|
|
if v, ok := os.LookupEnv("FORGEJO_" + k); ok {
|
|
os.Setenv("GITEA_"+k, v)
|
|
}
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
path, err := os.Executable()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
executable := filepath.Base(path)
|
|
|
|
var subCmds []cli.Command
|
|
|
|
//
|
|
// If the executable is forgejo-cli, provide a Forgejo specific CLI
|
|
// that is NOT compatible with Gitea.
|
|
//
|
|
if executable == "forgejo-cli" {
|
|
subCmds = []cli.Command{
|
|
forgejo.CmdActions(context.Background()),
|
|
}
|
|
} else {
|
|
//
|
|
// Otherwise provide a Gitea compatible CLI which includes Forgejo
|
|
// specific additions under the forgejo-cli subcommand. It allows
|
|
// admins to migration from Gitea to Forgejo by replacing the gitea
|
|
// binary and rename it to forgejo if they want.
|
|
//
|
|
subCmds = []cli.Command{
|
|
forgejo.CmdForgejo(context.Background()),
|
|
cmd.CmdActions,
|
|
}
|
|
}
|
|
|
|
mainApp(subCmds...)
|
|
}
|
|
|
|
func mainApp(subCmds ...cli.Command) {
|
|
forgejoEnv()
|
|
app := cli.NewApp()
|
|
app.Name = "Forgejo"
|
|
app.Usage = "Beyond coding. We forge."
|
|
app.Description = `By default, forgejo will start serving using the web-server with no
|
|
argument - which can alternatively be run by running the subcommand web.`
|
|
app.Version = Version + formatBuiltWith()
|
|
app.EnableBashCompletion = true
|
|
|
|
// these sub-commands need to use config file
|
|
subCmdWithIni := []cli.Command{
|
|
cmd.CmdWeb,
|
|
cmd.CmdServ,
|
|
cmd.CmdHook,
|
|
cmd.CmdDump,
|
|
cmd.CmdAdmin,
|
|
cmd.CmdMigrate,
|
|
cmd.CmdKeys,
|
|
cmd.CmdConvert,
|
|
cmd.CmdDoctor,
|
|
cmd.CmdManager,
|
|
cmd.CmdEmbedded,
|
|
cmd.CmdMigrateStorage,
|
|
cmd.CmdDumpRepository,
|
|
cmd.CmdRestoreRepository,
|
|
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
|
|
}
|
|
subCmdWithIni = append(subCmdWithIni, subCmds...)
|
|
// these sub-commands do not need the config file, and they do not depend on any path or environment variable.
|
|
subCmdStandalone := []cli.Command{
|
|
cmd.CmdCert,
|
|
cmd.CmdGenerate,
|
|
cmd.CmdDocs,
|
|
}
|
|
|
|
// shared configuration flags, they are for global and for each sub-command at the same time
|
|
// eg: such command is valid: "./gitea --config /tmp/app.ini web --config /tmp/app.ini", while it's discouraged indeed
|
|
// keep in mind that the short flags like "-C", "-c" and "-w" are globally polluted, they can't be used for sub-commands anymore.
|
|
globalFlags := []cli.Flag{
|
|
cli.HelpFlag,
|
|
cli.StringFlag{
|
|
Name: "custom-path, C",
|
|
Usage: "Set custom path (defaults to '{WorkPath}/custom')",
|
|
},
|
|
cli.StringFlag{
|
|
Name: "config, c",
|
|
Value: setting.CustomConf,
|
|
Usage: "Set custom config file (defaults to '{WorkPath}/custom/conf/app.ini')",
|
|
},
|
|
cli.StringFlag{
|
|
Name: "work-path, w",
|
|
Usage: "Set Gitea's working path (defaults to the Gitea's binary directory)",
|
|
},
|
|
}
|
|
|
|
// Set the default to be equivalent to cmdWeb and add the default flags
|
|
app.Flags = append(app.Flags, globalFlags...)
|
|
app.Flags = append(app.Flags, cmd.CmdWeb.Flags...) // TODO: the web flags polluted the global flags, they are not really global flags
|
|
app.Action = prepareWorkPathAndCustomConf(cmd.CmdWeb.Action)
|
|
app.HideHelp = true // use our own help action to show helps (with more information like default config)
|
|
app.Before = cmd.PrepareConsoleLoggerLevel(log.INFO)
|
|
for i := range subCmdWithIni {
|
|
prepareSubcommands(&subCmdWithIni[i], globalFlags)
|
|
}
|
|
app.Commands = append(app.Commands, subCmdWithIni...)
|
|
app.Commands = append(app.Commands, subCmdStandalone...)
|
|
|
|
err := app.Run(os.Args)
|
|
if err != nil {
|
|
_, _ = fmt.Fprintf(app.Writer, "\nFailed to run with %s: %v\n", os.Args, err)
|
|
}
|
|
|
|
log.GetManager().Close()
|
|
}
|
|
|
|
func prepareSubcommands(command *cli.Command, defaultFlags []cli.Flag) {
|
|
command.Flags = append(command.Flags, defaultFlags...)
|
|
command.Action = prepareWorkPathAndCustomConf(command.Action)
|
|
command.HideHelp = true
|
|
if command.Name != "help" {
|
|
command.Subcommands = append(command.Subcommands, cmdHelp)
|
|
}
|
|
for i := range command.Subcommands {
|
|
prepareSubcommands(&command.Subcommands[i], defaultFlags)
|
|
}
|
|
}
|
|
|
|
// prepareWorkPathAndCustomConf wraps the Action to prepare the work path and custom config
|
|
// 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
|
|
func prepareWorkPathAndCustomConf(action any) func(ctx *cli.Context) error {
|
|
return func(ctx *cli.Context) error {
|
|
var args setting.ArgWorkPathAndCustomConf
|
|
curCtx := ctx
|
|
for curCtx != nil {
|
|
if curCtx.IsSet("work-path") && args.WorkPath == "" {
|
|
args.WorkPath = curCtx.String("work-path")
|
|
}
|
|
if curCtx.IsSet("custom-path") && args.CustomPath == "" {
|
|
args.CustomPath = curCtx.String("custom-path")
|
|
}
|
|
if curCtx.IsSet("config") && args.CustomConf == "" {
|
|
args.CustomConf = curCtx.String("config")
|
|
}
|
|
curCtx = curCtx.Parent()
|
|
}
|
|
setting.InitWorkPathAndCommonConfig(os.Getenv, args)
|
|
if ctx.Bool("help") || action == nil {
|
|
// the default behavior of "urfave/cli": "nil action" means "show help"
|
|
return cmdHelp.Action.(func(ctx *cli.Context) error)(ctx)
|
|
}
|
|
return action.(func(*cli.Context) error)(ctx)
|
|
}
|
|
}
|
|
|
|
func formatBuiltWith() string {
|
|
version := runtime.Version()
|
|
if len(MakeVersion) > 0 {
|
|
version = MakeVersion + ", " + runtime.Version()
|
|
}
|
|
if len(Tags) == 0 {
|
|
return " built with " + version
|
|
}
|
|
|
|
return " built with " + version + " : " + strings.ReplaceAll(Tags, " ", ", ")
|
|
}
|