mirror of
				https://github.com/moby/moby.git
				synced 2022-11-09 12:21:53 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			88 lines
		
	
	
	
		
			2.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			88 lines
		
	
	
	
		
			2.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package continuity
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"sort"
 | |
| 
 | |
| 	"github.com/opencontainers/go-digest"
 | |
| )
 | |
| 
 | |
| // Digester produces a digest for a given read stream
 | |
| type Digester interface {
 | |
| 	Digest(io.Reader) (digest.Digest, error)
 | |
| }
 | |
| 
 | |
| // ContentProvider produces a read stream for a given digest
 | |
| type ContentProvider interface {
 | |
| 	Reader(digest.Digest) (io.ReadCloser, error)
 | |
| }
 | |
| 
 | |
| type simpleDigester struct {
 | |
| 	algorithm digest.Algorithm
 | |
| }
 | |
| 
 | |
| func (sd simpleDigester) Digest(r io.Reader) (digest.Digest, error) {
 | |
| 	digester := sd.algorithm.Digester()
 | |
| 
 | |
| 	if _, err := io.Copy(digester.Hash(), r); err != nil {
 | |
| 		return "", err
 | |
| 	}
 | |
| 
 | |
| 	return digester.Digest(), nil
 | |
| }
 | |
| 
 | |
| // uniqifyDigests sorts and uniqifies the provided digest, ensuring that the
 | |
| // digests are not repeated and no two digests with the same algorithm have
 | |
| // different values. Because a stable sort is used, this has the effect of
 | |
| // "zipping" digest collections from multiple resources.
 | |
| func uniqifyDigests(digests ...digest.Digest) ([]digest.Digest, error) {
 | |
| 	sort.Stable(digestSlice(digests)) // stable sort is important for the behavior here.
 | |
| 	seen := map[digest.Digest]struct{}{}
 | |
| 	algs := map[digest.Algorithm][]digest.Digest{} // detect different digests.
 | |
| 
 | |
| 	var out []digest.Digest
 | |
| 	// uniqify the digests
 | |
| 	for _, d := range digests {
 | |
| 		if _, ok := seen[d]; ok {
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		seen[d] = struct{}{}
 | |
| 		algs[d.Algorithm()] = append(algs[d.Algorithm()], d)
 | |
| 
 | |
| 		if len(algs[d.Algorithm()]) > 1 {
 | |
| 			return nil, fmt.Errorf("conflicting digests for %v found", d.Algorithm())
 | |
| 		}
 | |
| 
 | |
| 		out = append(out, d)
 | |
| 	}
 | |
| 
 | |
| 	return out, nil
 | |
| }
 | |
| 
 | |
| // digestsMatch compares the two sets of digests to see if they match.
 | |
| func digestsMatch(as, bs []digest.Digest) bool {
 | |
| 	all := append(as, bs...)
 | |
| 
 | |
| 	uniqified, err := uniqifyDigests(all...)
 | |
| 	if err != nil {
 | |
| 		// the only error uniqifyDigests returns is when the digests disagree.
 | |
| 		return false
 | |
| 	}
 | |
| 
 | |
| 	disjoint := len(as) + len(bs)
 | |
| 	if len(uniqified) == disjoint {
 | |
| 		// if these two sets have the same cardinality, we know both sides
 | |
| 		// didn't share any digests.
 | |
| 		return false
 | |
| 	}
 | |
| 
 | |
| 	return true
 | |
| }
 | |
| 
 | |
| type digestSlice []digest.Digest
 | |
| 
 | |
| func (p digestSlice) Len() int           { return len(p) }
 | |
| func (p digestSlice) Less(i, j int) bool { return p[i] < p[j] }
 | |
| func (p digestSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
 | 
