file.go (3008B)
1 package dati 2 3 /* 4 Copyright (C) 2023 gearsix <gearsix@tuta.io> 5 6 This program is free software: you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <https://www.gnu.org/licenses/>. 18 */ 19 20 import ( 21 "fmt" 22 "os" 23 "path/filepath" 24 "sort" 25 "time" 26 ) 27 28 // SortFileList sorts `filepath` (a list of filepaths) in `order`. `order` 29 // can be any of the following values: "filename", "filename-asc", 30 // "filename-desc", "modified", "modified-asc", "modified-desc"; by default 31 // "filename" and "modified" are in ascending direction, if specified an 32 // "-asc" suffix will set the direction to ascending and "-desc" will set the 33 // direction to descending. 34 // This was originally intended to be used before calling LoadDataFiles on a 35 // set of "data" files. 36 func SortFileList(paths []string, order string) (sorted []string, err error) { 37 if order == "filename-desc" { 38 sorted = sortFileListByName("desc", paths) 39 } else if order == "filename-asc" || order == "filename" { 40 sorted = sortFileListByName("asc", paths) 41 } else if order == "modified-desc" { 42 sorted, err = sortFileListByMod("desc", paths) 43 } else if order == "modified-asc" || order == "modified" { 44 sorted, err = sortFileListByMod("asc", paths) 45 } else { 46 err = fmt.Errorf("invalid order '%s'", order) 47 sorted = paths 48 } 49 return 50 } 51 52 func sortFileListByName(direction string, paths []string) []string { 53 if direction == "desc" { 54 sort.Slice(paths, func(i, j int) bool { 55 return filepath.Base(paths[i]) > filepath.Base(paths[j]) 56 }) 57 } else { 58 sort.Slice(paths, func(i, j int) bool { 59 return filepath.Base(paths[i]) < filepath.Base(paths[j]) 60 }) 61 } 62 return paths 63 } 64 65 func sortFileListByMod(direction string, paths []string) ([]string, error) { 66 stats := make(map[string]os.FileInfo) 67 for _, p := range paths { 68 stat, err := os.Stat(p) 69 if err != nil { 70 return paths, err 71 } 72 stats[p] = stat 73 } 74 75 modtimes := make([]time.Time, 0, len(paths)) 76 for _, stat := range stats { 77 modtimes = append(modtimes, stat.ModTime()) 78 } 79 if direction == "desc" { 80 sort.Slice(modtimes, func(i, j int) bool { 81 return modtimes[i].After(modtimes[j]) 82 }) 83 } else { 84 sort.Slice(modtimes, func(i, j int) bool { 85 return modtimes[i].Before(modtimes[j]) 86 }) 87 } 88 89 sorted := make([]string, 0) 90 for _, t := range modtimes { 91 for path, stat := range stats { 92 if t == stat.ModTime() { 93 sorted = append(sorted, path) 94 delete(stats, path) 95 break 96 } 97 } 98 } 99 if len(sorted) != len(paths) { 100 return nil, fmt.Errorf("sorted length invalid") 101 } 102 103 return sorted, nil 104 }