diff options
| author | 2026-03-25 14:49:17 +0000 | |
|---|---|---|
| committer | 2026-03-25 15:02:22 +0000 | |
| commit | 7847657e0820af98120031f719b8ede635ad8c07 (patch) | |
| tree | 8c4439c78f72f1382edc809b49be33115847b6e7 | |
| parent | object: Remove type.go (diff) | |
| signature | No signature | |
object: Split each object type into its own package v0.1.108
140 files changed, 768 insertions, 712 deletions
diff --git a/cmd/index-pack/main.go b/cmd/index-pack/main.go index 749e5e8a..69cf648a 100644 --- a/cmd/index-pack/main.go +++ b/cmd/index-pack/main.go @@ -9,7 +9,7 @@ import ( "path/filepath" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/object/storer" + objectstorer "codeberg.org/lindenii/furgit/object/storer" "codeberg.org/lindenii/furgit/packfile/ingest" "codeberg.org/lindenii/furgit/repository" ) diff --git a/cmd/show-object/main.go b/cmd/show-object/main.go index e5340aa4..b4b55a1b 100644 --- a/cmd/show-object/main.go +++ b/cmd/show-object/main.go @@ -9,8 +9,12 @@ import ( "strings" "codeberg.org/lindenii/furgit/object" + "codeberg.org/lindenii/furgit/object/blob" + "codeberg.org/lindenii/furgit/object/commit" objectid "codeberg.org/lindenii/furgit/object/id" "codeberg.org/lindenii/furgit/object/stored" + "codeberg.org/lindenii/furgit/object/tag" + "codeberg.org/lindenii/furgit/object/tree" objecttype "codeberg.org/lindenii/furgit/object/type" "codeberg.org/lindenii/furgit/repository" ) @@ -97,18 +101,18 @@ func printStored(s *stored.Stored[object.Object]) { fmt.Fprintf(&b, "type: %s\n", tyName) switch obj := s.Object().(type) { - case *object.Blob: + case *blob.Blob: blob := obj fmt.Fprintf(&b, "size: %d\n", len(blob.Data)) fmt.Fprintf(&b, "data: %q\n", string(blob.Data)) - case *object.Tree: + case *tree.Tree: tree := obj fmt.Fprintf(&b, "entries: %d\n", len(tree.Entries)) for _, entry := range tree.Entries { fmt.Fprintf(&b, "%06o %s\t%s\n", entry.Mode, entry.ID, entry.Name) } - case *object.Commit: + case *commit.Commit: commit := obj fmt.Fprintf(&b, "tree: %s\n", commit.Tree) @@ -119,7 +123,7 @@ func printStored(s *stored.Stored[object.Object]) { fmt.Fprintf(&b, "author: %s <%s>\n", commit.Author.Name, commit.Author.Email) fmt.Fprintf(&b, "committer: %s <%s>\n", commit.Committer.Name, commit.Committer.Email) fmt.Fprintf(&b, "message:\n%s\n", string(commit.Message)) - case *object.Tag: + case *tag.Tag: tag := obj targetTy, ok := objecttype.Name(tag.TargetType) diff --git a/commitquery/ancestor_unit_test.go b/commitquery/ancestor_unit_test.go index 3b7f36d7..1edee5b6 100644 --- a/commitquery/ancestor_unit_test.go +++ b/commitquery/ancestor_unit_test.go @@ -7,9 +7,9 @@ import ( giterrors "codeberg.org/lindenii/furgit/errors" "codeberg.org/lindenii/furgit/internal/testgit" - "codeberg.org/lindenii/furgit/object" objectid "codeberg.org/lindenii/furgit/object/id" "codeberg.org/lindenii/furgit/object/storer/memory" + objecttree "codeberg.org/lindenii/furgit/object/tree" objecttype "codeberg.org/lindenii/furgit/object/type" "codeberg.org/lindenii/furgit/commitquery" @@ -38,7 +38,7 @@ func ancestorTagBody(target objectid.ObjectID, targetType objecttype.Type) []byt } // mustSerializeAncestorTree serializes one tree or fails the test. -func mustSerializeAncestorTree(tb testing.TB, tree *object.Tree) []byte { +func mustSerializeAncestorTree(tb testing.TB, tree *objecttree.Tree) []byte { tb.Helper() body, err := tree.SerializeWithoutHeader() @@ -55,16 +55,16 @@ func TestIs(t *testing.T) { testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper store := memory.New(algo) blob := store.AddObject(objecttype.TypeBlob, []byte("blob\n")) - tree := store.AddObject(objecttype.TypeTree, mustSerializeAncestorTree(t, &object.Tree{Entries: []object.TreeEntry{{ - Mode: object.FileModeRegular, + tree := store.AddObject(objecttype.TypeTree, mustSerializeAncestorTree(t, &objecttree.Tree{Entries: []objecttree.TreeEntry{{ + Mode: objecttree.FileModeRegular, Name: []byte("f"), ID: blob, }}})) c1 := store.AddObject(objecttype.TypeCommit, ancestorCommitBody(tree)) c2 := store.AddObject(objecttype.TypeCommit, ancestorCommitBody(tree, c1)) otherBlob := store.AddObject(objecttype.TypeBlob, []byte("other-blob\n")) - otherTree := store.AddObject(objecttype.TypeTree, mustSerializeAncestorTree(t, &object.Tree{Entries: []object.TreeEntry{{ - Mode: object.FileModeRegular, + otherTree := store.AddObject(objecttype.TypeTree, mustSerializeAncestorTree(t, &objecttree.Tree{Entries: []objecttree.TreeEntry{{ + Mode: objecttree.FileModeRegular, Name: []byte("g"), ID: otherBlob, }}})) @@ -97,8 +97,8 @@ func TestIsRejectsNonCommitAfterPeel(t *testing.T) { testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper store := memory.New(algo) blob := store.AddObject(objecttype.TypeBlob, []byte("blob\n")) - tree := store.AddObject(objecttype.TypeTree, mustSerializeAncestorTree(t, &object.Tree{Entries: []object.TreeEntry{{ - Mode: object.FileModeRegular, + tree := store.AddObject(objecttype.TypeTree, mustSerializeAncestorTree(t, &objecttree.Tree{Entries: []objecttree.TreeEntry{{ + Mode: objecttree.FileModeRegular, Name: []byte("f"), ID: blob, }}})) diff --git a/commitquery/context.go b/commitquery/context.go index b87c66a3..df8ddd97 100644 --- a/commitquery/context.go +++ b/commitquery/context.go @@ -4,7 +4,7 @@ package commitquery import ( commitgraphread "codeberg.org/lindenii/furgit/commitgraph/read" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/object/storer" + objectstorer "codeberg.org/lindenii/furgit/object/storer" ) // Query owns the mutable node arena for commit-domain queries over one object diff --git a/commitquery/mergebase_unit_test.go b/commitquery/mergebase_unit_test.go index fd771f84..fc2981b1 100644 --- a/commitquery/mergebase_unit_test.go +++ b/commitquery/mergebase_unit_test.go @@ -10,9 +10,9 @@ import ( "codeberg.org/lindenii/furgit/commitquery" giterrors "codeberg.org/lindenii/furgit/errors" "codeberg.org/lindenii/furgit/internal/testgit" - "codeberg.org/lindenii/furgit/object" objectid "codeberg.org/lindenii/furgit/object/id" "codeberg.org/lindenii/furgit/object/storer/memory" + "codeberg.org/lindenii/furgit/object/tree" objecttype "codeberg.org/lindenii/furgit/object/type" ) @@ -56,7 +56,7 @@ func containsID(set map[objectid.ObjectID]struct{}, id objectid.ObjectID) bool { } // mustSerializeTree serializes one tree or fails the test. -func mustSerializeTree(tb testing.TB, tree *object.Tree) []byte { +func mustSerializeTree(tb testing.TB, tree *tree.Tree) []byte { tb.Helper() body, err := tree.SerializeWithoutHeader() @@ -74,8 +74,8 @@ func TestQueryLinearHistory(t *testing.T) { testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper store := memory.New(algo) blob := store.AddObject(objecttype.TypeBlob, []byte("blob\n")) - tree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{{ - Mode: object.FileModeRegular, + tree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &tree.Tree{Entries: []tree.TreeEntry{{ + Mode: tree.FileModeRegular, Name: []byte("f"), ID: blob, }}})) @@ -115,13 +115,13 @@ func TestQueryPeelsAnnotatedTags(t *testing.T) { testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper store := memory.New(algo) blob := store.AddObject(objecttype.TypeBlob, []byte("blob\n")) - leftTree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{{ - Mode: object.FileModeRegular, + leftTree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &tree.Tree{Entries: []tree.TreeEntry{{ + Mode: tree.FileModeRegular, Name: []byte("left"), ID: blob, }}})) - rightTree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{{ - Mode: object.FileModeRegular, + rightTree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &tree.Tree{Entries: []tree.TreeEntry{{ + Mode: tree.FileModeRegular, Name: []byte("right"), ID: blob, }}})) @@ -149,28 +149,28 @@ func TestQueryCrissCrossReturnsAllBestCommonAncestors(t *testing.T) { testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper store := memory.New(algo) blob := store.AddObject(objecttype.TypeBlob, []byte("blob\n")) - rootTree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{{ - Mode: object.FileModeRegular, + rootTree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &tree.Tree{Entries: []tree.TreeEntry{{ + Mode: tree.FileModeRegular, Name: []byte("root"), ID: blob, }}})) - base1Tree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{{ - Mode: object.FileModeRegular, + base1Tree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &tree.Tree{Entries: []tree.TreeEntry{{ + Mode: tree.FileModeRegular, Name: []byte("base1"), ID: blob, }}})) - base2Tree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{{ - Mode: object.FileModeRegular, + base2Tree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &tree.Tree{Entries: []tree.TreeEntry{{ + Mode: tree.FileModeRegular, Name: []byte("base2"), ID: blob, }}})) - leftTree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{{ - Mode: object.FileModeRegular, + leftTree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &tree.Tree{Entries: []tree.TreeEntry{{ + Mode: tree.FileModeRegular, Name: []byte("left"), ID: blob, }}})) - rightTree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{{ - Mode: object.FileModeRegular, + rightTree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &tree.Tree{Entries: []tree.TreeEntry{{ + Mode: tree.FileModeRegular, Name: []byte("right"), ID: blob, }}})) @@ -215,14 +215,14 @@ func TestQueryReturnsNoResultWhenNoCommonAncestorExists(t *testing.T) { testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper store := memory.New(algo) leftBlob := store.AddObject(objecttype.TypeBlob, []byte("left\n")) - leftTree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{{ - Mode: object.FileModeRegular, + leftTree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &tree.Tree{Entries: []tree.TreeEntry{{ + Mode: tree.FileModeRegular, Name: []byte("left"), ID: leftBlob, }}})) rightBlob := store.AddObject(objecttype.TypeBlob, []byte("right\n")) - rightTree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{{ - Mode: object.FileModeRegular, + rightTree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &tree.Tree{Entries: []tree.TreeEntry{{ + Mode: tree.FileModeRegular, Name: []byte("right"), ID: rightBlob, }}})) @@ -257,8 +257,8 @@ func TestQueryRejectsNonCommitAfterPeel(t *testing.T) { testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper store := memory.New(algo) blob := store.AddObject(objecttype.TypeBlob, []byte("blob\n")) - tree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{{ - Mode: object.FileModeRegular, + tree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &tree.Tree{Entries: []tree.TreeEntry{{ + Mode: tree.FileModeRegular, Name: []byte("f"), ID: blob, }}})) @@ -289,8 +289,8 @@ func TestQueryAllIsRepeatable(t *testing.T) { testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper store := memory.New(algo) blob := store.AddObject(objecttype.TypeBlob, []byte("blob\n")) - tree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{{ - Mode: object.FileModeRegular, + tree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &tree.Tree{Entries: []tree.TreeEntry{{ + Mode: tree.FileModeRegular, Name: []byte("f"), ID: blob, }}})) diff --git a/commitquery/oid.go b/commitquery/oid.go index 17dc2392..0308c85e 100644 --- a/commitquery/oid.go +++ b/commitquery/oid.go @@ -6,9 +6,9 @@ import ( commitgraphread "codeberg.org/lindenii/furgit/commitgraph/read" giterrors "codeberg.org/lindenii/furgit/errors" "codeberg.org/lindenii/furgit/internal/peel" - "codeberg.org/lindenii/furgit/object" + objectcommit "codeberg.org/lindenii/furgit/object/commit" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/object/storer" + objectstorer "codeberg.org/lindenii/furgit/object/storer" objecttype "codeberg.org/lindenii/furgit/object/type" ) @@ -81,7 +81,7 @@ func (query *Query) loadByOID(idx nodeIndex) error { return &giterrors.ObjectTypeError{OID: id, Got: ty, Want: objecttype.TypeCommit} } - commitObj, err := object.ParseCommit(content, id.Algorithm()) + commitObj, err := objectcommit.Parse(content, id.Algorithm()) if err != nil { return err } diff --git a/diff/trees/diff.go b/diff/trees/diff.go index 742d7397..0f3cf1f2 100644 --- a/diff/trees/diff.go +++ b/diff/trees/diff.go @@ -2,15 +2,15 @@ package trees import ( - "codeberg.org/lindenii/furgit/object" objectid "codeberg.org/lindenii/furgit/object/id" + "codeberg.org/lindenii/furgit/object/tree" ) // Diff compares two trees and returns recursive differences. // // readTree is used to lazily load child trees by object ID when recursion // reaches directory entries. -func Diff(a, b *object.Tree, readTree func(objectid.ObjectID) (*object.Tree, error)) ([]Entry, error) { +func Diff(a, b *tree.Tree, readTree func(objectid.ObjectID) (*tree.Tree, error)) ([]Entry, error) { var out []Entry err := diffRecursive(a, b, nil, readTree, &out) diff --git a/diff/trees/diff_recursive.go b/diff/trees/diff_recursive.go index 8ad4caf1..98848b24 100644 --- a/diff/trees/diff_recursive.go +++ b/diff/trees/diff_recursive.go @@ -1,11 +1,11 @@ package trees import ( - "codeberg.org/lindenii/furgit/object" objectid "codeberg.org/lindenii/furgit/object/id" + "codeberg.org/lindenii/furgit/object/tree" ) -func diffRecursive(a, b *object.Tree, prefix []byte, readTree func(objectid.ObjectID) (*object.Tree, error), out *[]Entry) error { +func diffRecursive(a, b *tree.Tree, prefix []byte, readTree func(objectid.ObjectID) (*tree.Tree, error), out *[]Entry) error { if a == nil && b == nil { return nil } @@ -16,7 +16,7 @@ func diffRecursive(a, b *object.Tree, prefix []byte, readTree func(objectid.Obje full := joinPath(prefix, entry.Name) *out = append(*out, Entry{Path: full, Kind: EntryKindAdded, Old: nil, New: entry}) - if entry.Mode != object.FileModeDir { + if entry.Mode != tree.FileModeDir { continue } @@ -40,7 +40,7 @@ func diffRecursive(a, b *object.Tree, prefix []byte, readTree func(objectid.Obje full := joinPath(prefix, entry.Name) *out = append(*out, Entry{Path: full, Kind: EntryKindDeleted, Old: entry, New: nil}) - if entry.Mode != object.FileModeDir { + if entry.Mode != tree.FileModeDir { continue } @@ -65,18 +65,18 @@ func diffRecursive(a, b *object.Tree, prefix []byte, readTree func(objectid.Obje left := &a.Entries[i] right := &b.Entries[j] - cmp := object.TreeEntryNameCompare( + cmp := tree.TreeEntryNameCompare( left.Name, left.Mode, right.Name, - right.Mode == object.FileModeDir, + right.Mode == tree.FileModeDir, ) switch { case cmp < 0: full := joinPath(prefix, left.Name) *out = append(*out, Entry{Path: full, Kind: EntryKindDeleted, Old: left, New: nil}) - if left.Mode == object.FileModeDir { + if left.Mode == tree.FileModeDir { sub, err := readTree(left.ID) if err != nil { return err @@ -93,7 +93,7 @@ func diffRecursive(a, b *object.Tree, prefix []byte, readTree func(objectid.Obje full := joinPath(prefix, right.Name) *out = append(*out, Entry{Path: full, Kind: EntryKindAdded, Old: nil, New: right}) - if right.Mode == object.FileModeDir { + if right.Mode == tree.FileModeDir { sub, err := readTree(right.ID) if err != nil { return err @@ -114,7 +114,7 @@ func diffRecursive(a, b *object.Tree, prefix []byte, readTree func(objectid.Obje *out = append(*out, Entry{Path: full, Kind: EntryKindModified, Old: left, New: right}) } - if left.Mode == object.FileModeDir && right.Mode == object.FileModeDir && left.ID != right.ID { + if left.Mode == tree.FileModeDir && right.Mode == tree.FileModeDir && left.ID != right.ID { leftSub, err := readTree(left.ID) if err != nil { return err @@ -141,7 +141,7 @@ func diffRecursive(a, b *object.Tree, prefix []byte, readTree func(objectid.Obje full := joinPath(prefix, left.Name) *out = append(*out, Entry{Path: full, Kind: EntryKindDeleted, Old: left, New: nil}) - if left.Mode == object.FileModeDir { + if left.Mode == tree.FileModeDir { sub, err := readTree(left.ID) if err != nil { return err @@ -159,7 +159,7 @@ func diffRecursive(a, b *object.Tree, prefix []byte, readTree func(objectid.Obje full := joinPath(prefix, right.Name) *out = append(*out, Entry{Path: full, Kind: EntryKindAdded, Old: nil, New: right}) - if right.Mode == object.FileModeDir { + if right.Mode == tree.FileModeDir { sub, err := readTree(right.ID) if err != nil { return err diff --git a/diff/trees/diff_test.go b/diff/trees/diff_test.go index 9924c2ad..8e8fed1c 100644 --- a/diff/trees/diff_test.go +++ b/diff/trees/diff_test.go @@ -6,9 +6,9 @@ import ( "codeberg.org/lindenii/furgit/diff/trees" "codeberg.org/lindenii/furgit/internal/testgit" - "codeberg.org/lindenii/furgit/object" objectid "codeberg.org/lindenii/furgit/object/id" "codeberg.org/lindenii/furgit/object/storer/loose" + "codeberg.org/lindenii/furgit/object/tree" objecttype "codeberg.org/lindenii/furgit/object/type" ) @@ -174,10 +174,10 @@ func openLooseStore(t *testing.T, repo *testgit.TestRepo, algo objectid.Algorith return store } -func makeReadTree(t *testing.T, store *loose.Store, algo objectid.Algorithm) func(objectid.ObjectID) (*object.Tree, error) { +func makeReadTree(t *testing.T, store *loose.Store, algo objectid.Algorithm) func(objectid.ObjectID) (*tree.Tree, error) { t.Helper() - return func(id objectid.ObjectID) (*object.Tree, error) { + return func(id objectid.ObjectID) (*tree.Tree, error) { ty, content, err := store.ReadBytesContent(id) if err != nil { return nil, err @@ -187,11 +187,11 @@ func makeReadTree(t *testing.T, store *loose.Store, algo objectid.Algorithm) fun return nil, errors.New("diff/trees test: object is not a tree") } - return object.ParseTree(content, algo) + return tree.Parse(content, algo) } } -func mustReadTree(t *testing.T, readTree func(objectid.ObjectID) (*object.Tree, error), id objectid.ObjectID) *object.Tree { +func mustReadTree(t *testing.T, readTree func(objectid.ObjectID) (*tree.Tree, error), id objectid.ObjectID) *tree.Tree { t.Helper() tree, err := readTree(id) diff --git a/diff/trees/entry.go b/diff/trees/entry.go index 267c3380..84813a79 100644 --- a/diff/trees/entry.go +++ b/diff/trees/entry.go @@ -1,6 +1,6 @@ package trees -import "codeberg.org/lindenii/furgit/object" +import "codeberg.org/lindenii/furgit/object/tree" // Entry is one recursive tree difference at a path. type Entry struct { @@ -9,7 +9,7 @@ type Entry struct { // Kind is the difference kind for this path. Kind EntryKind // Old is the old tree entry (nil when Kind is EntryKindAdded). - Old *object.TreeEntry + Old *tree.TreeEntry // New is the new tree entry (nil when Kind is EntryKindDeleted). - New *object.TreeEntry + New *tree.TreeEntry } diff --git a/internal/cpu/cpu.go b/internal/cpu/cpu.go index 41a0c1f9..ab4cc0bd 100644 --- a/internal/cpu/cpu.go +++ b/internal/cpu/cpu.go @@ -1,3 +1,4 @@ +// Package cpu provides routines for CPU feature detection. package cpu // X86 contains x86 CPU feature flags detected at runtime. diff --git a/internal/peel/peel.go b/internal/peel/peel.go index 603c29b3..236f6868 100644 --- a/internal/peel/peel.go +++ b/internal/peel/peel.go @@ -5,9 +5,9 @@ import ( stderrors "errors" giterrors "codeberg.org/lindenii/furgit/errors" - "codeberg.org/lindenii/furgit/object" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/object/storer" + objectstorer "codeberg.org/lindenii/furgit/object/storer" + "codeberg.org/lindenii/furgit/object/tag" objecttype "codeberg.org/lindenii/furgit/object/type" ) @@ -40,7 +40,7 @@ func ToCommit(store objectstorer.Store, id objectid.ObjectID) (objectid.ObjectID return objectid.ObjectID{}, err } - tag, err := object.ParseTag(content, id.Algorithm()) + tag, err := tag.Parse(content, id.Algorithm()) if err != nil { return objectid.ObjectID{}, err } diff --git a/internal/testgit/repo_open_object_store.go b/internal/testgit/repo_open_object_store.go index 902a2143..6e6c7b4d 100644 --- a/internal/testgit/repo_open_object_store.go +++ b/internal/testgit/repo_open_object_store.go @@ -3,7 +3,7 @@ package testgit import ( "testing" - "codeberg.org/lindenii/furgit/object/storer" + objectstorer "codeberg.org/lindenii/furgit/object/storer" "codeberg.org/lindenii/furgit/repository" ) diff --git a/object/blob.go b/object/blob/blob.go index 1c827190..977121fb 100644 --- a/object/blob.go +++ b/object/blob/blob.go @@ -1,6 +1,5 @@ -package object - -import objecttype "codeberg.org/lindenii/furgit/object/type" +// Package blob provides representations, parsers, and serializers for blob objects. +package blob // Blob represents a Git blob object. // @@ -10,10 +9,3 @@ import objecttype "codeberg.org/lindenii/furgit/object/type" type Blob struct { Data []byte } - -// ObjectType returns TypeBlob. -func (blob *Blob) ObjectType() objecttype.Type { - _ = blob - - return objecttype.TypeBlob -} diff --git a/object/blob/parse.go b/object/blob/parse.go new file mode 100644 index 00000000..faee9e46 --- /dev/null +++ b/object/blob/parse.go @@ -0,0 +1,6 @@ +package blob + +// Parse decodes a blob object body. +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 index eb8f2f56..09d5d5d0 100644 --- a/object/blob_parse_test.go +++ b/object/blob/parse_test.go @@ -1,11 +1,11 @@ -package object_test +package blob_test import ( "bytes" "testing" "codeberg.org/lindenii/furgit/internal/testgit" - "codeberg.org/lindenii/furgit/object" + "codeberg.org/lindenii/furgit/object/blob" objectid "codeberg.org/lindenii/furgit/object/id" ) @@ -18,12 +18,12 @@ func TestBlobParseFromGit(t *testing.T) { rawBody := testRepo.CatFile(t, "blob", blobID) - blob, err := object.ParseBlob(rawBody) + parsed, err := blob.Parse(rawBody) if err != nil { t.Fatalf("ParseBlob: %v", err) } - if !bytes.Equal(blob.Data, body) { + if !bytes.Equal(parsed.Data, body) { t.Fatalf("blob body mismatch") } }) diff --git a/object/blob_serialize.go b/object/blob/serialize.go index 2acc4c11..80cce8dc 100644 --- a/object/blob_serialize.go +++ b/object/blob/serialize.go @@ -1,4 +1,4 @@ -package object +package blob import ( "errors" diff --git a/object/blob_serialize_test.go b/object/blob/serialize_test.go index 704811ca..4292abad 100644 --- a/object/blob_serialize_test.go +++ b/object/blob/serialize_test.go @@ -1,10 +1,10 @@ -package object_test +package blob_test import ( "testing" "codeberg.org/lindenii/furgit/internal/testgit" - "codeberg.org/lindenii/furgit/object" + "codeberg.org/lindenii/furgit/object/blob" objectid "codeberg.org/lindenii/furgit/object/id" ) @@ -15,9 +15,9 @@ func TestBlobSerialize(t *testing.T) { body := []byte("hello\nblob\n") wantID := testRepo.HashObject(t, "blob", body) - blob := &object.Blob{Data: body} + obj := &blob.Blob{Data: body} - rawObj, err := blob.SerializeWithHeader() + rawObj, err := obj.SerializeWithHeader() if err != nil { t.Fatalf("SerializeWithHeader: %v", err) } diff --git a/object/blob/test.go b/object/blob/test.go new file mode 100644 index 00000000..9e538219 --- /dev/null +++ b/object/blob/test.go @@ -0,0 +1,10 @@ +package blob + +import objecttype "codeberg.org/lindenii/furgit/object/type" + +// ObjectType returns TypeBlob. +func (blob *Blob) ObjectType() objecttype.Type { + _ = blob + + return objecttype.TypeBlob +} diff --git a/object/blob_parse.go b/object/blob_parse.go deleted file mode 100644 index 61aacfac..00000000 --- a/object/blob_parse.go +++ /dev/null @@ -1,6 +0,0 @@ -package object - -// ParseBlob decodes a blob object body. -func ParseBlob(body []byte) (*Blob, error) { - return &Blob{Data: append([]byte(nil), body...)}, nil -} diff --git a/object/commit.go b/object/commit/commit.go index f7b0d676..e2e087f5 100644 --- a/object/commit.go +++ b/object/commit/commit.go @@ -1,24 +1,18 @@ -package object +// Package commit provides representations, parsers, and serializers for commit objects. +package commit import ( objectid "codeberg.org/lindenii/furgit/object/id" - objecttype "codeberg.org/lindenii/furgit/object/type" + objectsignature "codeberg.org/lindenii/furgit/object/signature" ) // Commit represents a Git commit object. type Commit struct { Tree objectid.ObjectID Parents []objectid.ObjectID - Author Signature - Committer Signature + Author objectsignature.Signature + Committer objectsignature.Signature Message []byte ChangeID string ExtraHeaders []ExtraHeader } - -// ObjectType returns TypeCommit. -func (commit *Commit) ObjectType() objecttype.Type { - _ = commit - - return objecttype.TypeCommit -} diff --git a/object/extraheader.go b/object/commit/extraheader.go index 4ad1ec09..79d4f9cc 100644 --- a/object/extraheader.go +++ b/object/commit/extraheader.go @@ -1,4 +1,4 @@ -package object +package commit // ExtraHeader represents an extra header in a Git object. type ExtraHeader struct { diff --git a/object/commit_parse.go b/object/commit/parse.go index 6578d523..9dcc930d 100644 --- a/object/commit_parse.go +++ b/object/commit/parse.go @@ -1,4 +1,4 @@ -package object +package commit import ( "bytes" @@ -6,10 +6,11 @@ import ( "fmt" objectid "codeberg.org/lindenii/furgit/object/id" + objectsignature "codeberg.org/lindenii/furgit/object/signature" ) -// ParseCommit decodes a commit object body. -func ParseCommit(body []byte, algo objectid.Algorithm) (*Commit, error) { +// Parse decodes a commit object body. +func Parse(body []byte, algo objectid.Algorithm) (*Commit, error) { c := new(Commit) i := 0 @@ -47,14 +48,14 @@ func ParseCommit(body []byte, algo objectid.Algorithm) (*Commit, error) { c.Parents = append(c.Parents, id) case "author": - idt, err := ParseSignature(value) + idt, err := objectsignature.Parse(value) if err != nil { return nil, fmt.Errorf("object: commit: author: %w", err) } c.Author = *idt case "committer": - idt, err := ParseSignature(value) + idt, err := objectsignature.Parse(value) if err != nil { return nil, fmt.Errorf("object: commit: committer: %w", err) } diff --git a/object/commit_parse_test.go b/object/commit/parse_test.go index fae2b4c1..ad2c7aed 100644 --- a/object/commit_parse_test.go +++ b/object/commit/parse_test.go @@ -1,4 +1,4 @@ -package object_test +package commit_test import ( "bytes" @@ -6,7 +6,7 @@ import ( "testing" "codeberg.org/lindenii/furgit/internal/testgit" - "codeberg.org/lindenii/furgit/object" + "codeberg.org/lindenii/furgit/object/commit" objectid "codeberg.org/lindenii/furgit/object/id" ) @@ -18,29 +18,29 @@ func TestCommitParseFromGit(t *testing.T) { rawBody := testRepo.CatFile(t, "commit", commitID) - commit, err := object.ParseCommit(rawBody, algo) + parsed, err := commit.Parse(rawBody, algo) if err != nil { t.Fatalf("ParseCommit: %v", err) } - if commit.Tree != treeID { - t.Fatalf("tree id mismatch: got %s want %s", commit.Tree, treeID) + if parsed.Tree != treeID { + t.Fatalf("tree id mismatch: got %s want %s", parsed.Tree, treeID) } - if len(commit.Parents) != 0 { - t.Fatalf("parent count = %d, want 0", len(commit.Parents)) + if len(parsed.Parents) != 0 { + t.Fatalf("parent count = %d, want 0", len(parsed.Parents)) } - if !bytes.Equal(commit.Author.Name, []byte("Test Author")) { - t.Fatalf("author name = %q, want %q", commit.Author.Name, "Test Author") + if !bytes.Equal(parsed.Author.Name, []byte("Test Author")) { + t.Fatalf("author name = %q, want %q", parsed.Author.Name, "Test Author") } - if !bytes.Equal(commit.Committer.Name, []byte("Test Committer")) { - t.Fatalf("committer name = %q, want %q", commit.Committer.Name, "Test Committer") + if !bytes.Equal(parsed.Committer.Name, []byte("Test Committer")) { + t.Fatalf("committer name = %q, want %q", parsed.Committer.Name, "Test Committer") } - if !bytes.Contains(commit.Message, []byte("subject")) { - t.Fatalf("commit message missing subject: %q", commit.Message) + if !bytes.Contains(parsed.Message, []byte("subject")) { + t.Fatalf("commit message missing subject: %q", parsed.Message) } }) } @@ -63,29 +63,29 @@ func TestCommitParseMultipleParents(t *testing.T) { mergeID := testRepo.HashObject(t, "commit", []byte(rawCommit)) rawBody := testRepo.CatFile(t, "commit", mergeID) - commit, err := object.ParseCommit(rawBody, algo) + parsed, err := commit.Parse(rawBody, algo) if err != nil { t.Fatalf("ParseCommit(merge): %v", err) } - if commit.Tree != treeID { - t.Fatalf("merge tree = %s, want %s", commit.Tree, treeID) + if parsed.Tree != treeID { + t.Fatalf("merge tree = %s, want %s", parsed.Tree, treeID) } - if len(commit.Parents) != 2 { - t.Fatalf("merge parent count = %d, want 2", len(commit.Parents)) + if len(parsed.Parents) != 2 { + t.Fatalf("merge parent count = %d, want 2", len(parsed.Parents)) } - if commit.Parents[0] != parent1 { - t.Fatalf("merge parent[0] = %s, want %s", commit.Parents[0], parent1) + if parsed.Parents[0] != parent1 { + t.Fatalf("merge parent[0] = %s, want %s", parsed.Parents[0], parent1) } - if commit.Parents[1] != parent2 { - t.Fatalf("merge parent[1] = %s, want %s", commit.Parents[1], parent2) + if parsed.Parents[1] != parent2 { + t.Fatalf("merge parent[1] = %s, want %s", parsed.Parents[1], parent2) } - if !bytes.Equal(commit.Message, []byte("Merge commit\n")) { - t.Fatalf("merge message = %q, want %q", commit.Message, "Merge commit\n") + if !bytes.Equal(parsed.Message, []byte("Merge commit\n")) { + t.Fatalf("merge message = %q, want %q", parsed.Message, "Merge commit\n") } }) } diff --git a/object/commit_serialize.go b/object/commit/serialize.go index ed81b1d6..721cacf6 100644 --- a/object/commit_serialize.go +++ b/object/commit/serialize.go @@ -1,4 +1,4 @@ -package object +package commit import ( "bytes" diff --git a/object/commit_serialize_test.go b/object/commit/serialize_test.go index cff47b40..e58a8078 100644 --- a/object/commit_serialize_test.go +++ b/object/commit/serialize_test.go @@ -1,10 +1,10 @@ -package object_test +package commit_test import ( "testing" "codeberg.org/lindenii/furgit/internal/testgit" - "codeberg.org/lindenii/furgit/object" + "codeberg.org/lindenii/furgit/object/commit" objectid "codeberg.org/lindenii/furgit/object/id" ) @@ -16,12 +16,12 @@ func TestCommitSerialize(t *testing.T) { rawBody := testRepo.CatFile(t, "commit", commitID) - commit, err := object.ParseCommit(rawBody, algo) + parsed, err := commit.Parse(rawBody, algo) if err != nil { t.Fatalf("ParseCommit: %v", err) } - rawObj, err := commit.SerializeWithHeader() + rawObj, err := parsed.SerializeWithHeader() if err != nil { t.Fatalf("SerializeWithHeader: %v", err) } diff --git a/object/commit/type.go b/object/commit/type.go new file mode 100644 index 00000000..b8aa11e8 --- /dev/null +++ b/object/commit/type.go @@ -0,0 +1,10 @@ +package commit + +import objecttype "codeberg.org/lindenii/furgit/object/type" + +// ObjectType returns TypeCommit. +func (commit *Commit) ObjectType() objecttype.Type { + _ = commit + + return objecttype.TypeCommit +} diff --git a/object/object.go b/object/object.go index 70d418df..f2325211 100644 --- a/object/object.go +++ b/object/object.go @@ -1,10 +1,9 @@ -// Package object parses and serializes objects such as blob, tree, commit, and -// tag. +// Package object provides shared object interfaces. package object import objecttype "codeberg.org/lindenii/furgit/object/type" -// Object is a Git object that can serialize itself. +// Object is a Git object. type Object interface { ObjectType() objecttype.Type SerializeWithoutHeader() ([]byte, error) diff --git a/object/parse.go b/object/parse.go index cb75cb43..7cc01a7a 100644 --- a/object/parse.go +++ b/object/parse.go @@ -3,8 +3,12 @@ package object import ( "fmt" + "codeberg.org/lindenii/furgit/object/blob" + "codeberg.org/lindenii/furgit/object/commit" objectheader "codeberg.org/lindenii/furgit/object/header" objectid "codeberg.org/lindenii/furgit/object/id" + "codeberg.org/lindenii/furgit/object/tag" + "codeberg.org/lindenii/furgit/object/tree" objecttype "codeberg.org/lindenii/furgit/object/type" ) @@ -31,13 +35,13 @@ func ParseObjectWithHeader(raw []byte, algo objectid.Algorithm) (Object, error) func ParseObjectWithoutHeader(ty objecttype.Type, body []byte, algo objectid.Algorithm) (Object, error) { switch ty { case objecttype.TypeBlob: - return ParseBlob(body) + return blob.Parse(body) case objecttype.TypeTree: - return ParseTree(body, algo) + return tree.Parse(body, algo) case objecttype.TypeCommit: - return ParseCommit(body, algo) + return commit.Parse(body, algo) case objecttype.TypeTag: - return ParseTag(body, algo) + return tag.Parse(body, algo) case objecttype.TypeInvalid, objecttype.TypeFuture, objecttype.TypeOfsDelta, objecttype.TypeRefDelta: return nil, fmt.Errorf("object: unsupported object type %d", ty) default: diff --git a/object/resolve/exact_blob.go b/object/resolve/exact_blob.go index 07501513..2cd8b298 100644 --- a/object/resolve/exact_blob.go +++ b/object/resolve/exact_blob.go @@ -3,19 +3,19 @@ package resolve import ( "fmt" - "codeberg.org/lindenii/furgit/object" + "codeberg.org/lindenii/furgit/object/blob" objectid "codeberg.org/lindenii/furgit/object/id" "codeberg.org/lindenii/furgit/object/stored" ) // ExactBlob reads, parses, and wraps the blob at id. -func (r *Resolver) ExactBlob(id objectid.ObjectID) (*stored.Stored[*object.Blob], error) { +func (r *Resolver) ExactBlob(id objectid.ObjectID) (*stored.Stored[*blob.Blob], error) { parsed, err := r.parseObject(id) if err != nil { return nil, err } - blob, ok := parsed.(*object.Blob) + blob, ok := parsed.(*blob.Blob) if !ok { return nil, fmt.Errorf("object/resolve: expected blob object %s, got %v", id, parsed.ObjectType()) } diff --git a/object/resolve/exact_commit.go b/object/resolve/exact_commit.go index ba76baa2..e6b379aa 100644 --- a/object/resolve/exact_commit.go +++ b/object/resolve/exact_commit.go @@ -3,19 +3,19 @@ package resolve import ( "fmt" - "codeberg.org/lindenii/furgit/object" + "codeberg.org/lindenii/furgit/object/commit" objectid "codeberg.org/lindenii/furgit/object/id" "codeberg.org/lindenii/furgit/object/stored" ) // ExactCommit reads, parses, and wraps the commit at id. -func (r *Resolver) ExactCommit(id objectid.ObjectID) (*stored.Stored[*object.Commit], error) { +func (r *Resolver) ExactCommit(id objectid.ObjectID) (*stored.Stored[*commit.Commit], error) { parsed, err := r.parseObject(id) if err != nil { return nil, err } - commit, ok := parsed.(*object.Commit) + commit, ok := parsed.(*commit.Commit) if !ok { return nil, fmt.Errorf("object/resolve: expected commit object %s, got %v", id, parsed.ObjectType()) } diff --git a/object/resolve/exact_tag.go b/object/resolve/exact_tag.go index 26bf2b11..8c5d22c9 100644 --- a/object/resolve/exact_tag.go +++ b/object/resolve/exact_tag.go @@ -3,19 +3,19 @@ package resolve import ( "fmt" - "codeberg.org/lindenii/furgit/object" objectid "codeberg.org/lindenii/furgit/object/id" "codeberg.org/lindenii/furgit/object/stored" + "codeberg.org/lindenii/furgit/object/tag" ) // ExactTag reads, parses, and wraps the tag at id. -func (r *Resolver) ExactTag(id objectid.ObjectID) (*stored.Stored[*object.Tag], error) { +func (r *Resolver) ExactTag(id objectid.ObjectID) (*stored.Stored[*tag.Tag], error) { parsed, err := r.parseObject(id) if err != nil { return nil, err } - tag, ok := parsed.(*object.Tag) + tag, ok := parsed.(*tag.Tag) if !ok { return nil, fmt.Errorf("object/resolve: expected tag object %s, got %v", id, parsed.ObjectType()) } diff --git a/object/resolve/exact_tree.go b/object/resolve/exact_tree.go index aaf40236..de58ddb1 100644 --- a/object/resolve/exact_tree.go +++ b/object/resolve/exact_tree.go @@ -3,19 +3,19 @@ package resolve import ( "fmt" - "codeberg.org/lindenii/furgit/object" objectid "codeberg.org/lindenii/furgit/object/id" "codeberg.org/lindenii/furgit/object/stored" + "codeberg.org/lindenii/furgit/object/tree" ) // ExactTree reads, parses, and wraps the tree at id. -func (r *Resolver) ExactTree(id objectid.ObjectID) (*stored.Stored[*object.Tree], error) { +func (r *Resolver) ExactTree(id objectid.ObjectID) (*stored.Stored[*tree.Tree], error) { parsed, err := r.parseObject(id) if err != nil { return nil, err } - tree, ok := parsed.(*object.Tree) + tree, ok := parsed.(*tree.Tree) if !ok { return nil, fmt.Errorf("object/resolve: expected tree object %s, got %v", id, parsed.ObjectType()) } diff --git a/object/resolve/path.go b/object/resolve/path.go index 1f865403..d11f3b48 100644 --- a/object/resolve/path.go +++ b/object/resolve/path.go @@ -3,8 +3,8 @@ package resolve import ( "fmt" - "codeberg.org/lindenii/furgit/object" objectid "codeberg.org/lindenii/furgit/object/id" + "codeberg.org/lindenii/furgit/object/tree" ) // PathEmptyError indicates that Path received no segments. @@ -59,24 +59,24 @@ func (err *PathNotTreeError) Error() string { // // If your entry names are valid UTF-8 and uses / solely as segment separators, // it may be convenient to use TreeFS for an io/fs.FS-like interface. -func (r *Resolver) Path(root objectid.ObjectID, parts [][]byte) (object.TreeEntry, error) { +func (r *Resolver) Path(root objectid.ObjectID, parts [][]byte) (tree.TreeEntry, error) { if len(parts) == 0 { - return object.TreeEntry{}, &PathEmptyError{} + return tree.TreeEntry{}, &PathEmptyError{} } current, err := r.PeelToTree(root) if err != nil { - return object.TreeEntry{}, err + return tree.TreeEntry{}, err } for i, part := range parts { if len(part) == 0 { - return object.TreeEntry{}, &PathSegmentEmptyError{Index: i} + return tree.TreeEntry{}, &PathSegmentEmptyError{Index: i} } entry := current.Object().Entry(part) if entry == nil { - return object.TreeEntry{}, &PathNotFoundError{ + return tree.TreeEntry{}, &PathNotFoundError{ Index: i, Name: append([]byte(nil), part...), } @@ -86,8 +86,8 @@ func (r *Resolver) Path(root objectid.ObjectID, parts [][]byte) (object.TreeEntr return *entry, nil } - if entry.Mode != object.FileModeDir { - return object.TreeEntry{}, &PathNotTreeError{ + if entry.Mode != tree.FileModeDir { + return tree.TreeEntry{}, &PathNotTreeError{ Index: i, Name: append([]byte(nil), part...), } @@ -95,9 +95,9 @@ func (r *Resolver) Path(root objectid.ObjectID, parts [][]byte) (object.TreeEntr current, err = r.ExactTree(entry.ID) if err != nil { - return object.TreeEntry{}, err + return tree.TreeEntry{}, err } } - return object.TreeEntry{}, &PathNotFoundError{Index: len(parts) - 1} + return tree.TreeEntry{}, &PathNotFoundError{Index: len(parts) - 1} } diff --git a/object/resolve/peel_to_blob.go b/object/resolve/peel_to_blob.go index 424e309f..c8aec1ad 100644 --- a/object/resolve/peel_to_blob.go +++ b/object/resolve/peel_to_blob.go @@ -3,13 +3,14 @@ package resolve import ( "fmt" - "codeberg.org/lindenii/furgit/object" + "codeberg.org/lindenii/furgit/object/blob" objectid "codeberg.org/lindenii/furgit/object/id" "codeberg.org/lindenii/furgit/object/stored" + "codeberg.org/lindenii/furgit/object/tag" ) // PeelToBlob peels tags until it reaches a blob. -func (r *Resolver) PeelToBlob(id objectid.ObjectID) (*stored.Stored[*object.Blob], error) { +func (r *Resolver) PeelToBlob(id objectid.ObjectID) (*stored.Stored[*blob.Blob], error) { for { obj, err := r.ExactObject(id) if err != nil { @@ -17,9 +18,9 @@ func (r *Resolver) PeelToBlob(id objectid.ObjectID) (*stored.Stored[*object.Blob } switch parsed := obj.Object().(type) { - case *object.Blob: + case *blob.Blob: return stored.New(id, parsed), nil - case *object.Tag: + case *tag.Tag: id = parsed.Target default: return nil, fmt.Errorf("object/resolve: expected blob-ish object %s, got %v", id, parsed.ObjectType()) diff --git a/object/resolve/peel_to_commit.go b/object/resolve/peel_to_commit.go index 355a3055..0272dd83 100644 --- a/object/resolve/peel_to_commit.go +++ b/object/resolve/peel_to_commit.go @@ -3,13 +3,14 @@ package resolve import ( "fmt" - "codeberg.org/lindenii/furgit/object" + "codeberg.org/lindenii/furgit/object/commit" objectid "codeberg.org/lindenii/furgit/object/id" "codeberg.org/lindenii/furgit/object/stored" + "codeberg.org/lindenii/furgit/object/tag" ) // PeelToCommit peels tags until it reaches a commit. -func (r *Resolver) PeelToCommit(id objectid.ObjectID) (*stored.Stored[*object.Commit], error) { +func (r *Resolver) PeelToCommit(id objectid.ObjectID) (*stored.Stored[*commit.Commit], error) { for { obj, err := r.ExactObject(id) if err != nil { @@ -17,9 +18,9 @@ func (r *Resolver) PeelToCommit(id objectid.ObjectID) (*stored.Stored[*object.Co } switch parsed := obj.Object().(type) { - case *object.Commit: + case *commit.Commit: return stored.New(id, parsed), nil - case *object.Tag: + case *tag.Tag: id = parsed.Target default: return nil, fmt.Errorf("object/resolve: expected commit-ish object %s, got %v", id, parsed.ObjectType()) diff --git a/object/resolve/peel_to_tag.go b/object/resolve/peel_to_tag.go index 6f61d7e1..e131f4c1 100644 --- a/object/resolve/peel_to_tag.go +++ b/object/resolve/peel_to_tag.go @@ -1,12 +1,12 @@ package resolve import ( - "codeberg.org/lindenii/furgit/object" objectid "codeberg.org/lindenii/furgit/object/id" "codeberg.org/lindenii/furgit/object/stored" + "codeberg.org/lindenii/furgit/object/tag" ) // PeelToTag returns the tag at id without further peeling. -func (r *Resolver) PeelToTag(id objectid.ObjectID) (*stored.Stored[*object.Tag], error) { +func (r *Resolver) PeelToTag(id objectid.ObjectID) (*stored.Stored[*tag.Tag], error) { return r.ExactTag(id) } diff --git a/object/resolve/peel_to_tree.go b/object/resolve/peel_to_tree.go index 3b12bdd8..2f2da4d7 100644 --- a/object/resolve/peel_to_tree.go +++ b/object/resolve/peel_to_tree.go @@ -3,14 +3,16 @@ package resolve import ( "fmt" - "codeberg.org/lindenii/furgit/object" + "codeberg.org/lindenii/furgit/object/commit" objectid "codeberg.org/lindenii/furgit/object/id" "codeberg.org/lindenii/furgit/object/stored" + "codeberg.org/lindenii/furgit/object/tag" + "codeberg.org/lindenii/furgit/object/tree" ) // PeelToTree peels tags until it reaches a tree or commit. If it reaches a // commit, it returns the commit's root tree. -func (r *Resolver) PeelToTree(id objectid.ObjectID) (*stored.Stored[*object.Tree], error) { +func (r *Resolver) PeelToTree(id objectid.ObjectID) (*stored.Stored[*tree.Tree], error) { for { obj, err := r.ExactObject(id) if err != nil { @@ -18,11 +20,11 @@ func (r *Resolver) PeelToTree(id objectid.ObjectID) (*stored.Stored[*object.Tree } switch parsed := obj.Object().(type) { - case *object.Tree: + case *tree.Tree: return stored.New(id, parsed), nil - case *object.Commit: + case *commit.Commit: return r.ExactTree(parsed.Tree) - case *object.Tag: + case *tag.Tag: id = parsed.Target default: return nil, fmt.Errorf("object/resolve: expected tree-ish object %s, got %v", id, parsed.ObjectType()) diff --git a/object/resolve/resolver.go b/object/resolve/resolver.go index 3e76e96a..f5e4e8c3 100644 --- a/object/resolve/resolver.go +++ b/object/resolve/resolver.go @@ -1,6 +1,6 @@ package resolve -import "codeberg.org/lindenii/furgit/object/storer" +import objectstorer "codeberg.org/lindenii/furgit/object/storer" // Resolver resolves parsed and streamed objects from an object store. // diff --git a/object/resolve/treefs.go b/object/resolve/treefs.go index de5d588a..a080d56d 100644 --- a/object/resolve/treefs.go +++ b/object/resolve/treefs.go @@ -3,8 +3,8 @@ package resolve import ( "io/fs" - "codeberg.org/lindenii/furgit/object" objectid "codeberg.org/lindenii/furgit/object/id" + "codeberg.org/lindenii/furgit/object/tree" ) // TreeFS exposes one Git tree as an fs.FS. @@ -18,7 +18,7 @@ import ( type TreeFS struct { resolver *Resolver rootTree objectid.ObjectID - rootEntry *object.TreeEntry + rootEntry *tree.TreeEntry } var ( diff --git a/object/resolve/treefs_entry.go b/object/resolve/treefs_entry.go index b37ac0a0..6d23e282 100644 --- a/object/resolve/treefs_entry.go +++ b/object/resolve/treefs_entry.go @@ -5,8 +5,8 @@ import ( "fmt" "io/fs" - "codeberg.org/lindenii/furgit/object" objectid "codeberg.org/lindenii/furgit/object/id" + "codeberg.org/lindenii/furgit/object/tree" ) func (treeFS *TreeFS) resolvePath(op treeFSOp, name string) (treeEntryValue, error) { @@ -17,7 +17,7 @@ func (treeFS *TreeFS) resolvePath(op treeFSOp, name string) (treeEntryValue, err if name == "." { return treeEntryValue{ name: ".", - mode: object.FileModeDir, + mode: tree.FileModeDir, treeID: treeFS.rootTree, treeEntry: treeFS.rootEntry, }, nil @@ -58,14 +58,14 @@ func (treeFS *TreeFS) pathResolveError(op treeFSOp, name string, err error) erro type treeEntryValue struct { name string - mode object.FileMode + mode tree.FileMode objectID objectid.ObjectID treeID objectid.ObjectID - treeEntry *object.TreeEntry + treeEntry *tree.TreeEntry } func (entry treeEntryValue) isDir() bool { - return entry.mode == object.FileModeDir + return entry.mode == tree.FileModeDir } func (entry treeEntryValue) blobSize(resolve *Resolver) (int64, error) { @@ -82,7 +82,7 @@ func (entry treeEntryValue) subtreeID() (objectid.ObjectID, error) { return entry.treeID, nil } - if entry.mode != object.FileModeDir { + if entry.mode != tree.FileModeDir { return objectid.ObjectID{}, fmt.Errorf("object/resolve: path %q is not a tree", entry.name) } diff --git a/object/resolve/treefs_info.go b/object/resolve/treefs_info.go index f554973d..f8eb1e9e 100644 --- a/object/resolve/treefs_info.go +++ b/object/resolve/treefs_info.go @@ -4,7 +4,7 @@ import ( "io/fs" "time" - "codeberg.org/lindenii/furgit/object" + "codeberg.org/lindenii/furgit/object/tree" ) type treeFSInfo struct { @@ -31,17 +31,17 @@ func (info *treeFSInfo) Info() (fs.FileInfo, error) { return info, nil } -func treeFSEntryMode(mode object.FileMode) fs.FileMode { +func treeFSEntryMode(mode tree.FileMode) fs.FileMode { switch mode { - case object.FileModeDir: + case tree.FileModeDir: return fs.ModeDir | 0o555 - case object.FileModeRegular: + case tree.FileModeRegular: return 0o444 - case object.FileModeExecutable: + case tree.FileModeExecutable: return 0o555 - case object.FileModeSymlink: + case tree.FileModeSymlink: return fs.ModeSymlink | 0o444 - case object.FileModeGitlink: + case tree.FileModeGitlink: return fs.ModeIrregular default: return fs.ModeIrregular @@ -51,7 +51,7 @@ func treeFSEntryMode(mode object.FileMode) fs.FileMode { func (treeFS *TreeFS) statEntry(entry treeEntryValue) (*treeFSInfo, error) { size := int64(0) - if entry.mode == object.FileModeRegular || entry.mode == object.FileModeExecutable || entry.mode == object.FileModeSymlink { + if entry.mode == tree.FileModeRegular || entry.mode == tree.FileModeExecutable || entry.mode == tree.FileModeSymlink { var err error size, err = entry.blobSize(treeFS.resolver) diff --git a/object/resolve/treefs_open.go b/object/resolve/treefs_open.go index c938505b..8e2b3588 100644 --- a/object/resolve/treefs_open.go +++ b/object/resolve/treefs_open.go @@ -5,7 +5,7 @@ import ( "io" "io/fs" - "codeberg.org/lindenii/furgit/object" + "codeberg.org/lindenii/furgit/object/tree" ) // Open opens name for reading. @@ -57,7 +57,7 @@ func (treeFS *TreeFS) Open(name string) (fs.File, error) { }, nil } - if entry.mode == object.FileModeGitlink { + if entry.mode == tree.FileModeGitlink { return nil, treeFSPathError(treeFSOpOpen, name, fmt.Errorf("object/resolve: gitlink entries are not readable as files")) } diff --git a/object/resolve/treefs_readfile.go b/object/resolve/treefs_readfile.go index e2bc1698..e1d514a3 100644 --- a/object/resolve/treefs_readfile.go +++ b/object/resolve/treefs_readfile.go @@ -4,7 +4,7 @@ import ( "fmt" "io" - "codeberg.org/lindenii/furgit/object" + "codeberg.org/lindenii/furgit/object/tree" ) // ReadFile reads the blob contents at name. @@ -20,7 +20,7 @@ func (treeFS *TreeFS) ReadFile(name string) ([]byte, error) { return nil, treeFSPathError(treeFSOpReadFile, name, fmt.Errorf("is a directory")) } - if entry.mode == object.FileModeGitlink { + if entry.mode == tree.FileModeGitlink { return nil, treeFSPathError(treeFSOpReadFile, name, fmt.Errorf("object/resolve: gitlink entries are not readable as files")) } diff --git a/object/resolve/treefs_stat.go b/object/resolve/treefs_stat.go index 044ba049..396dfbae 100644 --- a/object/resolve/treefs_stat.go +++ b/object/resolve/treefs_stat.go @@ -6,7 +6,7 @@ import "io/fs" // // TreeFS metadata reflects Git tree entry mode and blob size where applicable. // It does not represent filesystem stat metadata: ModTime is zero, ownership is -// unavailable, and Sys returns the underlying object.TreeEntry when one exists. +// unavailable, and Sys returns the underlying tree.TreeEntry when one exists. func (treeFS *TreeFS) Stat(name string) (fs.FileInfo, error) { entry, err := treeFS.resolvePath(treeFSOpStat, name) if err != nil { diff --git a/object/resolve/treefs_test.go b/object/resolve/treefs_test.go index a22e5019..0c436c0b 100644 --- a/object/resolve/treefs_test.go +++ b/object/resolve/treefs_test.go @@ -6,9 +6,9 @@ import ( "testing" "codeberg.org/lindenii/furgit/internal/testgit" - "codeberg.org/lindenii/furgit/object" objectid "codeberg.org/lindenii/furgit/object/id" "codeberg.org/lindenii/furgit/object/resolve" + "codeberg.org/lindenii/furgit/object/tree" "codeberg.org/lindenii/furgit/repository" ) @@ -71,13 +71,13 @@ func TestTreeFS(t *testing.T) { t.Fatalf("Stat(plain.txt): %v", err) } - entry, ok := info.Sys().(object.TreeEntry) + entry, ok := info.Sys().(tree.TreeEntry) if !ok { - t.Fatalf("Stat(plain.txt).Sys() type = %T, want object.TreeEntry", info.Sys()) + t.Fatalf("Stat(plain.txt).Sys() type = %T, want tree.TreeEntry", info.Sys()) } - if entry.Mode != object.FileModeRegular { - t.Fatalf("Stat(plain.txt).Sys().Mode = %o, want %o", entry.Mode, object.FileModeRegular) + if entry.Mode != tree.FileModeRegular { + t.Fatalf("Stat(plain.txt).Sys().Mode = %o, want %o", entry.Mode, tree.FileModeRegular) } subFS, err := treeFS.Sub("dir") diff --git a/object/ident.go b/object/signature/parse.go index 049b0c01..a6880eee 100644 --- a/object/ident.go +++ b/object/signature/parse.go @@ -1,27 +1,17 @@ -package object +package signature import ( "bytes" "errors" "fmt" "strconv" - "strings" - "time" "codeberg.org/lindenii/furgit/internal/intconv" ) -// Signature represents a Git signature (author/committer/tagger). -type Signature struct { - Name []byte - Email []byte - WhenUnix int64 - OffsetMinutes int32 -} - -// ParseSignature parses a canonical Git signature line: +// Parse parses a canonical Git signature line: // "Name <email> 123456789 +0000". -func ParseSignature(line []byte) (*Signature, error) { +func Parse(line []byte) (*Signature, error) { lt := bytes.IndexByte(line, '<') if lt < 0 { return nil, errors.New("object: signature: missing opening <") @@ -105,36 +95,3 @@ func ParseSignature(line []byte) (*Signature, error) { OffsetMinutes: offset, }, nil } - -// Serialize renders the signature in canonical Git format. -func (signature Signature) Serialize() ([]byte, error) { - var b strings.Builder - b.Grow(len(signature.Name) + len(signature.Email) + 32) - b.Write(signature.Name) - b.WriteString(" <") - b.Write(signature.Email) - b.WriteString("> ") - b.WriteString(strconv.FormatInt(signature.WhenUnix, 10)) - b.WriteByte(' ') - - offset := signature.OffsetMinutes - - sign := '+' - if offset < 0 { - sign = '-' - offset = -offset - } - - hh := offset / 60 - mm := offset % 60 - fmt.Fprintf(&b, "%c%02d%02d", sign, hh, mm) - - return []byte(b.String()), nil -} - -// When returns a time.Time with the signature's timezone offset. -func (signature Signature) When() time.Time { - loc := time.FixedZone("git", int(signature.OffsetMinutes)*60) - - return time.Unix(signature.WhenUnix, 0).In(loc) -} diff --git a/object/signature/serialize.go b/object/signature/serialize.go new file mode 100644 index 00000000..3f60d20d --- /dev/null +++ b/object/signature/serialize.go @@ -0,0 +1,33 @@ +package signature + +import ( + "fmt" + "strconv" + "strings" +) + +// Serialize renders the signature in canonical Git format. +func (signature Signature) Serialize() ([]byte, error) { + var b strings.Builder + b.Grow(len(signature.Name) + len(signature.Email) + 32) + b.Write(signature.Name) + b.WriteString(" <") + b.Write(signature.Email) + b.WriteString("> ") + b.WriteString(strconv.FormatInt(signature.WhenUnix, 10)) + b.WriteByte(' ') + + offset := signature.OffsetMinutes + + sign := '+' + if offset < 0 { + sign = '-' + offset = -offset + } + + hh := offset / 60 + mm := offset % 60 + fmt.Fprintf(&b, "%c%02d%02d", sign, hh, mm) + + return []byte(b.String()), nil +} diff --git a/object/signature/signature.go b/object/signature/signature.go new file mode 100644 index 00000000..22e516f9 --- /dev/null +++ b/object/signature/signature.go @@ -0,0 +1,10 @@ +// Package signature provides routines and representations that implement author/committer/tagger signatures. +package signature + +// Signature represents a Git signature (author/committer/tagger). +type Signature struct { + Name []byte + Email []byte + WhenUnix int64 + OffsetMinutes int32 +} diff --git a/object/signature/when.go b/object/signature/when.go new file mode 100644 index 00000000..0a252f68 --- /dev/null +++ b/object/signature/when.go @@ -0,0 +1,10 @@ +package signature + +import "time" + +// When returns a time.Time with the signature's timezone offset. +func (signature Signature) When() time.Time { + loc := time.FixedZone("git", int(signature.OffsetMinutes)*60) + + return time.Unix(signature.WhenUnix, 0).In(loc) +} diff --git a/object/stored/stored.go b/object/stored/stored.go index f48aaa77..4429a373 100644 --- a/object/stored/stored.go +++ b/object/stored/stored.go @@ -1,7 +1,7 @@ // Package stored wraps parsed objects with their storage object IDs. // // Stored values are typically instantiated with pointer object types such as -// *object.Blob, *object.Tree, *object.Commit, or *object.Tag, because those +// *blob.Blob, *tree.Tree, *commit.Commit, or *tag.Tag, because those // pointer types satisfy object.Object. package stored diff --git a/object/storer/chain/bytes.go b/object/storer/chain/bytes.go index c3ec1eb8..d41f3b92 100644 --- a/object/storer/chain/bytes.go +++ b/object/storer/chain/bytes.go @@ -5,7 +5,7 @@ import ( "fmt" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/object/storer" + objectstorer "codeberg.org/lindenii/furgit/object/storer" objecttype "codeberg.org/lindenii/furgit/object/type" ) diff --git a/object/storer/chain/chain.go b/object/storer/chain/chain.go index 8502b590..44909cff 100644 --- a/object/storer/chain/chain.go +++ b/object/storer/chain/chain.go @@ -2,9 +2,7 @@ // backends. package chain -import ( - "codeberg.org/lindenii/furgit/object/storer" -) +import objectstorer "codeberg.org/lindenii/furgit/object/storer" // Chain queries multiple object databases in order. // diff --git a/object/storer/chain/header.go b/object/storer/chain/header.go index e7791e9e..4feaf8e4 100644 --- a/object/storer/chain/header.go +++ b/object/storer/chain/header.go @@ -5,7 +5,7 @@ import ( "fmt" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/object/storer" + objectstorer "codeberg.org/lindenii/furgit/object/storer" objecttype "codeberg.org/lindenii/furgit/object/type" ) diff --git a/object/storer/chain/new.go b/object/storer/chain/new.go index f7a4f141..0368bfb3 100644 --- a/object/storer/chain/new.go +++ b/object/storer/chain/new.go @@ -1,6 +1,6 @@ package chain -import "codeberg.org/lindenii/furgit/object/storer" +import objectstorer "codeberg.org/lindenii/furgit/object/storer" // New creates an ordered object database chain. // diff --git a/object/storer/chain/reader.go b/object/storer/chain/reader.go index 3ac8cce7..e3c50013 100644 --- a/object/storer/chain/reader.go +++ b/object/storer/chain/reader.go @@ -6,7 +6,7 @@ import ( "io" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/object/storer" + objectstorer "codeberg.org/lindenii/furgit/object/storer" objecttype "codeberg.org/lindenii/furgit/object/type" ) diff --git a/object/storer/chain/size.go b/object/storer/chain/size.go index 6ad7d12c..c82b248d 100644 --- a/object/storer/chain/size.go +++ b/object/storer/chain/size.go @@ -5,7 +5,7 @@ import ( "fmt" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/object/storer" + objectstorer "codeberg.org/lindenii/furgit/object/storer" ) // ReadSize reads object content length from the first backend that has it. diff --git a/object/storer/loose/paths.go b/object/storer/loose/paths.go index 73cb0cf3..58ef6b8e 100644 --- a/object/storer/loose/paths.go +++ b/object/storer/loose/paths.go @@ -8,7 +8,7 @@ import ( "path/filepath" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/object/storer" + objectstorer "codeberg.org/lindenii/furgit/object/storer" ) // objectPath returns the loose object path for id relative to the objects root. diff --git a/object/storer/loose/read_test.go b/object/storer/loose/read_test.go index ece3c9db..d44ecea8 100644 --- a/object/storer/loose/read_test.go +++ b/object/storer/loose/read_test.go @@ -9,7 +9,7 @@ import ( "codeberg.org/lindenii/furgit/internal/testgit" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/object/storer" + objectstorer "codeberg.org/lindenii/furgit/object/storer" "codeberg.org/lindenii/furgit/object/storer/loose" objecttype "codeberg.org/lindenii/furgit/object/type" ) diff --git a/object/storer/memory/read_bytes.go b/object/storer/memory/read_bytes.go index 72eaba11..e8b437ea 100644 --- a/object/storer/memory/read_bytes.go +++ b/object/storer/memory/read_bytes.go @@ -3,7 +3,7 @@ package memory import ( objectheader "codeberg.org/lindenii/furgit/object/header" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/object/storer" + objectstorer "codeberg.org/lindenii/furgit/object/storer" objecttype "codeberg.org/lindenii/furgit/object/type" ) diff --git a/object/storer/memory/read_header.go b/object/storer/memory/read_header.go index 56979d3c..73cc4561 100644 --- a/object/storer/memory/read_header.go +++ b/object/storer/memory/read_header.go @@ -2,7 +2,7 @@ package memory import ( objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/object/storer" + objectstorer "codeberg.org/lindenii/furgit/object/storer" objecttype "codeberg.org/lindenii/furgit/object/type" ) diff --git a/object/storer/mix/bytes.go b/object/storer/mix/bytes.go index d2a7dc0e..a281c332 100644 --- a/object/storer/mix/bytes.go +++ b/object/storer/mix/bytes.go @@ -5,7 +5,7 @@ import ( "fmt" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/object/storer" + objectstorer "codeberg.org/lindenii/furgit/object/storer" objecttype "codeberg.org/lindenii/furgit/object/type" ) diff --git a/object/storer/mix/header.go b/object/storer/mix/header.go index 6a5abf26..8bab48c2 100644 --- a/object/storer/mix/header.go +++ b/object/storer/mix/header.go @@ -5,7 +5,7 @@ import ( "fmt" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/object/storer" + objectstorer "codeberg.org/lindenii/furgit/object/storer" objecttype "codeberg.org/lindenii/furgit/object/type" ) diff --git a/object/storer/mix/mix.go b/object/storer/mix/mix.go index 9edda31e..6154314f 100644 --- a/object/storer/mix/mix.go +++ b/object/storer/mix/mix.go @@ -5,7 +5,7 @@ package mix import ( "sync" - "codeberg.org/lindenii/furgit/object/storer" + objectstorer "codeberg.org/lindenii/furgit/object/storer" ) // Mix queries multiple object databases with an MRU backend preference. diff --git a/object/storer/mix/mru.go b/object/storer/mix/mru.go index 172a641a..644fe818 100644 --- a/object/storer/mix/mru.go +++ b/object/storer/mix/mru.go @@ -1,6 +1,6 @@ package mix -import "codeberg.org/lindenii/furgit/object/storer" +import objectstorer "codeberg.org/lindenii/furgit/object/storer" type backendNode struct { backend objectstorer.Store diff --git a/object/storer/mix/new.go b/object/storer/mix/new.go index f92e2724..c59d3b9f 100644 --- a/object/storer/mix/new.go +++ b/object/storer/mix/new.go @@ -1,6 +1,6 @@ package mix -import "codeberg.org/lindenii/furgit/object/storer" +import objectstorer "codeberg.org/lindenii/furgit/object/storer" // New creates a Mix from backends. // diff --git a/object/storer/mix/reader.go b/object/storer/mix/reader.go index 66fce069..7ddbaa4e 100644 --- a/object/storer/mix/reader.go +++ b/object/storer/mix/reader.go @@ -6,7 +6,7 @@ import ( "io" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/object/storer" + objectstorer "codeberg.org/lindenii/furgit/object/storer" objecttype "codeberg.org/lindenii/furgit/object/type" ) diff --git a/object/storer/mix/refresh.go b/object/storer/mix/refresh.go index 916d9e8f..2e861a61 100644 --- a/object/storer/mix/refresh.go +++ b/object/storer/mix/refresh.go @@ -3,7 +3,7 @@ package mix import ( "errors" - "codeberg.org/lindenii/furgit/object/storer" + objectstorer "codeberg.org/lindenii/furgit/object/storer" ) // Refresh forwards refresh calls to refresh-capable backends. diff --git a/object/storer/mix/size.go b/object/storer/mix/size.go index b761177d..da8e02b7 100644 --- a/object/storer/mix/size.go +++ b/object/storer/mix/size.go @@ -5,7 +5,7 @@ import ( "fmt" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/object/storer" + objectstorer "codeberg.org/lindenii/furgit/object/storer" ) // ReadSize reads object content length from one backend that has it. diff --git a/object/storer/packed/read_test.go b/object/storer/packed/read_test.go index 4686d192..841019fe 100644 --- a/object/storer/packed/read_test.go +++ b/object/storer/packed/read_test.go @@ -11,7 +11,7 @@ import ( "codeberg.org/lindenii/furgit/internal/testgit" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/object/storer" + objectstorer "codeberg.org/lindenii/furgit/object/storer" "codeberg.org/lindenii/furgit/object/storer/packed" ) diff --git a/object/storer/packed/store.go b/object/storer/packed/store.go index a95bedd7..99556d32 100644 --- a/object/storer/packed/store.go +++ b/object/storer/packed/store.go @@ -7,7 +7,7 @@ import ( "sync/atomic" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/object/storer" + objectstorer "codeberg.org/lindenii/furgit/object/storer" ) // Store reads Git objects from pack/index files under an objects/pack root. diff --git a/object/storer/packed/store_lookup.go b/object/storer/packed/store_lookup.go index 3985463b..accb2d25 100644 --- a/object/storer/packed/store_lookup.go +++ b/object/storer/packed/store_lookup.go @@ -4,7 +4,7 @@ import ( "errors" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/object/storer" + objectstorer "codeberg.org/lindenii/furgit/object/storer" ) // lookup resolves one object ID to its pack location. diff --git a/object/tag_parse.go b/object/tag/parse.go index afc9a2e9..f24d5965 100644 --- a/object/tag_parse.go +++ b/object/tag/parse.go @@ -1,4 +1,4 @@ -package object +package tag import ( "bytes" @@ -6,11 +6,12 @@ import ( "fmt" objectid "codeberg.org/lindenii/furgit/object/id" + objectsignature "codeberg.org/lindenii/furgit/object/signature" objecttype "codeberg.org/lindenii/furgit/object/type" ) -// ParseTag decodes a tag object body. -func ParseTag(body []byte, algo objectid.Algorithm) (*Tag, error) { +// Parse decodes a tag object body. +func Parse(body []byte, algo objectid.Algorithm) (*Tag, error) { t := new(Tag) i := 0 @@ -54,7 +55,7 @@ func ParseTag(body []byte, algo objectid.Algorithm) (*Tag, error) { case "tag": t.Name = append([]byte(nil), value...) case "tagger": - idt, err := ParseSignature(value) + idt, err := objectsignature.Parse(value) if err != nil { return nil, fmt.Errorf("object: tag: tagger: %w", err) } diff --git a/object/tag_parse_test.go b/object/tag/parse_test.go index 07998f1c..293350ed 100644 --- a/object/tag_parse_test.go +++ b/object/tag/parse_test.go @@ -1,12 +1,12 @@ -package object_test +package tag_test import ( "bytes" "testing" "codeberg.org/lindenii/furgit/internal/testgit" - "codeberg.org/lindenii/furgit/object" objectid "codeberg.org/lindenii/furgit/object/id" + "codeberg.org/lindenii/furgit/object/tag" objecttype "codeberg.org/lindenii/furgit/object/type" ) @@ -19,29 +19,29 @@ func TestTagParseFromGit(t *testing.T) { rawBody := testRepo.CatFile(t, "tag", tagID) - tag, err := object.ParseTag(rawBody, algo) + parsed, err := tag.Parse(rawBody, algo) if err != nil { t.Fatalf("ParseTag: %v", err) } - if tag.Target != commitID { - t.Fatalf("tag target mismatch: got %s want %s", tag.Target, commitID) + if parsed.Target != commitID { + t.Fatalf("tag target mismatch: got %s want %s", parsed.Target, commitID) } - if tag.TargetType != objecttype.TypeCommit { - t.Fatalf("tag target type = %v, want %v", tag.TargetType, objecttype.TypeCommit) + if parsed.TargetType != objecttype.TypeCommit { + t.Fatalf("tag target type = %v, want %v", parsed.TargetType, objecttype.TypeCommit) } - if !bytes.Equal(tag.Name, []byte("v1")) { - t.Fatalf("tag name = %q, want %q", tag.Name, "v1") + if !bytes.Equal(parsed.Name, []byte("v1")) { + t.Fatalf("tag name = %q, want %q", parsed.Name, "v1") } - if tag.Tagger == nil { + if parsed.Tagger == nil { t.Fatalf("expected tagger") } - if !bytes.Contains(tag.Message, []byte("tag message")) { - t.Fatalf("tag message mismatch: %q", tag.Message) + if !bytes.Contains(parsed.Message, []byte("tag message")) { + t.Fatalf("tag message mismatch: %q", parsed.Message) } }) } diff --git a/object/tag_serialize.go b/object/tag/serialize.go index c914e8dd..5f712950 100644 --- a/object/tag_serialize.go +++ b/object/tag/serialize.go @@ -1,4 +1,4 @@ -package object +package tag import ( "bytes" diff --git a/object/tag_serialize_test.go b/object/tag/serialize_test.go index de9f813d..a1311c39 100644 --- a/object/tag_serialize_test.go +++ b/object/tag/serialize_test.go @@ -1,11 +1,11 @@ -package object_test +package tag_test import ( "testing" "codeberg.org/lindenii/furgit/internal/testgit" - "codeberg.org/lindenii/furgit/object" objectid "codeberg.org/lindenii/furgit/object/id" + "codeberg.org/lindenii/furgit/object/tag" ) func TestTagSerialize(t *testing.T) { @@ -17,12 +17,12 @@ func TestTagSerialize(t *testing.T) { rawBody := testRepo.CatFile(t, "tag", tagID) - tag, err := object.ParseTag(rawBody, algo) + parsed, err := tag.Parse(rawBody, algo) if err != nil { t.Fatalf("ParseTag: %v", err) } - rawObj, err := tag.SerializeWithHeader() + rawObj, err := parsed.SerializeWithHeader() if err != nil { t.Fatalf("SerializeWithHeader: %v", err) } diff --git a/object/tag.go b/object/tag/tag.go index 50c4b273..4301557e 100644 --- a/object/tag.go +++ b/object/tag/tag.go @@ -1,7 +1,9 @@ -package object +// Package tag provides representations, parsers, and serializers for tag objects. +package tag import ( objectid "codeberg.org/lindenii/furgit/object/id" + objectsignature "codeberg.org/lindenii/furgit/object/signature" objecttype "codeberg.org/lindenii/furgit/object/type" ) @@ -10,13 +12,6 @@ type Tag struct { Target objectid.ObjectID TargetType objecttype.Type Name []byte - Tagger *Signature + Tagger *objectsignature.Signature Message []byte } - -// ObjectType returns TypeTag. -func (tag *Tag) ObjectType() objecttype.Type { - _ = tag - - return objecttype.TypeTag -} diff --git a/object/tag/type.go b/object/tag/type.go new file mode 100644 index 00000000..215103ab --- /dev/null +++ b/object/tag/type.go @@ -0,0 +1,10 @@ +package tag + +import objecttype "codeberg.org/lindenii/furgit/object/type" + +// ObjectType returns TypeTag. +func (tag *Tag) ObjectType() objecttype.Type { + _ = tag + + return objecttype.TypeTag +} diff --git a/object/tree.go b/object/tree.go deleted file mode 100644 index 83dcb508..00000000 --- a/object/tree.go +++ /dev/null @@ -1,163 +0,0 @@ -package object - -import ( - "bytes" - "fmt" - "sort" - - objectid "codeberg.org/lindenii/furgit/object/id" - objecttype "codeberg.org/lindenii/furgit/object/type" -) - -// 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 -) - -// TreeEntry represents a single entry in a tree. -type TreeEntry struct { - Mode FileMode - Name []byte - ID objectid.ObjectID -} - -// Tree represents a Git tree object. -type Tree struct { - Entries []TreeEntry -} - -// ObjectType returns TypeTree. -func (tree *Tree) ObjectType() objecttype.Type { - _ = tree - - return objecttype.TypeTree -} - -// Entry looks up a tree entry by name. -func (tree *Tree) Entry(name []byte) *TreeEntry { - if len(tree.Entries) == 0 { - return nil - } - - if e := tree.entry(name, true); e != nil { - return e - } - - return tree.entry(name, false) -} - -// InsertEntry inserts a tree entry while preserving Git ordering. -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) - } - - newIsTree := newEntry.Mode == FileModeDir - insertAt := sort.Search(len(tree.Entries), func(i int) bool { - return TreeEntryNameCompare(tree.Entries[i].Name, tree.Entries[i].Mode, newEntry.Name, newIsTree) >= 0 - }) - tree.Entries = append(tree.Entries, TreeEntry{}) - copy(tree.Entries[insertAt+1:], tree.Entries[insertAt:]) - tree.Entries[insertAt] = newEntry - - return nil -} - -// 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) - } - - for i := range tree.Entries { - if bytes.Equal(tree.Entries[i].Name, name) { - copy(tree.Entries[i:], tree.Entries[i+1:]) - tree.Entries = tree.Entries[:len(tree.Entries)-1] - - return nil - } - } - - return fmt.Errorf("object: tree: entry %q not found", name) -} - -func (tree *Tree) entry(name []byte, searchIsTree bool) *TreeEntry { - low, high := 0, len(tree.Entries)-1 - for low <= high { - mid := low + (high-low)/2 - entry := &tree.Entries[mid] - - cmp := TreeEntryNameCompare(entry.Name, entry.Mode, name, searchIsTree) - if cmp == 0 { - if bytes.Equal(entry.Name, name) { - return entry - } - - return nil - } - - if cmp < 0 { - low = mid + 1 - } else { - high = mid - 1 - } - } - - return nil -} - -// 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/entry.go b/object/tree/entry.go new file mode 100644 index 00000000..cddcde73 --- /dev/null +++ b/object/tree/entry.go @@ -0,0 +1,39 @@ +package tree + +import ( + "bytes" + + objectid "codeberg.org/lindenii/furgit/object/id" +) + +// TreeEntry represents a single entry in a tree. +type TreeEntry struct { + Mode FileMode + Name []byte + ID objectid.ObjectID +} + +func (tree *Tree) entry(name []byte, searchIsTree bool) *TreeEntry { + low, high := 0, len(tree.Entries)-1 + for low <= high { + mid := low + (high-low)/2 + entry := &tree.Entries[mid] + + cmp := TreeEntryNameCompare(entry.Name, entry.Mode, name, searchIsTree) + if cmp == 0 { + if bytes.Equal(entry.Name, name) { + return entry + } + + return nil + } + + if cmp < 0 { + low = mid + 1 + } else { + high = mid - 1 + } + } + + return nil +} diff --git a/object/tree/helpers_test.go b/object/tree/helpers_test.go new file mode 100644 index 00000000..3da92ce4 --- /dev/null +++ b/object/tree/helpers_test.go @@ -0,0 +1,114 @@ +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 new file mode 100644 index 00000000..bca4aa49 --- /dev/null +++ b/object/tree/insert.go @@ -0,0 +1,23 @@ +package tree + +import ( + "fmt" + "sort" +) + +// InsertEntry inserts a tree entry while preserving Git ordering. +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) + } + + newIsTree := newEntry.Mode == FileModeDir + insertAt := sort.Search(len(tree.Entries), func(i int) bool { + return TreeEntryNameCompare(tree.Entries[i].Name, tree.Entries[i].Mode, newEntry.Name, newIsTree) >= 0 + }) + tree.Entries = append(tree.Entries, TreeEntry{}) + copy(tree.Entries[insertAt+1:], tree.Entries[insertAt:]) + tree.Entries[insertAt] = newEntry + + return nil +} diff --git a/object/tree/lookup.go b/object/tree/lookup.go new file mode 100644 index 00000000..957b31c4 --- /dev/null +++ b/object/tree/lookup.go @@ -0,0 +1,14 @@ +package tree + +// Entry looks up a tree entry by name. +func (tree *Tree) Entry(name []byte) *TreeEntry { + if len(tree.Entries) == 0 { + return nil + } + + if e := tree.entry(name, true); e != nil { + return e + } + + return tree.entry(name, false) +} diff --git a/object/tree/mode.go b/object/tree/mode.go new file mode 100644 index 00000000..b1cbc6bc --- /dev/null +++ b/object/tree/mode.go @@ -0,0 +1,12 @@ +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/name.go b/object/tree/name.go new file mode 100644 index 00000000..02af3292 --- /dev/null +++ b/object/tree/name.go @@ -0,0 +1,51 @@ +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 index 944dc538..10bef968 100644 --- a/object/tree_parse.go +++ b/object/tree/parse.go @@ -1,4 +1,4 @@ -package object +package tree import ( "bytes" @@ -8,8 +8,8 @@ import ( objectid "codeberg.org/lindenii/furgit/object/id" ) -// ParseTree decodes a tree object body. -func ParseTree(body []byte, algo objectid.Algorithm) (*Tree, error) { +// Parse decodes a tree object body. +func Parse(body []byte, algo objectid.Algorithm) (*Tree, error) { var entries []TreeEntry i := 0 diff --git a/object/tree_parse_test.go b/object/tree/parse_test.go index 2e78243c..6f00220e 100644 --- a/object/tree_parse_test.go +++ b/object/tree/parse_test.go @@ -1,12 +1,12 @@ -package object_test +package tree_test import ( "bytes" "testing" "codeberg.org/lindenii/furgit/internal/testgit" - "codeberg.org/lindenii/furgit/object" objectid "codeberg.org/lindenii/furgit/object/id" + "codeberg.org/lindenii/furgit/object/tree" ) func TestTreeParseFromGit(t *testing.T) { @@ -15,7 +15,7 @@ func TestTreeParseFromGit(t *testing.T) { testRepo := testgit.NewRepo(t, testgit.RepoOptions{ObjectFormat: algo, Bare: true}) entries := adversarialRootEntries(t, testRepo) - inserted := &object.Tree{} + inserted := &tree.Tree{} for _, entry := range entries { err := inserted.InsertEntry(entry) if err != nil { @@ -27,17 +27,17 @@ func TestTreeParseFromGit(t *testing.T) { rawBody := testRepo.CatFile(t, "tree", treeID) - tree, err := object.ParseTree(rawBody, algo) + parsed, err := tree.Parse(rawBody, algo) if err != nil { t.Fatalf("ParseTree: %v", err) } - if len(tree.Entries) != len(inserted.Entries) { - t.Fatalf("entry count = %d, want %d", len(tree.Entries), len(inserted.Entries)) + 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 := tree.Entries[i] + got := parsed.Entries[i] want := inserted.Entries[i] if got.Mode != want.Mode || got.ID != want.ID || !bytes.Equal(got.Name, want.Name) { @@ -47,18 +47,18 @@ func TestTreeParseFromGit(t *testing.T) { } lsNames := gitLsTreeNames(testRepo.RunBytes(t, "ls-tree", "--name-only", "-z", treeID.String())) - if len(lsNames) != len(tree.Entries) { - t.Fatalf("ls-tree names = %d, want %d", len(lsNames), len(tree.Entries)) + 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], tree.Entries[i].Name) { - t.Fatalf("ordering mismatch at %d: git=%q parsed=%q", i, lsNames[i], tree.Entries[i].Name) + 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 := tree.Entry(want.Name) + got := parsed.Entry(want.Name) if got == nil { t.Fatalf("Entry(%q) returned nil", want.Name) @@ -69,7 +69,7 @@ func TestTreeParseFromGit(t *testing.T) { } } - if tree.Entry([]byte("does-not-exist")) != nil { + if parsed.Entry([]byte("does-not-exist")) != nil { t.Fatalf("Entry on missing name should be nil") } }) diff --git a/object/tree/remove.go b/object/tree/remove.go new file mode 100644 index 00000000..9eb42028 --- /dev/null +++ b/object/tree/remove.go @@ -0,0 +1,24 @@ +package tree + +import ( + "bytes" + "fmt" +) + +// 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) + } + + for i := range tree.Entries { + if bytes.Equal(tree.Entries[i].Name, name) { + copy(tree.Entries[i:], tree.Entries[i+1:]) + tree.Entries = tree.Entries[:len(tree.Entries)-1] + + return nil + } + } + + return fmt.Errorf("object: tree: entry %q not found", name) +} diff --git a/object/tree_serialize.go b/object/tree/serialize.go index 849738a9..be31297b 100644 --- a/object/tree_serialize.go +++ b/object/tree/serialize.go @@ -1,4 +1,4 @@ -package object +package tree import ( "errors" diff --git a/object/tree_serialize_test.go b/object/tree/serialize_test.go index 26f8768e..9c9a2f1c 100644 --- a/object/tree_serialize_test.go +++ b/object/tree/serialize_test.go @@ -1,11 +1,11 @@ -package object_test +package tree_test import ( "testing" "codeberg.org/lindenii/furgit/internal/testgit" - "codeberg.org/lindenii/furgit/object" objectid "codeberg.org/lindenii/furgit/object/id" + "codeberg.org/lindenii/furgit/object/tree" ) func TestTreeSerialize(t *testing.T) { @@ -13,54 +13,54 @@ func TestTreeSerialize(t *testing.T) { 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) - tree := &object.Tree{} + obj := &tree.Tree{} for i := len(entries) - 1; i >= 0; i-- { - err := tree.InsertEntry(entries[i]) + err := obj.InsertEntry(entries[i]) if err != nil { t.Fatalf("InsertEntry(%q): %v", entries[i].Name, err) } } - if len(tree.Entries) < 32 { - t.Fatalf("expected at least 32 entries, got %d", len(tree.Entries)) + if len(obj.Entries) < 32 { + t.Fatalf("expected at least 32 entries, got %d", len(obj.Entries)) } - dup := tree.Entries[0] + dup := obj.Entries[0] - err := tree.InsertEntry(dup) + err := obj.InsertEntry(dup) if err == nil { t.Fatalf("duplicate InsertEntry should fail") } - removed := tree.Entries[len(tree.Entries)/2] + removed := obj.Entries[len(obj.Entries)/2] - err = tree.RemoveEntry(removed.Name) + err = obj.RemoveEntry(removed.Name) if err != nil { t.Fatalf("RemoveEntry(%q): %v", removed.Name, err) } - if tree.Entry(removed.Name) != nil { + if obj.Entry(removed.Name) != nil { t.Fatalf("Entry(%q) should be nil after remove", removed.Name) } - err = tree.RemoveEntry([]byte("no-such-entry")) + err = obj.RemoveEntry([]byte("no-such-entry")) if err == nil { t.Fatalf("RemoveEntry missing entry should fail") } - err = tree.InsertEntry(removed) + err = obj.InsertEntry(removed) if err != nil { t.Fatalf("re-InsertEntry(%q): %v", removed.Name, err) } - if tree.Entry(removed.Name) == nil { + if obj.Entry(removed.Name) == nil { t.Fatalf("Entry(%q) should exist after reinsert", removed.Name) } - wantTreeID := testRepo.Mktree(t, buildGitMktreeInput(tree.Entries)) + wantTreeID := testRepo.Mktree(t, buildGitMktreeInput(obj.Entries)) - rawObj, err := tree.SerializeWithHeader() + rawObj, err := obj.SerializeWithHeader() if err != nil { t.Fatalf("SerializeWithHeader: %v", err) } diff --git a/object/tree/tree.go b/object/tree/tree.go new file mode 100644 index 00000000..3ea6f1ee --- /dev/null +++ b/object/tree/tree.go @@ -0,0 +1,7 @@ +// Package tree provides representations, parsers, and serializers for tree objects. +package tree + +// Tree represents a Git tree object. +type Tree struct { + Entries []TreeEntry +} diff --git a/object/tree/type.go b/object/tree/type.go new file mode 100644 index 00000000..416544af --- /dev/null +++ b/object/tree/type.go @@ -0,0 +1,10 @@ +package tree + +import objecttype "codeberg.org/lindenii/furgit/object/type" + +// ObjectType returns TypeTree. +func (tree *Tree) ObjectType() objecttype.Type { + _ = tree + + return objecttype.TypeTree +} diff --git a/object/tree_helpers_test.go b/object/tree_helpers_test.go deleted file mode 100644 index 2577e0e1..00000000 --- a/object/tree_helpers_test.go +++ /dev/null @@ -1,114 +0,0 @@ -package object_test - -import ( - "bytes" - "fmt" - "strings" - "testing" - - "codeberg.org/lindenii/furgit/internal/testgit" - "codeberg.org/lindenii/furgit/object" -) - -func buildGitMktreeInput(entries []object.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 object.FileMode) string { - switch mode { - case object.FileModeDir: - return "tree" - case object.FileModeRegular, object.FileModeExecutable, object.FileModeSymlink: - return "blob" - case object.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) []object.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 []object.TreeEntry{ - {Mode: object.FileModeRegular, Name: []byte("z"), ID: blobA}, - {Mode: object.FileModeRegular, Name: []byte("A"), ID: blobB}, - {Mode: object.FileModeRegular, Name: []byte("aa"), ID: blobC}, - {Mode: object.FileModeRegular, Name: []byte("a0"), ID: blobA}, - {Mode: object.FileModeRegular, Name: []byte("a-"), ID: blobB}, - {Mode: object.FileModeRegular, Name: []byte("a."), ID: blobC}, - {Mode: object.FileModeRegular, Name: []byte("a_"), ID: blobA}, - {Mode: object.FileModeRegular, Name: []byte("a~"), ID: blobB}, - {Mode: object.FileModeRegular, Name: []byte("Z"), ID: blobC}, - {Mode: object.FileModeRegular, Name: []byte("0"), ID: blobA}, - {Mode: object.FileModeRegular, Name: []byte("9"), ID: blobB}, - {Mode: object.FileModeRegular, Name: []byte("00"), ID: blobC}, - {Mode: object.FileModeRegular, Name: []byte("这是一些非 ASCII 的字符"), ID: blobC}, - {Mode: object.FileModeRegular, Name: []byte("是新进入 Unicode 的字符"), ID: blobC}, - {Mode: object.FileModeRegular, Name: []byte("Emoji 👀"), ID: blobC}, - {Mode: object.FileModeRegular, Name: []byte("_"), ID: blobA}, - {Mode: object.FileModeRegular, Name: []byte("-dash"), ID: blobB}, - {Mode: object.FileModeRegular, Name: []byte("dot.file"), ID: blobC}, - {Mode: object.FileModeRegular, Name: []byte(".hidden"), ID: blobA}, - {Mode: object.FileModeRegular, Name: []byte("CAPS"), ID: blobB}, - {Mode: object.FileModeRegular, Name: []byte("caps"), ID: blobC}, - {Mode: object.FileModeRegular, Name: []byte("mixCase"), ID: blobA}, - {Mode: object.FileModeRegular, Name: []byte("name with space"), ID: blobB}, - {Mode: object.FileModeRegular, Name: []byte("name-with-dash"), ID: blobC}, - {Mode: object.FileModeRegular, Name: []byte("name.with.dot"), ID: blobA}, - {Mode: object.FileModeRegular, Name: []byte("name_with_underscore"), ID: blobB}, - {Mode: object.FileModeRegular, Name: []byte("tilde~name"), ID: blobC}, - {Mode: object.FileModeRegular, Name: []byte("brace{name}"), ID: blobA}, - {Mode: object.FileModeRegular, Name: []byte("plus+name"), ID: blobB}, - {Mode: object.FileModeRegular, Name: []byte("equal=name"), ID: blobC}, - {Mode: object.FileModeRegular, Name: []byte("at@name"), ID: blobA}, - {Mode: object.FileModeRegular, Name: []byte("percent%name"), ID: blobB}, - {Mode: object.FileModeRegular, Name: []byte("caret^name"), ID: blobC}, - {Mode: object.FileModeRegular, Name: []byte("comma,name"), ID: blobA}, - {Mode: object.FileModeRegular, Name: []byte("semi;name"), ID: blobB}, - {Mode: object.FileModeRegular, Name: []byte("paren(name)"), ID: blobC}, - {Mode: object.FileModeRegular, Name: []byte("bracket[name]"), ID: blobA}, - {Mode: object.FileModeExecutable, Name: []byte("exec.sh"), ID: blobB}, - {Mode: object.FileModeSymlink, Name: []byte("sym.link"), ID: blobC}, - {Mode: object.FileModeDir, Name: []byte("dir"), ID: subDirA}, - {Mode: object.FileModeDir, Name: []byte("dir0"), ID: subDirB}, - {Mode: object.FileModeDir, Name: []byte("dir.space"), ID: subDirC}, - {Mode: object.FileModeDir, Name: []byte("x"), ID: subDirD}, - } -} diff --git a/packfile/ingest/api.go b/packfile/ingest/api.go index 860ce5f5..ce366a4f 100644 --- a/packfile/ingest/api.go +++ b/packfile/ingest/api.go @@ -8,7 +8,7 @@ import ( "os" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/object/storer" + objectstorer "codeberg.org/lindenii/furgit/object/storer" ) // Options controls one pack ingest operation. diff --git a/packfile/ingest/thin_fix.go b/packfile/ingest/thin_fix.go index 1be75f8e..83e5572a 100644 --- a/packfile/ingest/thin_fix.go +++ b/packfile/ingest/thin_fix.go @@ -6,7 +6,7 @@ import ( "codeberg.org/lindenii/furgit/internal/intconv" "codeberg.org/lindenii/furgit/internal/progress" - "codeberg.org/lindenii/furgit/object/storer" + objectstorer "codeberg.org/lindenii/furgit/object/storer" ) // maybeFixThin appends missing bases and rewrites pack header/trailer when needed. diff --git a/reachability/helpers.go b/reachability/helpers.go index 47fe313e..8d9eea6a 100644 --- a/reachability/helpers.go +++ b/reachability/helpers.go @@ -6,7 +6,7 @@ import ( giterrors "codeberg.org/lindenii/furgit/errors" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/object/storer" + objectstorer "codeberg.org/lindenii/furgit/object/storer" objecttype "codeberg.org/lindenii/furgit/object/type" ) diff --git a/reachability/reachability.go b/reachability/reachability.go index 54fc6e44..77a844a7 100644 --- a/reachability/reachability.go +++ b/reachability/reachability.go @@ -3,7 +3,7 @@ package reachability import ( commitgraphread "codeberg.org/lindenii/furgit/commitgraph/read" - "codeberg.org/lindenii/furgit/object/storer" + objectstorer "codeberg.org/lindenii/furgit/object/storer" ) // Reachability provides graph traversal over objects in one object store. diff --git a/reachability/unit_test.go b/reachability/unit_test.go index fad0280b..db9a5c26 100644 --- a/reachability/unit_test.go +++ b/reachability/unit_test.go @@ -9,9 +9,9 @@ import ( giterrors "codeberg.org/lindenii/furgit/errors" "codeberg.org/lindenii/furgit/internal/testgit" - "codeberg.org/lindenii/furgit/object" objectid "codeberg.org/lindenii/furgit/object/id" "codeberg.org/lindenii/furgit/object/storer/memory" + "codeberg.org/lindenii/furgit/object/tree" objecttype "codeberg.org/lindenii/furgit/object/type" "codeberg.org/lindenii/furgit/reachability" ) @@ -84,8 +84,8 @@ func TestWalkDomainCommitsIncludesTagNodes(t *testing.T) { testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper store := newCountingMemStore(algo) blob := store.AddObject(objecttype.TypeBlob, []byte("blob\n")) - tree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{{ - Mode: object.FileModeRegular, + tree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &tree.Tree{Entries: []tree.TreeEntry{{ + Mode: tree.FileModeRegular, Name: []byte("f"), ID: blob, }}})) @@ -119,8 +119,8 @@ func TestWalkExcludesHavesCompletely(t *testing.T) { testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper store := newCountingMemStore(algo) blob := store.AddObject(objecttype.TypeBlob, []byte("blob\n")) - tree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{{ - Mode: object.FileModeRegular, + tree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &tree.Tree{Entries: []tree.TreeEntry{{ + Mode: tree.FileModeRegular, Name: []byte("f"), ID: blob, }}})) @@ -148,8 +148,8 @@ func TestWalkDomainCommitsRejectsNonCommitRootAfterPeel(t *testing.T) { testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper store := newCountingMemStore(algo) blob := store.AddObject(objecttype.TypeBlob, []byte("blob\n")) - tree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{{ - Mode: object.FileModeRegular, + tree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &tree.Tree{Entries: []tree.TreeEntry{{ + Mode: tree.FileModeRegular, Name: []byte("f"), ID: blob, }}})) @@ -181,8 +181,8 @@ func TestWalkDomainCommitsHaveTagStopsTraversal(t *testing.T) { testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper store := newCountingMemStore(algo) blob := store.AddObject(objecttype.TypeBlob, []byte("blob\n")) - tree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{{ - Mode: object.FileModeRegular, + tree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &tree.Tree{Entries: []tree.TreeEntry{{ + Mode: tree.FileModeRegular, Name: []byte("f"), ID: blob, }}})) @@ -224,15 +224,15 @@ func TestWalkDomainObjectsRecursesTreesAndSkipsBlobContentReads(t *testing.T) { blob2 := store.AddObject(objecttype.TypeBlob, []byte("b2\n")) gitlinkTarget := store.Algorithm().Sum([]byte("external-submodule")) - subtree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{{ - Mode: object.FileModeRegular, + subtree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &tree.Tree{Entries: []tree.TreeEntry{{ + Mode: tree.FileModeRegular, Name: []byte("nested"), ID: blob2, }}})) - rootTree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{ - {Mode: object.FileModeRegular, Name: []byte("a"), ID: blob1}, - {Mode: object.FileModeDir, Name: []byte("dir"), ID: subtree}, - {Mode: object.FileModeGitlink, Name: []byte("submodule"), ID: gitlinkTarget}, + rootTree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &tree.Tree{Entries: []tree.TreeEntry{ + {Mode: tree.FileModeRegular, Name: []byte("a"), ID: blob1}, + {Mode: tree.FileModeDir, Name: []byte("dir"), ID: subtree}, + {Mode: tree.FileModeGitlink, Name: []byte("submodule"), ID: gitlinkTarget}, }})) commit := store.AddObject(objecttype.TypeCommit, commitBody(rootTree)) @@ -265,8 +265,8 @@ func TestCheckConnectedReturnsConcreteMissingObject(t *testing.T) { testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper store := newCountingMemStore(algo) blob := store.AddObject(objecttype.TypeBlob, []byte("blob\n")) - tree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{{ - Mode: object.FileModeRegular, + tree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &tree.Tree{Entries: []tree.TreeEntry{{ + Mode: tree.FileModeRegular, Name: []byte("f"), ID: blob, }}})) @@ -307,7 +307,7 @@ func TestWalkInvalidDomainReturnsPlainError(t *testing.T) { }) } -func mustSerializeTree(tb testing.TB, tree *object.Tree) []byte { +func mustSerializeTree(tb testing.TB, tree *tree.Tree) []byte { tb.Helper() body, err := tree.SerializeWithoutHeader() diff --git a/reachability/walk_expand_commits.go b/reachability/walk_expand_commits.go index f02da944..8cb93279 100644 --- a/reachability/walk_expand_commits.go +++ b/reachability/walk_expand_commits.go @@ -4,7 +4,8 @@ import ( "fmt" "codeberg.org/lindenii/furgit/errors" - "codeberg.org/lindenii/furgit/object" + objectcommit "codeberg.org/lindenii/furgit/object/commit" + objecttag "codeberg.org/lindenii/furgit/object/tag" objecttype "codeberg.org/lindenii/furgit/object/type" ) @@ -39,7 +40,7 @@ func (walk *Walk) expandCommits(item walkItem) ([]walkItem, error) { return nil, err } - commit, err := object.ParseCommit(content, item.id.Algorithm()) + commit, err := objectcommit.Parse(content, item.id.Algorithm()) if err != nil { return nil, err } @@ -56,7 +57,7 @@ func (walk *Walk) expandCommits(item walkItem) ([]walkItem, error) { return nil, err } - tag, err := object.ParseTag(content, item.id.Algorithm()) + tag, err := objecttag.Parse(content, item.id.Algorithm()) if err != nil { return nil, err } diff --git a/reachability/walk_expand_objects.go b/reachability/walk_expand_objects.go index 36e21745..9c5ed439 100644 --- a/reachability/walk_expand_objects.go +++ b/reachability/walk_expand_objects.go @@ -4,7 +4,9 @@ import ( "fmt" "codeberg.org/lindenii/furgit/errors" - "codeberg.org/lindenii/furgit/object" + objectcommit "codeberg.org/lindenii/furgit/object/commit" + objecttag "codeberg.org/lindenii/furgit/object/tag" + objecttree "codeberg.org/lindenii/furgit/object/tree" objecttype "codeberg.org/lindenii/furgit/object/type" ) @@ -27,7 +29,7 @@ func (walk *Walk) expandObjects(item walkItem) ([]walkItem, error) { return nil, err } - commit, err := object.ParseCommit(content, item.id.Algorithm()) + commit, err := objectcommit.Parse(content, item.id.Algorithm()) if err != nil { return nil, err } @@ -46,7 +48,7 @@ func (walk *Walk) expandObjects(item walkItem) ([]walkItem, error) { return nil, err } - tree, err := object.ParseTree(content, item.id.Algorithm()) + tree, err := objecttree.Parse(content, item.id.Algorithm()) if err != nil { return nil, err } @@ -54,11 +56,11 @@ func (walk *Walk) expandObjects(item walkItem) ([]walkItem, error) { next := make([]walkItem, 0, len(tree.Entries)) for _, entry := range tree.Entries { switch entry.Mode { - case object.FileModeGitlink: + case objecttree.FileModeGitlink: continue - case object.FileModeDir: + case objecttree.FileModeDir: next = append(next, walkItem{id: entry.ID, want: objecttype.TypeTree}) - case object.FileModeRegular, object.FileModeExecutable, object.FileModeSymlink: + case objecttree.FileModeRegular, objecttree.FileModeExecutable, objecttree.FileModeSymlink: next = append(next, walkItem{id: entry.ID, want: objecttype.TypeBlob}) } } @@ -70,7 +72,7 @@ func (walk *Walk) expandObjects(item walkItem) ([]walkItem, error) { return nil, err } - tag, err := object.ParseTag(content, item.id.Algorithm()) + tag, err := objecttag.Parse(content, item.id.Algorithm()) if err != nil { return nil, err } diff --git a/reachability/walk_verify.go b/reachability/walk_verify.go index 0469a8e2..c1409ba7 100644 --- a/reachability/walk_verify.go +++ b/reachability/walk_verify.go @@ -2,7 +2,7 @@ package reachability import ( "codeberg.org/lindenii/furgit/errors" - "codeberg.org/lindenii/furgit/object" + objectcommit "codeberg.org/lindenii/furgit/object/commit" objectid "codeberg.org/lindenii/furgit/object/id" objecttype "codeberg.org/lindenii/furgit/object/type" ) @@ -22,7 +22,7 @@ func (walk *Walk) validateCommitObject(id objectid.ObjectID) error { return err } - _, err = object.ParseCommit(content, id.Algorithm()) + _, err = objectcommit.Parse(content, id.Algorithm()) return err } diff --git a/receivepack/advertise.go b/receivepack/advertise.go index 772fe680..d7258c37 100644 --- a/receivepack/advertise.go +++ b/receivepack/advertise.go @@ -5,7 +5,7 @@ import ( common "codeberg.org/lindenii/furgit/protocol/v0v1/server" "codeberg.org/lindenii/furgit/ref" - "codeberg.org/lindenii/furgit/ref/store" + refstore "codeberg.org/lindenii/furgit/ref/store" ) func advertisedRefs(opts Options) ([]common.AdvertisedRef, error) { diff --git a/receivepack/hook.go b/receivepack/hook.go index 2a87276a..431fd66f 100644 --- a/receivepack/hook.go +++ b/receivepack/hook.go @@ -5,9 +5,9 @@ import ( "io" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/object/storer" + objectstorer "codeberg.org/lindenii/furgit/object/storer" "codeberg.org/lindenii/furgit/receivepack/service" - "codeberg.org/lindenii/furgit/ref/store" + refstore "codeberg.org/lindenii/furgit/ref/store" ) type HookIO struct { diff --git a/receivepack/hooks/reject_force_push.go b/receivepack/hooks/reject_force_push.go index 82f13644..e6b112ea 100644 --- a/receivepack/hooks/reject_force_push.go +++ b/receivepack/hooks/reject_force_push.go @@ -9,7 +9,7 @@ import ( objectid "codeberg.org/lindenii/furgit/object/id" objectmix "codeberg.org/lindenii/furgit/object/storer/mix" receivepack "codeberg.org/lindenii/furgit/receivepack" - "codeberg.org/lindenii/furgit/ref/store" + refstore "codeberg.org/lindenii/furgit/ref/store" ) // RejectForcePush rejects updates whose new value is not a fast-forward of the diff --git a/receivepack/options.go b/receivepack/options.go index 8bbd8bbe..139c3839 100644 --- a/receivepack/options.go +++ b/receivepack/options.go @@ -4,8 +4,8 @@ import ( "os" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/object/storer" - "codeberg.org/lindenii/furgit/ref/store" + objectstorer "codeberg.org/lindenii/furgit/object/storer" + refstore "codeberg.org/lindenii/furgit/ref/store" ) // Options configures one receive-pack invocation. diff --git a/receivepack/service/apply.go b/receivepack/service/apply.go index 9c1900a4..8fa500ca 100644 --- a/receivepack/service/apply.go +++ b/receivepack/service/apply.go @@ -3,7 +3,7 @@ package service import ( "codeberg.org/lindenii/furgit/internal/utils" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/ref/store" + refstore "codeberg.org/lindenii/furgit/ref/store" ) func (service *Service) applyAtomic(result *Result, commands []Command) error { diff --git a/receivepack/service/hook.go b/receivepack/service/hook.go index 5fb7d41f..750720dd 100644 --- a/receivepack/service/hook.go +++ b/receivepack/service/hook.go @@ -5,8 +5,8 @@ import ( "io" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/object/storer" - "codeberg.org/lindenii/furgit/ref/store" + objectstorer "codeberg.org/lindenii/furgit/object/storer" + refstore "codeberg.org/lindenii/furgit/ref/store" ) type HookIO struct { diff --git a/receivepack/service/options.go b/receivepack/service/options.go index f252bbc8..7edf4f06 100644 --- a/receivepack/service/options.go +++ b/receivepack/service/options.go @@ -6,8 +6,8 @@ import ( "os" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/object/storer" - "codeberg.org/lindenii/furgit/ref/store" + objectstorer "codeberg.org/lindenii/furgit/object/storer" + refstore "codeberg.org/lindenii/furgit/ref/store" ) type PromotedObjectPermissions struct { diff --git a/receivepack/service/run_hook.go b/receivepack/service/run_hook.go index fd8a83a2..94467078 100644 --- a/receivepack/service/run_hook.go +++ b/receivepack/service/run_hook.go @@ -5,7 +5,7 @@ import ( "os" "codeberg.org/lindenii/furgit/internal/utils" - "codeberg.org/lindenii/furgit/object/storer" + objectstorer "codeberg.org/lindenii/furgit/object/storer" "codeberg.org/lindenii/furgit/object/storer/loose" objectmix "codeberg.org/lindenii/furgit/object/storer/mix" "codeberg.org/lindenii/furgit/object/storer/packed" diff --git a/ref/store/chain/chain.go b/ref/store/chain/chain.go index 6a4a0eed..ae69633e 100644 --- a/ref/store/chain/chain.go +++ b/ref/store/chain/chain.go @@ -2,7 +2,7 @@ // of backends. package chain -import "codeberg.org/lindenii/furgit/ref/store" +import refstore "codeberg.org/lindenii/furgit/ref/store" // Chain queries multiple reference stores in order. // diff --git a/ref/store/chain/new.go b/ref/store/chain/new.go index dc8c0779..f4b8ef6e 100644 --- a/ref/store/chain/new.go +++ b/ref/store/chain/new.go @@ -1,6 +1,6 @@ package chain -import "codeberg.org/lindenii/furgit/ref/store" +import refstore "codeberg.org/lindenii/furgit/ref/store" // New creates an ordered reference store chain. // diff --git a/ref/store/chain/resolve.go b/ref/store/chain/resolve.go index f69d51ef..06c3d8f5 100644 --- a/ref/store/chain/resolve.go +++ b/ref/store/chain/resolve.go @@ -5,7 +5,7 @@ import ( "fmt" "codeberg.org/lindenii/furgit/ref" - "codeberg.org/lindenii/furgit/ref/store" + refstore "codeberg.org/lindenii/furgit/ref/store" ) // Resolve resolves a reference from the first backend that has it. diff --git a/ref/store/files/batch.go b/ref/store/files/batch.go index 8f514422..1d396bd5 100644 --- a/ref/store/files/batch.go +++ b/ref/store/files/batch.go @@ -1,6 +1,6 @@ package files -import "codeberg.org/lindenii/furgit/ref/store" +import refstore "codeberg.org/lindenii/furgit/ref/store" type Batch struct { store *Store diff --git a/ref/store/files/batch_apply.go b/ref/store/files/batch_apply.go index d6fb1a4d..138026a3 100644 --- a/ref/store/files/batch_apply.go +++ b/ref/store/files/batch_apply.go @@ -1,6 +1,6 @@ package files -import "codeberg.org/lindenii/furgit/ref/store" +import refstore "codeberg.org/lindenii/furgit/ref/store" func (batch *Batch) Apply() ([]refstore.BatchResult, error) { results := make([]refstore.BatchResult, len(batch.ops)) diff --git a/ref/store/files/batch_begin.go b/ref/store/files/batch_begin.go index 9c2b98d2..c8a0dca7 100644 --- a/ref/store/files/batch_begin.go +++ b/ref/store/files/batch_begin.go @@ -1,6 +1,6 @@ package files -import "codeberg.org/lindenii/furgit/ref/store" +import refstore "codeberg.org/lindenii/furgit/ref/store" // BeginBatch creates one new files batch. // diff --git a/ref/store/files/batch_rejection.go b/ref/store/files/batch_rejection.go index a1f8e39c..6ec4bbda 100644 --- a/ref/store/files/batch_rejection.go +++ b/ref/store/files/batch_rejection.go @@ -3,7 +3,7 @@ package files import ( "errors" - "codeberg.org/lindenii/furgit/ref/store" + refstore "codeberg.org/lindenii/furgit/ref/store" ) func isBatchRejected(err error) bool { diff --git a/ref/store/files/batch_test.go b/ref/store/files/batch_test.go index 2a4eb055..5580a2ce 100644 --- a/ref/store/files/batch_test.go +++ b/ref/store/files/batch_test.go @@ -6,7 +6,7 @@ import ( "codeberg.org/lindenii/furgit/internal/testgit" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/ref/store" + refstore "codeberg.org/lindenii/furgit/ref/store" ) func TestBatchApplyRejectsStaleDeleteAndAppliesIndependentDelete(t *testing.T) { diff --git a/ref/store/files/packed_delete_test.go b/ref/store/files/packed_delete_test.go index 3d14b71a..184eb79c 100644 --- a/ref/store/files/packed_delete_test.go +++ b/ref/store/files/packed_delete_test.go @@ -10,7 +10,7 @@ import ( "codeberg.org/lindenii/furgit/internal/testgit" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/ref/store" + refstore "codeberg.org/lindenii/furgit/ref/store" ) func TestFilesTransactionPackedDeleteFailureLeavesRefsUnchanged(t *testing.T) { diff --git a/ref/store/files/read_list.go b/ref/store/files/read_list.go index b8efd046..5a828276 100644 --- a/ref/store/files/read_list.go +++ b/ref/store/files/read_list.go @@ -6,7 +6,7 @@ import ( "slices" "codeberg.org/lindenii/furgit/ref" - "codeberg.org/lindenii/furgit/ref/store" + refstore "codeberg.org/lindenii/furgit/ref/store" ) // List lists references from the visible files ref namespace. diff --git a/ref/store/files/read_loose.go b/ref/store/files/read_loose.go index fbbdb109..e9b1435a 100644 --- a/ref/store/files/read_loose.go +++ b/ref/store/files/read_loose.go @@ -8,7 +8,7 @@ import ( objectid "codeberg.org/lindenii/furgit/object/id" "codeberg.org/lindenii/furgit/ref" - "codeberg.org/lindenii/furgit/ref/store" + refstore "codeberg.org/lindenii/furgit/ref/store" ) func (store *Store) readLooseRef(name string) (ref.Ref, error) { //nolint:ireturn diff --git a/ref/store/files/read_resolve.go b/ref/store/files/read_resolve.go index bba6c7e7..a998f970 100644 --- a/ref/store/files/read_resolve.go +++ b/ref/store/files/read_resolve.go @@ -4,7 +4,7 @@ import ( "errors" "codeberg.org/lindenii/furgit/ref" - "codeberg.org/lindenii/furgit/ref/store" + refstore "codeberg.org/lindenii/furgit/ref/store" ) // Resolve resolves one reference name from the files store visible namespace. diff --git a/ref/store/files/store.go b/ref/store/files/store.go index e0cced65..7c3f07af 100644 --- a/ref/store/files/store.go +++ b/ref/store/files/store.go @@ -8,7 +8,7 @@ import ( "time" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/ref/store" + refstore "codeberg.org/lindenii/furgit/ref/store" ) // Store reads and writes one Git files ref namespace rooted at one repository diff --git a/ref/store/files/transaction.go b/ref/store/files/transaction.go index 26d6613d..ede2d483 100644 --- a/ref/store/files/transaction.go +++ b/ref/store/files/transaction.go @@ -1,7 +1,7 @@ package files import ( - "codeberg.org/lindenii/furgit/ref/store" + refstore "codeberg.org/lindenii/furgit/ref/store" ) type Transaction struct { diff --git a/ref/store/files/transaction_begin.go b/ref/store/files/transaction_begin.go index 1eca2375..cdd3bad1 100644 --- a/ref/store/files/transaction_begin.go +++ b/ref/store/files/transaction_begin.go @@ -1,6 +1,6 @@ package files -import "codeberg.org/lindenii/furgit/ref/store" +import refstore "codeberg.org/lindenii/furgit/ref/store" // BeginTransaction creates one new files transaction. // diff --git a/ref/store/files/transaction_names_test.go b/ref/store/files/transaction_names_test.go index f23294e5..b362cb08 100644 --- a/ref/store/files/transaction_names_test.go +++ b/ref/store/files/transaction_names_test.go @@ -6,7 +6,7 @@ import ( "codeberg.org/lindenii/furgit/internal/testgit" objectid "codeberg.org/lindenii/furgit/object/id" "codeberg.org/lindenii/furgit/ref" - "codeberg.org/lindenii/furgit/ref/store" + refstore "codeberg.org/lindenii/furgit/ref/store" ) func TestFilesTransactionValidateUpdateNames(t *testing.T) { diff --git a/ref/store/files/transaction_pseudoref_test.go b/ref/store/files/transaction_pseudoref_test.go index 53fb26c0..ea57e92f 100644 --- a/ref/store/files/transaction_pseudoref_test.go +++ b/ref/store/files/transaction_pseudoref_test.go @@ -6,7 +6,7 @@ import ( "codeberg.org/lindenii/furgit/internal/testgit" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/ref/store" + refstore "codeberg.org/lindenii/furgit/ref/store" ) func TestFilesTransactionPseudorefLifecycle(t *testing.T) { diff --git a/ref/store/files/transaction_symbolic_test.go b/ref/store/files/transaction_symbolic_test.go index cc5a590b..360686d6 100644 --- a/ref/store/files/transaction_symbolic_test.go +++ b/ref/store/files/transaction_symbolic_test.go @@ -6,7 +6,7 @@ import ( "codeberg.org/lindenii/furgit/internal/testgit" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/ref/store" + refstore "codeberg.org/lindenii/furgit/ref/store" ) func TestFilesTransactionDirectSymbolicDeletes(t *testing.T) { diff --git a/ref/store/files/transaction_update_test.go b/ref/store/files/transaction_update_test.go index 62879b32..a29d586e 100644 --- a/ref/store/files/transaction_update_test.go +++ b/ref/store/files/transaction_update_test.go @@ -8,7 +8,7 @@ import ( "codeberg.org/lindenii/furgit/internal/testgit" objectid "codeberg.org/lindenii/furgit/object/id" "codeberg.org/lindenii/furgit/ref" - "codeberg.org/lindenii/furgit/ref/store" + refstore "codeberg.org/lindenii/furgit/ref/store" ) func TestFilesTransactionPackedUpdateCreatesLooseOverride(t *testing.T) { diff --git a/ref/store/files/update_direct_read.go b/ref/store/files/update_direct_read.go index 03fb2e11..e3557965 100644 --- a/ref/store/files/update_direct_read.go +++ b/ref/store/files/update_direct_read.go @@ -6,7 +6,7 @@ import ( "codeberg.org/lindenii/furgit/ref" "codeberg.org/lindenii/furgit/ref/refname" - "codeberg.org/lindenii/furgit/ref/store" + refstore "codeberg.org/lindenii/furgit/ref/store" ) func (executor *refUpdateExecutor) directRead(name string) (directRefState, error) { diff --git a/ref/store/files/update_prepare_resolve.go b/ref/store/files/update_prepare_resolve.go index c78d77e2..19d209b0 100644 --- a/ref/store/files/update_prepare_resolve.go +++ b/ref/store/files/update_prepare_resolve.go @@ -1,6 +1,6 @@ package files -import "codeberg.org/lindenii/furgit/ref/store" +import refstore "codeberg.org/lindenii/furgit/ref/store" func (executor *refUpdateExecutor) resolvePreparedUpdates(ops []queuedUpdate) ([]preparedUpdate, error) { prepared := make([]preparedUpdate, 0, len(ops)) diff --git a/ref/store/files/update_resolve_target_ordinary.go b/ref/store/files/update_resolve_target_ordinary.go index d22eafdd..cf8e1978 100644 --- a/ref/store/files/update_resolve_target_ordinary.go +++ b/ref/store/files/update_resolve_target_ordinary.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" - "codeberg.org/lindenii/furgit/ref/store" + refstore "codeberg.org/lindenii/furgit/ref/store" ) func (executor *refUpdateExecutor) resolveOrdinaryTarget(name string, allowMissing bool) (resolvedUpdateTarget, error) { diff --git a/ref/store/files/update_validate.go b/ref/store/files/update_validate.go index 4767957b..4e5c2be6 100644 --- a/ref/store/files/update_validate.go +++ b/ref/store/files/update_validate.go @@ -6,7 +6,7 @@ import ( objectid "codeberg.org/lindenii/furgit/object/id" "codeberg.org/lindenii/furgit/ref/refname" - "codeberg.org/lindenii/furgit/ref/store" + refstore "codeberg.org/lindenii/furgit/ref/store" ) func (executor *refUpdateExecutor) validateQueuedUpdate(op queuedUpdate) error { diff --git a/ref/store/files/update_verify_current.go b/ref/store/files/update_verify_current.go index 77be54e8..51ed1b42 100644 --- a/ref/store/files/update_verify_current.go +++ b/ref/store/files/update_verify_current.go @@ -3,7 +3,7 @@ package files import ( "strings" - "codeberg.org/lindenii/furgit/ref/store" + refstore "codeberg.org/lindenii/furgit/ref/store" ) func (executor *refUpdateExecutor) verifyPreparedUpdateCurrent(item preparedUpdate) error { diff --git a/ref/store/files/update_verify_refnames.go b/ref/store/files/update_verify_refnames.go index 308a9868..8bc34a62 100644 --- a/ref/store/files/update_verify_refnames.go +++ b/ref/store/files/update_verify_refnames.go @@ -3,7 +3,7 @@ package files import ( "strings" - "codeberg.org/lindenii/furgit/ref/store" + refstore "codeberg.org/lindenii/furgit/ref/store" ) func verifyRefnameAvailable(name string, existing map[string]struct{}, writes []string, deleted map[string]struct{}) error { diff --git a/ref/store/files/worktree_test.go b/ref/store/files/worktree_test.go index c4df76cf..ae3dc299 100644 --- a/ref/store/files/worktree_test.go +++ b/ref/store/files/worktree_test.go @@ -7,7 +7,7 @@ import ( "codeberg.org/lindenii/furgit/internal/testgit" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/ref/store" + refstore "codeberg.org/lindenii/furgit/ref/store" ) func TestFilesWorktreeRefsMatchGit(t *testing.T) { diff --git a/repository/objects.go b/repository/objects.go index 7f44e1d6..fd0be480 100644 --- a/repository/objects.go +++ b/repository/objects.go @@ -6,7 +6,7 @@ import ( "os" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/object/storer" + objectstorer "codeberg.org/lindenii/furgit/object/storer" objectloose "codeberg.org/lindenii/furgit/object/storer/loose" objectmix "codeberg.org/lindenii/furgit/object/storer/mix" objectpacked "codeberg.org/lindenii/furgit/object/storer/packed" diff --git a/repository/refs.go b/repository/refs.go index 1337162b..5c085ef9 100644 --- a/repository/refs.go +++ b/repository/refs.go @@ -1,6 +1,6 @@ package repository -import "codeberg.org/lindenii/furgit/ref/store" +import refstore "codeberg.org/lindenii/furgit/ref/store" // Refs returns the configured ref store. // diff --git a/repository/repository.go b/repository/repository.go index fabc52a8..6a24abdc 100644 --- a/repository/repository.go +++ b/repository/repository.go @@ -6,10 +6,10 @@ import ( "codeberg.org/lindenii/furgit/config" objectid "codeberg.org/lindenii/furgit/object/id" - "codeberg.org/lindenii/furgit/object/storer" + objectstorer "codeberg.org/lindenii/furgit/object/storer" objectloose "codeberg.org/lindenii/furgit/object/storer/loose" objectpacked "codeberg.org/lindenii/furgit/object/storer/packed" - "codeberg.org/lindenii/furgit/ref/store" + refstore "codeberg.org/lindenii/furgit/ref/store" ) // Repository is a thin composition root for repository-local stores. diff --git a/repository/stored_test.go b/repository/stored_test.go index f8eac6f0..3ebd9a76 100644 --- a/repository/stored_test.go +++ b/repository/stored_test.go @@ -6,8 +6,8 @@ import ( "testing" "codeberg.org/lindenii/furgit/internal/testgit" - "codeberg.org/lindenii/furgit/object" objectid "codeberg.org/lindenii/furgit/object/id" + "codeberg.org/lindenii/furgit/object/tree" ) func TestReadStoredTyped(t *testing.T) { @@ -86,8 +86,8 @@ func TestResolverPath(t *testing.T) { t.Fatalf("Path: %v", err) } - if entry.Mode != object.FileModeRegular { - t.Fatalf("Path mode = %o, want %o", entry.Mode, object.FileModeRegular) + if entry.Mode != tree.FileModeRegular { + t.Fatalf("Path mode = %o, want %o", entry.Mode, tree.FileModeRegular) } if entry.ID != blobID { @@ -169,8 +169,8 @@ func TestResolverPathDeepPath(t *testing.T) { t.Fatalf("Path(deep): %v", err) } - if entry.Mode != object.FileModeRegular { - t.Fatalf("Path(deep) mode = %o, want %o", entry.Mode, object.FileModeRegular) + if entry.Mode != tree.FileModeRegular { + t.Fatalf("Path(deep) mode = %o, want %o", entry.Mode, tree.FileModeRegular) } if entry.ID != leafBlobID { @@ -212,11 +212,11 @@ func TestReadStoredTreeMixedModes(t *testing.T) { t.Fatalf("ExactTree(root): %v", err) } - expect := map[string]object.FileMode{ - "normal.txt": object.FileModeRegular, - "run.sh": object.FileModeExecutable, - "link.txt": object.FileModeSymlink, - "dir": object.FileModeDir, + expect := map[string]tree.FileMode{ + "normal.txt": tree.FileModeRegular, + "run.sh": tree.FileModeExecutable, + "link.txt": tree.FileModeSymlink, + "dir": tree.FileModeDir, } for name, wantMode := range expect { diff --git a/repository/traversal_test.go b/repository/traversal_test.go index 403ee788..29f0cc81 100644 --- a/repository/traversal_test.go +++ b/repository/traversal_test.go @@ -8,8 +8,11 @@ import ( "testing" "codeberg.org/lindenii/furgit/internal/testgit" - "codeberg.org/lindenii/furgit/object" + "codeberg.org/lindenii/furgit/object/blob" + "codeberg.org/lindenii/furgit/object/commit" objectid "codeberg.org/lindenii/furgit/object/id" + "codeberg.org/lindenii/furgit/object/tag" + "codeberg.org/lindenii/furgit/object/tree" "codeberg.org/lindenii/furgit/repository" ) @@ -183,21 +186,21 @@ func traverseReachableIter(repo *repository.Repository, root objectid.ObjectID) total++ switch obj := stored.Object().(type) { - case *object.Commit: + case *commit.Commit: stack = append(stack, obj.Tree) stack = append(stack, obj.Parents...) - case *object.Tree: + case *tree.Tree: for i := len(obj.Entries) - 1; i >= 0; i-- { entry := obj.Entries[i] - if entry.Mode == object.FileModeGitlink { + if entry.Mode == tree.FileModeGitlink { continue } stack = append(stack, entry.ID) } - case *object.Tag: + case *tag.Tag: stack = append(stack, obj.Target) - case *object.Blob: + case *blob.Blob: default: // Unknown parsed object variants are treated as leaves. } |
