github.com/sealerio/sealer@v0.11.1-0.20240507115618-f4f89c5853ae/pkg/imageengine/buildah/commit.go (about)

     1  // Copyright © 2022 Alibaba Group Holding Ltd.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package buildah
    16  
    17  import (
    18  	"os"
    19  	"time"
    20  
    21  	"github.com/containers/buildah"
    22  	"github.com/containers/buildah/define"
    23  	"github.com/containers/buildah/util"
    24  	"github.com/containers/image/v5/pkg/shortnames"
    25  	storageTransport "github.com/containers/image/v5/storage"
    26  	"github.com/containers/image/v5/transports/alltransports"
    27  	"github.com/containers/image/v5/types"
    28  	"github.com/containers/storage"
    29  	"github.com/pkg/errors"
    30  	"github.com/sirupsen/logrus"
    31  
    32  	"github.com/sealerio/sealer/pkg/define/options"
    33  )
    34  
    35  func (engine *Engine) Commit(opts *options.CommitOptions) (string, error) {
    36  	var dest types.ImageReference
    37  	if len(opts.ContainerID) == 0 {
    38  		return "", errors.Errorf("container ID must be specified")
    39  	}
    40  	if len(opts.Image) == 0 && len(opts.Manifest) == 0 {
    41  		return "", errors.Errorf("image name should be specified")
    42  	}
    43  
    44  	name := opts.ContainerID
    45  	image := opts.Image
    46  	manifest := opts.Manifest
    47  	compress := define.Gzip
    48  	if opts.DisableCompression {
    49  		compress = define.Uncompressed
    50  	}
    51  
    52  	format, err := getImageType(opts.Format)
    53  	if err != nil {
    54  		return "", err
    55  	}
    56  
    57  	ctx := getContext()
    58  	store := engine.ImageStore()
    59  	builder, err := OpenBuilder(ctx, store, name)
    60  	if err != nil {
    61  		return "", errors.Wrapf(err, "error reading build container %q", name)
    62  	}
    63  
    64  	systemCxt := engine.SystemContext()
    65  
    66  	// If the user specified an image, we may need to massage it a bit if
    67  	// no transport is specified.
    68  	// TODO we support commit to local image only, we'd better limit the input of name
    69  	if image != "" {
    70  		dest, err = getImageReference(image, store, systemCxt)
    71  		if err != nil {
    72  			return "", err
    73  		}
    74  	}
    75  
    76  	options := buildah.CommitOptions{
    77  		PreferredManifestType: format,
    78  		Manifest:              manifest,
    79  		Compression:           compress,
    80  		SystemContext:         systemCxt,
    81  		Squash:                opts.Squash,
    82  	}
    83  	if opts.Timestamp != 0 {
    84  		timestamp := time.Unix(opts.Timestamp, 0).UTC()
    85  		options.HistoryTimestamp = &timestamp
    86  	}
    87  
    88  	if !opts.Quiet {
    89  		options.ReportWriter = os.Stderr
    90  	}
    91  	id, ref, _, err := builder.Commit(ctx, dest, options)
    92  	if err != nil {
    93  		return "", util.GetFailureCause(err, errors.Wrapf(err, "error committing container %q to %q", builder.Container, image))
    94  	}
    95  	if ref != nil && id != "" {
    96  		logrus.Debugf("wrote image %s with ID %s", ref, id)
    97  	} else if ref != nil {
    98  		logrus.Debugf("wrote image %s", ref)
    99  	} else if id != "" {
   100  		logrus.Debugf("wrote image with ID %s", id)
   101  	} else {
   102  		logrus.Debugf("wrote image")
   103  	}
   104  
   105  	if opts.Rm {
   106  		return id, builder.Delete()
   107  	}
   108  	return id, nil
   109  }
   110  
   111  func getImageReference(image string, store storage.Store, systemCxt *types.SystemContext) (types.ImageReference, error) {
   112  	dest, err := alltransports.ParseImageName(image)
   113  	if err == nil {
   114  		return dest, nil
   115  	}
   116  
   117  	candidates, err := shortnames.ResolveLocally(systemCxt, image)
   118  	if err != nil {
   119  		return nil, err
   120  	}
   121  	if len(candidates) == 0 {
   122  		return nil, errors.Errorf("no candidate tags for target image name %q", image)
   123  	}
   124  	dest, err = storageTransport.Transport.ParseStoreReference(store, candidates[0].String())
   125  	if err != nil {
   126  		return nil, errors.Wrapf(err, "error parsing target image name %q", image)
   127  	}
   128  
   129  	return dest, nil
   130  }