package dehub import ( "crypto/sha256" "encoding/binary" "fmt" "hash" "sort" "gopkg.in/src-d/go-git.v4/plumbing/object" ) var ( defaultHashHelperAlgo = sha256.New ) type hashHelper struct { hash.Hash varintBuf []byte } // if h is nil it then defaultHashHelperAlgo will be used func newHashHelper(h hash.Hash) *hashHelper { if h == nil { h = defaultHashHelperAlgo() } s := &hashHelper{ Hash: h, varintBuf: make([]byte, binary.MaxVarintLen64), } return s } func (s *hashHelper) sum(prefix []byte) []byte { out := make([]byte, len(prefix), len(prefix)+s.Hash.Size()) copy(out, prefix) return s.Hash.Sum(out) } func (s *hashHelper) writeUint(i uint64) { n := binary.PutUvarint(s.varintBuf, i) if _, err := s.Write(s.varintBuf[:n]); err != nil { panic(fmt.Sprintf("error writing %x to sha256 sum: %v", s.varintBuf[:n], err)) } } func (s *hashHelper) writeStr(str string) { s.writeUint(uint64(len(str))) s.Write([]byte(str)) } func (s *hashHelper) writeTreeDiff(from, to *object.Tree) { filesChanged, err := calcDiff(from, to) if err != nil { panic(err.Error()) } sort.Slice(filesChanged, func(i, j int) bool { return filesChanged[i].path < filesChanged[j].path }) s.writeUint(uint64(len(filesChanged))) for _, fileChanged := range filesChanged { s.writeStr(fileChanged.path) s.Write(fileChanged.fromMode.Bytes()) s.Write(fileChanged.fromHash[:]) s.Write(fileChanged.toMode.Bytes()) s.Write(fileChanged.toHash[:]) } } var ( changeHashVersion = []byte{0} commentHashVersion = []byte{0} ) // if h is nil it then defaultHashHelperAlgo will be used func genChangeHash(h hash.Hash, msg string, from, to *object.Tree) []byte { s := newHashHelper(h) s.writeStr(msg) s.writeTreeDiff(from, to) return s.sum(changeHashVersion) } // if h is nil it then defaultHashHelperAlgo will be used func genCommentHash(h hash.Hash, comment string) []byte { s := newHashHelper(h) s.writeStr(comment) return s.sum(commentHashVersion) }