aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--object/blob/blob.go15
-rw-r--r--object/blob/parse.go8
-rw-r--r--object/blob/parse_test.go30
-rw-r--r--object/blob/serialize.go18
-rw-r--r--object/blob/serialize_test.go30
-rw-r--r--object/blob/type.go10
6 files changed, 111 insertions, 0 deletions
diff --git a/object/blob/blob.go b/object/blob/blob.go
new file mode 100644
index 00000000..4ba132d1
--- /dev/null
+++ b/object/blob/blob.go
@@ -0,0 +1,15 @@
+// Package blob provides
+// representations, parsers, and serializers
+// for blob objects.
+package blob
+
+// Blob represents a Git blob object.
+//
+// Blob is fully materialized in memory.
+// Consider using objectstore.Reader.ReadReaderContent,
+// or appropriate streaming write APIs.
+//
+// Labels: MT-Unsafe.
+type Blob struct {
+ Data []byte
+}
diff --git a/object/blob/parse.go b/object/blob/parse.go
new file mode 100644
index 00000000..b98b0f14
--- /dev/null
+++ b/object/blob/parse.go
@@ -0,0 +1,8 @@
+package blob
+
+// Parse decodes a blob object body.
+//
+// Labels: Deps-Owned, Life-Independent
+func Parse(body []byte) (*Blob, error) {
+ return &Blob{Data: append([]byte(nil), body...)}, nil
+}
diff --git a/object/blob/parse_test.go b/object/blob/parse_test.go
new file mode 100644
index 00000000..09d5d5d0
--- /dev/null
+++ b/object/blob/parse_test.go
@@ -0,0 +1,30 @@
+package blob_test
+
+import (
+ "bytes"
+ "testing"
+
+ "codeberg.org/lindenii/furgit/internal/testgit"
+ "codeberg.org/lindenii/furgit/object/blob"
+ objectid "codeberg.org/lindenii/furgit/object/id"
+)
+
+func TestBlobParseFromGit(t *testing.T) {
+ t.Parallel()
+ testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper
+ testRepo := testgit.NewRepo(t, testgit.RepoOptions{ObjectFormat: algo, Bare: true})
+ body := []byte("hello\nblob\n")
+ blobID := testRepo.HashObject(t, "blob", body)
+
+ rawBody := testRepo.CatFile(t, "blob", blobID)
+
+ parsed, err := blob.Parse(rawBody)
+ if err != nil {
+ t.Fatalf("ParseBlob: %v", err)
+ }
+
+ if !bytes.Equal(parsed.Data, body) {
+ t.Fatalf("blob body mismatch")
+ }
+ })
+}
diff --git a/object/blob/serialize.go b/object/blob/serialize.go
new file mode 100644
index 00000000..2dcc147f
--- /dev/null
+++ b/object/blob/serialize.go
@@ -0,0 +1,18 @@
+package blob
+
+import (
+ "codeberg.org/lindenii/furgit/object/header"
+ "codeberg.org/lindenii/furgit/object/typ"
+)
+
+// BytesWithoutHeader renders the raw blob body bytes.
+func (blob *Blob) AppendWithoutHeader(dst []byte) ([]byte, error) {
+ return append(dst, blob.Data...), nil
+}
+
+// BytesWithHeader renders the raw object (header + body).
+func (blob *Blob) AppendWithHeader(dst []byte) ([]byte, error) {
+ dst = header.Append(dst, typ.TypeBlob, uint64(len(blob.Data)))
+
+ return blob.AppendWithoutHeader(dst)
+}
diff --git a/object/blob/serialize_test.go b/object/blob/serialize_test.go
new file mode 100644
index 00000000..62a0b9a9
--- /dev/null
+++ b/object/blob/serialize_test.go
@@ -0,0 +1,30 @@
+package blob_test
+
+import (
+ "testing"
+
+ "codeberg.org/lindenii/furgit/internal/testgit"
+ "codeberg.org/lindenii/furgit/object/blob"
+ objectid "codeberg.org/lindenii/furgit/object/id"
+)
+
+func TestBlobSerialize(t *testing.T) {
+ t.Parallel()
+ testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper
+ testRepo := testgit.NewRepo(t, testgit.RepoOptions{ObjectFormat: algo, Bare: true})
+ body := []byte("hello\nblob\n")
+ wantID := testRepo.HashObject(t, "blob", body)
+
+ obj := &blob.Blob{Data: body}
+
+ rawObj, err := obj.AppendWithHeader([]byte(nil))
+ if err != nil {
+ t.Fatalf("BytesWithHeader: %v", err)
+ }
+
+ gotID := algo.Sum(rawObj)
+ if gotID != wantID {
+ t.Fatalf("object id mismatch: got %s want %s", gotID, wantID)
+ }
+ })
+}
diff --git a/object/blob/type.go b/object/blob/type.go
new file mode 100644
index 00000000..1a3f8b16
--- /dev/null
+++ b/object/blob/type.go
@@ -0,0 +1,10 @@
+package blob
+
+import "codeberg.org/lindenii/furgit/object/typ"
+
+// ObjectType returns TypeBlob.
+func (blob *Blob) ObjectType() typ.Type {
+ _ = blob
+
+ return typ.TypeBlob
+}