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:
A | file.go | | | 104 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | file_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--
+ }
+}