dati

data and template interface
git clone git://git.gearsix.net/dati
Log | Files | Refs | Atom | README | LICENSE

commit c2ab20a6dafc85965b0a107df8cee5728301818b
parent 8d5fb64edeea48893381ebe4a85058fb28849cc2
Author: gearsix <gearsix@tuta.io>
Date:   Tue, 13 Apr 2021 11:22:37 +0100

added file.go to provide SortFileList()

This is a stand-in replacement for removing LoadDataFiles, which
provided the ability to sort loaded file data

Diffstat:
Afile.go | 104+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Afile_test.go | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 173 insertions(+), 0 deletions(-)

diff --git a/file.go b/file.go @@ -0,0 +1,104 @@ +package suti + +/* +Copyright (C) 2021 gearsix <gearsix@tuta.io> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +import ( + "fmt" + "path/filepath" + "sort" + "time" + "os" +) + +// SortFileList sorts `filepath` (a list of filepaths) in `order`. `order` +// can be any of the following values: "filename", "filename-asc", +// "filename-desc", "modified", "modified-asc", "modified-desc"; by default +// "filename" and "modified" are in ascending direction, if specified an +// "-asc" suffix will set the direction to ascending and "-desc" will set the +// direction to descending. +// This was originally intended to be used before calling LoadDataFiles on a +// set of "data" files. +func SortFileList(paths []string, order string) (sorted []string, err error) { + if order == "filename-desc" { + sorted = sortFileListByName("desc", paths) + } else if order == "filename-asc" || order == "filename" { + sorted = sortFileListByName("asc", paths) + } else if order == "modified-desc" { + sorted, err = sortFileListByMod("desc", paths) + } else if order == "modified-asc" || order == "modified" { + sorted, err = sortFileListByMod("asc", paths) + } else { + err = fmt.Errorf("invalid order '%s'", order) + sorted = paths + } + return +} + +func sortFileListByName(direction string, paths[]string) []string { + if direction == "desc" { + sort.Slice(paths, func(i, j int) bool { + return filepath.Base(paths[i]) > filepath.Base(paths[j]) + }) + } else { + sort.Slice(paths, func(i, j int) bool { + return filepath.Base(paths[i]) < filepath.Base(paths[j]) + }) + } + return paths +} + +func sortFileListByMod(direction string, paths []string) ([]string, error) { + stats := make(map[string]os.FileInfo) + for _, p := range paths { + stat, err := os.Stat(p) + if err != nil { + return paths, err + } + stats[p] = stat + } + + modtimes := make([]time.Time, 0, len(paths)) + for _, stat := range stats { + modtimes = append(modtimes, stat.ModTime()) + } + if direction == "desc" { + sort.Slice(modtimes, func(i, j int) bool { + return modtimes[i].After(modtimes[j]) + }) + } else { + sort.Slice(modtimes, func(i, j int) bool { + return modtimes[i].Before(modtimes[j]) + }) + } + + sorted := make([]string, 0) + for _, t := range modtimes { + for path, stat := range stats { + if t == stat.ModTime() { + sorted = append(sorted, path) + delete(stats, path) + break + } + } + } + if len(sorted) != len(paths) { + fmt.Errorf("sorted length invalid") + } + + return sorted, nil +} diff --git a/file_test.go b/file_test.go @@ -0,0 +1,69 @@ +package suti + +import ( + "testing" + "strconv" + "os" + "time" + "path/filepath" +) + +func TestSortFileList(t *testing.T) { + var err error + tdir := t.TempDir() + paths := []string{tdir+"/1", tdir+"/3", tdir+"/2"} + sorted := make([]string, 0, len(paths)) + + sorted, err = SortFileList(paths, "filename") + if err != nil { + t.Error(err) + } + for i, p := range sorted { + if filepath.Base(p) != strconv.Itoa(i+1) { + t.Errorf("invalid order returned sorted[%d] is %s", i, p) + } + } + + sorted, err = SortFileList(paths, "filename-desc") + if err != nil { + t.Error(err) + } + j := 3 + for i := 0; i < len(sorted); i++ { + if filepath.Base(sorted[i]) != strconv.Itoa(j) { + t.Errorf("invalid order returned sorted[%d] is %s", i, sorted[i]) + } + j-- + } + + for _, path := range paths { + var f *os.File + if f, err = os.Create(path); err != nil { + t.Skip(err) + } + defer f.Close() + time.Sleep(100 * time.Millisecond) + } + + sorted, err = SortFileList(paths, "modified") + if err != nil { + t.Error(err) + } + for i, _ := range paths { + if sorted[i] != paths[i] { + t.Errorf("invalid order returned %s - %s", sorted, paths) + } + } + + sorted, err = SortFileList(paths, "modified-desc") + if err != nil { + t.Error(err) + } + j = 2 + for i := 0; i < len(paths); i++ { + if sorted[i] != paths[j] { + t.Errorf("invalid order returned %s - %s", sorted, paths) + } + j-- + } +}