package responses import ( "errors" "fmt" "html/template" "io/ioutil" "log" "net/http" "os" "strings" "git.kirsle.net/apps/gophertype/pkg/bundled" ) // GetTemplate returns the template file's data, wherever it is. // Checks the embedded bindata, then the user root on disk, then error. // If it can be found, returns the contents or error. func GetFile(path string) ([]byte, error) { // Check bindata. if b, err := bundled.Asset(path); err == nil { return b, nil } // Check the filesystem. TODO if b, err := ioutil.ReadFile("./pvt-www/" + path); err == nil { return b, nil } else { return []byte{}, err } } // GetFileExists checks if the file exists but doesn't return its data. func GetFileExists(path string) bool { // Check bindata. if _, err := bundled.AssetInfo(path); err == nil { return true } // Check the filesystem. TODO if _, err := os.Stat(path); err == nil { return true } return false } /* ResolveFile searches for the existence of a file from a fuzzy URL path. `path` is a request path like "/about" This function would return e.g. "about.gohtml" as being a file path that is sure to return data in GetFile(). Path finding rules follow expected behavior from dominant web servers: - If the exact path is found, return it immediately. - Try assuming a ".gohtml" or ".md" file extension for the path. - Try checking if the path is a directory with an "index.gohtml" inside it, etc. */ func ResolveFile(path string) (string, error) { // Ensure the path doesn't begin with a slash. path = strings.TrimLeft(path, "/") // Try the exact path. if GetFileExists(path) { return path, nil } // Try fuzzy file matches. var tries = []string{ path + ".gohtml", path + ".md", path + "/index.gohtml", path + "/index.html", } for _, try := range tries { path = strings.TrimLeft(try, "/") if GetFileExists(path) { return path, nil } } return "", errors.New("not found") } // RenderTemplate renders a Go HTML template. // The io.Writer can be an http.ResponseWriter. func RenderTemplate(w http.ResponseWriter, r *http.Request, tmpl string, vars interface{}) error { w.Header().Set("Content-Type", "text/html; charset=utf-8") // Look for the built-in template. if b, err := GetFile(tmpl); err == nil { t, err := template.New(tmpl).Funcs(TemplateFuncs(r)).Parse(string(b)) if err != nil { log.Printf("bundled template '%s': %s", tmpl, err) return err } // We found the template. Can we find the layout html? if layout, err := GetFile(".layout.gohtml"); err == nil { _, err := t.New("layout").Parse(string(layout)) if err != nil { log.Printf("RenderTemplate(.layout.gohtml): %s", err) } } else { log.Printf("RenderTemplate: .layout.gohtml not found to wrap %s", tmpl) } fmt.Printf("Render Templ: %s", tmpl) if err := t.ExecuteTemplate(w, "layout", vars); err != nil { log.Printf("RenderTemplate(%s): %s", tmpl, err) } log.Println("Done") return nil } else { Panic(w, http.StatusInternalServerError, err.Error()) } return nil }