github.com/containerd/nerdctl/v2@v2.0.0-beta.5.0.20240520001846-b5758f54fa28/pkg/imgutil/pull/pull.go (about)

     1  /*
     2     Copyright The containerd Authors.
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  // Package pull forked from https://github.com/containerd/containerd/blob/v1.4.3/cmd/ctr/commands/content/fetch.go
    18  package pull
    19  
    20  import (
    21  	"context"
    22  	"io"
    23  
    24  	"github.com/containerd/containerd"
    25  	"github.com/containerd/containerd/images"
    26  	"github.com/containerd/containerd/remotes"
    27  	"github.com/containerd/log"
    28  	"github.com/containerd/nerdctl/v2/pkg/imgutil/jobs"
    29  	"github.com/containerd/nerdctl/v2/pkg/platformutil"
    30  	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
    31  )
    32  
    33  // Config for content fetch
    34  type Config struct {
    35  	// Resolver
    36  	Resolver remotes.Resolver
    37  	// ProgressOutput to display progress
    38  	ProgressOutput io.Writer
    39  	// RemoteOpts, e.g. containerd.WithPullUnpack.
    40  	//
    41  	// Regardless to RemoteOpts, the following opts are always set:
    42  	// WithResolver, WithImageHandler, WithSchema1Conversion
    43  	//
    44  	// RemoteOpts related to unpacking can be set only when len(Platforms) is 1.
    45  	RemoteOpts []containerd.RemoteOpt
    46  	Platforms  []ocispec.Platform // empty for all-platforms
    47  }
    48  
    49  // Pull loads all resources into the content store and returns the image
    50  func Pull(ctx context.Context, client *containerd.Client, ref string, config *Config) (containerd.Image, error) {
    51  	ongoing := jobs.New(ref)
    52  
    53  	pctx, stopProgress := context.WithCancel(ctx)
    54  	progress := make(chan struct{})
    55  
    56  	go func() {
    57  		if config.ProgressOutput != nil {
    58  			// no progress bar, because it hides some debug logs
    59  			jobs.ShowProgress(pctx, ongoing, client.ContentStore(), config.ProgressOutput)
    60  		}
    61  		close(progress)
    62  	}()
    63  
    64  	h := images.HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
    65  		if desc.MediaType != images.MediaTypeDockerSchema1Manifest {
    66  			ongoing.Add(desc)
    67  		}
    68  		return nil, nil
    69  	})
    70  
    71  	log.G(pctx).WithField("image", ref).Debug("fetching")
    72  	platformMC := platformutil.NewMatchComparerFromOCISpecPlatformSlice(config.Platforms)
    73  	opts := []containerd.RemoteOpt{
    74  		containerd.WithResolver(config.Resolver),
    75  		containerd.WithImageHandler(h),
    76  		//nolint:staticcheck
    77  		containerd.WithSchema1Conversion, //lint:ignore SA1019 nerdctl should support schema1 as well.
    78  		containerd.WithPlatformMatcher(platformMC),
    79  	}
    80  	opts = append(opts, config.RemoteOpts...)
    81  
    82  	var (
    83  		img containerd.Image
    84  		err error
    85  	)
    86  	if len(config.Platforms) == 1 {
    87  		// client.Pull is for single-platform (w/ unpacking)
    88  		img, err = client.Pull(pctx, ref, opts...)
    89  	} else {
    90  		// client.Fetch is for multi-platform (w/o unpacking)
    91  		var imagesImg images.Image
    92  		imagesImg, err = client.Fetch(pctx, ref, opts...)
    93  		img = containerd.NewImageWithPlatform(client, imagesImg, platformMC)
    94  	}
    95  	stopProgress()
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  
   100  	<-progress
   101  	return img, nil
   102  }