|
@@ -0,0 +1,125 @@
|
|
|
|
+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()
|
|
|
|
+}
|