templates-noembed.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. //go:build !embed
  2. // +build !embed
  3. package static
  4. import (
  5. "bytes"
  6. "io/fs"
  7. "os"
  8. "strings"
  9. "time"
  10. )
  11. var Templates FS
  12. type file struct {
  13. path string
  14. name string
  15. content []byte
  16. }
  17. var templateNames = []string{}
  18. var templates = make(map[string][]file)
  19. var StaticPath string
  20. func CopyTemplatesToMemory() {
  21. baseDir, err := os.ReadDir(StaticPath)
  22. try(err)
  23. for _, c := range baseDir {
  24. if c.IsDir() {
  25. templateNames = append(templateNames, c.Name())
  26. var filePath strings.Builder
  27. filePath.WriteString(StaticPath)
  28. filePath.WriteString("/")
  29. filePath.WriteString(c.Name())
  30. dir, err := os.ReadDir(filePath.String())
  31. try(err)
  32. filePath.WriteString("/")
  33. for _, cd := range dir {
  34. f, err := os.ReadFile(filePath.String() + cd.Name())
  35. try(err)
  36. templates[c.Name()] = append(templates[c.Name()], file{
  37. content: f,
  38. name: cd.Name(),
  39. path: c.Name() + "/" + cd.Name(),
  40. })
  41. }
  42. }
  43. }
  44. }
  45. type FS struct{}
  46. func (FS) Open(name string) (fs.File, error) {
  47. for i, l := 0, len(templateNames); i < l; i++ {
  48. for _, x := range templates[templateNames[i]] {
  49. if x.content != nil && name == x.path {
  50. return &File{
  51. name: x.path,
  52. content: bytes.NewBuffer(x.content),
  53. }, nil
  54. }
  55. }
  56. }
  57. return nil, &fs.PathError{}
  58. }
  59. func (FS) Glob(pattern string) ([]string, error) {
  60. trimmed := strings.Split(pattern, "/")
  61. var matches = []string{}
  62. for x, s := range templates {
  63. for i, l := 0, len(s); i < l && trimmed[0] == x; i++ {
  64. s := s[i]
  65. matches = append(matches, s.path)
  66. }
  67. }
  68. if len(matches) != 0 {
  69. return matches, nil
  70. }
  71. return nil, &fs.PathError{}
  72. }
  73. func try(err error) {
  74. if err != nil {
  75. println(err.Error())
  76. os.Exit(1)
  77. }
  78. }
  79. /* сделано на основе https://github.com/psanford/memfs; требуется для корректной работы templates.ParseFS */
  80. type fileInfo struct {
  81. name string
  82. }
  83. func (fi fileInfo) Name() string {
  84. return fi.name
  85. }
  86. func (fi fileInfo) Size() int64 {
  87. return 4096
  88. }
  89. func (fileInfo) Mode() fs.FileMode {
  90. return 0
  91. }
  92. func (fileInfo) ModTime() time.Time {
  93. return time.Time{}
  94. }
  95. func (fileInfo) IsDir() bool {
  96. return false
  97. }
  98. func (fileInfo) Sys() interface{} {
  99. return nil
  100. }
  101. type File struct {
  102. name string
  103. content *bytes.Buffer
  104. closed bool
  105. }
  106. func (f *File) Stat() (fs.FileInfo, error) {
  107. return fileInfo{
  108. name: f.name,
  109. }, nil
  110. }
  111. func (f *File) Read(b []byte) (int, error) {
  112. if f.closed {
  113. return 0, fs.ErrClosed
  114. }
  115. return f.content.Read(b)
  116. }
  117. func (f *File) Close() error {
  118. if f.closed {
  119. return fs.ErrClosed
  120. }
  121. f.closed = true
  122. return nil
  123. }