Skip to content

Commit 08d770a

Browse files
committed
fix git tree sorting bug; consolidate proxies code
1 parent be6be10 commit 08d770a

9 files changed

Lines changed: 121 additions & 96 deletions

File tree

git/cache.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,32 +71,33 @@ func (x *Cache) clone(ctx context.Context, addr Address, all bool) Cloned {
7171
all: all,
7272
cache: x,
7373
addr: addr,
74-
diskRepo: openOrInitOnDisk(ctx, x.urlCachePath(addr.Repo)),
74+
diskRepo: openOrInitOnDisk(ctx, x.urlCachePath(addr.Repo), true), // cache must be bare, otherwise checkout branch cannot be pushed
7575
memRepo: initInMemory(ctx),
7676
}
7777
c.pull(ctx)
78+
switchToBranch(ctx, c.memRepo, addr.Branch)
79+
return c
80+
}
7881

79-
// switch to or create branch
80-
err := must.Try(func() { Checkout(ctx, Worktree(ctx, c.memRepo), addr.Branch) })
82+
func switchToBranch(ctx context.Context, repo *Repository, branch Branch) {
83+
err := must.Try(func() { Checkout(ctx, Worktree(ctx, repo), branch) })
8184
switch {
8285
case err == plumbing.ErrReferenceNotFound:
83-
must.NoError(ctx, c.memRepo.CreateBranch(&config.Branch{Name: string(addr.Branch)}))
84-
SetHeadToBranch(ctx, c.memRepo, addr.Branch)
85-
// must.NoError(ctx, Worktree(ctx, c.memRepo).Reset(&git.ResetOptions{Mode: git.HardReset}))
86+
must.NoError(ctx, repo.CreateBranch(&config.Branch{Name: string(branch)}))
87+
SetHeadToBranch(ctx, repo, branch)
88+
// must.NoError(ctx, Worktree(ctx, repo).Reset(&git.ResetOptions{Mode: git.HardReset}))
8689
case err != nil:
8790
must.NoError(ctx, err)
8891
}
89-
90-
return c
9192
}
9293

