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) }