Fast implementation of Git in pure Go codeberg.org/lindenii/furgit
git go
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

reachability: Use fetcher and clean up some legacy helper stuff

Runxi Yu b82af688 3ce59c32

+46 -140
+11
reachability/domain.go
··· 1 1 package reachability 2 2 3 + import "fmt" 4 + 3 5 // Domain specifies which graph edges are traversed. 4 6 type Domain uint8 5 7 ··· 9 11 // DomainObjects traverses full commit/tree/blob objects. 10 12 DomainObjects 11 13 ) 14 + 15 + func validateDomain(domain Domain) error { 16 + switch domain { 17 + case DomainCommits, DomainObjects: 18 + return nil 19 + default: 20 + return fmt.Errorf("reachability: invalid domain %d", domain) 21 + } 22 + }
-72
reachability/helpers.go
··· 1 - package reachability 2 - 3 - import ( 4 - "errors" 5 - "fmt" 6 - 7 - giterrors "codeberg.org/lindenii/furgit/errors" 8 - objectid "codeberg.org/lindenii/furgit/object/id" 9 - objectstore "codeberg.org/lindenii/furgit/object/store" 10 - objecttype "codeberg.org/lindenii/furgit/object/type" 11 - ) 12 - 13 - func validateDomain(domain Domain) error { 14 - switch domain { 15 - case DomainCommits, DomainObjects: 16 - return nil 17 - default: 18 - return fmt.Errorf("reachability: invalid domain %d", domain) 19 - } 20 - } 21 - 22 - func containsOID(set map[objectid.ObjectID]struct{}, id objectid.ObjectID) bool { 23 - if len(set) == 0 { 24 - return false 25 - } 26 - 27 - _, ok := set[id] 28 - 29 - return ok 30 - } 31 - 32 - // The following helpers exist because we don't have unified error handling across the entire project. 33 - // This will be fixed later. 34 - 35 - func (walk *Walk) readHeaderType(id objectid.ObjectID) (objecttype.Type, error) { 36 - return walk.reachability.readHeaderType(id) 37 - } 38 - 39 - func (r *Reachability) readHeaderType(id objectid.ObjectID) (objecttype.Type, error) { 40 - ty, _, err := r.store.ReadHeader(id) 41 - if err != nil { 42 - if errors.Is(err, objectstore.ErrObjectNotFound) { 43 - return objecttype.TypeInvalid, &giterrors.ObjectMissingError{OID: id} 44 - } 45 - 46 - return objecttype.TypeInvalid, err 47 - } 48 - 49 - return ty, nil 50 - } 51 - 52 - func (walk *Walk) readBytesContent(id objectid.ObjectID) ([]byte, error) { 53 - content, err := walk.reachability.readBytesContent(id) 54 - if err != nil { 55 - return nil, err 56 - } 57 - 58 - return content, nil 59 - } 60 - 61 - func (r *Reachability) readBytesContent(id objectid.ObjectID) ([]byte, error) { 62 - _, content, err := r.store.ReadBytesContent(id) 63 - if err != nil { 64 - if errors.Is(err, objectstore.ErrObjectNotFound) { 65 - return nil, &giterrors.ObjectMissingError{OID: id} 66 - } 67 - 68 - return nil, err 69 - } 70 - 71 - return content, nil 72 - }
+2 -1
reachability/integration_test.go
··· 11 11 12 12 giterrors "codeberg.org/lindenii/furgit/errors" 13 13 "codeberg.org/lindenii/furgit/internal/testgit" 14 + objectfetch "codeberg.org/lindenii/furgit/object/fetch" 14 15 objectid "codeberg.org/lindenii/furgit/object/id" 15 16 "codeberg.org/lindenii/furgit/reachability" 16 17 ) ··· 249 250 func openReachabilityFromTestRepo(t *testing.T, testRepo *testgit.TestRepo) *reachability.Reachability { 250 251 t.Helper() 251 252 252 - return reachability.New(testRepo.OpenObjectStore(t), nil) 253 + return reachability.New(objectfetch.New(testRepo.OpenObjectStore(t)), nil) 253 254 } 254 255 255 256 func oidSetFromSeq(seq func(func(objectid.ObjectID) bool)) map[objectid.ObjectID]struct{} {
+6 -6
reachability/reachability.go
··· 2 2 3 3 import ( 4 4 commitgraphread "codeberg.org/lindenii/furgit/format/commitgraph/read" 5 - objectstore "codeberg.org/lindenii/furgit/object/store" 5 + objectfetch "codeberg.org/lindenii/furgit/object/fetch" 6 6 ) 7 7 8 8 // Reachability provides graph traversal over objects in one object store. 9 9 // 10 10 // Labels: MT-Safe. 11 11 type Reachability struct { 12 - store objectstore.Reader 13 - graph *commitgraphread.Reader 12 + fetcher *objectfetch.Fetcher 13 + graph *commitgraphread.Reader 14 14 } 15 15 16 - // New builds a Reachability over one object store with an optional 16 + // New builds a Reachability over one object fetcher with an optional 17 17 // commit-graph reader for faster commit-domain traversal. 18 18 // 19 19 // Labels: Deps-Borrowed, Life-Parent. 20 - func New(store objectstore.Reader, graph *commitgraphread.Reader) *Reachability { 21 - return &Reachability{store: store, graph: graph} 20 + func New(fetcher *objectfetch.Fetcher, graph *commitgraphread.Reader) *Reachability { 21 + return &Reachability{fetcher: fetcher, graph: graph} 22 22 }
+8 -7
reachability/unit_test.go
··· 9 9 10 10 giterrors "codeberg.org/lindenii/furgit/errors" 11 11 "codeberg.org/lindenii/furgit/internal/testgit" 12 + objectfetch "codeberg.org/lindenii/furgit/object/fetch" 12 13 objectid "codeberg.org/lindenii/furgit/object/id" 13 14 "codeberg.org/lindenii/furgit/object/store/memory" 14 15 "codeberg.org/lindenii/furgit/object/tree" ··· 118 119 t.Fatal(err) 119 120 } 120 121 121 - r := reachability.New(store, nil) 122 + r := reachability.New(objectfetch.New(store), nil) 122 123 walk := r.Walk(reachability.DomainCommits, nil, map[objectid.ObjectID]struct{}{tag2: {}}) 123 124 124 125 got := collectSeq(walk.Seq()) ··· 162 163 t.Fatal(err) 163 164 } 164 165 165 - r := reachability.New(store, nil) 166 + r := reachability.New(objectfetch.New(store), nil) 166 167 walk := r.Walk(reachability.DomainCommits, map[objectid.ObjectID]struct{}{commit: {}}, map[objectid.ObjectID]struct{}{commit: {}}) 167 168 168 169 got := collectSeq(walk.Seq()) ··· 203 204 t.Fatal(err) 204 205 } 205 206 206 - r := reachability.New(store, nil) 207 + r := reachability.New(objectfetch.New(store), nil) 207 208 walk := r.Walk(reachability.DomainCommits, nil, map[objectid.ObjectID]struct{}{tag: {}}) 208 209 _ = collectSeq(walk.Seq()) 209 210 ··· 263 264 t.Fatal(err) 264 265 } 265 266 266 - r := reachability.New(store, nil) 267 + r := reachability.New(objectfetch.New(store), nil) 267 268 walk := r.Walk( 268 269 reachability.DomainCommits, 269 270 map[objectid.ObjectID]struct{}{tag1: {}}, ··· 327 328 t.Fatal(err) 328 329 } 329 330 330 - r := reachability.New(store, nil) 331 + r := reachability.New(objectfetch.New(store), nil) 331 332 walk := r.Walk(reachability.DomainObjects, nil, map[objectid.ObjectID]struct{}{commit: {}}) 332 333 333 334 got := collectSeq(walk.Seq()) ··· 377 378 t.Fatal(err) 378 379 } 379 380 380 - r := reachability.New(store, nil) 381 + r := reachability.New(objectfetch.New(store), nil) 381 382 382 383 err = r.CheckConnected(reachability.DomainCommits, nil, map[objectid.ObjectID]struct{}{commit: {}}) 383 384 if err == nil { ··· 399 400 t.Parallel() 400 401 401 402 testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper 402 - r := reachability.New(newCountingMemStore(algo), nil) 403 + r := reachability.New(objectfetch.New(newCountingMemStore(algo)), nil) 403 404 walk := r.Walk(reachability.Domain(99), nil, nil) 404 405 405 406 _ = collectSeq(walk.Seq())
+6 -18
reachability/walk_expand_commits.go
··· 4 4 "fmt" 5 5 6 6 "codeberg.org/lindenii/furgit/errors" 7 - objectcommit "codeberg.org/lindenii/furgit/object/commit" 8 - objecttag "codeberg.org/lindenii/furgit/object/tag" 9 7 objecttype "codeberg.org/lindenii/furgit/object/type" 10 8 ) 11 9 ··· 28 26 } 29 27 } 30 28 31 - ty, err := walk.readHeaderType(item.id) 29 + ty, _, err := walk.reachability.fetcher.Header(item.id) 32 30 if err != nil { 33 31 return nil, err 34 32 } 35 33 36 34 switch ty { 37 35 case objecttype.TypeCommit: 38 - content, err := walk.readBytesContent(item.id) 39 - if err != nil { 40 - return nil, err 41 - } 42 - 43 - commit, err := objectcommit.Parse(content, item.id.Algorithm()) 36 + commit, err := walk.reachability.fetcher.ExactCommit(item.id) 44 37 if err != nil { 45 38 return nil, err 46 39 } 47 40 48 - next := make([]walkItem, 0, len(commit.Parents)) 49 - for _, parent := range commit.Parents { 41 + next := make([]walkItem, 0, len(commit.Object().Parents)) 42 + for _, parent := range commit.Object().Parents { 50 43 next = append(next, walkItem{id: parent, want: objecttype.TypeInvalid}) 51 44 } 52 45 53 46 return next, nil 54 47 case objecttype.TypeTag: 55 - content, err := walk.readBytesContent(item.id) 56 - if err != nil { 57 - return nil, err 58 - } 59 - 60 - tag, err := objecttag.Parse(content, item.id.Algorithm()) 48 + tag, err := walk.reachability.fetcher.ExactTag(item.id) 61 49 if err != nil { 62 50 return nil, err 63 51 } 64 52 65 - return []walkItem{{id: tag.Target, want: objecttype.TypeInvalid}}, nil 53 + return []walkItem{{id: tag.Object().Target, want: objecttype.TypeInvalid}}, nil 66 54 case objecttype.TypeTree, objecttype.TypeBlob, objecttype.TypeInvalid, 67 55 objecttype.TypeFuture, objecttype.TypeOfsDelta, objecttype.TypeRefDelta: 68 56 return nil, &errors.ObjectTypeError{OID: item.id, Got: ty, Want: objecttype.TypeCommit}
+10 -27
reachability/walk_expand_objects.go
··· 4 4 "fmt" 5 5 6 6 "codeberg.org/lindenii/furgit/errors" 7 - objectcommit "codeberg.org/lindenii/furgit/object/commit" 8 - objecttag "codeberg.org/lindenii/furgit/object/tag" 9 7 objecttree "codeberg.org/lindenii/furgit/object/tree" 10 8 objecttype "codeberg.org/lindenii/furgit/object/type" 11 9 ) 12 10 13 11 func (walk *Walk) expandObjects(item walkItem) ([]walkItem, error) { 14 - ty, err := walk.readHeaderType(item.id) 12 + ty, _, err := walk.reachability.fetcher.Header(item.id) 15 13 if err != nil { 16 14 return nil, err 17 15 } ··· 24 22 case objecttype.TypeBlob: 25 23 return nil, nil 26 24 case objecttype.TypeCommit: 27 - content, err := walk.readBytesContent(item.id) 25 + commit, err := walk.reachability.fetcher.ExactCommit(item.id) 28 26 if err != nil { 29 27 return nil, err 30 28 } 31 29 32 - commit, err := objectcommit.Parse(content, item.id.Algorithm()) 33 - if err != nil { 34 - return nil, err 35 - } 30 + next := make([]walkItem, 0, len(commit.Object().Parents)+1) 36 31 37 - next := make([]walkItem, 0, len(commit.Parents)+1) 38 - 39 - next = append(next, walkItem{id: commit.Tree, want: objecttype.TypeTree}) 40 - for _, parent := range commit.Parents { 32 + next = append(next, walkItem{id: commit.Object().Tree, want: objecttype.TypeTree}) 33 + for _, parent := range commit.Object().Parents { 41 34 next = append(next, walkItem{id: parent, want: objecttype.TypeCommit}) 42 35 } 43 36 44 37 return next, nil 45 38 case objecttype.TypeTree: 46 - content, err := walk.readBytesContent(item.id) 39 + tree, err := walk.reachability.fetcher.ExactTree(item.id) 47 40 if err != nil { 48 41 return nil, err 49 42 } 50 43 51 - tree, err := objecttree.Parse(content, item.id.Algorithm()) 52 - if err != nil { 53 - return nil, err 54 - } 55 - 56 - next := make([]walkItem, 0, len(tree.Entries)) 57 - for _, entry := range tree.Entries { 44 + next := make([]walkItem, 0, len(tree.Object().Entries)) 45 + for _, entry := range tree.Object().Entries { 58 46 switch entry.Mode { 59 47 case objecttree.FileModeGitlink: 60 48 continue ··· 67 55 68 56 return next, nil 69 57 case objecttype.TypeTag: 70 - content, err := walk.readBytesContent(item.id) 58 + tag, err := walk.reachability.fetcher.ExactTag(item.id) 71 59 if err != nil { 72 60 return nil, err 73 61 } 74 62 75 - tag, err := objecttag.Parse(content, item.id.Algorithm()) 76 - if err != nil { 77 - return nil, err 78 - } 79 - 80 - return []walkItem{{id: tag.Target, want: tag.TargetType}}, nil 63 + return []walkItem{{id: tag.Object().Target, want: tag.Object().TargetType}}, nil 81 64 case objecttype.TypeInvalid, objecttype.TypeFuture, objecttype.TypeOfsDelta, objecttype.TypeRefDelta: 82 65 return nil, &errors.ObjectTypeError{OID: item.id, Got: ty, Want: item.want} 83 66 }
+1 -1
reachability/walk_seq.go
··· 37 37 item := stack[len(stack)-1] 38 38 stack = stack[:len(stack)-1] 39 39 40 - if containsOID(walk.haves, item.id) { 40 + if _, ok := walk.haves[item.id]; ok { 41 41 continue 42 42 } 43 43
+2 -8
reachability/walk_verify.go
··· 2 2 3 3 import ( 4 4 "codeberg.org/lindenii/furgit/errors" 5 - objectcommit "codeberg.org/lindenii/furgit/object/commit" 6 5 objectid "codeberg.org/lindenii/furgit/object/id" 7 6 objecttype "codeberg.org/lindenii/furgit/object/type" 8 7 ) 9 8 10 9 func (walk *Walk) validateCommitObject(id objectid.ObjectID) error { 11 - ty, err := walk.readHeaderType(id) 10 + ty, _, err := walk.reachability.fetcher.Header(id) 12 11 if err != nil { 13 12 return err 14 13 } ··· 17 16 return &errors.ObjectTypeError{OID: id, Got: ty, Want: objecttype.TypeCommit} 18 17 } 19 18 20 - content, err := walk.readBytesContent(id) 21 - if err != nil { 22 - return err 23 - } 24 - 25 - _, err = objectcommit.Parse(content, id.Algorithm()) 19 + _, err = walk.reachability.fetcher.ExactCommit(id) 26 20 27 21 return err 28 22 }