mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-11-04 18:13:42 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			115 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			115 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package dockerui
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"encoding/json"
 | 
						|
	"fmt"
 | 
						|
 | 
						|
	"github.com/containerd/containerd/platforms"
 | 
						|
	"github.com/moby/buildkit/exporter/containerimage/exptypes"
 | 
						|
	"github.com/moby/buildkit/exporter/containerimage/image"
 | 
						|
	"github.com/moby/buildkit/frontend/gateway/client"
 | 
						|
	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
 | 
						|
	"github.com/pkg/errors"
 | 
						|
	"golang.org/x/sync/errgroup"
 | 
						|
)
 | 
						|
 | 
						|
type BuildFunc func(ctx context.Context, platform *ocispecs.Platform, idx int) (client.Reference, *image.Image, error)
 | 
						|
 | 
						|
func (bc *Client) Build(ctx context.Context, fn BuildFunc) (*ResultBuilder, error) {
 | 
						|
	res := client.NewResult()
 | 
						|
 | 
						|
	targets := make([]*ocispecs.Platform, 0, len(bc.TargetPlatforms))
 | 
						|
	for _, p := range bc.TargetPlatforms {
 | 
						|
		p := p
 | 
						|
		targets = append(targets, &p)
 | 
						|
	}
 | 
						|
	if len(targets) == 0 {
 | 
						|
		targets = append(targets, nil)
 | 
						|
	}
 | 
						|
	expPlatforms := &exptypes.Platforms{
 | 
						|
		Platforms: make([]exptypes.Platform, len(targets)),
 | 
						|
	}
 | 
						|
 | 
						|
	eg, ctx := errgroup.WithContext(ctx)
 | 
						|
 | 
						|
	for i, tp := range targets {
 | 
						|
		i, tp := i, tp
 | 
						|
		eg.Go(func() error {
 | 
						|
			ref, img, err := fn(ctx, tp, i)
 | 
						|
			if err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
 | 
						|
			config, err := json.Marshal(img)
 | 
						|
			if err != nil {
 | 
						|
				return errors.Wrapf(err, "failed to marshal image config")
 | 
						|
			}
 | 
						|
 | 
						|
			p := platforms.DefaultSpec()
 | 
						|
			if tp != nil {
 | 
						|
				p = *tp
 | 
						|
			}
 | 
						|
 | 
						|
			// in certain conditions we allow input platform to be extended from base image
 | 
						|
			if p.OS == "windows" && img.OS == p.OS {
 | 
						|
				if p.OSVersion == "" && img.OSVersion != "" {
 | 
						|
					p.OSVersion = img.OSVersion
 | 
						|
				}
 | 
						|
				if p.OSFeatures == nil && len(img.OSFeatures) > 0 {
 | 
						|
					p.OSFeatures = img.OSFeatures
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			p = platforms.Normalize(p)
 | 
						|
			k := platforms.Format(p)
 | 
						|
 | 
						|
			if bc.MultiPlatformRequested {
 | 
						|
				res.AddRef(k, ref)
 | 
						|
				res.AddMeta(fmt.Sprintf("%s/%s", exptypes.ExporterImageConfigKey, k), config)
 | 
						|
			} else {
 | 
						|
				res.SetRef(ref)
 | 
						|
				res.AddMeta(exptypes.ExporterImageConfigKey, config)
 | 
						|
			}
 | 
						|
			expPlatforms.Platforms[i] = exptypes.Platform{
 | 
						|
				ID:       k,
 | 
						|
				Platform: p,
 | 
						|
			}
 | 
						|
			return nil
 | 
						|
		})
 | 
						|
	}
 | 
						|
	if err := eg.Wait(); err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	return &ResultBuilder{
 | 
						|
		Result:       res,
 | 
						|
		expPlatforms: expPlatforms,
 | 
						|
	}, nil
 | 
						|
}
 | 
						|
 | 
						|
type ResultBuilder struct {
 | 
						|
	*client.Result
 | 
						|
	expPlatforms *exptypes.Platforms
 | 
						|
}
 | 
						|
 | 
						|
func (rb *ResultBuilder) Finalize() (*client.Result, error) {
 | 
						|
	dt, err := json.Marshal(rb.expPlatforms)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	rb.AddMeta(exptypes.ExporterPlatformsKey, dt)
 | 
						|
 | 
						|
	return rb.Result, nil
 | 
						|
}
 | 
						|
 | 
						|
func (rb *ResultBuilder) EachPlatform(ctx context.Context, fn func(ctx context.Context, id string, p ocispecs.Platform) error) error {
 | 
						|
	eg, ctx := errgroup.WithContext(ctx)
 | 
						|
	for _, p := range rb.expPlatforms.Platforms {
 | 
						|
		p := p
 | 
						|
		eg.Go(func() error {
 | 
						|
			return fn(ctx, p.ID, p.Platform)
 | 
						|
		})
 | 
						|
	}
 | 
						|
	return eg.Wait()
 | 
						|
}
 |