shithub: furgit

Download patch

ref: b82af688be4d94245c4a7eb730b12348b08b414b
parent: 3ce59c3248dec0eb0f918c42f37f53bc2ac20425
author: Runxi Yu <runxiyu@umich.edu>
date: Mon Mar 30 23:19:39 EDT 2026

reachability: Use fetcher and clean up some legacy helper stuff

--- a/reachability/domain.go
+++ b/reachability/domain.go
@@ -1,5 +1,7 @@
 package reachability
 
+import "fmt"
+
 // Domain specifies which graph edges are traversed.
 type Domain uint8
 
@@ -9,3 +11,12 @@
 	// DomainObjects traverses full commit/tree/blob objects.
 	DomainObjects
 )
+
+func validateDomain(domain Domain) error {
+	switch domain {
+	case DomainCommits, DomainObjects:
+		return nil
+	default:
+		return fmt.Errorf("reachability: invalid domain %d", domain)
+	}
+}
--- a/reachability/helpers.go
+++ /dev/null
@@ -1,72 +1,0 @@
-package reachability
-
-import (
-	"errors"
-	"fmt"
-
-	giterrors "codeberg.org/lindenii/furgit/errors"
-	objectid "codeberg.org/lindenii/furgit/object/id"
-	objectstore "codeberg.org/lindenii/furgit/object/store"
-	objecttype "codeberg.org/lindenii/furgit/object/type"
-)
-
-func validateDomain(domain Domain) error {
-	switch domain {
-	case DomainCommits, DomainObjects:
-		return nil
-	default:
-		return fmt.Errorf("reachability: invalid domain %d", domain)
-	}
-}
-
-func containsOID(set map[objectid.ObjectID]struct{}, id objectid.ObjectID) bool {
-	if len(set) == 0 {
-		return false
-	}
-
-	_, ok := set[id]
-
-	return ok
-}
-
-// The following helpers exist because we don't have unified error handling across the entire project.
-// This will be fixed later.
-
-func (walk *Walk) readHeaderType(id objectid.ObjectID) (objecttype.Type, error) {
-	return walk.reachability.readHeaderType(id)
-}
-
-func (r *Reachability) readHeaderType(id objectid.ObjectID) (objecttype.Type, error) {
-	ty, _, err := r.store.ReadHeader(id)
-	if err != nil {
-		if errors.Is(err, objectstore.ErrObjectNotFound) {
-			return objecttype.TypeInvalid, &giterrors.ObjectMissingError{OID: id}
-		}
-
-		return objecttype.TypeInvalid, err
-	}
-
-	return ty, nil
-}
-
-func (walk *Walk) readBytesContent(id objectid.ObjectID) ([]byte, error) {
-	content, err := walk.reachability.readBytesContent(id)
-	if err != nil {
-		return nil, err
-	}
-
-	return content, nil
-}
-
-func (r *Reachability) readBytesContent(id objectid.ObjectID) ([]byte, error) {
-	_, content, err := r.store.ReadBytesContent(id)
-	if err != nil {
-		if errors.Is(err, objectstore.ErrObjectNotFound) {
-			return nil, &giterrors.ObjectMissingError{OID: id}
-		}
-
-		return nil, err
-	}
-
-	return content, nil
-}
--- a/reachability/integration_test.go
+++ b/reachability/integration_test.go
@@ -11,6 +11,7 @@
 
 	giterrors "codeberg.org/lindenii/furgit/errors"
 	"codeberg.org/lindenii/furgit/internal/testgit"
+	objectfetch "codeberg.org/lindenii/furgit/object/fetch"
 	objectid "codeberg.org/lindenii/furgit/object/id"
 	"codeberg.org/lindenii/furgit/reachability"
 )
@@ -249,7 +250,7 @@
 func openReachabilityFromTestRepo(t *testing.T, testRepo *testgit.TestRepo) *reachability.Reachability {
 	t.Helper()
 
-	return reachability.New(testRepo.OpenObjectStore(t), nil)
+	return reachability.New(objectfetch.New(testRepo.OpenObjectStore(t)), nil)
 }
 
 func oidSetFromSeq(seq func(func(objectid.ObjectID) bool)) map[objectid.ObjectID]struct{} {
--- a/reachability/reachability.go
+++ b/reachability/reachability.go
@@ -2,7 +2,7 @@
 
 import (
 	commitgraphread "codeberg.org/lindenii/furgit/format/commitgraph/read"
-	objectstore "codeberg.org/lindenii/furgit/object/store"
+	objectfetch "codeberg.org/lindenii/furgit/object/fetch"
 )
 
 // Reachability provides graph traversal over objects in one object store.
@@ -9,14 +9,14 @@
 //
 // Labels: MT-Safe.
 type Reachability struct {
-	store objectstore.Reader
-	graph *commitgraphread.Reader
+	fetcher *objectfetch.Fetcher
+	graph   *commitgraphread.Reader
 }
 
-// New builds a Reachability over one object store with an optional
+// New builds a Reachability over one object fetcher with an optional
 // commit-graph reader for faster commit-domain traversal.
 //
 // Labels: Deps-Borrowed, Life-Parent.
-func New(store objectstore.Reader, graph *commitgraphread.Reader) *Reachability {
-	return &Reachability{store: store, graph: graph}
+func New(fetcher *objectfetch.Fetcher, graph *commitgraphread.Reader) *Reachability {
+	return &Reachability{fetcher: fetcher, graph: graph}
 }
--- a/reachability/unit_test.go
+++ b/reachability/unit_test.go
@@ -9,6 +9,7 @@
 
 	giterrors "codeberg.org/lindenii/furgit/errors"
 	"codeberg.org/lindenii/furgit/internal/testgit"
+	objectfetch "codeberg.org/lindenii/furgit/object/fetch"
 	objectid "codeberg.org/lindenii/furgit/object/id"
 	"codeberg.org/lindenii/furgit/object/store/memory"
 	"codeberg.org/lindenii/furgit/object/tree"
@@ -118,7 +119,7 @@
 			t.Fatal(err)
 		}
 
-		r := reachability.New(store, nil)
+		r := reachability.New(objectfetch.New(store), nil)
 		walk := r.Walk(reachability.DomainCommits, nil, map[objectid.ObjectID]struct{}{tag2: {}})
 
 		got := collectSeq(walk.Seq())
@@ -162,7 +163,7 @@
 			t.Fatal(err)
 		}
 
