diff --git a/fs.go b/fs.go index f33195bc..905be9fb 100644 --- a/fs.go +++ b/fs.go @@ -6,25 +6,61 @@ import ( "path/filepath" ) -type IFileSystem interface { - http.FileSystem - Walk(string, filepath.WalkFunc) error -} - -// A File is returned by a FileSystem's Open method and can be -// served by the FileServer implementation. -// -// The methods should behave the same as those on an *os.File. -type File struct { - *os.File -} - type FileSystem struct { } func (d FileSystem) Open(name string) (http.File, error) { return os.Open(name) } -func (d FileSystem) Walk(root string, walkFn filepath.WalkFunc) error { - return filepath.Walk(root, walkFn) + +func Walk(fs http.FileSystem, root string, walkFn filepath.WalkFunc) error { + + f, err := fs.Open(root) + if err != nil { + return err + } + info, err := f.Stat() + if err != nil { + err = walkFn(root, nil, err) + } else { + err = walk(fs, root, info, walkFn) + } + if err == filepath.SkipDir { + return nil + } + return err +} + +// walk recursively descends path, calling walkFn. +func walk(fs http.FileSystem, path string, info os.FileInfo, walkFn filepath.WalkFunc) error { + var err error + if !info.IsDir() { + return walkFn(path, info, nil) + } + + dir, err := fs.Open(path) + defer dir.Close() + dirs, err := dir.Readdir(-1) + err1 := walkFn(path, info, err) + // If err != nil, walk can't walk into this directory. + // err1 != nil means walkFn want walk to skip this directory or stop walking. + // Therefore, if one of err and err1 isn't nil, walk will return. + if err != nil || err1 != nil { + // The caller's behavior is controlled by the return value, which is decided + // by walkFn. walkFn may ignore err and return nil. + // If walkFn returns SkipDir, it will be handled by the caller. + // So walk should return whatever walkFn returns. + return err1 + } + + for _, fileInfo := range dirs { + filename := filepath.Join(path, fileInfo.Name()) + err = walk(fs, filename, fileInfo, walkFn) + if err != nil { + if !fileInfo.IsDir() || err != filepath.SkipDir { + return err + } + } + } + return nil } diff --git a/template.go b/template.go index 3321d13f..f8589445 100644 --- a/template.go +++ b/template.go @@ -20,6 +20,7 @@ import ( "html/template" "io" "io/ioutil" + "net/http" "os" "path/filepath" "regexp" @@ -201,7 +202,7 @@ func BuildTemplate(dir string, files ...string) error { root: dir, files: make(map[string][]string), } - err = fs.Walk(dir, func(path string, f os.FileInfo, err error) error { + err = Walk(fs, dir, func(path string, f os.FileInfo, err error) error { return self.visit(path, f, err) }) if err != nil { @@ -235,7 +236,7 @@ func BuildTemplate(dir string, files ...string) error { return nil } -func getTplDeep(root string, fs IFileSystem, file string, parent string, t *template.Template) (*template.Template, [][]string, error) { +func getTplDeep(root string, fs http.FileSystem, file string, parent string, t *template.Template) (*template.Template, [][]string, error) { var fileAbsPath string var rParent string var err error @@ -279,7 +280,7 @@ func getTplDeep(root string, fs IFileSystem, file string, parent string, t *temp return t, allSub, nil } -func getTemplate(root string, fs IFileSystem, file string, others ...string) (t *template.Template, err error) { +func getTemplate(root string, fs http.FileSystem, file string, others ...string) (t *template.Template, err error) { t = template.New(file).Delims(BConfig.WebConfig.TemplateLeft, BConfig.WebConfig.TemplateRight).Funcs(beegoTplFuncMap) var subMods [][]string t, subMods, err = getTplDeep(root, fs, file, "", t) @@ -294,7 +295,7 @@ func getTemplate(root string, fs IFileSystem, file string, others ...string) (t return } -func _getTemplate(t0 *template.Template, root string, fs IFileSystem, subMods [][]string, others ...string) (t *template.Template, err error) { +func _getTemplate(t0 *template.Template, root string, fs http.FileSystem, subMods [][]string, others ...string) (t *template.Template, err error) { t = t0 for _, m := range subMods { if len(m) == 2 { @@ -347,9 +348,9 @@ func _getTemplate(t0 *template.Template, root string, fs IFileSystem, subMods [] return } -type templateFSFunc func() IFileSystem +type templateFSFunc func() http.FileSystem -func defaultFSFunc() IFileSystem { +func defaultFSFunc() http.FileSystem { return FileSystem{} } func SetTemplateFSFunc(fnt templateFSFunc) { diff --git a/template_test.go b/template_test.go index d42f7663..287faadc 100644 --- a/template_test.go +++ b/template_test.go @@ -267,57 +267,6 @@ type TestingFileSystem struct { func (d TestingFileSystem) Open(name string) (http.File, error) { return d.assetfs.Open(name) } -func (d TestingFileSystem) Walk(root string, walkFn filepath.WalkFunc) error { - - f, err := d.Open(root) - if err != nil { - return err - } - info, err := f.Stat() - if err != nil { - err = walkFn(root, nil, err) - } else { - err = d.walk(root, info, walkFn) - } - if err == filepath.SkipDir { - return nil - } - return err -} - -// walk recursively descends path, calling walkFn. -func (d TestingFileSystem) walk(path string, info os.FileInfo, walkFn filepath.WalkFunc) error { - var err error - if !info.IsDir() { - return walkFn(path, info, nil) - } - - dir, err := d.Open(path) - defer dir.Close() - dirs, err := dir.Readdir(-1) - err1 := walkFn(path, info, err) - // If err != nil, walk can't walk into this directory. - // err1 != nil means walkFn want walk to skip this directory or stop walking. - // Therefore, if one of err and err1 isn't nil, walk will return. - if err != nil || err1 != nil { - // The caller's behavior is controlled by the return value, which is decided - // by walkFn. walkFn may ignore err and return nil. - // If walkFn returns SkipDir, it will be handled by the caller. - // So walk should return whatever walkFn returns. - return err1 - } - - for _, fileInfo := range dirs { - filename := filepath.Join(path, fileInfo.Name()) - err = d.walk(filename, fileInfo, walkFn) - if err != nil { - if !fileInfo.IsDir() || err != filepath.SkipDir { - return err - } - } - } - return nil -} var outputBinData = ` @@ -341,7 +290,7 @@ var outputBinData = ` ` func TestFsBinData(t *testing.T) { - SetTemplateFSFunc(func() IFileSystem { + SetTemplateFSFunc(func() http.FileSystem { return TestingFileSystem{&assetfs.AssetFS{Asset: testdata.Asset, AssetDir: testdata.AssetDir, AssetInfo: testdata.AssetInfo}} }) dir := "views"