github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/pkg/tarsum/fileinfosums.go (about) 1 package tarsum // import "github.com/demonoid81/moby/pkg/tarsum" 2 3 import ( 4 "runtime" 5 "sort" 6 "strings" 7 ) 8 9 // FileInfoSumInterface provides an interface for accessing file checksum 10 // information within a tar file. This info is accessed through interface 11 // so the actual name and sum cannot be melded with. 12 type FileInfoSumInterface interface { 13 // File name 14 Name() string 15 // Checksum of this particular file and its headers 16 Sum() string 17 // Position of file in the tar 18 Pos() int64 19 } 20 21 type fileInfoSum struct { 22 name string 23 sum string 24 pos int64 25 } 26 27 func (fis fileInfoSum) Name() string { 28 return fis.name 29 } 30 func (fis fileInfoSum) Sum() string { 31 return fis.sum 32 } 33 func (fis fileInfoSum) Pos() int64 { 34 return fis.pos 35 } 36 37 // FileInfoSums provides a list of FileInfoSumInterfaces. 38 type FileInfoSums []FileInfoSumInterface 39 40 // GetFile returns the first FileInfoSumInterface with a matching name. 41 func (fis FileInfoSums) GetFile(name string) FileInfoSumInterface { 42 // We do case insensitive matching on Windows as c:\APP and c:\app are 43 // the same. See issue #33107. 44 for i := range fis { 45 if (runtime.GOOS == "windows" && strings.EqualFold(fis[i].Name(), name)) || 46 (runtime.GOOS != "windows" && fis[i].Name() == name) { 47 return fis[i] 48 } 49 } 50 return nil 51 } 52 53 // GetAllFile returns a FileInfoSums with all matching names. 54 func (fis FileInfoSums) GetAllFile(name string) FileInfoSums { 55 f := FileInfoSums{} 56 for i := range fis { 57 if fis[i].Name() == name { 58 f = append(f, fis[i]) 59 } 60 } 61 return f 62 } 63 64 // GetDuplicatePaths returns a FileInfoSums with all duplicated paths. 65 func (fis FileInfoSums) GetDuplicatePaths() (dups FileInfoSums) { 66 seen := make(map[string]int, len(fis)) // allocate earl. no need to grow this map. 67 for i := range fis { 68 f := fis[i] 69 if _, ok := seen[f.Name()]; ok { 70 dups = append(dups, f) 71 } else { 72 seen[f.Name()] = 0 73 } 74 } 75 return dups 76 } 77 78 // Len returns the size of the FileInfoSums. 79 func (fis FileInfoSums) Len() int { return len(fis) } 80 81 // Swap swaps two FileInfoSum values if a FileInfoSums list. 82 func (fis FileInfoSums) Swap(i, j int) { fis[i], fis[j] = fis[j], fis[i] } 83 84 // SortByPos sorts FileInfoSums content by position. 85 func (fis FileInfoSums) SortByPos() { 86 sort.Sort(byPos{fis}) 87 } 88 89 // SortByNames sorts FileInfoSums content by name. 90 func (fis FileInfoSums) SortByNames() { 91 sort.Sort(byName{fis}) 92 } 93 94 // SortBySums sorts FileInfoSums content by sums. 95 func (fis FileInfoSums) SortBySums() { 96 dups := fis.GetDuplicatePaths() 97 if len(dups) > 0 { 98 sort.Sort(bySum{fis, dups}) 99 } else { 100 sort.Sort(bySum{fis, nil}) 101 } 102 } 103 104 // byName is a sort.Sort helper for sorting by file names. 105 // If names are the same, order them by their appearance in the tar archive 106 type byName struct{ FileInfoSums } 107 108 func (bn byName) Less(i, j int) bool { 109 if bn.FileInfoSums[i].Name() == bn.FileInfoSums[j].Name() { 110 return bn.FileInfoSums[i].Pos() < bn.FileInfoSums[j].Pos() 111 } 112 return bn.FileInfoSums[i].Name() < bn.FileInfoSums[j].Name() 113 } 114 115 // bySum is a sort.Sort helper for sorting by the sums of all the fileinfos in the tar archive 116 type bySum struct { 117 FileInfoSums 118 dups FileInfoSums 119 } 120 121 func (bs bySum) Less(i, j int) bool { 122 if bs.dups != nil && bs.FileInfoSums[i].Name() == bs.FileInfoSums[j].Name() { 123 return bs.FileInfoSums[i].Pos() < bs.FileInfoSums[j].Pos() 124 } 125 return bs.FileInfoSums[i].Sum() < bs.FileInfoSums[j].Sum() 126 } 127 128 // byPos is a sort.Sort helper for sorting by the sums of all the fileinfos by their original order 129 type byPos struct{ FileInfoSums } 130 131 func (bp byPos) Less(i, j int) bool { 132 return bp.FileInfoSums[i].Pos() < bp.FileInfoSums[j].Pos() 133 }