mirror of
https://github.com/go-gitea/gitea
synced 2025-07-22 18:28:37 +00:00
Use a general approach to access custom/static/builtin assets (#24022)
The idea is to use a Layered Asset File-system (modules/assetfs/layered.go) For example: when there are 2 layers: "custom", "builtin", when access to asset "my/page.tmpl", the Layered Asset File-system will first try to use "custom" assets, if not found, then use "builtin" assets. This approach will hugely simplify a lot of code, make them testable. Other changes: * Simplify the AssetsHandlerFunc code * Simplify the `gitea embedded` sub-command code --------- Co-authored-by: Jason Song <i@wolfogre.com> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
This commit is contained in:
@@ -4,14 +4,10 @@
|
||||
package templates
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/assetfs"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
@@ -47,81 +43,30 @@ func BaseVars() Vars {
|
||||
}
|
||||
}
|
||||
|
||||
func getDirTemplateAssetNames(dir string) []string {
|
||||
return getDirAssetNames(dir, false)
|
||||
func AssetFS() *assetfs.LayeredFS {
|
||||
return assetfs.Layered(CustomAssets(), BuiltinAssets())
|
||||
}
|
||||
|
||||
func getDirAssetNames(dir string, mailer bool) []string {
|
||||
var tmpls []string
|
||||
func CustomAssets() *assetfs.Layer {
|
||||
return assetfs.Local("custom", setting.CustomPath, "templates")
|
||||
}
|
||||
|
||||
if mailer {
|
||||
dir += filepath.Join(dir, "mail")
|
||||
}
|
||||
f, err := os.Stat(dir)
|
||||
func ListWebTemplateAssetNames(assets *assetfs.LayeredFS) ([]string, error) {
|
||||
files, err := assets.ListAllFiles(".", true)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return tmpls
|
||||
}
|
||||
log.Warn("Unable to check if templates dir %s is a directory. Error: %v", dir, err)
|
||||
return tmpls
|
||||
}
|
||||
if !f.IsDir() {
|
||||
log.Warn("Templates dir %s is a not directory.", dir)
|
||||
return tmpls
|
||||
return nil, err
|
||||
}
|
||||
return util.SliceRemoveAllFunc(files, func(file string) bool {
|
||||
return strings.HasPrefix(file, "mail/") || !strings.HasSuffix(file, ".tmpl")
|
||||
}), nil
|
||||
}
|
||||
|
||||
files, err := util.StatDir(dir)
|
||||
func ListMailTemplateAssetNames(assets *assetfs.LayeredFS) ([]string, error) {
|
||||
files, err := assets.ListAllFiles(".", true)
|
||||
if err != nil {
|
||||
log.Warn("Failed to read %s templates dir. %v", dir, err)
|
||||
return tmpls
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prefix := "templates/"
|
||||
if mailer {
|
||||
prefix += "mail/"
|
||||
}
|
||||
for _, filePath := range files {
|
||||
if !mailer && strings.HasPrefix(filePath, "mail/") {
|
||||
continue
|
||||
}
|
||||
|
||||
if !strings.HasSuffix(filePath, ".tmpl") {
|
||||
continue
|
||||
}
|
||||
|
||||
tmpls = append(tmpls, prefix+filePath)
|
||||
}
|
||||
return tmpls
|
||||
}
|
||||
|
||||
func walkAssetDir(root string, skipMail bool, callback func(path, name string, d fs.DirEntry, err error) error) error {
|
||||
mailRoot := filepath.Join(root, "mail")
|
||||
if err := filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
|
||||
name := path[len(root):]
|
||||
if len(name) > 0 && name[0] == '/' {
|
||||
name = name[1:]
|
||||
}
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return callback(path, name, d, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
if skipMail && path == mailRoot && d.IsDir() {
|
||||
return fs.SkipDir
|
||||
}
|
||||
if util.CommonSkip(d.Name()) {
|
||||
if d.IsDir() {
|
||||
return fs.SkipDir
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if strings.HasSuffix(d.Name(), ".tmpl") || d.IsDir() {
|
||||
return callback(path, name, d, err)
|
||||
}
|
||||
return nil
|
||||
}); err != nil && !os.IsNotExist(err) {
|
||||
return fmt.Errorf("unable to get files for template assets in %s: %w", root, err)
|
||||
}
|
||||
return nil
|
||||
return util.SliceRemoveAllFunc(files, func(file string) bool {
|
||||
return !strings.HasPrefix(file, "mail/") || !strings.HasSuffix(file, ".tmpl")
|
||||
}), nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user