package dehub import ( "crypto/sha256" "encoding/binary" "fmt" "hash" "sort" ) var ( defaultHashHelperAlgo = sha256.New ) type hashHelper struct { hash 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.hash.Write(s.varintBuf[:n]); err != nil { panic(fmt.Sprintf("error writing %x to %T: %v", s.varintBuf[:n], s.hash, err)) } } func (s *hashHelper) writeStr(str string) { s.writeUint(uint64(len(str))) s.hash.Write([]byte(str)) } func (s *hashHelper) writeChangedFiles(changedFiles []ChangedFile) { sort.Slice(changedFiles, func(i, j int) bool { return changedFiles[i].Path < changedFiles[j].Path }) s.writeUint(uint64(len(changedFiles))) for _, fileChanged := range changedFiles { s.writeStr(fileChanged.Path) s.hash.Write(fileChanged.FromMode.Bytes()) s.hash.Write(fileChanged.FromHash[:]) s.hash.Write(fileChanged.ToMode.Bytes()) s.hash.Write(fileChanged.ToHash[:]) } } var ( changeHashVersion = []byte{0} commentHashVersion = []byte{0} ) // if h is nil it then defaultHashHelperAlgo will be used func genChangeFingerprint(h hash.Hash, msg string, changedFiles []ChangedFile) []byte { s := newHashHelper(h) s.writeStr(msg) s.writeChangedFiles(changedFiles) return s.sum(changeHashVersion) } // if h is nil it then defaultHashHelperAlgo will be used func genCommentFingerprint(h hash.Hash, comment string) []byte { s := newHashHelper(h) s.writeStr(comment) return s.sum(commentHashVersion) }