93-
func openOrInitOnDisk(ctx context.Context, path URL) *Repository {
94+
func openOrInitOnDisk(ctx context.Context, path URL, bare bool) *Repository {
9495
repo, err := git.PlainOpen(string(path))
9596
if err == nil {
9697
return repo
9798
}
9899
must.Assertf(ctx, err == git.ErrRepositoryNotExists, "%v", err)
99-
return InitPlain(ctx, string(path), true) // cache must be bare, otherwise checkout branch cannot be pushed
100+
return InitPlain(ctx, string(path), bare)
100101
}
101102

102103
type clonedCacheProxy struct {

git/clone.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ func UseCache(ctx context.Context, dir string) {
1616
proxy = NewCache(ctx, dir)
1717
}
1818

19+
func UseNoCacheOnDisk(ctx context.Context, dir string) {
20+
cacheLk.Lock()
21+
defer cacheLk.Unlock()
22+
proxy = NewNoCacheOnDisk(dir)
23+
}
24+
1925
func getProxy() Proxy {
2026
cacheLk.Lock()
2127
defer cacheLk.Unlock()
@@ -26,12 +32,12 @@ func CloneOne(ctx context.Context, addr Address) Cloned {
2632
if pxy := getProxy(); pxy != nil {
2733
return pxy.CloneOne(ctx, addr)
2834
}
29-
return cloneOneNoProxy(ctx, addr)
35+
return NoCache{}.CloneOne(ctx, addr)
3036
}
3137

3238
func CloneAll(ctx context.Context, addr Address) Cloned {
3339
if pxy := getProxy(); pxy != nil {
3440
return pxy.CloneAll(ctx, addr)
3541
}
36-
return cloneAllNoProxy(ctx, addr)
42+
return NoCache{}.CloneAll(ctx, addr)
3743
}

git/embed.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ func EmbedOnCommit(
8181
embeddingsTreeHash := MergeTrees(ctx, repo, remoteTreeHashes, allowOverride, filter)
8282

8383
// merge embeddings into the toBranch tree
84-
// XXX: check if merge produced changes
84+
// XXX: check if merge produced changes, don't commit if it didn't
8585
mergedTreeHash := mergeTrees(ctx, repo, ns.NS{}, parentCommit.TreeHash, embeddingsTreeHash, false, MergePassFilter)
8686

8787
// create a commit

git/merge.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package git
22

33
import (
44
"context"
5+
"sort"
56

67
"github.com/go-git/go-git/v5/plumbing"
78
"github.com/go-git/go-git/v5/plumbing/filemode"
@@ -73,9 +74,24 @@ func mergeTrees(
7374
}
7475

7576
// make tree
76-
entries := make([]object.TreeEntry, 0, len(merged))
77+
entries := make(TreeEntries, 0, len(merged))
7778
for _, mergedEntry := range merged {
7879
entries = append(entries, mergedEntry)
7980
}
81+
sort.Sort(entries)
8082
return MakeTree(ctx, repo, object.Tree{Entries: entries})
8183
}
84+
85+
type TreeEntries []object.TreeEntry
86+
87+
func (x TreeEntries) Len() int {
88+
return len(x)
89+
}
90+
91+
func (x TreeEntries) Less(i, j int) bool {
92+
return x[i].Name < x[j].Name
93+
}
94+
95+
func (x TreeEntries) Swap(i, j int) {
96+
x[i], x[j] = x[j], x[i]
97+
}

git/nocache.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package git
2+
3+
import (
4+
"context"
5+
"path/filepath"
6+
7+
"github.com/gov4git/lib4git/base"
8+
)
9+
10+
type NoCache struct {
11+
dir string // if non empty, repositories will be created on disk within this dir
12+
}
13+
14+
func NewNoCacheInMemory() Proxy {
15+
return NoCache{}
16+
}
17+
18+
func NewNoCacheOnDisk(dir string) Proxy {
19+
return NoCache{dir: dir}
20+
}
21+
22+
func (x NoCache) CloneOne(ctx context.Context, addr Address) Cloned {
23+
return x.clone(ctx, addr, false)
24+
}
25+
26+
func (x NoCache) CloneAll(ctx context.Context, addr Address) Cloned {
27+
return x.clone(ctx, addr, true)
28+
}
29+
30+
func (x NoCache) clone(ctx context.Context, addr Address, all bool) Cloned {
31+
var repo *Repository
32+
if x.dir == "" {
33+
repo = initInMemory(ctx)
34+
} else {
35+
p := URL(filepath.Join(x.dir, nonceName()))
36+
base.Infof("materializing repo %v on disk %v\n", addr.Repo, p)
37+
repo = openOrInitOnDisk(ctx, p, false)
38+
}
39+
c := &clonedNoCache{all: all, addr: addr, repo: repo}
40+
c.Pull(ctx)
41+
switchToBranch(ctx, c.repo, addr.Branch)
42+
return c
43+
}
44+
45+
type clonedNoCache struct {
46+
all bool
47+
addr Address
48+
repo *Repository
49+
}
50+
51+
func (x *clonedNoCache) Push(ctx context.Context) {
52+
PushOnce(ctx, x.repo, x.addr.Repo, mirrorRefSpecs)
53+
}
54+
55+
func (x *clonedNoCache) Pull(ctx context.Context) {
56+
PullOnce(ctx, x.repo, x.addr.Repo, clonePullRefSpecs(x.addr, x.all))
57+
}
58+
59+
func (x *clonedNoCache) Repo() *Repository {
60+
return x.repo
61+
}
62+
63+
func (x *clonedNoCache) Tree() *Tree {
64+
t, _ := x.Repo().Worktree()
65+
return t
66+
}

git/proxy.go

Lines changed: 0 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@ import (
55

66
"github.com/go-git/go-billy/v5/memfs"
77
"github.com/go-git/go-git/v5"
8-
"github.com/go-git/go-git/v5/config"
9-
"github.com/go-git/go-git/v5/plumbing"
10-
"github.com/go-git/go-git/v5/plumbing/transport"
118
"github.com/go-git/go-git/v5/storage/memory"
129
"github.com/gov4git/lib4git/must"
1310
)
@@ -28,78 +25,8 @@ type Cloned interface {
2825
Tree() *Tree
2926
}
3027

31-
func cloneOneNoProxy(ctx context.Context, addr Address) Cloned {
32-
return &clonedNoProxy{all: false, addr: addr, repo: cloneToMemoryOrInit(ctx, addr)}
33-
}
34-
35-
func cloneAllNoProxy(ctx context.Context, addr Address) Cloned {
36-
c := &clonedNoProxy{all: true, addr: addr, repo: cloneToMemoryOrInit(ctx, addr)}
37-
c.Pull(ctx)
38-
return c
39-
}
40-
41-
func cloneToMemoryOrInit(ctx context.Context, addr Address) *Repository {
42-
repo, err := must.Try1(func() *Repository { return cloneToMemory(ctx, addr) })
43-
if err == nil {
44-
return repo
45-
}
46-
_, isNoBranch := err.(git.NoMatchingRefSpecError)
47-
if !isNoBranch && err != transport.ErrEmptyRemoteRepository && err != plumbing.ErrReferenceNotFound {
48-
must.Panic(ctx, err)
49-
}
50-
repo = initInMemory(ctx)
51-
52-
_, err = repo.CreateRemote(&config.RemoteConfig{Name: Origin, URLs: []string{string(addr.Repo)}})
53-
must.NoError(ctx, err)
54-
55-
err = repo.CreateBranch(&config.Branch{Name: string(addr.Branch), Remote: Origin})
56-
must.NoError(ctx, err)
57-
58-
ChangeDefaultBranch(ctx, repo, addr.Branch)
59-
60-
return repo
61-
}
62-
6328
func initInMemory(ctx context.Context) *Repository {
6429
repo, err := git.Init(memory.NewStorage(), memfs.New())
6530
must.NoError(ctx, err)
6631
return repo
6732
}
68-
69-
func cloneToMemory(ctx context.Context, addr Address) *Repository {
70-
repo, err := git.CloneContext(ctx,
71-
memory.NewStorage(),
72-
memfs.New(),
73-
&git.CloneOptions{
74-
URL: string(addr.Repo),
75-
Auth: GetAuth(ctx, addr.Repo),
76-
ReferenceName: plumbing.NewBranchReferenceName(string(addr.Branch)),
77-
},
78-
)
79-
must.NoError(ctx, err)
80-
81-
return repo
82-
}
83-
84-
type clonedNoProxy struct {
85-
all bool
86-
addr Address
87-
repo *Repository
88-
}
89-
90-
func (x *clonedNoProxy) Push(ctx context.Context) {
91-
PushOnce(ctx, x.repo, x.addr.Repo, mirrorRefSpecs)
92-
}
93-
94-
func (x *clonedNoProxy) Pull(ctx context.Context) {
95-
PullOnce(ctx, x.repo, x.addr.Repo, clonePullRefSpecs(x.addr, x.all))
96-
}
97-
98-
func (x *clonedNoProxy) Repo() *Repository {
99-
return x.repo
100-
}
101-
102-
func (x *clonedNoProxy) Tree() *Tree {
103-
t, _ := x.Repo().Worktree()
104-
return t
105-
}

git/surgery.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,15 @@ func CreateCommit(
3636
parents []plumbing.Hash,
3737
) plumbing.Hash {
3838

39-
opts := git.CommitOptions{Author: GetAuthor()}
39+
opts := git.CommitOptions{
40+
All: true,
41+
AllowEmptyCommits: true,
42+
Author: GetAuthor(),
43+
}
4044
must.NoError(ctx, opts.Validate(repo))
4145
commit := object.Commit{
42-
Author: *opts.Author,
43-
// Committer: *opts.Committer,
46+
Author: *opts.Author,
47+
Committer: *opts.Author,
4448
Message: msg,
4549
TreeHash: treeHash,
4650
ParentHashes: parents,

git/sync.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,18 @@ func nonceName() string {
1616
return "nonce-" + strconv.FormatUint(uint64(rand.Int63()), 36)
1717
}
1818

19-
const mirrorBranchesRefSpec = "refs/heads/*:refs/heads/*"
20-
const mirrorTagsRefSpec = "refs/tags/*:refs/tags/*"
21-
const mirrorHeadRefSpec = "refs/HEAD:refs/HEAD"
19+
const (
20+
mirrorBranchesRefSpec = "refs/heads/*:refs/heads/*"
21+
mirrorRemotesRefSpec = "refs/remotes/*:refs/remotes/*"
22+
mirrorTagsRefSpec = "refs/tags/*:refs/tags/*"
23+
mirrorHeadRefSpec = "refs/HEAD:refs/HEAD"
24+
)
2225

23-
var mirrorRefSpecs = []config.RefSpec{mirrorBranchesRefSpec /*, mirrorTagsRefSpec, mirrorHeadRefSpec*/}
26+
var mirrorRefSpecs = []config.RefSpec{
27+
mirrorBranchesRefSpec,
28+
// mirrorRemotesRefSpec,
29+
// mirrorTagsRefSpec, mirrorHeadRefSpec,
30+
}
2431

2532
func branchRefSpec(b Branch) []config.RefSpec {
2633
return []config.RefSpec{

go.mod

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ require (
1010
go.uber.org/zap v1.24.0
1111
)
1212

13-
// replace github.com/go-git/go-git => /Users/petar/github.com/go-git/go-git
14-
1513
require (
1614
github.com/Microsoft/go-winio v0.5.2 // indirect
1715
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect

0 commit comments

Comments
 (0)