189 lines
4.1 KiB
Go
189 lines
4.1 KiB
Go
|
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 d’accè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)
|
|||
|
}
|