gob/shell/file/filelist.go

189 lines
4.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package file
import (
"cmp"
"sort"
"strings"
"time"
"gitea.zaclys.com/bvaudour/gob/compare"
)
// FileList représente une liste de fichiers.
type FileList []*File
func (fl *FileList) Add(files ...*File) { *fl = append(*fl, files...) }
// CmpFunc est une fonction comparant deux répertoires.
// Elle peut être utilisée pour trier des répertoires.
type CmpFunc func(*File, *File) int
// CmpAll agrège plusieurs fonctions de comparaison
// en une seule.
func CmpAll(args ...CmpFunc) CmpFunc {
return func(f1, f2 *File) int {
for _, cb := range args {
if c := cb(f1, f2); c != 0 {
return c
}
}
return 0
}
}
// ReverseCmp inverse la fonction de comparaison.
func ReverseCmp(cb CmpFunc) CmpFunc {
return func(f1, f2 *File) int {
return -cb(f1, f2)
}
}
// Sort trie la liste de fichier selon la fonction de comparaison.
func (fl FileList) Sort(cb CmpFunc) FileList {
if cb == nil {
return fl
}
less := func(i, j int) bool { return cb(fl[i], fl[j]) < 0 }
sort.Slice(fl, less)
return fl
}
func tr(e1, e2 string, t compare.TransformFunc) []string { return []string{t(e1), t(e2)} }
func trAll(e1, e2 string) [][]string {
a := tr(e1, e2, compare.ToAscii)
ai := tr(a[0], a[1], compare.ToLower)
i := tr(e1, e2, compare.ToLower)
return [][]string{ai, a, i, []string{e1, e2}}
}
func trf(f1, f2 *File) (h1, h2 bool, data [][]string) {
n1, n2 := f1.name, f2.name
h1, h2 = len(n1) > 0 && n1[0] == '.', len(n2) > 0 && n2[0] == '.'
if h1 {
n1 = n1[1:]
}
if h2 {
n2 = n2[1:]
}
data = trAll(n1, n2)
return
}
func cmpStrings(data [][]string, cb compare.CompareFunc) int {
for _, d := range data {
if c := cb(d[0], d[1]); c != 0 {
return c
}
}
return 0
}
func cmpRoot(f1, f2 *File) (int, bool) {
switch {
case f1.name == f2.name:
return 0, true
case f1.name == ".":
return -1, true
case f2.name == ".":
return 1, true
case f1.name == "..":
return -1, true
case f2.name == "..":
return 1, true
}
return 0, false
}
func cmpHidden(h1, h2 bool) int {
if h1 != h2 {
if h1 {
return -1
}
return 1
}
return 0
}
func cmpInt(cb func(*File) int64) CmpFunc {
return func(f1, f2 *File) int {
e1, e2 := cb(f1), cb(f2)
return cmp.Compare(e1, e2)
}
}
func cmpDate(cb func(*File) time.Time) CmpFunc {
return func(f1, f2 *File) int {
e1, e2 := cb(f1), cb(f2)
return cmp.Compare(e1.Unix(), e2.Unix())
}
}
func cmpName(cb compare.CompareFunc) CmpFunc {
return func(f1, f2 *File) int {
if c, ok := cmpRoot(f1, f2); ok {
return c
}
h1, h2, data := trf(f1, f2)
if c := cmpStrings(data, cb); c != 0 {
return c
}
return cmpHidden(h1, h2)
}
}
// CmpDir place les répertoires en premier.
func CmpDir(f1, f2 *File) int {
d1, d2 := f1.IsDir(), f2.IsDir()
if d1 == d2 {
return 0
} else if d1 {
return -1
}
return 1
}
// CmpExt compare deux fichiers de même nom par leur extension.
func CmpExt(f1, f2 *File) int {
return compare.CompareInsensitive(f1.Extension(), f2.Extension())
}
// CmpSize compare deux fichiers par leur taille.
func CmpSize(f1, f2 *File) int {
return cmpInt(func(f *File) int64 { return f.Size() })(f1, f2)
}
// CmpBlockSize compare deux fichiers par leur taille de bloc.
func CmpBlockSize(f1, f2 *File) int {
return cmpInt(func(f *File) int64 { return f.BlockSize() })(f1, f2)
}
// CmpCreationTime compare deux fichiers par leur date de création.
func CmpCreationTime(f1, f2 *File) int {
return cmpDate(func(f *File) time.Time { return f.CreationTime() })(f1, f2)
}
// CmpAccessTime compare deux fichiers par leur date daccès.
func CmpAccessTime(f1, f2 *File) int {
return cmpDate(func(f *File) time.Time { return f.AccessTime() })(f1, f2)
}
// CmpModificationTime compare deux fichiers par leur date de modification.
func CmpModificationTime(f1, f2 *File) int {
return cmpDate(func(f *File) time.Time { return f.ModificationTime() })(f1, f2)
}
// CmpName compare deux fichiers par leur nom.
func CmpName(f1, f2 *File) int {
return cmpName(strings.Compare)(f1, f2)
}
// CmpNatural compare deux fichier par leur nom de manière naturelle.
func CmpNatural(f1, f2 *File) int {
return cmpName(func(e1, e2 string) int { return compare.Natural(e1, e2) })(f1, f2)
}