package tarsum import "sort" // This info will be accessed through interface so the actual name and sum cannot be medled with type FileInfoSumInterface interface { // File name Name() string // Checksum of this particular file and its headers Sum() string // Position of file in the tar Pos() int64 } type fileInfoSum struct { name string sum string pos int64 } func (fis fileInfoSum) Name() string { return fis.name } func (fis fileInfoSum) Sum() string { return fis.sum } func (fis fileInfoSum) Pos() int64 { return fis.pos } type FileInfoSums []FileInfoSumInterface // GetFile returns the first FileInfoSumInterface with a matching name func (fis FileInfoSums) GetFile(name string) FileInfoSumInterface { for i := range fis { if fis[i].Name() == name { return fis[i] } } return nil } // GetAllFile returns a FileInfoSums with all matching names func (fis FileInfoSums) GetAllFile(name string) FileInfoSums { f := FileInfoSums{} for i := range fis { if fis[i].Name() == name { f = append(f, fis[i]) } } return f } func contains(s []string, e string) bool { for _, a := range s { if a == e { return true } } return false } func (fis FileInfoSums) GetDuplicatePaths() (dups FileInfoSums) { seen := make(map[string]int, len(fis)) // allocate earl. no need to grow this map. for i := range fis { f := fis[i] if _, ok := seen[f.Name()]; ok { dups = append(dups, f) } else { seen[f.Name()] = 0 } } return dups } func (fis FileInfoSums) Len() int { return len(fis) } func (fis FileInfoSums) Swap(i, j int) { fis[i], fis[j] = fis[j], fis[i] } func (fis FileInfoSums) SortByPos() { sort.Sort(byPos{fis}) } func (fis FileInfoSums) SortByNames() { sort.Sort(byName{fis}) } func (fis FileInfoSums) SortBySums() { dups := fis.GetDuplicatePaths() if len(dups) > 0 { sort.Sort(bySum{fis, dups}) } else { sort.Sort(bySum{fis, nil}) } } // byName is a sort.Sort helper for sorting by file names. // If names are the same, order them by their appearance in the tar archive type byName struct{ FileInfoSums } func (bn byName) Less(i, j int) bool { if bn.FileInfoSums[i].Name() == bn.FileInfoSums[j].Name() { return bn.FileInfoSums[i].Pos() < bn.FileInfoSums[j].Pos() } return bn.FileInfoSums[i].Name() < bn.FileInfoSums[j].Name() } // bySum is a sort.Sort helper for sorting by the sums of all the fileinfos in the tar archive type bySum struct { FileInfoSums dups FileInfoSums } func (bs bySum) Less(i, j int) bool { if bs.dups != nil && bs.FileInfoSums[i].Name() == bs.FileInfoSums[j].Name() { return bs.FileInfoSums[i].Pos() < bs.FileInfoSums[j].Pos() } return bs.FileInfoSums[i].Sum() < bs.FileInfoSums[j].Sum() } // byPos is a sort.Sort helper for sorting by the sums of all the fileinfos by their original order type byPos struct{ FileInfoSums } func (bp byPos) Less(i, j int) bool { return bp.FileInfoSums[i].Pos() < bp.FileInfoSums[j].Pos() }