aboutsummaryrefslogtreecommitdiff
path: root/objectstore/loose/write_reader.go
diff options
context:
space:
mode:
authorGravatar Runxi Yu2026-02-21 17:49:18 +0800
committerGravatar Runxi Yu2026-02-21 17:49:18 +0800
commit3ecd35180fa8cb842589e28744fed7d130120dc1 (patch)
tree066c034bd5cf51aa26e8a1a63348c255ccc794ad /objectstore/loose/write_reader.go
parentobjectstore/packed: Fix ReadHeader to return resolved delta object size (diff)
signatureNo 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.go70
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
+}