-		r := reachability.New(store, nil)
+		r := reachability.New(objectfetch.New(store), nil)
 		walk := r.Walk(reachability.DomainCommits, map[objectid.ObjectID]struct{}{commit: {}}, map[objectid.ObjectID]struct{}{commit: {}})
 
 		got := collectSeq(walk.Seq())
@@ -203,7 +204,7 @@
 			t.Fatal(err)
 		}
 
-		r := reachability.New(store, nil)
+		r := reachability.New(objectfetch.New(store), nil)
 		walk := r.Walk(reachability.DomainCommits, nil, map[objectid.ObjectID]struct{}{tag: {}})
 		_ = collectSeq(walk.Seq())
 
@@ -263,7 +264,7 @@
 			t.Fatal(err)
 		}
 
-		r := reachability.New(store, nil)
+		r := reachability.New(objectfetch.New(store), nil)
 		walk := r.Walk(
 			reachability.DomainCommits,
 			map[objectid.ObjectID]struct{}{tag1: {}},
@@ -327,7 +328,7 @@
 			t.Fatal(err)
 		}
 
-		r := reachability.New(store, nil)
+		r := reachability.New(objectfetch.New(store), nil)
 		walk := r.Walk(reachability.DomainObjects, nil, map[objectid.ObjectID]struct{}{commit: {}})
 
 		got := collectSeq(walk.Seq())
@@ -377,7 +378,7 @@
 			t.Fatal(err)
 		}
 
-		r := reachability.New(store, nil)
+		r := reachability.New(objectfetch.New(store), nil)
 
 		err = r.CheckConnected(reachability.DomainCommits, nil, map[objectid.ObjectID]struct{}{commit: {}})
 		if err == nil {
@@ -399,7 +400,7 @@
 	t.Parallel()
 
 	testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper
-		r := reachability.New(newCountingMemStore(algo), nil)
+		r := reachability.New(objectfetch.New(newCountingMemStore(algo)), nil)
 		walk := r.Walk(reachability.Domain(99), nil, nil)
 
 		_ = collectSeq(walk.Seq())
--- a/reachability/walk_expand_commits.go
+++ b/reachability/walk_expand_commits.go
@@ -4,8 +4,6 @@
 	"fmt"
 
 	"codeberg.org/lindenii/furgit/errors"
-	objectcommit "codeberg.org/lindenii/furgit/object/commit"
-	objecttag "codeberg.org/lindenii/furgit/object/tag"
 	objecttype "codeberg.org/lindenii/furgit/object/type"
 )
 
@@ -28,7 +26,7 @@
 		}
 	}
 
-	ty, err := walk.readHeaderType(item.id)
+	ty, _, err := walk.reachability.fetcher.Header(item.id)
 	if err != nil {
 		return nil, err
 	}
