package furgit import ( "bytes" "errors" "fmt" "strconv" ) // ObjectType mirrors Git's object type tags. type ObjectType uint8 const ( ObjInvalid ObjectType = 0 ObjCommit ObjectType = 1 ObjTree ObjectType = 2 ObjBlob ObjectType = 3 ObjTag ObjectType = 4 ObjFuture ObjectType = 5 ObjOfsDelta ObjectType = 6 ObjRefDelta ObjectType = 7 ) const ( objNameBlob = "blob" objNameTree = "tree" objNameCommit = "commit" objNameTag = "tag" ) // Object describes any Git object variant. type Object interface { ObjectType() ObjectType } func headerForType(ty ObjectType, body []byte) ([]byte, error) { var tyStr string switch ty { case ObjBlob: tyStr = objNameBlob case ObjTree: tyStr = objNameTree case ObjCommit: tyStr = objNameCommit case ObjTag: tyStr = objNameTag case ObjInvalid, ObjFuture, ObjOfsDelta, ObjRefDelta: return nil, fmt.Errorf("furgit: object: unsupported type %d", ty) default: return nil, fmt.Errorf("furgit: object: unsupported type %d", ty) } size := strconv.Itoa(len(body)) var buf bytes.Buffer buf.Grow(len(tyStr) + len(size) + 1) buf.WriteString(tyStr) buf.WriteByte(' ') buf.WriteString(size) buf.WriteByte(0) return buf.Bytes(), nil } func parseObjectBody(ty ObjectType, id Hash, body []byte, repo *Repository) (Object, error) { switch ty { case ObjBlob: return parseBlob(id, body) case ObjTree: return parseTree(id, body, repo) case ObjCommit: return parseCommit(id, body, repo) case ObjTag: return parseTag(id, body, repo) case ObjInvalid, ObjFuture, ObjOfsDelta, ObjRefDelta: return nil, fmt.Errorf("furgit: object: unsupported type %d", ty) default: return nil, fmt.Errorf("furgit: object: unknown type %d", ty) } } // ReadObject resolves an ID by consulting loose then packed storage. func (repo *Repository) ReadObject(id Hash) (Object, error) { obj, err := repo.looseRead(id) if err == nil { return obj, nil } if !errors.Is(err, ErrNotFound) { return nil, err } obj, err = repo.packRead(id) if errors.Is(err, ErrNotFound) { return nil, ErrInvalidObject } return obj, err } // ReadObjectTypeSize reports the object type and size without inflating the body. func (repo *Repository) ReadObjectTypeSize(id Hash) (ObjectType, int64, error) { ty, size, err := repo.looseTypeSize(id) if err == nil { return ty, size, nil } if !errors.Is(err, ErrNotFound) { return ObjInvalid, 0, err } loc, err := repo.packIndexFind(id) if err != nil { if errors.Is(err, ErrNotFound) { return ObjInvalid, 0, ErrInvalidObject } return ObjInvalid, 0, err } return repo.packTypeSizeAtLocation(loc, nil) }