github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/pkg/tarsum/fileinfosums.go (about)

     1  package tarsum // import "github.com/docker/docker/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  }