1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
package remoterepo
import (
"context"
"fmt"
"sync"
"gitlab.com/gitlab-org/gitaly/v16/client"
"gitlab.com/gitlab-org/gitaly/v16/internal/git"
"gitlab.com/gitlab-org/gitaly/v16/internal/gitaly/storage"
"gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
"google.golang.org/grpc"
)
// Repo represents a Git repository on a different Gitaly storage
type Repo struct {
*gitalypb.Repository
conn *grpc.ClientConn
detectObjectHashOnce sync.Once
objectHash git.ObjectHash
objectHashErr error
}
// New creates a new remote Repository from its protobuf representation.
func New(ctx context.Context, repo *gitalypb.Repository, pool *client.Pool) (*Repo, error) {
server, err := storage.ExtractGitalyServer(ctx, repo.GetStorageName())
if err != nil {
return nil, fmt.Errorf("remote repository: %w", err)
}
cc, err := pool.Dial(ctx, server.Address, server.Token)
if err != nil {
return nil, fmt.Errorf("dial: %w", err)
}
return &Repo{
Repository: repo,
conn: cc,
}, nil
}
// ObjectHash detects the object hash used by this particular repository.
func (rr *Repo) ObjectHash(ctx context.Context) (git.ObjectHash, error) {
rr.detectObjectHashOnce.Do(func() {
rr.objectHash, rr.objectHashErr = func() (git.ObjectHash, error) {
client := gitalypb.NewRepositoryServiceClient(rr.conn)
response, err := client.ObjectFormat(ctx, &gitalypb.ObjectFormatRequest{
Repository: rr.Repository,
})
if err != nil {
return git.ObjectHash{}, err
}
return git.ObjectHashByProto(response.Format)
}()
})
return rr.objectHash, rr.objectHashErr
}
// ResolveRevision will dial to the remote repository and attempt to resolve the
// revision string via the gRPC interface.
func (rr *Repo) ResolveRevision(ctx context.Context, revision git.Revision) (git.ObjectID, error) {
cli := gitalypb.NewCommitServiceClient(rr.conn)
resp, err := cli.FindCommit(ctx, &gitalypb.FindCommitRequest{
Repository: rr.Repository,
Revision: []byte(revision.String()),
})
if err != nil {
return "", err
}
oidHex := resp.GetCommit().GetId()
if oidHex == "" {
return "", git.ErrReferenceNotFound
}
objectHash, err := rr.ObjectHash(ctx)
if err != nil {
return "", fmt.Errorf("detecting object hash: %w", err)
}
oid, err := objectHash.FromHex(oidHex)
if err != nil {
return "", fmt.Errorf("parsing object ID: %w", err)
}
return oid, nil
}
// HasBranches will dial to the remote repository and check whether the repository has any branches.
func (rr *Repo) HasBranches(ctx context.Context) (bool, error) {
resp, err := gitalypb.NewRepositoryServiceClient(rr.conn).HasLocalBranches(
ctx, &gitalypb.HasLocalBranchesRequest{Repository: rr.Repository})
if err != nil {
return false, fmt.Errorf("has local branches: %w", err)
}
return resp.Value, nil
}
// GetDefaultBranch returns the default branch for the remote repository. It does so by invoking
// `FindDefaultBranchName()`, which itself is a wrapper around `localrepo.GetDefaultBranch()`.
// Semantics of this function thus match the localrepo semantics.
func (rr *Repo) GetDefaultBranch(ctx context.Context) (git.ReferenceName, error) {
resp, err := gitalypb.NewRefServiceClient(rr.conn).FindDefaultBranchName(
ctx, &gitalypb.FindDefaultBranchNameRequest{Repository: rr.Repository})
if err != nil {
return "", err
}
return git.ReferenceName(resp.Name), nil
}
|