A web blog and personal homepage engine written in Go.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

122 lignes
2.9 KiB

  1. package responses
  2. import (
  3. "errors"
  4. "fmt"
  5. "html/template"
  6. "io/ioutil"
  7. "log"
  8. "net/http"
  9. "os"
  10. "strings"
  11. "git.kirsle.net/apps/gophertype/pkg/bundled"
  12. )
  13. // GetTemplate returns the template file's data, wherever it is.
  14. // Checks the embedded bindata, then the user root on disk, then error.
  15. // If it can be found, returns the contents or error.
  16. func GetFile(path string) ([]byte, error) {
  17. // Check bindata.
  18. if b, err := bundled.Asset(path); err == nil {
  19. return b, nil
  20. }
  21. // Check the filesystem. TODO
  22. if b, err := ioutil.ReadFile("./pvt-www/" + path); err == nil {
  23. return b, nil
  24. } else {
  25. return []byte{}, err
  26. }
  27. }
  28. // GetFileExists checks if the file exists but doesn't return its data.
  29. func GetFileExists(path string) bool {
  30. // Check bindata.
  31. if _, err := bundled.AssetInfo(path); err == nil {
  32. return true
  33. }
  34. // Check the filesystem. TODO
  35. if _, err := os.Stat(path); err == nil {
  36. return true
  37. }
  38. return false
  39. }
  40. /*
  41. ResolveFile searches for the existence of a file from a fuzzy URL path.
  42. `path` is a request path like "/about"
  43. This function would return e.g. "about.gohtml" as being a file path that is
  44. sure to return data in GetFile().
  45. Path finding rules follow expected behavior from dominant web servers:
  46. - If the exact path is found, return it immediately.
  47. - Try assuming a ".gohtml" or ".md" file extension for the path.
  48. - Try checking if the path is a directory with an "index.gohtml" inside it, etc.
  49. */
  50. func ResolveFile(path string) (string, error) {
  51. // Ensure the path doesn't begin with a slash.
  52. path = strings.TrimLeft(path, "/")
  53. // Try the exact path.
  54. if GetFileExists(path) {
  55. return path, nil
  56. }
  57. // Try fuzzy file matches.
  58. var tries = []string{
  59. path + ".gohtml",
  60. path + ".md",
  61. path + "/index.gohtml",
  62. path + "/index.html",
  63. }
  64. for _, try := range tries {
  65. path = strings.TrimLeft(try, "/")
  66. if GetFileExists(path) {
  67. return path, nil
  68. }
  69. }
  70. return "", errors.New("not found")
  71. }
  72. // RenderTemplate renders a Go HTML template.
  73. // The io.Writer can be an http.ResponseWriter.
  74. func RenderTemplate(w http.ResponseWriter, tmpl string, vars interface{}) error {
  75. w.Header().Set("Content-Type", "text/html; charset=utf-8")
  76. // Look for the built-in template.
  77. if b, err := GetFile(tmpl); err == nil {
  78. t, err := template.New(tmpl).Parse(string(b))
  79. if err != nil {
  80. return fmt.Errorf("bundled template '%s': %s", tmpl, err)
  81. }
  82. // We found the template. Can we find the layout html?
  83. if layout, err := GetFile(".layout.gohtml"); err == nil {
  84. _, err := t.New("layout").Parse(string(layout))
  85. if err != nil {
  86. fmt.Errorf("RenderTemplate(.layout.gohtml): %s", err)
  87. }
  88. } else {
  89. log.Printf("RenderTemplate: .layout.gohtml not found to wrap %s", tmpl)
  90. }
  91. fmt.Printf("Render Templ: %s", tmpl)
  92. if err := t.ExecuteTemplate(w, "layout", vars); err != nil {
  93. log.Printf("RenderTemplate(%s): %s", tmpl, err)
  94. }
  95. log.Println("Done")
  96. return nil
  97. } else {
  98. Panic(w, http.StatusInternalServerError, err.Error())
  99. }
  100. return nil
  101. }