Esempio n. 1
0
func (pk *PackReader) extractAt(off int64) (typ int, data []byte, err error) {
	var buf [16]byte // 109-bit sizes should be enough for everybody.
	_, err = pk.pack.ReadAt(buf[:], off)
	if err == io.EOF || err == io.ErrUnexpectedEOF {
		err = nil
	}
	if err != nil {
		return
	}
	varint, n := binary.Uvarint(buf[:])
	objsize := int64((varint>>7)<<4 | (varint & 0xf))
	objtype := int(varint>>4) & 0x7 // 3 bits.

	switch objtype {
	case pkCommit, pkTree, pkBlob, pkTag:
		// objsize is the *uncompressed* size.
		data = make([]byte, objsize)
		n, err := readCompressed(pk.pack, off+int64(n), data)
		return objtype, data[:n], err
	case pkRefDelta:
		// Ref delta: parent hash (20 bytes) + deflated delta (objsize bytes)
		var parent Hash
		_, err := pk.pack.ReadAt(parent[:], off+int64(n))
		if err != nil {
			return typ, data, err
		}
		patch := make([]byte, objsize)
		_, err = readCompressed(pk.pack, off+int64(n)+20, patch)
		// FIXME: check that parent object is always in the same pack.
		typ, data, err = pk.extract(parent)
		if err != nil {
			return typ, patch, err
		}
		data, err = gitdelta.Patch(data, patch)
		if err != nil {
			return typ, patch, err
		}
		return typ, data, err
	case pkOfsDelta:
		// Offset delta: distance to parent (varint bytes) + deflated delta (objsize bytes)
		parentOff, n2, err := readVaroffset(pk.pack, off+int64(n))
		if err != nil {
			return objtype, data, err
		}
		patch := make([]byte, objsize)
		_, err = readCompressed(pk.pack, off+int64(n+n2), patch)
		typ, data, err = pk.extractAt(off - parentOff)
		if err != nil {
			return typ, patch, err
		}
		data, err = gitdelta.Patch(data, patch)
		if err != nil {
			return typ, patch, err
		}
		return typ, data, err
	}
	return typ, data, errInvalidPackEntryType
}
Esempio n. 2
0
// Patch applies a diff on a revision and returns a new revision patched to the
// latest version.
//
// TODO NOTE TODO NOTE This function will not be compleeted until the Revision
// struct is moved inside shared application code so that the client
// application can use it.
func (r *Revision) Patch(diff []byte) *Revision {
	oldbytes := r.bytes()
	patched, err := gitdelta.Patch(oldbytes, diff)
	if err != nil {
		panic(err)
	}
	content := make([]string, 0)
	reader := bytes.NewReader(patched)
	scanner := bufio.NewScanner(reader)
	for scanner.Scan() {
		item := scanner.Text()
		if item != "" {
			content = append(content, item)
		}
	}
	if err := scanner.Err(); err != nil {
		panic(err)
	}
	return NewRevision(content)
}