@@ -35,34 +33,24 @@
 
 	switch ty {
 	case objecttype.TypeCommit:
-		content, err := walk.readBytesContent(item.id)
+		commit, err := walk.reachability.fetcher.ExactCommit(item.id)
 		if err != nil {
 			return nil, err
 		}
 
-		commit, err := objectcommit.Parse(content, item.id.Algorithm())
-		if err != nil {
-			return nil, err
-		}
-
-		next := make([]walkItem, 0, len(commit.Parents))
-		for _, parent := range commit.Parents {
+		next := make([]walkItem, 0, len(commit.Object().Parents))
+		for _, parent := range commit.Object().Parents {
 			next = append(next, walkItem{id: parent, want: objecttype.TypeInvalid})
 		}
 
 		return next, nil
 	case objecttype.TypeTag:
-		content, err := walk.readBytesContent(item.id)
+		tag, err := walk.reachability.fetcher.ExactTag(item.id)
 		if err != nil {
 			return nil, err
 		}
 
-		tag, err := objecttag.Parse(content, item.id.Algorithm())
-		if err != nil {
-			return nil, err
-		}
-
-		return []walkItem{{id: tag.Target, want: objecttype.TypeInvalid}}, nil
+		return []walkItem{{id: tag.Object().Target, want: objecttype.TypeInvalid}}, nil
 	case objecttype.TypeTree, objecttype.TypeBlob, objecttype.TypeInvalid,
 		objecttype.TypeFuture, objecttype.TypeOfsDelta, objecttype.TypeRefDelta:
 		return nil, &errors.ObjectTypeError{OID: item.id, Got: ty, Want: objecttype.TypeCommit}
--- a/reachability/walk_expand_objects.go
+++ b/reachability/walk_expand_objects.go
@@ -4,14 +4,12 @@
 	"fmt"
 
 	"codeberg.org/lindenii/furgit/errors"
-	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"
 )
 
 func (walk *Walk) expandObjects(item walkItem) ([]walkItem, error) {
-	ty, err := walk.readHeaderType(item.id)
+	ty, _, err := walk.reachability.fetcher.Header(item.id)
 	if err != nil {
 		return nil, err
 	}
@@ -24,37 +22,27 @@
 	case objecttype.TypeBlob:
 		return nil, nil
 	case objecttype.TypeCommit:
-		content, err := walk.readBytesContent(item.id)
+		commit, err := walk.reachability.fetcher.ExactCommit(item.id)
 		if err != nil {
 			return nil, err
 		}
 
-		commit, err := objectcommit.Parse(content, item.id.Algorithm())
-		if err != nil {
-			return nil, err
-		}
+		next := make([]walkItem, 0, len(commit.Object().Parents)+1)
 
-		next := make([]walkItem, 0, len(commit.Parents)+1)
-
-		next = append(next, walkItem{id: commit.Tree, want: objecttype.TypeTree})
-		for _, parent := range commit.Parents {
+		next = append(next, walkItem{id: commit.Object().Tree, want: objecttype.TypeTree})
+		for _, parent := range commit.Object().Parents {
 			next = append(next, walkItem{id: parent, want: objecttype.TypeCommit})
 		}
 
 		return next, nil
 	case objecttype.TypeTree:
-		content, err := walk.readBytesContent(item.id)
+		tree, err := walk.reachability.fetcher.ExactTree(item.id)
 		if err != nil {
 			return nil, err
 		}
 
-		tree, err := objecttree.Parse(content, item.id.Algorithm())
-		if err != nil {
-			return nil, err
-		}
-
-		next := make([]walkItem, 0, len(tree.Entries))
-		for _, entry := range tree.Entries {
+		next := make([]walkItem, 0, len(tree.Object().Entries))
+		for _, entry := range tree.Object().Entries {
 			switch entry.Mode {
 			case objecttree.FileModeGitlink:
 				continue
@@ -67,17 +55,12 @@
 
 		return next, nil
 	case objecttype.TypeTag:
-		content, err := walk.readBytesContent(item.id)
+		tag, err := walk.reachability.fetcher.ExactTag(item.id)
 		if err != nil {
 			return nil, err
 		}
 
-		tag, err := objecttag.Parse(content, item.id.Algorithm())
-		if err != nil {
-			return nil, err
-		}
-
-		return []walkItem{{id: tag.Target, want: tag.TargetType}}, nil
+		return []walkItem{{id: tag.Object().Target, want: tag.Object().TargetType}}, nil
 	case objecttype.TypeInvalid, objecttype.TypeFuture, objecttype.TypeOfsDelta, objecttype.TypeRefDelta:
 		return nil, &errors.ObjectTypeError{OID: item.id, Got: ty, Want: item.want}
 	}
--- a/reachability/walk_seq.go
+++ b/reachability/walk_seq.go
@@ -37,7 +37,7 @@
 			item := stack[len(stack)-1]
 			stack = stack[:len(stack)-1]
 
-			if containsOID(walk.haves, item.id) {
+			if _, ok := walk.haves[item.id]; ok {
 				continue
 			}
 
--- a/reachability/walk_verify.go
+++ b/reachability/walk_verify.go
@@ -2,13 +2,12 @@
 
 import (
 	"codeberg.org/lindenii/furgit/errors"
-	objectcommit "codeberg.org/lindenii/furgit/object/commit"
 	objectid "codeberg.org/lindenii/furgit/object/id"
 	objecttype "codeberg.org/lindenii/furgit/object/type"
 )
 
 func (walk *Walk) validateCommitObject(id objectid.ObjectID) error {
-	ty, err := walk.readHeaderType(id)
+	ty, _, err := walk.reachability.fetcher.Header(id)
 	if err != nil {
 		return err
 	}
@@ -17,12 +16,7 @@
 		return &errors.ObjectTypeError{OID: id, Got: ty, Want: objecttype.TypeCommit}
 	}
 
-	content, err := walk.readBytesContent(id)
-	if err != nil {
-		return err
-	}
-
-	_, err = objectcommit.Parse(content, id.Algorithm())
+	_, err = walk.reachability.fetcher.ExactCommit(id)
 
 	return err
 }
--