build: refactor to avoid unneccessary nesting

Signed-off-by: Justin Chadwell <me@jedevc.com>
pull/1750/head
Justin Chadwell 2 years ago
parent 1fd23933c2
commit c6a78d216c

@ -792,320 +792,313 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
multiTarget := len(opt) > 1 multiTarget := len(opt) > 1
for k, opt := range opt { for k, opt := range opt {
err := func(k string) error { k, opt := k, opt
opt := opt dps := m[k]
dps := m[k] multiDriver := len(m[k]) > 1
multiDriver := len(m[k]) > 1
var span trace.Span
var span trace.Span ctx := ctx
ctx := ctx if multiTarget {
if multiTarget { span, ctx = tracing.StartSpan(ctx, k)
span, ctx = tracing.StartSpan(ctx, k) }
} baseCtx := ctx
baseCtx := ctx
res := make([]*client.SolveResponse, len(dps))
res := make([]*client.SolveResponse, len(dps)) eg2, ctx := errgroup.WithContext(ctx)
eg2, ctx := errgroup.WithContext(ctx)
var pushNames string
var pushNames string var insecurePush bool
var insecurePush bool
for i, dp := range dps {
for i, dp := range dps { i, dp, so := i, dp, *dp.so
i, dp, so := i, dp, *dp.so if multiDriver {
if multiDriver { for i, e := range so.Exports {
for i, e := range so.Exports { switch e.Type {
switch e.Type { case "oci", "tar":
case "oci", "tar": return nil, errors.Errorf("%s for multi-node builds currently not supported", e.Type)
return errors.Errorf("%s for multi-node builds currently not supported", e.Type) case "image":
case "image": if pushNames == "" && e.Attrs["push"] != "" {
if pushNames == "" && e.Attrs["push"] != "" { if ok, _ := strconv.ParseBool(e.Attrs["push"]); ok {
if ok, _ := strconv.ParseBool(e.Attrs["push"]); ok { pushNames = e.Attrs["name"]
pushNames = e.Attrs["name"] if pushNames == "" {
if pushNames == "" { return nil, errors.Errorf("tag is needed when pushing to registry")
return errors.Errorf("tag is needed when pushing to registry")
}
names, err := toRepoOnly(e.Attrs["name"])
if err != nil {
return err
}
if ok, _ := strconv.ParseBool(e.Attrs["registry.insecure"]); ok {
insecurePush = true
}
e.Attrs["name"] = names
e.Attrs["push-by-digest"] = "true"
so.Exports[i].Attrs = e.Attrs
} }
names, err := toRepoOnly(e.Attrs["name"])
if err != nil {
return nil, err
}
if ok, _ := strconv.ParseBool(e.Attrs["registry.insecure"]); ok {
insecurePush = true
}
e.Attrs["name"] = names
e.Attrs["push-by-digest"] = "true"
so.Exports[i].Attrs = e.Attrs
} }
} }
} }
} }
}
pw := progress.WithPrefix(w, k, multiTarget)
pw := progress.WithPrefix(w, k, multiTarget) c := clients[dp.driverIndex]
eg2.Go(func() error {
pw = progress.ResetTime(pw)
c := clients[dp.driverIndex] if err := waitContextDeps(ctx, dp.driverIndex, results, &so); err != nil {
eg2.Go(func() error { return err
pw = progress.ResetTime(pw) }
if err := waitContextDeps(ctx, dp.driverIndex, results, &so); err != nil { frontendInputs := make(map[string]*pb.Definition)
for key, st := range so.FrontendInputs {
def, err := st.Marshal(ctx)
if err != nil {
return err return err
} }
frontendInputs[key] = def.ToPB()
}
frontendInputs := make(map[string]*pb.Definition) req := gateway.SolveRequest{
for key, st := range so.FrontendInputs { Frontend: so.Frontend,
def, err := st.Marshal(ctx) FrontendInputs: frontendInputs,
if err != nil { FrontendOpt: make(map[string]string),
return err }
for k, v := range so.FrontendAttrs {
req.FrontendOpt[k] = v
}
so.Frontend = ""
so.FrontendInputs = nil
ch, done := progress.NewChannel(pw)
defer func() { <-done }()
cc := c
var printRes map[string][]byte
rr, err := c.Build(ctx, so, "buildx", func(ctx context.Context, c gateway.Client) (*gateway.Result, error) {
var isFallback bool
var origErr error
for {
if opt.PrintFunc != nil {
if _, ok := req.FrontendOpt["frontend.caps"]; !ok {
req.FrontendOpt["frontend.caps"] = "moby.buildkit.frontend.subrequests+forward"
} else {
req.FrontendOpt["frontend.caps"] += ",moby.buildkit.frontend.subrequests+forward"
}
req.FrontendOpt["requestid"] = "frontend." + opt.PrintFunc.Name
if isFallback {
req.FrontendOpt["build-arg:BUILDKIT_SYNTAX"] = printFallbackImage
}
} }
frontendInputs[key] = def.ToPB() res, err := c.Solve(ctx, req)
} if err != nil {
if origErr != nil {
req := gateway.SolveRequest{ return nil, err
Frontend: so.Frontend,
FrontendInputs: frontendInputs,
FrontendOpt: make(map[string]string),
}
for k, v := range so.FrontendAttrs {
req.FrontendOpt[k] = v
}
so.Frontend = ""
so.FrontendInputs = nil
ch, done := progress.NewChannel(pw)
defer func() { <-done }()
cc := c
var printRes map[string][]byte
rr, err := c.Build(ctx, so, "buildx", func(ctx context.Context, c gateway.Client) (*gateway.Result, error) {
var isFallback bool
var origErr error
for {
if opt.PrintFunc != nil {
if _, ok := req.FrontendOpt["frontend.caps"]; !ok {
req.FrontendOpt["frontend.caps"] = "moby.buildkit.frontend.subrequests+forward"
} else {
req.FrontendOpt["frontend.caps"] += ",moby.buildkit.frontend.subrequests+forward"
}
req.FrontendOpt["requestid"] = "frontend." + opt.PrintFunc.Name
if isFallback {
req.FrontendOpt["build-arg:BUILDKIT_SYNTAX"] = printFallbackImage
}
} }
res, err := c.Solve(ctx, req) var reqErr *errdefs.UnsupportedSubrequestError
if err != nil { if !isFallback {
if origErr != nil { if errors.As(err, &reqErr) {
return nil, err switch reqErr.Name {
} case "frontend.outline", "frontend.targets":
var reqErr *errdefs.UnsupportedSubrequestError
if !isFallback {
if errors.As(err, &reqErr) {
switch reqErr.Name {
case "frontend.outline", "frontend.targets":
isFallback = true
origErr = err
continue
}
return nil, err
}
// buildkit v0.8 vendored in Docker 20.10 does not support typed errors
if strings.Contains(err.Error(), "unsupported request frontend.outline") || strings.Contains(err.Error(), "unsupported request frontend.targets") {
isFallback = true isFallback = true
origErr = err origErr = err
continue continue
} }
return nil, err
} }
return nil, err // buildkit v0.8 vendored in Docker 20.10 does not support typed errors
} if strings.Contains(err.Error(), "unsupported request frontend.outline") || strings.Contains(err.Error(), "unsupported request frontend.targets") {
if opt.PrintFunc != nil { isFallback = true
printRes = res.Metadata origErr = err
} continue
results.Set(resultKey(dp.driverIndex, k), res)
if resultHandleFunc != nil {
resultCtx, err := NewResultContext(cc, so, res)
if err == nil {
resultHandleFunc(dp.driverIndex, resultCtx)
} else {
logrus.Warnf("failed to record result: %s", err)
} }
} }
return res, nil return nil, err
} }
}, ch) if opt.PrintFunc != nil {
if err != nil { printRes = res.Metadata
return err }
results.Set(resultKey(dp.driverIndex, k), res)
if resultHandleFunc != nil {
resultCtx, err := NewResultContext(cc, so, res)
if err == nil {
resultHandleFunc(dp.driverIndex, resultCtx)
} else {
logrus.Warnf("failed to record result: %s", err)
}
}
return res, nil
} }
res[i] = rr }, ch)
if err != nil {
return err
}
res[i] = rr
if rr.ExporterResponse == nil { if rr.ExporterResponse == nil {
rr.ExporterResponse = map[string]string{} rr.ExporterResponse = map[string]string{}
} }
for k, v := range printRes { for k, v := range printRes {
rr.ExporterResponse[k] = string(v) rr.ExporterResponse[k] = string(v)
} }
node := nodes[dp.driverIndex].Driver node := nodes[dp.driverIndex].Driver
if node.IsMobyDriver() { if node.IsMobyDriver() {
for _, e := range so.Exports { for _, e := range so.Exports {
if e.Type == "moby" && e.Attrs["push"] != "" { if e.Type == "moby" && e.Attrs["push"] != "" {
if ok, _ := strconv.ParseBool(e.Attrs["push"]); ok { if ok, _ := strconv.ParseBool(e.Attrs["push"]); ok {
pushNames = e.Attrs["name"] pushNames = e.Attrs["name"]
if pushNames == "" { if pushNames == "" {
return errors.Errorf("tag is needed when pushing to registry") return errors.Errorf("tag is needed when pushing to registry")
} }
pw := progress.ResetTime(pw) pw := progress.ResetTime(pw)
pushList := strings.Split(pushNames, ",") pushList := strings.Split(pushNames, ",")
for _, name := range pushList { for _, name := range pushList {
if err := progress.Wrap(fmt.Sprintf("pushing %s with docker", name), pw.Write, func(l progress.SubLogger) error { if err := progress.Wrap(fmt.Sprintf("pushing %s with docker", name), pw.Write, func(l progress.SubLogger) error {
return pushWithMoby(ctx, node, name, l) return pushWithMoby(ctx, node, name, l)
}); err != nil { }); err != nil {
return err return err
}
} }
remoteDigest, err := remoteDigestWithMoby(ctx, node, pushList[0]) }
if err == nil && remoteDigest != "" { remoteDigest, err := remoteDigestWithMoby(ctx, node, pushList[0])
// old daemons might not have containerimage.config.digest set if err == nil && remoteDigest != "" {
// in response so use containerimage.digest value for it if available // old daemons might not have containerimage.config.digest set
if _, ok := rr.ExporterResponse[exptypes.ExporterImageConfigDigestKey]; !ok { // in response so use containerimage.digest value for it if available
if v, ok := rr.ExporterResponse[exptypes.ExporterImageDigestKey]; ok { if _, ok := rr.ExporterResponse[exptypes.ExporterImageConfigDigestKey]; !ok {
rr.ExporterResponse[exptypes.ExporterImageConfigDigestKey] = v if v, ok := rr.ExporterResponse[exptypes.ExporterImageDigestKey]; ok {
} rr.ExporterResponse[exptypes.ExporterImageConfigDigestKey] = v
} }
rr.ExporterResponse[exptypes.ExporterImageDigestKey] = remoteDigest
} else if err != nil {
return err
} }
rr.ExporterResponse[exptypes.ExporterImageDigestKey] = remoteDigest
} else if err != nil {
return err
} }
} }
} }
} }
return nil
})
}
eg.Go(func() (err error) {
ctx := baseCtx
defer func() {
if span != nil {
tracing.FinishWithError(span, err)
}
}()
pw := progress.WithPrefix(w, "default", false)
if err := eg2.Wait(); err != nil {
return err
} }
return nil
})
}
respMu.Lock() eg.Go(func() (err error) {
resp[k] = res[0] ctx := baseCtx
respMu.Unlock() defer func() {
if len(res) == 1 { if span != nil {
return nil tracing.FinishWithError(span, err)
} }
}()
pw := progress.WithPrefix(w, "default", false)
if err := eg2.Wait(); err != nil {
return err
}
if pushNames != "" { respMu.Lock()
progress.Write(pw, fmt.Sprintf("merging manifest list %s", pushNames), func() error { resp[k] = res[0]
descs := make([]specs.Descriptor, 0, len(res)) respMu.Unlock()
if len(res) == 1 {
for _, r := range res { return nil
s, ok := r.ExporterResponse[exptypes.ExporterImageDescriptorKey] }
if ok {
dt, err := base64.StdEncoding.DecodeString(s)
if err != nil {
return err
}
var desc specs.Descriptor
if err := json.Unmarshal(dt, &desc); err != nil {
return errors.Wrapf(err, "failed to unmarshal descriptor %s", s)
}
descs = append(descs, desc)
continue
}
// This is fallback for some very old buildkit versions.
// Note that the mediatype isn't really correct as most of the time it is image manifest and
// not manifest list but actually both are handled because for Docker mediatypes the
// mediatype value in the Accpet header does not seem to matter.
s, ok = r.ExporterResponse[exptypes.ExporterImageDigestKey]
if ok {
descs = append(descs, specs.Descriptor{
Digest: digest.Digest(s),
MediaType: images.MediaTypeDockerSchema2ManifestList,
Size: -1,
})
}
}
if len(descs) > 0 {
var imageopt imagetools.Opt
for _, dp := range dps {
imageopt = nodes[dp.driverIndex].ImageOpt
break
}
names := strings.Split(pushNames, ",")
if insecurePush {
insecureTrue := true
httpTrue := true
nn, err := reference.ParseNormalizedNamed(names[0])
if err != nil {
return err
}
imageopt.RegistryConfig = map[string]resolver.RegistryConfig{
reference.Domain(nn): {
Insecure: &insecureTrue,
PlainHTTP: &httpTrue,
},
}
}
itpull := imagetools.New(imageopt) if pushNames != "" {
progress.Write(pw, fmt.Sprintf("merging manifest list %s", pushNames), func() error {
descs := make([]specs.Descriptor, 0, len(res))
ref, err := reference.ParseNormalizedNamed(names[0]) for _, r := range res {
s, ok := r.ExporterResponse[exptypes.ExporterImageDescriptorKey]
if ok {
dt, err := base64.StdEncoding.DecodeString(s)
if err != nil { if err != nil {
return err return err
} }
ref = reference.TagNameOnly(ref) var desc specs.Descriptor
if err := json.Unmarshal(dt, &desc); err != nil {
srcs := make([]*imagetools.Source, len(descs)) return errors.Wrapf(err, "failed to unmarshal descriptor %s", s)
for i, desc := range descs {
srcs[i] = &imagetools.Source{
Desc: desc,
Ref: ref,
}
} }
descs = append(descs, desc)
continue
}
// This is fallback for some very old buildkit versions.
// Note that the mediatype isn't really correct as most of the time it is image manifest and
// not manifest list but actually both are handled because for Docker mediatypes the
// mediatype value in the Accpet header does not seem to matter.
s, ok = r.ExporterResponse[exptypes.ExporterImageDigestKey]
if ok {
descs = append(descs, specs.Descriptor{
Digest: digest.Digest(s),
MediaType: images.MediaTypeDockerSchema2ManifestList,
Size: -1,
})
}
}
if len(descs) > 0 {
var imageopt imagetools.Opt
for _, dp := range dps {
imageopt = nodes[dp.driverIndex].ImageOpt
break
}
names := strings.Split(pushNames, ",")
dt, desc, err := itpull.Combine(ctx, srcs) if insecurePush {
insecureTrue := true
httpTrue := true
nn, err := reference.ParseNormalizedNamed(names[0])
if err != nil { if err != nil {
return err return err
} }
imageopt.RegistryConfig = map[string]resolver.RegistryConfig{
reference.Domain(nn): {
Insecure: &insecureTrue,
PlainHTTP: &httpTrue,
},
}
}
itpush := imagetools.New(imageopt) itpull := imagetools.New(imageopt)
for _, n := range names { ref, err := reference.ParseNormalizedNamed(names[0])
nn, err := reference.ParseNormalizedNamed(n) if err != nil {
if err != nil { return err
return err }
} ref = reference.TagNameOnly(ref)
if err := itpush.Push(ctx, nn, desc, dt); err != nil {
return err srcs := make([]*imagetools.Source, len(descs))
} for i, desc := range descs {
srcs[i] = &imagetools.Source{
Desc: desc,
Ref: ref,
} }
}
respMu.Lock() dt, desc, err := itpull.Combine(ctx, srcs)
resp[k] = &client.SolveResponse{ if err != nil {
ExporterResponse: map[string]string{ return err
exptypes.ExporterImageDigestKey: desc.Digest.String(), }
},
itpush := imagetools.New(imageopt)
for _, n := range names {
nn, err := reference.ParseNormalizedNamed(n)
if err != nil {
return err
}
if err := itpush.Push(ctx, nn, desc, dt); err != nil {
return err
} }
respMu.Unlock()
} }
return nil
})
}
return nil
})
respMu.Lock()
resp[k] = &client.SolveResponse{
ExporterResponse: map[string]string{
exptypes.ExporterImageDigestKey: desc.Digest.String(),
},
}
respMu.Unlock()
}
return nil
})
}
return nil return nil
}(k) })
if err != nil {
return nil, err
}
} }
if err := eg.Wait(); err != nil { if err := eg.Wait(); err != nil {

Loading…
Cancel
Save