aboutsummaryrefslogtreecommitdiff
path: root/object/store/loose/write_reader.go
diff options
context:
space:
mode:
Diffstat (limited to 'object/store/loose/write_reader.go')
-rw-r--r--object/store/loose/write_reader.go81
1 files changed, 81 insertions, 0 deletions
diff --git a/object/store/loose/write_reader.go b/object/store/loose/write_reader.go
new file mode 100644
index 00000000..f686f279
--- /dev/null
+++ b/object/store/loose/write_reader.go
@@ -0,0 +1,81 @@
+package loose
+
+import (
+ "fmt"
+ "io"
+
+ objectheader "codeberg.org/lindenii/furgit/object/header"
+ objectid "codeberg.org/lindenii/furgit/object/id"
+ objecttype "codeberg.org/lindenii/furgit/object/type"
+)
+
+// 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
+
+ err = writer.writeRawChunk(header)
+ if 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) {
+ _, err := io.Copy(writer, src)
+ if err != nil {
+ _ = writer.Close()
+ _ = writer.store.root.Remove(writer.tmpRelPath)
+
+ return objectid.ObjectID{}, err
+ }
+
+ err = writer.Close()
+ if 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
+}