github.com/sijibomii/docker@v0.0.0-20231230191044-5cf6ca554647/daemon/import.go (about)

     1  package daemon
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"io"
     7  	"net/http"
     8  	"net/url"
     9  	"runtime"
    10  	"time"
    11  
    12  	"github.com/docker/docker/builder/dockerfile"
    13  	"github.com/docker/docker/dockerversion"
    14  	"github.com/docker/docker/image"
    15  	"github.com/docker/docker/layer"
    16  	"github.com/docker/docker/pkg/archive"
    17  	"github.com/docker/docker/pkg/httputils"
    18  	"github.com/docker/docker/pkg/progress"
    19  	"github.com/docker/docker/pkg/streamformatter"
    20  	"github.com/docker/docker/reference"
    21  	"github.com/docker/engine-api/types/container"
    22  )
    23  
    24  // ImportImage imports an image, getting the archived layer data either from
    25  // inConfig (if src is "-"), or from a URI specified in src. Progress output is
    26  // written to outStream. Repository and tag names can optionally be given in
    27  // the repo and tag arguments, respectively.
    28  func (daemon *Daemon) ImportImage(src string, repository, tag string, msg string, inConfig io.ReadCloser, outStream io.Writer, changes []string) error {
    29  	var (
    30  		sf     = streamformatter.NewJSONStreamFormatter()
    31  		rc     io.ReadCloser
    32  		resp   *http.Response
    33  		newRef reference.Named
    34  	)
    35  
    36  	if repository != "" {
    37  		var err error
    38  		newRef, err = reference.ParseNamed(repository)
    39  		if err != nil {
    40  			return err
    41  		}
    42  
    43  		if _, isCanonical := newRef.(reference.Canonical); isCanonical {
    44  			return errors.New("cannot import digest reference")
    45  		}
    46  
    47  		if tag != "" {
    48  			newRef, err = reference.WithTag(newRef, tag)
    49  			if err != nil {
    50  				return err
    51  			}
    52  		}
    53  	}
    54  
    55  	config, err := dockerfile.BuildFromConfig(&container.Config{}, changes)
    56  	if err != nil {
    57  		return err
    58  	}
    59  	if src == "-" {
    60  		rc = inConfig
    61  	} else {
    62  		inConfig.Close()
    63  		u, err := url.Parse(src)
    64  		if err != nil {
    65  			return err
    66  		}
    67  		if u.Scheme == "" {
    68  			u.Scheme = "http"
    69  			u.Host = src
    70  			u.Path = ""
    71  		}
    72  		outStream.Write(sf.FormatStatus("", "Downloading from %s", u))
    73  		resp, err = httputils.Download(u.String())
    74  		if err != nil {
    75  			return err
    76  		}
    77  		progressOutput := sf.NewProgressOutput(outStream, true)
    78  		rc = progress.NewProgressReader(resp.Body, progressOutput, resp.ContentLength, "", "Importing")
    79  	}
    80  
    81  	defer rc.Close()
    82  	if len(msg) == 0 {
    83  		msg = "Imported from " + src
    84  	}
    85  
    86  	inflatedLayerData, err := archive.DecompressStream(rc)
    87  	if err != nil {
    88  		return err
    89  	}
    90  	// TODO: support windows baselayer?
    91  	l, err := daemon.layerStore.Register(inflatedLayerData, "")
    92  	if err != nil {
    93  		return err
    94  	}
    95  	defer layer.ReleaseAndLog(daemon.layerStore, l)
    96  
    97  	created := time.Now().UTC()
    98  	imgConfig, err := json.Marshal(&image.Image{
    99  		V1Image: image.V1Image{
   100  			DockerVersion: dockerversion.Version,
   101  			Config:        config,
   102  			Architecture:  runtime.GOARCH,
   103  			OS:            runtime.GOOS,
   104  			Created:       created,
   105  			Comment:       msg,
   106  		},
   107  		RootFS: &image.RootFS{
   108  			Type:    "layers",
   109  			DiffIDs: []layer.DiffID{l.DiffID()},
   110  		},
   111  		History: []image.History{{
   112  			Created: created,
   113  			Comment: msg,
   114  		}},
   115  	})
   116  	if err != nil {
   117  		return err
   118  	}
   119  
   120  	id, err := daemon.imageStore.Create(imgConfig)
   121  	if err != nil {
   122  		return err
   123  	}
   124  
   125  	// FIXME: connect with commit code and call refstore directly
   126  	if newRef != nil {
   127  		if err := daemon.TagImageWithReference(id, newRef); err != nil {
   128  			return err
   129  		}
   130  	}
   131  
   132  	daemon.LogImageEvent(id.String(), id.String(), "import")
   133  	outStream.Write(sf.FormatStatus("", id.String()))
   134  	return nil
   135  }