1
0
mirror of https://github.com/moby/buildkit.git synced 2025-11-07 23:06:20 +03:00

source: add raw commit/tag object access to resolveMetadata

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
Tonis Tiigi
2025-10-15 23:40:44 -07:00
parent a248127a90
commit 5f6a7ef751
11 changed files with 1419 additions and 288 deletions

View File

@@ -51,6 +51,13 @@ type Metadata struct {
Ref string
Checksum string
CommitChecksum string
CommitObject []byte
TagObject []byte
}
type MetadataOpts struct {
ReturnObject bool
}
// Supported returns nil if the system supports Git source
@@ -237,7 +244,7 @@ func (gs *gitSourceHandler) shaToCacheKey(sha, ref string) string {
return key
}
func (gs *Source) ResolveMetadata(ctx context.Context, id *GitIdentifier, sm *session.Manager, jobCtx solver.JobContext) (*Metadata, error) {
func (gs *Source) ResolveMetadata(ctx context.Context, id *GitIdentifier, sm *session.Manager, jobCtx solver.JobContext, opt MetadataOpts) (*Metadata, error) {
gsh := &gitSourceHandler{
src: *id,
Source: gs,
@@ -247,6 +254,56 @@ func (gs *Source) ResolveMetadata(ctx context.Context, id *GitIdentifier, sm *se
if err != nil {
return nil, err
}
if !opt.ReturnObject {
return md, nil
}
gsh.cacheCommit = md.Checksum
gsh.sha256 = len(md.Checksum) == 64
repo, err := gsh.remoteFetch(ctx, nil)
if err != nil {
return nil, err
}
defer repo.Release()
// if ref was commit sha then we don't know the type of the object yet
buf, err := repo.Run(ctx, "cat-file", "-t", md.Checksum)
if err != nil {
return nil, err
}
objType := strings.TrimSpace(string(buf))
if objType != "commit" && objType != "tag" {
return nil, errors.Errorf("expected commit or tag object, got %s", objType)
}
if objType == "tag" && md.CommitChecksum == "" {
buf, err := repo.Run(ctx, "rev-parse", md.Checksum+"^{commit}")
if err != nil {
return nil, err
}
md.CommitChecksum = strings.TrimSpace(string(buf))
} else if objType == "commit" {
md.CommitChecksum = ""
}
commitChecksum := md.Checksum
if md.CommitChecksum != "" {
buf, err := repo.Run(ctx, "cat-file", "tag", md.Checksum)
if err != nil {
return nil, err
}
md.TagObject = buf
commitChecksum = md.CommitChecksum
}
buf, err = repo.Run(ctx, "cat-file", "commit", commitChecksum)
if err != nil {
return nil, err
}
md.CommitObject = buf
return md, nil
}
@@ -557,6 +614,65 @@ func (gs *gitSourceHandler) CacheKey(ctx context.Context, jobCtx solver.JobConte
return cacheKey, md.Checksum, nil, true, nil
}
func (gs *gitSourceHandler) remoteFetch(ctx context.Context, g session.Group) (_ *gitRepo, retErr error) {
gs.locker.Lock(gs.src.Remote)
cleanup := func() error { return gs.locker.Unlock(gs.src.Remote) }
defer func() {
if retErr != nil {
cleanup()
}
}()
repo, err := gs.tryRemoteFetch(ctx, g, false)
if err != nil {
var wce *wouldClobberExistingTagError
var ulre *unableToUpdateLocalRefError
if errors.As(err, &wce) || errors.As(err, &ulre) {
repo, err = gs.tryRemoteFetch(ctx, g, true)
if err != nil {
return nil, err
}
} else {
return nil, err
}
}
repo.releasers = append(repo.releasers, cleanup)
defer func() {
if retErr != nil {
repo.Release()
repo = nil
}
}()
ref := gs.src.Ref
git := repo.GitCLI
if gs.src.Checksum != "" {
actualHashBuf, err := repo.Run(ctx, "rev-parse", ref)
if err != nil {
return nil, errors.Wrapf(err, "failed to rev-parse %s for %s", ref, urlutil.RedactCredentials(gs.src.Remote))
}
actualHash := strings.TrimSpace(string(actualHashBuf))
if !strings.HasPrefix(actualHash, gs.src.Checksum) {
retErr := errors.Errorf("expected checksum to match %s, got %s", gs.src.Checksum, actualHash)
actualHashBuf2, err := git.Run(ctx, "rev-parse", ref+"^{}")
if err != nil {
return nil, retErr
}
actualHash2 := strings.TrimSpace(string(actualHashBuf2))
if actualHash2 == actualHash {
return nil, retErr
}
if !strings.HasPrefix(actualHash2, gs.src.Checksum) {
return nil, errors.Errorf("expected checksum to match %s, got %s or %s", gs.src.Checksum, actualHash, actualHash2)
}
}
}
return repo, nil
}
func (gs *gitSourceHandler) Snapshot(ctx context.Context, jobCtx solver.JobContext) (cache.ImmutableRef, error) {
cacheKey := gs.cacheKey
if cacheKey == "" {
@@ -585,21 +701,9 @@ func (gs *gitSourceHandler) Snapshot(ctx context.Context, jobCtx solver.JobConte
return gs.cache.Get(ctx, sis[0].ID(), nil)
}
gs.locker.Lock(gs.src.Remote)
defer gs.locker.Unlock(gs.src.Remote)
repo, err := gs.tryRemoteFetch(ctx, g, false)
repo, err := gs.remoteFetch(ctx, g)
if err != nil {
var wce *wouldClobberExistingTagError
var ulre *unableToUpdateLocalRefError
if errors.As(err, &wce) || errors.As(err, &ulre) {
repo, err = gs.tryRemoteFetch(ctx, g, true)
if err != nil {
return nil, err
}
} else {
return nil, err
}
return nil, err
}
defer repo.Release()
@@ -801,28 +905,6 @@ func (gs *gitSourceHandler) checkout(ctx context.Context, repo *gitRepo, g sessi
subdir = "."
}
if gs.src.Checksum != "" {
actualHashBuf, err := git.Run(ctx, "rev-parse", ref)
if err != nil {
return nil, errors.Wrapf(err, "failed to rev-parse %s for %s", ref, urlutil.RedactCredentials(gs.src.Remote))
}
actualHash := strings.TrimSpace(string(actualHashBuf))
if !strings.HasPrefix(actualHash, gs.src.Checksum) {
retErr := errors.Errorf("expected checksum to match %s, got %s", gs.src.Checksum, actualHash)
actualHashBuf2, err := git.Run(ctx, "rev-parse", ref+"^{}")
if err != nil {
return nil, retErr
}
actualHash2 := strings.TrimSpace(string(actualHashBuf2))
if actualHash2 == actualHash {
return nil, retErr
}
if !strings.HasPrefix(actualHash2, gs.src.Checksum) {
return nil, errors.Errorf("expected checksum to match %s, got %s or %s", gs.src.Checksum, actualHash, actualHash2)
}
}
}
cd := checkoutDir
if gs.src.KeepGitDir && subdir == "." {
checkoutDirGit := filepath.Join(checkoutDir, ".git")