diff options
| author | 2026-02-21 17:49:18 +0800 | |
|---|---|---|
| committer | 2026-02-21 17:49:18 +0800 | |
| commit | 3ecd35180fa8cb842589e28744fed7d130120dc1 (patch) | |
| tree | 066c034bd5cf51aa26e8a1a63348c255ccc794ad /objectstore/loose/write_reader.go | |
| parent | objectstore/packed: Fix ReadHeader to return resolved delta object size (diff) | |
| signature | No signature | |
objectstore/loose, repository: Use a Reader-based API v0.1.22
Diffstat (limited to 'objectstore/loose/write_reader.go')
| -rw-r--r-- | objectstore/loose/write_reader.go | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/objectstore/loose/write_reader.go b/objectstore/loose/write_reader.go new file mode 100644 index 00000000..b2329f02 --- /dev/null +++ b/objectstore/loose/write_reader.go @@ -0,0 +1,70 @@ +package loose + +import ( + "fmt" + "io" + + "codeberg.org/lindenii/furgit/objectheader" + "codeberg.org/lindenii/furgit/objectid" + "codeberg.org/lindenii/furgit/objecttype" +) + +// WriteReaderContent writes one loose object from typed content bytes read from src. +// src must provide exactly size bytes. +// size is required because loose object headers are "type size\0content", so the +// header must be emitted before streaming content without buffering. +func (store *Store) WriteReaderContent(ty objecttype.Type, size int64, src io.Reader) (objectid.ObjectID, error) { + if size < 0 { + return objectid.ObjectID{}, fmt.Errorf("objectstore/loose: negative content size: %d", size) + } + + header, ok := objectheader.Encode(ty, size) + if !ok { + return objectid.ObjectID{}, fmt.Errorf("objectstore/loose: failed to encode object header for type %v", ty) + } + + writer, err := store.newStreamWriter(false) + if err != nil { + return objectid.ObjectID{}, err + } + writer.headerDone = true + writer.expectedContentLeft = size + + if err := writer.writeRawChunk(header); err != nil { + _ = writer.Close() + _ = store.root.Remove(writer.tmpRelPath) + return objectid.ObjectID{}, err + } + + return writeReaderIntoStreamWriter(writer, src) +} + +// WriteReaderFull writes one loose object from raw bytes "type size\0content" +// read from src. +func (store *Store) WriteReaderFull(src io.Reader) (objectid.ObjectID, error) { + writer, err := store.newStreamWriter(true) + if err != nil { + return objectid.ObjectID{}, err + } + return writeReaderIntoStreamWriter(writer, src) +} + +// writeReaderIntoStreamWriter copies src into writer and publishes the object. +func writeReaderIntoStreamWriter(writer *streamWriter, src io.Reader) (objectid.ObjectID, error) { + if _, err := io.Copy(writer, src); err != nil { + _ = writer.Close() + _ = writer.store.root.Remove(writer.tmpRelPath) + return objectid.ObjectID{}, err + } + if err := writer.Close(); err != nil { + _ = writer.store.root.Remove(writer.tmpRelPath) + return objectid.ObjectID{}, err + } + + id, err := writer.finalize() + if err != nil { + _ = writer.store.root.Remove(writer.tmpRelPath) + return objectid.ObjectID{}, err + } + return id, nil +} |
