Skip to content

Commit d5bc0f0

Browse files
authored
Merge pull request #4779 from must108/progress-bar
feature: show progress output during conversion
2 parents e430d80 + 509d08b commit d5bc0f0

File tree

3 files changed

+55
-3
lines changed

3 files changed

+55
-3
lines changed

cmd/nerdctl/image/image_convert.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,13 @@ func convertCommand() *cobra.Command {
113113

114114
func convertOptions(cmd *cobra.Command) (types.ImageConvertOptions, error) {
115115
globalOptions, err := helpers.ProcessRootCmdFlags(cmd)
116+
116117
if err != nil {
117118
return types.ImageConvertOptions{}, err
118119
}
120+
121+
progressOutput := cmd.ErrOrStderr()
122+
119123
format, err := cmd.Flags().GetString("format")
120124
if err != nil {
121125
return types.ImageConvertOptions{}, err
@@ -313,7 +317,8 @@ func convertOptions(cmd *cobra.Command) (types.ImageConvertOptions, error) {
313317
AllPlatforms: allPlatforms,
314318
},
315319
},
316-
Stdout: cmd.OutOrStdout(),
320+
ProgressOutput: progressOutput,
321+
Stdout: cmd.OutOrStdout(),
317322
}, nil
318323
}
319324

pkg/api/types/image_types.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,9 @@ type ImageListOptions struct {
4747

4848
// ImageConvertOptions specifies options for `nerdctl image convert`.
4949
type ImageConvertOptions struct {
50-
Stdout io.Writer
51-
GOptions GlobalCommandOptions
50+
Stdout io.Writer
51+
ProgressOutput io.Writer
52+
GOptions GlobalCommandOptions
5253

5354
// #region generic flags
5455
// Uncompress convert tar.gz layers to uncompressed tar layers

pkg/cmd/image/convert.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import (
3636
"github.com/containerd/containerd/v2/core/images/converter/uncompress"
3737
"github.com/containerd/log"
3838
nydusconvert "github.com/containerd/nydus-snapshotter/pkg/converter"
39+
"github.com/containerd/platforms"
3940
"github.com/containerd/stargz-snapshotter/estargz"
4041
estargzconvert "github.com/containerd/stargz-snapshotter/nativeconverter/estargz"
4142
estargzexternaltocconvert "github.com/containerd/stargz-snapshotter/nativeconverter/estargz/externaltoc"
@@ -45,7 +46,9 @@ import (
4546

4647
"github.com/containerd/nerdctl/v2/pkg/api/types"
4748
"github.com/containerd/nerdctl/v2/pkg/clientutil"
49+
"github.com/containerd/nerdctl/v2/pkg/containerdutil"
4850
converterutil "github.com/containerd/nerdctl/v2/pkg/imgutil/converter"
51+
"github.com/containerd/nerdctl/v2/pkg/imgutil/jobs"
4952
"github.com/containerd/nerdctl/v2/pkg/platformutil"
5053
"github.com/containerd/nerdctl/v2/pkg/referenceutil"
5154
"github.com/containerd/nerdctl/v2/pkg/snapshotterutil"
@@ -205,6 +208,25 @@ func Convert(ctx context.Context, client *containerd.Client, srcRawRef, targetRa
205208
convertOpts = append(convertOpts, converter.WithDockerToOCI(true))
206209
}
207210

211+
if options.ProgressOutput != nil {
212+
ongoing := jobs.New(targetRef)
213+
if err := addDescriptorsToJobs(ctx, client, srcRef, platMC, ongoing); err != nil {
214+
return err
215+
}
216+
217+
progressCtx, cancelProgress := context.WithCancel(ctx)
218+
progressDone := make(chan struct{})
219+
220+
go func() {
221+
jobs.ShowProgress(progressCtx, ongoing, client.ContentStore(), options.ProgressOutput)
222+
close(progressDone)
223+
}()
224+
defer func() {
225+
cancelProgress()
226+
<-progressDone
227+
}()
228+
}
229+
208230
// converter.Convert() gains the lease by itself
209231
newImg, err := converterutil.Convert(ctx, client, targetRef, srcRef, convertOpts...)
210232
if err != nil {
@@ -264,6 +286,30 @@ func getESGZConverter(options types.ImageConvertOptions) (convertFunc converter.
264286
return convertFunc, finalize, nil
265287
}
266288

289+
func addDescriptorsToJobs(ctx context.Context, client *containerd.Client, srcRef string, platMC platforms.MatchComparer, ongoing *jobs.Jobs) error {
290+
imageService := client.ImageService()
291+
img, err := imageService.Get(ctx, srcRef)
292+
if err != nil {
293+
return err
294+
}
295+
296+
provider := containerdutil.NewProvider(client)
297+
handler := images.ChildrenHandler(provider)
298+
if platMC != nil {
299+
handler = images.HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
300+
if desc.Platform != nil && !platMC.Match(*desc.Platform) {
301+
return nil, nil
302+
}
303+
return images.Children(ctx, provider, desc)
304+
})
305+
}
306+
307+
return images.Walk(ctx, images.HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
308+
ongoing.Add(desc)
309+
return handler(ctx, desc)
310+
}), img.Target)
311+
}
312+
267313
func getESGZConvertOpts(options types.ImageConvertOptions) ([]estargz.Option, error) {
268314

269315
esgzOpts := []estargz.Option{

0 commit comments

Comments
 (0)