package fs import ( "bytes" "io" "os" "sort" "strings" "text/template" sr "tildegit.org/tjp/sliderule" ) // RenderDirectoryListing provides an io.Reader with the output of a directory listing template. // // The template is provided the following namespace: // - .FullPath: the complete path to the listed directory // - .DirName: the name of the directory itself // - .Entries: the []fs.DirEntry of the directory contents // - .Hostname: the hostname of the server hosting the file // - .Port: the port on which the server is listening // // Each entry in .Entries has the following fields: // - .Name the string name of the item within the directory // - .IsDir is a boolean // - .Type is the FileMode bits // - .Info is a method returning (fs.FileInfo, error) func RenderDirectoryListing( path string, requestpath string, template *template.Template, server sr.Server, ) (io.Reader, error) { buf := &bytes.Buffer{} environ, err := dirlistNamespace(path, requestpath, server) if err != nil { return nil, err } if err := template.Execute(buf, environ); err != nil { return nil, err } return buf, nil } func dirlistNamespace(path, requestpath string, server sr.Server) (map[string]any, error) { entries, err := os.ReadDir(path) if err != nil { return nil, err } for i := len(entries) - 1; i >= 0; i-- { if strings.HasPrefix(entries[i].Name(), ".") { copy(entries[i:], entries[i+1:]) entries = entries[:len(entries)-1] } } sort.Slice(entries, func(i, j int) bool { return entries[i].Name() < entries[j].Name() }) var dirname string if requestpath == "" { dirname = "(root)" } else { dirname = path[strings.LastIndex(path, "/")+1:] } hostname := "none" port := "0" if server != nil { hostname = server.Hostname() port = server.Port() } m := map[string]any{ "FullPath": path, "DirName": dirname, "Entries": entries, "Hostname": hostname, "Port": port, } return m, nil }