Skip to content

Commit d8ab512

Browse files
committed
Refactor load from archive functionality
Signed-off-by: Austin Vazquez <[email protected]>
1 parent ec12b58 commit d8ab512

File tree

2 files changed

+57
-38
lines changed

2 files changed

+57
-38
lines changed

cmd/nerdctl/image/image_load.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,5 +94,6 @@ func loadAction(cmd *cobra.Command, _ []string) error {
9494
}
9595
defer cancel()
9696

97-
return load.Load(ctx, client, options)
97+
_, err = load.FromArchive(ctx, client, options)
98+
return err
9899
}

pkg/imgutil/load/load.go

Lines changed: 55 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -34,80 +34,98 @@ import (
3434
"github.com/containerd/nerdctl/v2/pkg/platformutil"
3535
)
3636

37-
type readCounter struct {
38-
io.Reader
39-
N int
40-
}
41-
42-
func (r *readCounter) Read(p []byte) (int, error) {
43-
n, err := r.Reader.Read(p)
44-
if n > 0 {
45-
r.N += n
46-
}
47-
return n, err
48-
}
49-
50-
func Load(ctx context.Context, client *containerd.Client, options types.ImageLoadOptions) error {
37+
// FromArchive loads and unpacks the images from the tar archive specified in image load options.
38+
func FromArchive(ctx context.Context, client *containerd.Client, options types.ImageLoadOptions) ([]images.Image, error) {
5139
if options.Input != "" {
5240
f, err := os.Open(options.Input)
5341
if err != nil {
54-
return err
42+
return nil, err
5543
}
5644
defer f.Close()
5745
options.Stdin = f
5846
} else {
5947
// check if stdin is empty.
6048
stdinStat, err := os.Stdin.Stat()
6149
if err != nil {
62-
return err
50+
return nil, err
6351
}
6452
if stdinStat.Size() == 0 && (stdinStat.Mode()&os.ModeNamedPipe) == 0 {
65-
return errors.New("stdin is empty and input flag is not specified")
53+
return nil, errors.New("stdin is empty and input flag is not specified")
6654
}
6755
}
6856
decompressor, err := compression.DecompressStream(options.Stdin)
6957
if err != nil {
70-
return err
58+
return nil, err
7159
}
7260
platMC, err := platformutil.NewMatchComparer(options.AllPlatforms, options.Platform)
7361
if err != nil {
74-
return err
62+
return nil, err
63+
}
64+
imgs, err := importImages(ctx, client, decompressor, options.GOptions.Snapshotter, platMC)
65+
if err != nil {
66+
return nil, err
67+
}
68+
unpackedImages := make([]images.Image, 0, len(imgs))
69+
for _, img := range imgs {
70+
err := unpackImage(ctx, client, img, platMC, options)
71+
if err != nil {
72+
return unpackedImages, fmt.Errorf("error unpacking image (%s): %w", img.Name, err)
73+
}
74+
unpackedImages = append(unpackedImages, img)
75+
}
76+
return unpackedImages, nil
77+
}
78+
79+
type readCounter struct {
80+
io.Reader
81+
N int
82+
}
83+
84+
func (r *readCounter) Read(p []byte) (int, error) {
85+
n, err := r.Reader.Read(p)
86+
if n > 0 {
87+
r.N += n
7588
}
76-
return loadImage(ctx, client, decompressor, platMC, options)
89+
return n, err
7790
}
7891

79-
func loadImage(ctx context.Context, client *containerd.Client, in io.Reader, platMC platforms.MatchComparer, options types.ImageLoadOptions) error {
92+
func importImages(ctx context.Context, client *containerd.Client, in io.Reader, snapshotter string, platformMC platforms.MatchComparer) ([]images.Image, error) {
8093
// In addition to passing WithImagePlatform() to client.Import(), we also need to pass WithDefaultPlatform() to NewClient().
8194
// Otherwise unpacking may fail.
8295
r := &readCounter{Reader: in}
83-
imgs, err := client.Import(ctx, r, containerd.WithDigestRef(archive.DigestTranslator(options.GOptions.Snapshotter)), containerd.WithSkipDigestRef(func(name string) bool { return name != "" }), containerd.WithImportPlatform(platMC))
96+
imgs, err := client.Import(ctx, r,
97+
containerd.WithDigestRef(archive.DigestTranslator(snapshotter)),
98+
containerd.WithSkipDigestRef(func(name string) bool { return name != "" }),
99+
containerd.WithImportPlatform(platformMC),
100+
)
84101
if err != nil {
85102
if r.N == 0 {
86103
// Avoid confusing "unrecognized image format"
87-
return errors.New("no image was built")
104+
return nil, errors.New("no image was built")
88105
}
89106
if errors.Is(err, images.ErrEmptyWalk) {
90107
err = fmt.Errorf("%w (Hint: set `--platform=PLATFORM` or `--all-platforms`)", err)
91108
}
92-
return err
109+
return nil, err
93110
}
94-
for _, img := range imgs {
95-
image := containerd.NewImageWithPlatform(client, img, platMC)
111+
return imgs, nil
112+
}
96113

97-
// TODO: Show unpack status
98-
if !options.Quiet {
99-
fmt.Fprintf(options.Stdout, "unpacking %s (%s)...\n", img.Name, img.Target.Digest)
100-
}
114+
func unpackImage(ctx context.Context, client *containerd.Client, model images.Image, platform platforms.MatchComparer, options types.ImageLoadOptions) error {
115+
image := containerd.NewImageWithPlatform(client, model, platform)
101116

102-
err = image.Unpack(ctx, options.GOptions.Snapshotter)
103-
if err != nil {
104-
return err
105-
}
117+
if !options.Quiet {
118+
fmt.Fprintf(options.Stdout, "unpacking %s (%s)...\n", model.Name, model.Target.Digest)
119+
}
106120

107-
// Loaded message is shown even when quiet.
108-
repo, tag := imgutil.ParseRepoTag(img.Name)
109-
fmt.Fprintf(options.Stdout, "Loaded image: %s:%s\n", repo, tag)
121+
err := image.Unpack(ctx, options.GOptions.Snapshotter)
122+
if err != nil {
123+
return err
110124
}
111125

126+
// Loaded message is shown even when quiet.
127+
repo, tag := imgutil.ParseRepoTag(model.Name)
128+
fmt.Fprintf(options.Stdout, "Loaded image: %s:%s\n", repo, tag)
129+
112130
return nil
113131
}

0 commit comments

Comments
 (0)