embed.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. // Copyright 2020 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package templates
  5. import (
  6. "bytes"
  7. "embed"
  8. "fmt"
  9. "io"
  10. "io/fs"
  11. "os"
  12. "path"
  13. "strings"
  14. "gopkg.in/macaron.v1"
  15. "gogs.io/gogs/internal/osutil"
  16. )
  17. //go:embed *.tmpl **/*
  18. var files embed.FS
  19. // fileSystem implements the macaron.TemplateFileSystem interface.
  20. type fileSystem struct {
  21. files []macaron.TemplateFile
  22. }
  23. func (fs *fileSystem) ListFiles() []macaron.TemplateFile {
  24. return fs.files
  25. }
  26. func (fs *fileSystem) Get(name string) (io.Reader, error) {
  27. for i := range fs.files {
  28. if fs.files[i].Name()+fs.files[i].Ext() == name {
  29. return bytes.NewReader(fs.files[i].Data()), nil
  30. }
  31. }
  32. return nil, fmt.Errorf("file %q not found", name)
  33. }
  34. func mustNames(fsys fs.FS) []string {
  35. var names []string
  36. walkDirFunc := func(path string, d fs.DirEntry, err error) error {
  37. if !d.IsDir() {
  38. names = append(names, path)
  39. }
  40. return nil
  41. }
  42. if err := fs.WalkDir(fsys, ".", walkDirFunc); err != nil {
  43. panic("assetNames failure: " + err.Error())
  44. }
  45. return names
  46. }
  47. // NewTemplateFileSystem returns a macaron.TemplateFileSystem instance for embedded assets.
  48. // The argument "dir" can be used to serve subset of embedded assets. Template file
  49. // found under the "customDir" on disk has higher precedence over embedded assets.
  50. func NewTemplateFileSystem(dir, customDir string) macaron.TemplateFileSystem {
  51. if dir != "" && !strings.HasSuffix(dir, "/") {
  52. dir += "/"
  53. }
  54. var err error
  55. var tmplFiles []macaron.TemplateFile
  56. names := mustNames(files)
  57. for _, name := range names {
  58. if !strings.HasPrefix(name, dir) {
  59. continue
  60. }
  61. // Check if corresponding custom file exists
  62. var data []byte
  63. fpath := path.Join(customDir, name)
  64. if osutil.IsFile(fpath) {
  65. data, err = os.ReadFile(fpath)
  66. } else {
  67. data, err = files.ReadFile(name)
  68. }
  69. if err != nil {
  70. panic(err)
  71. }
  72. name = strings.TrimPrefix(name, dir)
  73. ext := path.Ext(name)
  74. name = strings.TrimSuffix(name, ext)
  75. tmplFiles = append(tmplFiles, macaron.NewTplFile(name, data, ext))
  76. }
  77. return &fileSystem{files: tmplFiles}
  78. }