gddo-server: consolidate template initialization
This is in preparation for passing around the template map explicitly
instead of using it as a global. It also moves the manifest of template
sets into templates.go and out of main.go.
Change-Id: Ic7db8d5ab0186c1f4eb2446871e2c18ae1554d82
Reviewed-on: https://go-review.googlesource.com/67051
Reviewed-by: Tuo Shan <shantuo@google.com>
diff --git a/gddo-server/main.go b/gddo-server/main.go
index 9e94ef5..d970b94 100644
--- a/gddo-server/main.go
+++ b/gddo-server/main.go
@@ -310,10 +310,10 @@
}
template += templateExt(req)
- return executeTemplate(resp, template, status, http.Header{"Etag": {etag}}, map[string]interface{}{
+ return templates.execute(resp, template, status, http.Header{"Etag": {etag}}, map[string]interface{}{
"flashMessages": flashMessages,
"pkgs": pkgs,
- "pdoc": newTDoc(pdoc),
+ "pdoc": newTDoc(viper.GetViper(), pdoc),
"importerCount": importerCount,
})
case isView(req, "imports"):
@@ -324,20 +324,20 @@
if err != nil {
return err
}
- return executeTemplate(resp, "imports.html", http.StatusOK, nil, map[string]interface{}{
+ return templates.execute(resp, "imports.html", http.StatusOK, nil, map[string]interface{}{
"flashMessages": flashMessages,
"pkgs": pkgs,
- "pdoc": newTDoc(pdoc),
+ "pdoc": newTDoc(viper.GetViper(), pdoc),
})
case isView(req, "tools"):
proto := "http"
if req.Host == "godoc.org" {
proto = "https"
}
- return executeTemplate(resp, "tools.html", http.StatusOK, nil, map[string]interface{}{
+ return templates.execute(resp, "tools.html", http.StatusOK, nil, map[string]interface{}{
"flashMessages": flashMessages,
"uri": fmt.Sprintf("%s://%s/%s", proto, req.Host, importPath),
- "pdoc": newTDoc(pdoc),
+ "pdoc": newTDoc(viper.GetViper(), pdoc),
})
case isView(req, "importers"):
if pdoc.Name == "" {
@@ -352,10 +352,10 @@
// Hide back links from robots.
template = "importers_robot.html"
}
- return executeTemplate(resp, template, http.StatusOK, nil, map[string]interface{}{
+ return templates.execute(resp, template, http.StatusOK, nil, map[string]interface{}{
"flashMessages": flashMessages,
"pkgs": pkgs,
- "pdoc": newTDoc(pdoc),
+ "pdoc": newTDoc(viper.GetViper(), pdoc),
})
case isView(req, "import-graph"):
if requestType == robotRequest {
@@ -379,10 +379,10 @@
if err != nil {
return err
}
- return executeTemplate(resp, "graph.html", http.StatusOK, nil, map[string]interface{}{
+ return templates.execute(resp, "graph.html", http.StatusOK, nil, map[string]interface{}{
"flashMessages": flashMessages,
"svg": template.HTML(b),
- "pdoc": newTDoc(pdoc),
+ "pdoc": newTDoc(viper.GetViper(), pdoc),
"hide": hide,
})
case isView(req, "play"):
@@ -447,7 +447,7 @@
if err != nil {
return err
}
- return executeTemplate(resp, "std.html", http.StatusOK, nil, map[string]interface{}{
+ return templates.execute(resp, "std.html", http.StatusOK, nil, map[string]interface{}{
"pkgs": pkgs,
})
}
@@ -457,7 +457,7 @@
if err != nil {
return err
}
- return executeTemplate(resp, "subrepo.html", http.StatusOK, nil, map[string]interface{}{
+ return templates.execute(resp, "subrepo.html", http.StatusOK, nil, map[string]interface{}{
"pkgs": pkgs,
})
}
@@ -540,7 +540,7 @@
return err
}
- return executeTemplate(resp, "home"+templateExt(req), http.StatusOK, nil,
+ return templates.execute(resp, "home"+templateExt(req), http.StatusOK, nil,
map[string]interface{}{"Popular": pkgs})
}
@@ -573,17 +573,17 @@
gceLogger.LogEvent(resp, req, logPkgs)
}
- return executeTemplate(resp, "results"+templateExt(req), http.StatusOK, nil,
+ return templates.execute(resp, "results"+templateExt(req), http.StatusOK, nil,
map[string]interface{}{"q": q, "pkgs": pkgs})
}
func serveAbout(resp http.ResponseWriter, req *http.Request) error {
- return executeTemplate(resp, "about.html", http.StatusOK, nil,
+ return templates.execute(resp, "about.html", http.StatusOK, nil,
map[string]interface{}{"Host": req.Host})
}
func serveBot(resp http.ResponseWriter, req *http.Request) error {
- return executeTemplate(resp, "bot.html", http.StatusOK, nil, nil)
+ return templates.execute(resp, "bot.html", http.StatusOK, nil, nil)
}
func serveHealthCheck(resp http.ResponseWriter, req *http.Request) {
@@ -757,7 +757,7 @@
func handleError(resp http.ResponseWriter, req *http.Request, status int, err error) {
switch status {
case http.StatusNotFound:
- executeTemplate(resp, "notfound"+templateExt(req), status, nil, map[string]interface{}{
+ templates.execute(resp, "notfound"+templateExt(req), status, nil, map[string]interface{}{
"flashMessages": getFlashMessages(resp, req),
})
default:
@@ -846,38 +846,12 @@
doc.SetDefaultGOOS(viper.GetString(ConfigDefaultGOOS))
httpClient = newHTTPClient(viper.GetViper())
- if err := parseHTMLTemplates([][]string{
- {"about.html", "common.html", "layout.html"},
- {"bot.html", "common.html", "layout.html"},
- {"cmd.html", "common.html", "layout.html"},
- {"dir.html", "common.html", "layout.html"},
- {"home.html", "common.html", "layout.html"},
- {"importers.html", "common.html", "layout.html"},
- {"importers_robot.html", "common.html", "layout.html"},
- {"imports.html", "common.html", "layout.html"},
- {"notfound.html", "common.html", "layout.html"},
- {"pkg.html", "common.html", "layout.html"},
- {"results.html", "common.html", "layout.html"},
- {"tools.html", "common.html", "layout.html"},
- {"std.html", "common.html", "layout.html"},
- {"subrepo.html", "common.html", "layout.html"},
- {"graph.html", "common.html"},
- }); err != nil {
- log.Fatal(err)
- }
-
- if err := parseTextTemplates([][]string{
- {"cmd.txt", "common.txt"},
- {"dir.txt", "common.txt"},
- {"home.txt", "common.txt"},
- {"notfound.txt", "common.txt"},
- {"pkg.txt", "common.txt"},
- {"results.txt", "common.txt"},
- }); err != nil {
- log.Fatal(err)
- }
-
var err error
+ templates, err = parseTemplates(viper.GetString(ConfigAssetsDir), viper.GetViper())
+ if err != nil {
+ log.Fatal(err)
+ }
+
db, err = database.New(
viper.GetString(ConfigDBServer),
viper.GetDuration(ConfigDBIdleTimeout),
diff --git a/gddo-server/template.go b/gddo-server/template.go
index 3aefd5b..8679607 100644
--- a/gddo-server/template.go
+++ b/gddo-server/template.go
@@ -80,7 +80,8 @@
type tdoc struct {
*doc.Package
- allExamples []*texample
+ allExamples []*texample
+ sourcegraphURL string
}
type texample struct {
@@ -91,8 +92,11 @@
obj interface{}
}
-func newTDoc(pdoc *doc.Package) *tdoc {
- return &tdoc{Package: pdoc}
+func newTDoc(v *viper.Viper, pdoc *doc.Package) *tdoc {
+ return &tdoc{
+ Package: pdoc,
+ sourcegraphURL: v.GetString(ConfigSourcegraphURL),
+ }
}
func (pdoc *tdoc) SourceLink(pos doc.Pos, text string, textOnlyOK bool) htemp.HTML {
@@ -110,7 +114,7 @@
// UsesLink generates a link to uses of a symbol definition.
// title is used as the tooltip. defParts are parts of the symbol definition name.
func (pdoc *tdoc) UsesLink(title string, defParts ...string) htemp.HTML {
- if viper.GetString(ConfigSourcegraphURL) == "" {
+ if pdoc.sourcegraphURL == "" {
return ""
}
@@ -146,7 +150,7 @@
"pkg": {pdoc.ImportPath},
"def": {def},
}
- u := viper.GetString(ConfigSourcegraphURL) + "/-/godoc/refs?" + q.Encode()
+ u := pdoc.sourcegraphURL + "/-/godoc/refs?" + q.Encode()
return htemp.HTML(fmt.Sprintf(`<a class="uses" title="%s" href="%s">Uses</a>`, htemp.HTMLEscapeString(title), htemp.HTMLEscapeString(u)))
}
@@ -485,7 +489,15 @@
".txt": textMIMEType,
}
-func executeTemplate(resp http.ResponseWriter, name string, status int, header http.Header, data interface{}) error {
+// TODO(light): pass templates explicitly, not as a global.
+
+var templates templateMap
+
+type templateMap map[string]interface {
+ Execute(io.Writer, interface{}) error
+}
+
+func (m templateMap) execute(resp http.ResponseWriter, name string, status int, header http.Header, data interface{}) error {
for k, v := range header {
resp.Header()[k] = v
}
@@ -494,7 +506,7 @@
mimeType = textMIMEType
}
resp.Header().Set("Content-Type", mimeType)
- t := templates[name]
+ t := m[name]
if t == nil {
return fmt.Errorf("template %s not found", name)
}
@@ -505,10 +517,6 @@
return t.Execute(resp, data)
}
-var templates = map[string]interface {
- Execute(io.Writer, interface{}) error
-}{}
-
func joinTemplateDir(base string, files []string) []string {
result := make([]string, len(files))
for i := range files {
@@ -517,53 +525,76 @@
return result
}
-func parseHTMLTemplates(sets [][]string) error {
- for _, set := range sets {
+func parseTemplates(dir string, v *viper.Viper) (templateMap, error) {
+ m := make(templateMap)
+ htmlSets := [][]string{
+ {"about.html", "common.html", "layout.html"},
+ {"bot.html", "common.html", "layout.html"},
+ {"cmd.html", "common.html", "layout.html"},
+ {"dir.html", "common.html", "layout.html"},
+ {"home.html", "common.html", "layout.html"},
+ {"importers.html", "common.html", "layout.html"},
+ {"importers_robot.html", "common.html", "layout.html"},
+ {"imports.html", "common.html", "layout.html"},
+ {"notfound.html", "common.html", "layout.html"},
+ {"pkg.html", "common.html", "layout.html"},
+ {"results.html", "common.html", "layout.html"},
+ {"tools.html", "common.html", "layout.html"},
+ {"std.html", "common.html", "layout.html"},
+ {"subrepo.html", "common.html", "layout.html"},
+ {"graph.html", "common.html"},
+ }
+ hfuncs := htemp.FuncMap{
+ "code": codeFn,
+ "comment": commentFn,
+ "equal": reflect.DeepEqual,
+ "gaAccount": func() string { return v.GetString(ConfigGAAccount) },
+ "host": hostFn,
+ "htmlComment": htmlCommentFn,
+ "importPath": importPathFn,
+ "isInterface": isInterfaceFn,
+ "isValidImportPath": gosrc.IsValidPath,
+ "map": mapFn,
+ "noteTitle": noteTitleFn,
+ "relativePath": relativePathFn,
+ "sidebarEnabled": func() bool { return v.GetBool(ConfigSidebar) },
+ "staticPath": func(p string) string { return cacheBusters.AppendQueryParam(p, "v") },
+ }
+ for _, set := range htmlSets {
templateName := set[0]
- t := htemp.New("")
- t.Funcs(htemp.FuncMap{
- "code": codeFn,
- "comment": commentFn,
- "equal": reflect.DeepEqual,
- "gaAccount": func() string { return viper.GetString(ConfigGAAccount) },
- "host": hostFn,
- "htmlComment": htmlCommentFn,
- "importPath": importPathFn,
- "isInterface": isInterfaceFn,
- "isValidImportPath": gosrc.IsValidPath,
- "map": mapFn,
- "noteTitle": noteTitleFn,
- "relativePath": relativePathFn,
- "sidebarEnabled": func() bool { return viper.GetBool(ConfigSidebar) },
- "staticPath": func(p string) string { return cacheBusters.AppendQueryParam(p, "v") },
- "templateName": func() string { return templateName },
+ t := htemp.New("").Funcs(hfuncs).Funcs(htemp.FuncMap{
+ "templateName": func() string { return templateName },
})
- if _, err := t.ParseFiles(joinTemplateDir(viper.GetString(ConfigAssetsDir), set)...); err != nil {
- return err
+ if _, err := t.ParseFiles(joinTemplateDir(dir, set)...); err != nil {
+ return nil, err
}
t = t.Lookup("ROOT")
if t == nil {
- return fmt.Errorf("ROOT template not found in %v", set)
+ return nil, fmt.Errorf("ROOT template not found in %v", set)
}
- templates[set[0]] = t
+ m[set[0]] = t
}
- return nil
-}
-
-func parseTextTemplates(sets [][]string) error {
- for _, set := range sets {
- t := ttemp.New("")
- t.Funcs(ttemp.FuncMap{
- "comment": commentTextFn,
- })
- if _, err := t.ParseFiles(joinTemplateDir(viper.GetString(ConfigAssetsDir), set)...); err != nil {
- return err
+ textSets := [][]string{
+ {"cmd.txt", "common.txt"},
+ {"dir.txt", "common.txt"},
+ {"home.txt", "common.txt"},
+ {"notfound.txt", "common.txt"},
+ {"pkg.txt", "common.txt"},
+ {"results.txt", "common.txt"},
+ }
+ tfuncs := ttemp.FuncMap{
+ "comment": commentTextFn,
+ }
+ for _, set := range textSets {
+ t := ttemp.New("").Funcs(tfuncs)
+ if _, err := t.ParseFiles(joinTemplateDir(dir, set)...); err != nil {
+ return nil, err
}
t = t.Lookup("ROOT")
if t == nil {
- return fmt.Errorf("ROOT template not found in %v", set)
+ return nil, fmt.Errorf("ROOT template not found in %v", set)
}
- templates[set[0]] = t
+ m[set[0]] = t
}
- return nil
+ return m, nil
}