func (builder *Builder) pushImage(image imagename.ImageName) (digest string, err error) { var ( pipeReader, pipeWriter = io.Pipe() errch = make(chan error) buf bytes.Buffer outStream = io.MultiWriter(pipeWriter, &buf) ) go func() { err := builder.Docker.PushImage(docker.PushImageOptions{ Name: image.NameWithRegistry(), Tag: image.GetTag(), Registry: image.Registry, OutputStream: outStream, RawJSONStream: true, }, *builder.Auth) if err := pipeWriter.Close(); err != nil { fmt.Fprintf(builder.OutStream, "pipeWriter.Close() err: %s\n", err) } errch <- err }() if err := jsonmessage.DisplayJSONMessagesStream(pipeReader, builder.OutStream, builder.fdOut, builder.isTerminalOut); err != nil { return "", fmt.Errorf("Failed to process json stream for image: %s, error: %s", image, err) } if err := <-errch; err != nil { return "", fmt.Errorf("Failed to push image: %s, error: %s", image, err) } // It is the best way to have pushed image digest so far matches := captureDigest.FindStringSubmatch(buf.String()) if len(matches) > 0 { digest = matches[1] } return digest, nil }
// lookupImage looks up for the image by name and returns *docker.Image object (result of the inspect) // `Pull` config option defines whether we want to update the latest version of the image from the remote registry // See build.Config struct for more details about other build config options. // // If `Pull` is false, it tries to lookup locally by exact matching, e.g. if the image is already // pulled with that exact name given (no fuzzy semver matching) // // Then the function fetches the list of all pulled images and tries to match one of them by the given name. // // If `Pull` is set to true or if it cannot find the image locally, it then fetches all image // tags from the remote registry and finds the best match for the given image name. // // If it cannot find the image either locally or in the remote registry, it returns `nil` // // In case the given image has sha256 tag, it looks for it locally and pulls if it's not found. // No semver matching is done for sha256 tagged images. // // See also TestBuild_LookupImage_* test cases in build_test.go func (b *Build) lookupImage(name string) (img *docker.Image, err error) { var ( candidate, remoteCandidate *imagename.ImageName imgName = imagename.NewFromString(name) pull = false hub = b.cfg.Pull isSha = imgName.TagIsSha() ) // If hub is true, then there is no sense to inspect the local image if !hub || isSha { // Try to inspect image as is, without version resolution if img, err := b.client.InspectImage(name); err != nil || img != nil { return img, err } } if isSha { // If we are still here and image not found locally, we want to pull it candidate = imgName hub = false pull = true } if !isSha && !hub { // List local images var localImages = []*imagename.ImageName{} if localImages, err = b.client.ListImages(); err != nil { return nil, err } // Resolve local candidate candidate = imgName.ResolveVersion(localImages) } // In case we want to include external images as well, pulling list of available // images from the remote registry if hub || candidate == nil { log.Debugf("Getting list of tags for %s from the registry", imgName) var remoteImages []*imagename.ImageName if remoteImages, err = b.client.ListImageTags(imgName.String()); err != nil { err = fmt.Errorf("Failed to list tags of image %s from the remote registry, error: %s", imgName, err) } // Since we found the remote image, we want to pull it if remoteCandidate = imgName.ResolveVersion(remoteImages); remoteCandidate != nil { pull = true candidate = remoteCandidate } } // If not candidate found, it's an error if candidate == nil { err = fmt.Errorf("Image not found: %s (also checked in the remote registry)", imgName) return } if !isSha && imgName.GetTag() != candidate.GetTag() { if remoteCandidate != nil { log.Infof("Resolve %s --> %s (found remotely)", imgName, candidate.GetTag()) } else { log.Infof("Resolve %s --> %s", imgName, candidate.GetTag()) } } if pull { if err = b.client.PullImage(candidate.String()); err != nil { return } } return b.client.InspectImage(candidate.String()) }