From 4bc668a36b80133ea394140d625ef1af80478596 Mon Sep 17 00:00:00 2001 From: "A. Diamond" Date: Tue, 26 Mar 2024 11:47:40 -0400 Subject: [PATCH] Added static template loading --- server/dev_loader.go | 61 +++++++++++++++++++++++++++ server/release_loader.go | 90 ++++++++++++++++++++++++++++++++++++++++ server/server.go | 51 ----------------------- 3 files changed, 151 insertions(+), 51 deletions(-) create mode 100644 server/dev_loader.go create mode 100644 server/release_loader.go diff --git a/server/dev_loader.go b/server/dev_loader.go new file mode 100644 index 0000000..aae1c6f --- /dev/null +++ b/server/dev_loader.go @@ -0,0 +1,61 @@ +//go:build xxx + +package server + +import ( + "html/template" + + "github.com/APTrust/dart-runner/constants" + "github.com/APTrust/dart-runner/core" + "github.com/APTrust/dart-runner/util" + "github.com/gin-gonic/gin" +) + +// initTemplates loads templates and sets up template helper functions. +func initTemplates(router *gin.Engine) { + + // Note: We can't put workflowList in util with the + // other template helpers because it creates a cyclical + // import cycle between core and util. So we define the + // body of that helper here inline. + + router.SetFuncMap(template.FuncMap{ + "add": util.Add, + "dateISO": util.DateISO, + "dateTimeISO": util.DateTimeISO, + "dateTimeUS": util.DateTimeUS, + "dateUS": util.DateUS, + "dict": util.Dict, + "dirStats": util.DirStats, + "displayDate": util.DisplayDate, + "escapeAttr": util.EscapeAttr, + "escapeHTML": util.EscapeHTML, + "fileIconFor": util.FileIconFor, + "humanSize": util.HumanSize, + "mod": util.Mod, + "strEq": util.StrEq, + "strStartsWith": util.StrStartsWith, + "truncate": util.Truncate, + "truncateMiddle": util.TruncateMiddle, + "truncateStart": util.TruncateStart, + "unixToISO": util.UnixToISO, + "workflowList": func() []core.NameIDPair { return core.ObjNameIdList(constants.TypeWorkflow) }, + "yesNo": util.YesNo, + }) + + // Load the view templates + // If we're running from main, templates will come + // from ./views. When running tests, templates come + // from ../../views because http tests run from web + // from ../../../views for member api and admin api + // sub directory. + if util.FileExists("./views") { + router.LoadHTMLGlob("./views/**/*.html") + } else if util.FileExists("./server/views") { + router.LoadHTMLGlob("./server/views/**/*.html") + } else if util.FileExists("../server/views") { + router.LoadHTMLGlob("../server/views/**/*.html") + } else { + router.LoadHTMLGlob("../../server/views/**/*.html") + } +} diff --git a/server/release_loader.go b/server/release_loader.go new file mode 100644 index 0000000..24c46d8 --- /dev/null +++ b/server/release_loader.go @@ -0,0 +1,90 @@ +package server + +import ( + "embed" + "fmt" + "html/template" + "io/fs" + "regexp" + "strings" + + "github.com/APTrust/dart-runner/constants" + "github.com/APTrust/dart-runner/core" + "github.com/APTrust/dart-runner/util" + "github.com/gin-gonic/gin" +) + +//go:embed views +var views embed.FS + +//go:embed assets +var assets embed.FS + +// initTemplates loads templates and sets up template helper functions. +func initTemplates(router *gin.Engine) { + + // Note: We can't put workflowList in util with the + // other template helpers because it creates a cyclical + // import cycle between core and util. So we define the + // body of that helper here inline. + + router.SetFuncMap(template.FuncMap{ + "add": util.Add, + "dateISO": util.DateISO, + "dateTimeISO": util.DateTimeISO, + "dateTimeUS": util.DateTimeUS, + "dateUS": util.DateUS, + "dict": util.Dict, + "dirStats": util.DirStats, + "displayDate": util.DisplayDate, + "escapeAttr": util.EscapeAttr, + "escapeHTML": util.EscapeHTML, + "fileIconFor": util.FileIconFor, + "humanSize": util.HumanSize, + "mod": util.Mod, + "strEq": util.StrEq, + "strStartsWith": util.StrStartsWith, + "truncate": util.Truncate, + "truncateMiddle": util.TruncateMiddle, + "truncateStart": util.TruncateStart, + "unixToISO": util.UnixToISO, + "workflowList": func() []core.NameIDPair { return core.ObjNameIdList(constants.TypeWorkflow) }, + "yesNo": util.YesNo, + }) + + loadHTMLFromEmbedFS(router, views, "*.html") +} + +// Next two functions courtest of https://github.com/gin-gonic/gin/issues/2795 + +// loadHTMLFromEmbedFS loads HTML templates from an embedded file system +func loadHTMLFromEmbedFS(engine *gin.Engine, embedFS embed.FS, pattern string) { + root := template.New("") + tmpl := template.Must(root, loadAndAddToRoot(engine.FuncMap, root, embedFS, pattern)) + engine.SetHTMLTemplate(tmpl) +} + +// loadAndAddToRoot recursively loads and parses template files from embedded FS +func loadAndAddToRoot(funcMap template.FuncMap, rootTemplate *template.Template, embedFS embed.FS, pattern string) error { + pattern = strings.ReplaceAll(pattern, ".", "\\.") + pattern = strings.ReplaceAll(pattern, "*", ".*") + + err := fs.WalkDir(embedFS, ".", func(path string, d fs.DirEntry, walkErr error) error { + if walkErr != nil { + return walkErr + } + if matched, _ := regexp.MatchString(pattern, path); !d.IsDir() && matched { + data, readErr := embedFS.ReadFile(path) + if readErr != nil { + return readErr + } + t := rootTemplate.New(path).Funcs(funcMap) + if _, parseErr := t.Parse(string(data)); parseErr != nil { + return parseErr + } + fmt.Println(" template", path) + } + return nil + }) + return err +} diff --git a/server/server.go b/server/server.go index d112997..87ce124 100644 --- a/server/server.go +++ b/server/server.go @@ -1,13 +1,11 @@ package server import ( - "html/template" "io" "github.com/APTrust/dart-runner/constants" "github.com/APTrust/dart-runner/core" "github.com/APTrust/dart-runner/server/controllers" - "github.com/APTrust/dart-runner/util" "github.com/gin-gonic/gin" ) @@ -40,55 +38,6 @@ func InitAppEngine(discardStdOut bool) *gin.Engine { return r } -// initTemplates loads templates and sets up template helper functions. -func initTemplates(router *gin.Engine) { - - // Note: We can't put workflowList in util with the - // other template helpers because it creates a cyclical - // import cycle between core and util. So we define the - // body of that helper here inline. - - router.SetFuncMap(template.FuncMap{ - "add": util.Add, - "dateISO": util.DateISO, - "dateTimeISO": util.DateTimeISO, - "dateTimeUS": util.DateTimeUS, - "dateUS": util.DateUS, - "dict": util.Dict, - "dirStats": util.DirStats, - "displayDate": util.DisplayDate, - "escapeAttr": util.EscapeAttr, - "escapeHTML": util.EscapeHTML, - "fileIconFor": util.FileIconFor, - "humanSize": util.HumanSize, - "mod": util.Mod, - "strEq": util.StrEq, - "strStartsWith": util.StrStartsWith, - "truncate": util.Truncate, - "truncateMiddle": util.TruncateMiddle, - "truncateStart": util.TruncateStart, - "unixToISO": util.UnixToISO, - "workflowList": func() []core.NameIDPair { return core.ObjNameIdList(constants.TypeWorkflow) }, - "yesNo": util.YesNo, - }) - - // Load the view templates - // If we're running from main, templates will come - // from ./views. When running tests, templates come - // from ../../views because http tests run from web - // from ../../../views for member api and admin api - // sub directory. - if util.FileExists("./views") { - router.LoadHTMLGlob("./views/**/*.html") - } else if util.FileExists("./server/views") { - router.LoadHTMLGlob("./server/views/**/*.html") - } else if util.FileExists("../server/views") { - router.LoadHTMLGlob("../server/views/**/*.html") - } else { - router.LoadHTMLGlob("../../server/views/**/*.html") - } -} - func initRoutes(router *gin.Engine) { // This ensures that routes match even when they contain