From 3588edbb08f93aaa56defa82dffdbb202cd9aa4a Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 22 May 2023 17:51:40 +0200 Subject: [PATCH] Add gitea manager reload-templates command (#24843) This can be useful to update custom templates in production mode, when they are updated frequently and a full Gitea restart each time is disruptive. --- cmd/manager.go | 20 ++++++++++++++++++++ modules/private/manager.go | 7 +++++++ modules/templates/htmlrenderer.go | 12 +++++++++--- routers/private/internal.go | 1 + routers/private/manager.go | 13 +++++++++++++ 5 files changed, 50 insertions(+), 3 deletions(-) diff --git a/cmd/manager.go b/cmd/manager.go index 3f1e223190..2024d5ebbd 100644 --- a/cmd/manager.go +++ b/cmd/manager.go @@ -21,6 +21,7 @@ var ( Subcommands: []cli.Command{ subcmdShutdown, subcmdRestart, + subcmdReloadTemplates, subcmdFlushQueues, subcmdLogging, subCmdProcesses, @@ -46,6 +47,16 @@ var ( }, Action: runRestart, } + subcmdReloadTemplates = cli.Command{ + Name: "reload-templates", + Usage: "Reload template files in the running process", + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "debug", + }, + }, + Action: runReloadTemplates, + } subcmdFlushQueues = cli.Command{ Name: "flush-queues", Usage: "Flush queues in the running process", @@ -115,6 +126,15 @@ func runRestart(c *cli.Context) error { return handleCliResponseExtra(extra) } +func runReloadTemplates(c *cli.Context) error { + ctx, cancel := installSignals() + defer cancel() + + setup(ctx, c.Bool("debug")) + extra := private.ReloadTemplates(ctx) + return handleCliResponseExtra(extra) +} + func runFlushQueues(c *cli.Context) error { ctx, cancel := installSignals() defer cancel() diff --git a/modules/private/manager.go b/modules/private/manager.go index a974c3ed05..382986bf1d 100644 --- a/modules/private/manager.go +++ b/modules/private/manager.go @@ -29,6 +29,13 @@ func Restart(ctx context.Context) ResponseExtra { return requestJSONClientMsg(req, "Restarting") } +// ReloadTemplates calls the internal reload-templates function +func ReloadTemplates(ctx context.Context) ResponseExtra { + reqURL := setting.LocalURL + "api/internal/manager/reload-templates" + req := newInternalRequest(ctx, reqURL, "POST") + return requestJSONClientMsg(req, "Reloaded") +} + // FlushOptions represents the options for the flush call type FlushOptions struct { Timeout time.Duration diff --git a/modules/templates/htmlrenderer.go b/modules/templates/htmlrenderer.go index 311e5b741d..21c268da78 100644 --- a/modules/templates/htmlrenderer.go +++ b/modules/templates/htmlrenderer.go @@ -96,6 +96,14 @@ func HTMLRenderer() *HTMLRender { return htmlRender } +func ReloadHTMLTemplates() error { + if err := htmlRender.CompileTemplates(); err != nil { + log.Error("Template error: %v\n%s", err, log.Stack(2)) + return err + } + return nil +} + func initHTMLRenderer() { rendererType := "static" if !setting.IsProd { @@ -115,9 +123,7 @@ func initHTMLRenderer() { if !setting.IsProd { go AssetFS().WatchLocalChanges(graceful.GetManager().ShutdownContext(), func() { - if err := htmlRender.CompileTemplates(); err != nil { - log.Error("Template error: %v\n%s", err, log.Stack(2)) - } + _ = ReloadHTMLTemplates() }) } } diff --git a/routers/private/internal.go b/routers/private/internal.go index b09fb58d05..407edebeed 100644 --- a/routers/private/internal.go +++ b/routers/private/internal.go @@ -67,6 +67,7 @@ func Routes() *web.Route { r.Get("/serv/command/{keyid}/{owner}/{repo}", ServCommand) r.Post("/manager/shutdown", Shutdown) r.Post("/manager/restart", Restart) + r.Post("/manager/reload-templates", ReloadTemplates) r.Post("/manager/flush-queues", bind(private.FlushOptions{}), FlushQueues) r.Post("/manager/pause-logging", PauseLogging) r.Post("/manager/resume-logging", ResumeLogging) diff --git a/routers/private/manager.go b/routers/private/manager.go index 8ed05da6a5..26096c403b 100644 --- a/routers/private/manager.go +++ b/routers/private/manager.go @@ -15,9 +15,22 @@ import ( "code.gitea.io/gitea/modules/private" "code.gitea.io/gitea/modules/queue" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/web" ) +// ReloadTemplates reloads all the templates +func ReloadTemplates(ctx *context.PrivateContext) { + err := templates.ReloadHTMLTemplates() + if err != nil { + ctx.JSON(http.StatusInternalServerError, private.Response{ + UserMsg: fmt.Sprintf("Template error: %v", err), + }) + return + } + ctx.PlainText(http.StatusOK, "success") +} + // FlushQueues flushes all the Queues func FlushQueues(ctx *context.PrivateContext) { opts := web.GetForm(ctx).(*private.FlushOptions)