aboutsummaryrefslogtreecommitdiff
path: root/object/tree
diff options
context:
space:
mode:
authorGravatar Runxi Yu2026-04-02 06:23:30 +0000
committerGravatar Runxi Yu2026-04-02 06:28:39 +0000
commita041d523de389b65b98a5373a8034041db2a8d83 (patch)
tree7b423dc735f463be616045f2c3c2095a7737aca7 /object/tree
parentresearch: Add dynamic pack resources (diff)
signatureNo signature
*: Remove
Diffstat (limited to 'object/tree')
-rw-r--r--object/tree/entry.go57
-rw-r--r--object/tree/helpers_test.go114
-rw-r--r--object/tree/insert.go24
-rw-r--r--object/tree/lookup.go18
-rw-r--r--object/tree/mode.go12
-rw-r--r--object/tree/mode_details.go10
-rw-r--r--object/tree/mode_has_same_type.go12
-rw-r--r--object/tree/mode_is_blob_like.go8
-rw-r--r--object/tree/mode_is_regular_file.go6
-rw-r--r--object/tree/mode_table.go24
-rw-r--r--object/tree/name.go51
-rw-r--r--object/tree/parse.go58
-rw-r--r--object/tree/parse_test.go109
-rw-r--r--object/tree/path_append.go14
-rw-r--r--object/tree/path_clone.go16
-rw-r--r--object/tree/path_prefix.go19
-rw-r--r--object/tree/path_split.go19
-rw-r--r--object/tree/remove.go22
-rw-r--r--object/tree/serialize.go55
-rw-r--r--object/tree/serialize_test.go73
-rw-r--r--object/tree/tree.go12
-rw-r--r--object/tree/type.go10
22 files changed, 0 insertions, 743 deletions
diff --git a/object/tree/entry.go b/object/tree/entry.go
deleted file mode 100644
index b3089b74..00000000
--- a/object/tree/entry.go
+++ /dev/null
@@ -1,57 +0,0 @@
-package tree
-
-import (
- "bytes"
- "slices"
-
- objectid "codeberg.org/lindenii/furgit/object/id"
-)
-
-// TreeEntry represents a single entry in a tree.
-type TreeEntry struct {
- Mode FileMode
- // Name is part of the tree ordering. Mutating it after insertion may break
- // Tree ordering and lookup behavior.
- Name []byte
- ID objectid.ObjectID
-}
-
-func (tree *Tree) entry(name []byte, searchIsTree bool) *TreeEntry {
- index, ok := slices.BinarySearchFunc(tree.Entries, name, func(entry TreeEntry, name []byte) int {
- return TreeEntryNameCompare(entry.Name, entry.Mode, name, searchIsTree)
- })
- if !ok {
- return nil
- }
-
- entry := &tree.Entries[index]
- if !bytes.Equal(entry.Name, name) {
- return nil
- }
-
- return entry
-}
-
-func (tree *Tree) entryIndex(name []byte) (int, bool) {
- index, ok := tree.entryIndexWithMode(name, true)
- if ok {
- return index, true
- }
-
- return tree.entryIndexWithMode(name, false)
-}
-
-func (tree *Tree) entryIndexWithMode(name []byte, searchIsTree bool) (int, bool) {
- index, ok := slices.BinarySearchFunc(tree.Entries, name, func(entry TreeEntry, name []byte) int {
- return TreeEntryNameCompare(entry.Name, entry.Mode, name, searchIsTree)
- })
- if !ok {
- return 0, false
- }
-
- if !bytes.Equal(tree.Entries[index].Name, name) {
- return 0, false
- }
-
- return index, true
-}
diff --git a/object/tree/helpers_test.go b/object/tree/helpers_test.go
deleted file mode 100644
index 3da92ce4..00000000
--- a/object/tree/helpers_test.go
+++ /dev/null
@@ -1,114 +0,0 @@
-package tree_test
-
-import (
- "bytes"
- "fmt"
- "strings"
- "testing"
-
- "codeberg.org/lindenii/furgit/internal/testgit"
- "codeberg.org/lindenii/furgit/object/tree"
-)
-
-func buildGitMktreeInput(entries []tree.TreeEntry) string {
- var b strings.Builder
- for _, e := range entries {
- fmt.Fprintf(&b, "%o %s %s\t%s\n", e.Mode, mktreeTypeFromMode(e.Mode), e.ID.String(), e.Name)
- }
-
- return b.String()
-}
-
-func mktreeTypeFromMode(mode tree.FileMode) string {
- switch mode {
- case tree.FileModeDir:
- return "tree"
- case tree.FileModeRegular, tree.FileModeExecutable, tree.FileModeSymlink:
- return "blob"
- case tree.FileModeGitlink:
- return "commit"
- default:
- return ""
- }
-}
-
-func gitLsTreeNames(out []byte) [][]byte {
- if len(out) == 0 {
- return nil
- }
-
- parts := bytes.Split(out, []byte{0})
- if len(parts) > 0 && len(parts[len(parts)-1]) == 0 {
- parts = parts[:len(parts)-1]
- }
-
- names := make([][]byte, 0, len(parts))
- for _, name := range parts {
- names = append(names, append([]byte(nil), name...))
- }
-
- return names
-}
-
-func adversarialRootEntries(t *testing.T, testRepo *testgit.TestRepo) []tree.TreeEntry {
- t.Helper()
-
- blobA := testRepo.HashObject(t, "blob", []byte("blob-A\n"))
- blobB := testRepo.HashObject(t, "blob", []byte("blob-B\n"))
- blobC := testRepo.HashObject(t, "blob", []byte("blob-C\n"))
-
- subDirA := testRepo.Mktree(t,
- fmt.Sprintf("100644 blob %s\tnested-a.txt\n100755 blob %s\trun-a.sh\n", blobA.String(), blobB.String()))
- subDirB := testRepo.Mktree(t,
- fmt.Sprintf("100644 blob %s\tnested-b.txt\n100644 blob %s\tz-last\n", blobB.String(), blobC.String()))
- subDirC := testRepo.Mktree(t,
- fmt.Sprintf("120000 blob %s\tlink-c\n100644 blob %s\tchild\n", blobC.String(), blobA.String()))
- subDirD := testRepo.Mktree(t,
- fmt.Sprintf("100644 blob %s\tleaf\n", blobA.String()))
-
- return []tree.TreeEntry{
- {Mode: tree.FileModeRegular, Name: []byte("z"), ID: blobA},
- {Mode: tree.FileModeRegular, Name: []byte("A"), ID: blobB},
- {Mode: tree.FileModeRegular, Name: []byte("aa"), ID: blobC},
- {Mode: tree.FileModeRegular, Name: []byte("a0"), ID: blobA},
- {Mode: tree.FileModeRegular, Name: []byte("a-"), ID: blobB},
- {Mode: tree.FileModeRegular, Name: []byte("a."), ID: blobC},
- {Mode: tree.FileModeRegular, Name: []byte("a_"), ID: blobA},
- {Mode: tree.FileModeRegular, Name: []byte("a~"), ID: blobB},
- {Mode: tree.FileModeRegular, Name: []byte("Z"), ID: blobC},
- {Mode: tree.FileModeRegular, Name: []byte("0"), ID: blobA},
- {Mode: tree.FileModeRegular, Name: []byte("9"), ID: blobB},
- {Mode: tree.FileModeRegular, Name: []byte("00"), ID: blobC},
- {Mode: tree.FileModeRegular, Name: []byte("这是一些非 ASCII 的字符"), ID: blobC},
- {Mode: tree.FileModeRegular, Name: []byte("𲰼是新进入 Unicode 的字符"), ID: blobC},
- {Mode: tree.FileModeRegular, Name: []byte("Emoji 👀"), ID: blobC},
- {Mode: tree.FileModeRegular, Name: []byte("_"), ID: blobA},
- {Mode: tree.FileModeRegular, Name: []byte("-dash"), ID: blobB},
- {Mode: tree.FileModeRegular, Name: []byte("dot.file"), ID: blobC},
- {Mode: tree.FileModeRegular, Name: []byte(".hidden"), ID: blobA},
- {Mode: tree.FileModeRegular, Name: []byte("CAPS"), ID: blobB},
- {Mode: tree.FileModeRegular, Name: []byte("caps"), ID: blobC},
- {Mode: tree.FileModeRegular, Name: []byte("mixCase"), ID: blobA},
- {Mode: tree.FileModeRegular, Name: []byte("name with space"), ID: blobB},
- {Mode: tree.FileModeRegular, Name: []byte("name-with-dash"), ID: blobC},
- {Mode: tree.FileModeRegular, Name: []byte("name.with.dot"), ID: blobA},
- {Mode: tree.FileModeRegular, Name: []byte("name_with_underscore"), ID: blobB},
- {Mode: tree.FileModeRegular, Name: []byte("tilde~name"), ID: blobC},
- {Mode: tree.FileModeRegular, Name: []byte("brace{name}"), ID: blobA},
- {Mode: tree.FileModeRegular, Name: []byte("plus+name"), ID: blobB},
- {Mode: tree.FileModeRegular, Name: []byte("equal=name"), ID: blobC},
- {Mode: tree.FileModeRegular, Name: []byte("at@name"), ID: blobA},
- {Mode: tree.FileModeRegular, Name: []byte("percent%name"), ID: blobB},
- {Mode: tree.FileModeRegular, Name: []byte("caret^name"), ID: blobC},
- {Mode: tree.FileModeRegular, Name: []byte("comma,name"), ID: blobA},
- {Mode: tree.FileModeRegular, Name: []byte("semi;name"), ID: blobB},
- {Mode: tree.FileModeRegular, Name: []byte("paren(name)"), ID: blobC},
- {Mode: tree.FileModeRegular, Name: []byte("bracket[name]"), ID: blobA},
- {Mode: tree.FileModeExecutable, Name: []byte("exec.sh"), ID: blobB},
- {Mode: tree.FileModeSymlink, Name: []byte("sym.link"), ID: blobC},
- {Mode: tree.FileModeDir, Name: []byte("dir"), ID: subDirA},
- {Mode: tree.FileModeDir, Name: []byte("dir0"), ID: subDirB},
- {Mode: tree.FileModeDir, Name: []byte("dir.space"), ID: subDirC},
- {Mode: tree.FileModeDir, Name: []byte("x"), ID: subDirD},
- }
-}
diff --git a/object/tree/insert.go b/object/tree/insert.go
deleted file mode 100644
index 22bda74f..00000000
--- a/object/tree/insert.go
+++ /dev/null
@@ -1,24 +0,0 @@
-package tree
-
-import (
- "fmt"
- "slices"
-)
-
-// InsertEntry inserts a tree entry while preserving Git ordering.
-//
-// InsertEntry copies newEntry.Name.
-func (tree *Tree) InsertEntry(newEntry TreeEntry) error {
- if tree.entry(newEntry.Name, true) != nil || tree.entry(newEntry.Name, false) != nil {
- return fmt.Errorf("object: tree: entry %q already exists", newEntry.Name)
- }
-
- newEntry.Name = append([]byte(nil), newEntry.Name...)
-
- insertAt, _ := slices.BinarySearchFunc(tree.Entries, newEntry.Name, func(entry TreeEntry, name []byte) int {
- return TreeEntryNameCompare(entry.Name, entry.Mode, name, newEntry.Mode == FileModeDir)
- })
- tree.Entries = slices.Insert(tree.Entries, insertAt, newEntry)
-
- return nil
-}
diff --git a/object/tree/lookup.go b/object/tree/lookup.go
deleted file mode 100644
index 249efd0f..00000000
--- a/object/tree/lookup.go
+++ /dev/null
@@ -1,18 +0,0 @@
-package tree
-
-// Entry looks up a tree entry by name.
-//
-// The returned pointer refers to storage within tree.Entries and must not be
-// retained across InsertEntry or RemoveEntry calls.
-func (tree *Tree) Entry(name []byte) *TreeEntry {
- if len(tree.Entries) == 0 {
- return nil
- }
-
- index, ok := tree.entryIndex(name)
- if !ok {
- return nil
- }
-
- return &tree.Entries[index]
-}
diff --git a/object/tree/mode.go b/object/tree/mode.go
deleted file mode 100644
index b1cbc6bc..00000000
--- a/object/tree/mode.go
+++ /dev/null
@@ -1,12 +0,0 @@
-package tree
-
-// FileMode represents the mode of a file in a Git tree.
-type FileMode uint32
-
-const (
- FileModeDir FileMode = 0o40000
- FileModeRegular FileMode = 0o100644
- FileModeExecutable FileMode = 0o100755
- FileModeSymlink FileMode = 0o120000
- FileModeGitlink FileMode = 0o160000
-)
diff --git a/object/tree/mode_details.go b/object/tree/mode_details.go
deleted file mode 100644
index 9c34fd7c..00000000
--- a/object/tree/mode_details.go
+++ /dev/null
@@ -1,10 +0,0 @@
-package tree
-
-type fileModeDetails struct {
- isBlobLike bool
- isRegularFile bool
-}
-
-func (mode FileMode) details() fileModeDetails {
- return fileModeTable[mode]
-}
diff --git a/object/tree/mode_has_same_type.go b/object/tree/mode_has_same_type.go
deleted file mode 100644
index a058cb9c..00000000
--- a/object/tree/mode_has_same_type.go
+++ /dev/null
@@ -1,12 +0,0 @@
-package tree
-
-// HasSameType reports whether mode and other describe the same tree entry kind.
-//
-// Regular files and executable files have the same type for diff-status purposes.
-func (mode FileMode) HasSameType(other FileMode) bool {
- if mode == other {
- return true
- }
-
- return mode.details().isRegularFile && other.details().isRegularFile
-}
diff --git a/object/tree/mode_is_blob_like.go b/object/tree/mode_is_blob_like.go
deleted file mode 100644
index 3ec3a308..00000000
--- a/object/tree/mode_is_blob_like.go
+++ /dev/null
@@ -1,8 +0,0 @@
-package tree
-
-// IsBlobLike reports whether mode names one blob-like tree entry kind.
-//
-// Blob-like entries store blob object IDs as their targets.
-func (mode FileMode) IsBlobLike() bool {
- return mode.details().isBlobLike
-}
diff --git a/object/tree/mode_is_regular_file.go b/object/tree/mode_is_regular_file.go
deleted file mode 100644
index 115395c0..00000000
--- a/object/tree/mode_is_regular_file.go
+++ /dev/null
@@ -1,6 +0,0 @@
-package tree
-
-// IsRegularFile reports whether mode names one regular-file variant.
-func (mode FileMode) IsRegularFile() bool {
- return mode.details().isRegularFile
-}
diff --git a/object/tree/mode_table.go b/object/tree/mode_table.go
deleted file mode 100644
index 1695f270..00000000
--- a/object/tree/mode_table.go
+++ /dev/null
@@ -1,24 +0,0 @@
-package tree
-
-var fileModeTable = map[FileMode]fileModeDetails{ //nolint:gochecknoglobals
- FileModeDir: {
- isBlobLike: false,
- isRegularFile: false,
- },
- FileModeRegular: {
- isBlobLike: true,
- isRegularFile: true,
- },
- FileModeExecutable: {
- isBlobLike: true,
- isRegularFile: true,
- },
- FileModeSymlink: {
- isBlobLike: true,
- isRegularFile: false,
- },
- FileModeGitlink: {
- isBlobLike: false,
- isRegularFile: false,
- },
-}
diff --git a/object/tree/name.go b/object/tree/name.go
deleted file mode 100644
index 02af3292..00000000
--- a/object/tree/name.go
+++ /dev/null
@@ -1,51 +0,0 @@
-package tree
-
-// TreeEntryNameCompare compares names using Git tree ordering rules.
-func TreeEntryNameCompare(entryName []byte, entryMode FileMode, searchName []byte, searchIsTree bool) int {
- isEntryTree := entryMode == FileModeDir
-
- entryLen := len(entryName)
- if isEntryTree {
- entryLen++
- }
-
- searchLen := len(searchName)
- if searchIsTree {
- searchLen++
- }
-
- n := min(searchLen, entryLen)
-
- for i := range n {
- var ec, sc byte
- if i < len(entryName) {
- ec = entryName[i]
- } else {
- ec = '/'
- }
-
- if i < len(searchName) {
- sc = searchName[i]
- } else {
- sc = '/'
- }
-
- if ec < sc {
- return -1
- }
-
- if ec > sc {
- return 1
- }
- }
-
- if entryLen < searchLen {
- return -1
- }
-
- if entryLen > searchLen {
- return 1
- }
-
- return 0
-}
diff --git a/object/tree/parse.go b/object/tree/parse.go
deleted file mode 100644
index bb874828..00000000
--- a/object/tree/parse.go
+++ /dev/null
@@ -1,58 +0,0 @@
-package tree
-
-import (
- "bytes"
- "fmt"
- "strconv"
-
- objectid "codeberg.org/lindenii/furgit/object/id"
-)
-
-// Parse decodes a tree object body into a fully materialized Tree.
-func Parse(body []byte, algo objectid.Algorithm) (*Tree, error) {
- var entries []TreeEntry
-
- i := 0
- for i < len(body) {
- space := bytes.IndexByte(body[i:], ' ')
- if space < 0 {
- return nil, fmt.Errorf("object: tree: missing mode terminator")
- }
-
- modeBytes := body[i : i+space]
- i += space + 1
-
- nul := bytes.IndexByte(body[i:], 0)
- if nul < 0 {
- return nil, fmt.Errorf("object: tree: missing name terminator")
- }
-
- nameBytes := body[i : i+nul]
- i += nul + 1
-
- idEnd := i + algo.Size()
- if idEnd > len(body) {
- return nil, fmt.Errorf("object: tree: truncated child object id")
- }
-
- id, err := objectid.FromBytes(algo, body[i:idEnd])
- if err != nil {
- return nil, err
- }
-
- i = idEnd
-
- mode, err := strconv.ParseUint(string(modeBytes), 8, 32)
- if err != nil {
- return nil, fmt.Errorf("object: tree: parse mode: %w", err)
- }
-
- entries = append(entries, TreeEntry{
- Mode: FileMode(mode),
- Name: append([]byte(nil), nameBytes...),
- ID: id,
- })
- }
-
- return &Tree{Entries: entries}, nil
-}
diff --git a/object/tree/parse_test.go b/object/tree/parse_test.go
deleted file mode 100644
index 2b98ede7..00000000
--- a/object/tree/parse_test.go
+++ /dev/null
@@ -1,109 +0,0 @@
-package tree_test
-
-import (
- "bytes"
- "testing"
-
- "codeberg.org/lindenii/furgit/internal/testgit"
- objectid "codeberg.org/lindenii/furgit/object/id"
- "codeberg.org/lindenii/furgit/object/tree"
-)
-
-func TestTreeParseFromGit(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})
- entries := adversarialRootEntries(t, testRepo)
-
- inserted := &tree.Tree{}
- for _, entry := range entries {
- err := inserted.InsertEntry(entry)
- if err != nil {
- t.Fatalf("InsertEntry(%q): %v", entry.Name, err)
- }
- }
-
- treeID := testRepo.Mktree(t, buildGitMktreeInput(inserted.Entries))
-
- rawBody := testRepo.CatFile(t, "tree", treeID)
-
- parsed, err := tree.Parse(rawBody, algo)
- if err != nil {
- t.Fatalf("ParseTree: %v", err)
- }
-
- if len(parsed.Entries) != len(inserted.Entries) {
- t.Fatalf("entry count = %d, want %d", len(parsed.Entries), len(inserted.Entries))
- }
-
- for i := range inserted.Entries {
- got := parsed.Entries[i]
-
- want := inserted.Entries[i]
- if got.Mode != want.Mode || got.ID != want.ID || !bytes.Equal(got.Name, want.Name) {
- t.Fatalf("entry[%d] mismatch: got (%o,%q,%s) want (%o,%q,%s)",
- i, got.Mode, got.Name, got.ID, want.Mode, want.Name, want.ID)
- }
- }
-
- lsNames := gitLsTreeNames(testRepo.RunBytes(t, "ls-tree", "--name-only", "-z", treeID.String()))
- if len(lsNames) != len(parsed.Entries) {
- t.Fatalf("ls-tree names = %d, want %d", len(lsNames), len(parsed.Entries))
- }
-
- for i := range lsNames {
- if !bytes.Equal(lsNames[i], parsed.Entries[i].Name) {
- t.Fatalf("ordering mismatch at %d: git=%q parsed=%q", i, lsNames[i], parsed.Entries[i].Name)
- }
- }
-
- for _, want := range inserted.Entries {
- got := parsed.Entry(want.Name)
-
- if got == nil {
- t.Fatalf("Entry(%q) returned nil", want.Name)
- }
-
- if got.Mode != want.Mode || got.ID != want.ID {
- t.Fatalf("Entry(%q) mismatch", want.Name)
- }
- }
-
- if parsed.Entry([]byte("does-not-exist")) != nil {
- t.Fatalf("Entry on missing name should be nil")
- }
- })
-}
-
-func TestTreeInsertEntryCopiesName(t *testing.T) {
- t.Parallel()
-
- var tr tree.Tree
-
- name := []byte("alpha")
- entry := tree.TreeEntry{
- Mode: tree.FileModeRegular,
- Name: name,
- ID: objectid.ObjectID{},
- }
-
- err := tr.InsertEntry(entry)
- if err != nil {
- t.Fatalf("InsertEntry: %v", err)
- }
-
- name[0] = 'b'
-
- got := tr.Entry([]byte("alpha"))
- if got == nil {
- t.Fatalf("Entry(alpha) returned nil")
- }
-
- if !bytes.Equal(got.Name, []byte("alpha")) {
- t.Fatalf("stored name = %q, want %q", got.Name, []byte("alpha"))
- }
-
- if tr.Entry([]byte("blpha")) != nil {
- t.Fatalf("mutating caller name should not affect stored entry")
- }
-}
diff --git a/object/tree/path_append.go b/object/tree/path_append.go
deleted file mode 100644
index 609d5279..00000000
--- a/object/tree/path_append.go
+++ /dev/null
@@ -1,14 +0,0 @@
-package tree
-
-// AppendPath appends path to dst as one slash-separated byte path.
-func AppendPath(dst []byte, path [][]byte) []byte {
- for i := range path {
- if i > 0 {
- dst = append(dst, '/')
- }
-
- dst = append(dst, path[i]...)
- }
-
- return dst
-}
diff --git a/object/tree/path_clone.go b/object/tree/path_clone.go
deleted file mode 100644
index a4668add..00000000
--- a/object/tree/path_clone.go
+++ /dev/null
@@ -1,16 +0,0 @@
-package tree
-
-import (
- "bytes"
- "slices"
-)
-
-// ClonePath returns one deep copy of path.
-func ClonePath(path [][]byte) [][]byte {
- cloned := slices.Clone(path)
- for i := range cloned {
- cloned[i] = bytes.Clone(cloned[i])
- }
-
- return cloned
-}
diff --git a/object/tree/path_prefix.go b/object/tree/path_prefix.go
deleted file mode 100644
index ed658cee..00000000
--- a/object/tree/path_prefix.go
+++ /dev/null
@@ -1,19 +0,0 @@
-package tree
-
-import (
- "bytes"
- "slices"
-)
-
-// HasPathPrefix reports whether path begins with prefix as whole components.
-func HasPathPrefix(path, prefix [][]byte) bool {
- if len(prefix) == 0 {
- return true
- }
-
- if len(path) < len(prefix) {
- return false
- }
-
- return slices.EqualFunc(path[:len(prefix)], prefix, bytes.Equal)
-}
diff --git a/object/tree/path_split.go b/object/tree/path_split.go
deleted file mode 100644
index c147dd25..00000000
--- a/object/tree/path_split.go
+++ /dev/null
@@ -1,19 +0,0 @@
-package tree
-
-import (
- "bytes"
-)
-
-// SplitPath splits one slash-separated tree path into components.
-func SplitPath(path []byte) [][]byte {
- if len(path) == 0 {
- return nil
- }
-
- parts := bytes.Split(path, []byte{'/'})
- for i := range parts {
- parts[i] = bytes.Clone(parts[i])
- }
-
- return parts
-}
diff --git a/object/tree/remove.go b/object/tree/remove.go
deleted file mode 100644
index 94de88da..00000000
--- a/object/tree/remove.go
+++ /dev/null
@@ -1,22 +0,0 @@
-package tree
-
-import (
- "fmt"
- "slices"
-)
-
-// RemoveEntry removes a tree entry by name.
-func (tree *Tree) RemoveEntry(name []byte) error {
- if len(tree.Entries) == 0 {
- return fmt.Errorf("object: tree: entry %q not found", name)
- }
-
- index, ok := tree.entryIndex(name)
- if !ok {
- return fmt.Errorf("object: tree: entry %q not found", name)
- }
-
- tree.Entries = slices.Delete(tree.Entries, index, index+1)
-
- return nil
-}
diff --git a/object/tree/serialize.go b/object/tree/serialize.go
deleted file mode 100644
index 69deacda..00000000
--- a/object/tree/serialize.go
+++ /dev/null
@@ -1,55 +0,0 @@
-package tree
-
-import (
- "errors"
- "strconv"
-
- objectheader "codeberg.org/lindenii/furgit/object/header"
- objecttype "codeberg.org/lindenii/furgit/object/type"
-)
-
-// SerializeWithoutHeader renders the raw tree body bytes.
-func (tree *Tree) SerializeWithoutHeader() ([]byte, error) {
- var bodyLen int
-
- for _, entry := range tree.Entries {
- mode := strconv.FormatUint(uint64(entry.Mode), 8)
- bodyLen += len(mode) + 1 + len(entry.Name) + 1 + entry.ID.Algorithm().Size()
- }
-
- body := make([]byte, bodyLen)
- pos := 0
-
- for _, entry := range tree.Entries {
- mode := strconv.FormatUint(uint64(entry.Mode), 8)
- pos += copy(body[pos:], mode)
- body[pos] = ' '
- pos++
- pos += copy(body[pos:], entry.Name)
- body[pos] = 0
- pos++
- id := entry.ID.Bytes()
- pos += copy(body[pos:], id)
- }
-
- return body, nil
-}
-
-// SerializeWithHeader renders the raw object (header + body).
-func (tree *Tree) SerializeWithHeader() ([]byte, error) {
- body, err := tree.SerializeWithoutHeader()
- if err != nil {
- return nil, err
- }
-
- header, ok := objectheader.Encode(objecttype.TypeTree, int64(len(body)))
- if !ok {
- return nil, errors.New("object: tree: failed to encode object header")
- }
-
- raw := make([]byte, len(header)+len(body))
- copy(raw, header)
- copy(raw[len(header):], body)
-
- return raw, nil
-}
diff --git a/object/tree/serialize_test.go b/object/tree/serialize_test.go
deleted file mode 100644
index 9c9a2f1c..00000000
--- a/object/tree/serialize_test.go
+++ /dev/null
@@ -1,73 +0,0 @@
-package tree_test
-
-import (
- "testing"
-
- "codeberg.org/lindenii/furgit/internal/testgit"
- objectid "codeberg.org/lindenii/furgit/object/id"
- "codeberg.org/lindenii/furgit/object/tree"
-)
-
-func TestTreeSerialize(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})
- entries := adversarialRootEntries(t, testRepo)
- obj := &tree.Tree{}
-
- for i := len(entries) - 1; i >= 0; i-- {
- err := obj.InsertEntry(entries[i])
- if err != nil {
- t.Fatalf("InsertEntry(%q): %v", entries[i].Name, err)
- }
- }
-
- if len(obj.Entries) < 32 {
- t.Fatalf("expected at least 32 entries, got %d", len(obj.Entries))
- }
-
- dup := obj.Entries[0]
-
- err := obj.InsertEntry(dup)
- if err == nil {
- t.Fatalf("duplicate InsertEntry should fail")
- }
-
- removed := obj.Entries[len(obj.Entries)/2]
-
- err = obj.RemoveEntry(removed.Name)
- if err != nil {
- t.Fatalf("RemoveEntry(%q): %v", removed.Name, err)
- }
-
- if obj.Entry(removed.Name) != nil {
- t.Fatalf("Entry(%q) should be nil after remove", removed.Name)
- }
-
- err = obj.RemoveEntry([]byte("no-such-entry"))
- if err == nil {
- t.Fatalf("RemoveEntry missing entry should fail")
- }
-
- err = obj.InsertEntry(removed)
- if err != nil {
- t.Fatalf("re-InsertEntry(%q): %v", removed.Name, err)
- }
-
- if obj.Entry(removed.Name) == nil {
- t.Fatalf("Entry(%q) should exist after reinsert", removed.Name)
- }
-
- wantTreeID := testRepo.Mktree(t, buildGitMktreeInput(obj.Entries))
-
- rawObj, err := obj.SerializeWithHeader()
- if err != nil {
- t.Fatalf("SerializeWithHeader: %v", err)
- }
-
- gotTreeID := algo.Sum(rawObj)
- if gotTreeID != wantTreeID {
- t.Fatalf("tree id mismatch: got %s want %s", gotTreeID, wantTreeID)
- }
- })
-}
diff --git a/object/tree/tree.go b/object/tree/tree.go
deleted file mode 100644
index d0c7f4f0..00000000
--- a/object/tree/tree.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// Package tree provides representations, parsers, and serializers for tree objects.
-package tree
-
-// Tree represents a fully materialized Git tree object.
-//
-// Labels: MT-Unsafe.
-type Tree struct {
- // Entries must be sorted by TreeEntryNameCompare.
- // Use the Tree methods to preserve ordering and copy semantics rather than
- // modifying the slice directly.
- Entries []TreeEntry
-}
diff --git a/object/tree/type.go b/object/tree/type.go
deleted file mode 100644
index 416544af..00000000
--- a/object/tree/type.go
+++ /dev/null
@@ -1,10 +0,0 @@
-package tree
-
-import objecttype "codeberg.org/lindenii/furgit/object/type"
-
-// ObjectType returns TypeTree.
-func (tree *Tree) ObjectType() objecttype.Type {
- _ = tree
-
- return objecttype.TypeTree
-}