diff --git a/commands/history/export.go b/commands/history/export.go index 35114450d..4869056c5 100644 --- a/commands/history/export.go +++ b/commands/history/export.go @@ -4,7 +4,6 @@ import ( "context" "io" "os" - "slices" "github.com/containerd/console" "github.com/containerd/platforms" @@ -53,37 +52,52 @@ func runExport(ctx context.Context, dockerCli command.Cli, opts exportOptions) e return errors.Errorf("no record found for ref %q", ref) } - if opts.finalize { - var finalized bool + toExport := recs + if !opts.all && ref == "" { + latestRef := recs[0].Ref + recCount := 0 for _, rec := range recs { - if rec.Trace == nil { - finalized = true - if err := finalizeRecord(ctx, rec.Ref, nodes); err != nil { - return err - } + if rec.Ref != latestRef { + break + } + recCount++ + } + toExport = recs[:recCount] + } + if opts.finalize { + seen := make(map[string]struct{}, len(toExport)) + var finalized bool + for _, rec := range toExport { + if rec.node == nil || rec.Trace != nil { + continue + } + key := rec.node.Builder + "\x00" + rec.node.Name + "\x00" + rec.Ref + if _, ok := seen[key]; ok { + continue + } + seen[key] = struct{}{} + finalized = true + if err := finalizeRecord(ctx, rec.Ref, *rec.node); err != nil { + return err } } if finalized { - recs, err = queryRecords(ctx, ref, nodes, &queryOptions{ + queryRef := ref + if !opts.all { + queryRef = toExport[0].Ref + } + recs, err = queryRecords(ctx, queryRef, nodes, &queryOptions{ CompletedOnly: true, }) if err != nil { return err } + toExport = recs } } - - if ref == "" { - slices.SortFunc(recs, func(a, b historyRecord) int { - return b.CreatedAt.AsTime().Compare(a.CreatedAt.AsTime()) - }) - } - + res = append(res, toExport...) if opts.all { - res = append(res, recs...) break - } else { - res = append(res, recs[0]) } } diff --git a/commands/history/trace.go b/commands/history/trace.go index 1b2145dd8..dd806b649 100644 --- a/commands/history/trace.go +++ b/commands/history/trace.go @@ -56,7 +56,7 @@ func loadTrace(ctx context.Context, ref string, nodes []builder.Node) (string, [ // build is complete but no trace yet. try to finalize the trace time.Sleep(1 * time.Second) // give some extra time for last parts of trace to be written - err := finalizeRecord(ctx, rec.Ref, []builder.Node{*rec.node}) + err := finalizeRecord(ctx, rec.Ref, *rec.node) if err != nil { return "", nil, err } diff --git a/commands/history/utils.go b/commands/history/utils.go index beab15a22..f79260254 100644 --- a/commands/history/utils.go +++ b/commands/history/utils.go @@ -257,25 +257,19 @@ func queryRecords(ctx context.Context, ref string, nodes []builder.Node, opts *q return out, nil } -func finalizeRecord(ctx context.Context, ref string, nodes []builder.Node) error { - eg, ctx := errgroup.WithContext(ctx) - for _, node := range nodes { - eg.Go(func() error { - if node.Driver == nil { - return nil - } - c, err := node.Driver.Client(ctx) - if err != nil { - return err - } - _, err = c.ControlClient().UpdateBuildHistory(ctx, &controlapi.UpdateBuildHistoryRequest{ - Ref: ref, - Finalize: true, - }) - return err - }) +func finalizeRecord(ctx context.Context, ref string, node builder.Node) error { + if node.Driver == nil { + return nil } - return eg.Wait() + c, err := node.Driver.Client(ctx) + if err != nil { + return err + } + _, err = c.ControlClient().UpdateBuildHistory(ctx, &controlapi.UpdateBuildHistoryRequest{ + Ref: ref, + Finalize: true, + }) + return err } func formatDuration(d time.Duration) string {