//go:build !embed // +build !embed package static import ( "bytes" "io/fs" "os" "strings" "time" ) var Templates FS type file struct { path string name string content []byte } var templateNames = []string{} var templates = make(map[string][]file) var StaticPath string func CopyTemplatesToMemory() { baseDir, err := os.ReadDir(StaticPath) try(err) for _, c := range baseDir { if c.IsDir() { templateNames = append(templateNames, c.Name()) var filePath strings.Builder filePath.WriteString(StaticPath) filePath.WriteString("/") filePath.WriteString(c.Name()) dir, err := os.ReadDir(filePath.String()) try(err) filePath.WriteString("/") for _, cd := range dir { f, err := os.ReadFile(filePath.String() + cd.Name()) try(err) templates[c.Name()] = append(templates[c.Name()], file{ content: f, name: cd.Name(), path: c.Name() + "/" + cd.Name(), }) } } } } type FS struct{} func (FS) Open(name string) (fs.File, error) { for i, l := 0, len(templateNames); i < l; i++ { for _, x := range templates[templateNames[i]] { if x.content != nil && name == x.path { return &File{ name: x.path, content: bytes.NewBuffer(x.content), }, nil } } } return nil, &fs.PathError{} } func (FS) Glob(pattern string) ([]string, error) { trimmed := strings.Split(pattern, "/") var matches = []string{} for x, s := range templates { for i, l := 0, len(s); i < l && trimmed[0] == x; i++ { s := s[i] matches = append(matches, s.path) } } if len(matches) != 0 { return matches, nil } return nil, &fs.PathError{} } func try(err error) { if err != nil { println(err.Error()) os.Exit(1) } } /* сделано на основе https://github.com/psanford/memfs; требуется для корректной работы templates.ParseFS */ type fileInfo struct { name string } func (fi fileInfo) Name() string { return fi.name } func (fi fileInfo) Size() int64 { return 4096 } func (fileInfo) Mode() fs.FileMode { return 0 } func (fileInfo) ModTime() time.Time { return time.Time{} } func (fileInfo) IsDir() bool { return false } func (fileInfo) Sys() interface{} { return nil } type File struct { name string content *bytes.Buffer closed bool } func (f *File) Stat() (fs.FileInfo, error) { return fileInfo{ name: f.name, }, nil } func (f *File) Read(b []byte) (int, error) { if f.closed { return 0, fs.ErrClosed } return f.content.Read(b) } func (f *File) Close() error { if f.closed { return fs.ErrClosed } f.closed = true return nil }