// Every image is named after the following pattern:
//   <registry>/<repository>:<tag>
// with registry being of the form "<hostname>:<port>" and repository being a string of [A-Za-z0-9_].
335517
func splitImageName(name string) (registry, repository, tag string) {
	s := imageNameRegexp.FindStringSubmatch(name)
	if len(s[3]) > 0 {
		tag = s[3][1:]
	}
	repository = s[2]
	if len(s[1]) > 0 {
		registry = s[1][0 : len(s[1])-1]
	}
	return registry, repository, tag
}
41873
func (iid ImageID) Registry() string {
	s := []string{}

	if len(iid.Host) == 0 {
		return ""
	}

	s = append(s, iid.Host)

	if iid.Port != 0 {
		s = append(s, ":", strconv.Itoa(iid.Port))
	}

	return strings.Join(s, "")
}
662199
func (image Image) String() string {
	ret := ""
	ret = "<img" + image.Attrs()
	if image.Source != "" {
		ret += " src='" + image.Source + "'"
	}
	ret += "/>"

	return ret
}
335083
func (d *dockerAPI) tagImage(imageID string, ref string) error {
	glog.V(4).Infof("docker tag for image %q, tag %q", imageID, ref)

	ctx := context.Background()
	options := types.ImageTagOptions{}
	err := d.client.ImageTag(ctx, imageID, ref, options)
	if err != nil {
		return fmt.Errorf("error tagging image %q with tag %q: %v", imageID, ref, err)
	}
	return nil
}
1189802
func SplitImageSignatureName(imageSignatureName string) (imageName, signatureName string, err error) {
	segments := strings.Split(imageSignatureName, "@")
	switch len(segments) {
	case 2:
		signatureName = segments[1]
		imageName = segments[0]
		if len(imageName) == 0 || len(signatureName) == 0 {
			err = fmt.Errorf("image signature name %q must have an image name and signature name", imageSignatureName)
		}
	default:
		err = fmt.Errorf("expected exactly one @ in the image signature name %q", imageSignatureName)
	}
	return
}
350029
func FormatRepositories(refs ...ImageRef) ([]byte, error) {
	// new Registry, ref.host function
	for _, ref := range refs {
		if ref.ID() == "" {
			re := NewRegistry(ref.Host())
			if _, err := re.ImageID(ref); err != nil {
				return nil, err
			}
		}
	}
	// {"busybox":{"latest":"4986bf8c15363d1c5d15512d5266f8777bfba4974ac56e3270e7760f6f0a8125"}}
	repoInfo := map[string]map[string]string{}
	for _, ref := range refs {
		if repoInfo[ref.Name()] == nil {
			repoInfo[ref.Name()] = map[string]string{ref.Tag(): ref.ID()}
		} else {
			repoInfo[ref.Name()][ref.Tag()] = ref.ID()
		}
	}
	return json.Marshal(repoInfo)
}
606441
func splitDockerImageName(imageName string) (host, namespace, repo, tag string) {
	hostNamespaceImage := strings.Split(imageName, "/")
	last := len(hostNamespaceImage) - 1
	repoTag := strings.Split(hostNamespaceImage[last], ":")
	repo = repoTag[0]
	if len(repoTag) > 1 {
		tag = repoTag[1]
	}
	switch len(hostNamespaceImage) {
	case 2:
		host = ""
		namespace = hostNamespaceImage[0]
	case 3:
		host = hostNamespaceImage[0]
		namespace = hostNamespaceImage[1]
	}
	return
}
878417
func parseNamedDockerImageReference(spec string) (namedDockerImageReference, error) {
	var ref namedDockerImageReference

	namedRef, err := reference.ParseNormalizedNamed(spec)
	if err != nil {
		return ref, err
	}

	name := namedRef.Name()
	i := strings.IndexRune(name, '/')
	if i == -1 || (!strings.ContainsAny(name[:i], ":.") && name[:i] != "localhost") {
		ref.Name = name
	} else {
		ref.Registry, ref.Name = name[:i], name[i+1:]
	}

	if named, ok := namedRef.(reference.NamedTagged); ok {
		ref.Tag = named.Tag()
	}

	if named, ok := namedRef.(reference.Canonical); ok {
		ref.ID = named.Digest().String()
	}

	// It's not enough just to use the reference.ParseNamed(). We have to fill
	// ref.Namespace from ref.Name
	if i := strings.IndexRune(ref.Name, '/'); i != -1 {
		ref.Namespace, ref.Name = ref.Name[:i], ref.Name[i+1:]
	}

	return ref, nil
}
1104177
func DockerImageReferenceExact(r imagev1.DockerImageReference) string {
	name := DockerImageReferenceNameString(r)
	if len(name) == 0 {
		return name
	}
	s := r.Registry
	if len(s) > 0 {
		s += "/"
	}
	if len(r.Namespace) != 0 {
		s += r.Namespace + "/"
	}
	return s + name
}
1187179
func (l *RegistryListener) ImagePath(image string) (string, error) {
	imageID, err := commons.ParseImageID(image)
	if err != nil {
		return "", err
	}
	rImage := &registry.Image{
		Library: imageID.User,
		Repo:    imageID.Repo,
		Tag:     imageID.Tag,
	}
	if imageID.IsLatest() {
		rImage.Tag = docker.Latest
	}
	return path.Join(l.address, rImage.String()), nil
}
513636
func (svc *imageService) ResolveNames(imageName string) ([]string, error) {
	// _Maybe_ it's a truncated image ID.  Don't prepend a registry name, then.
	if len(imageName) >= minimumTruncatedIDLength && svc.store != nil {
		if img, err := svc.store.Image(imageName); err == nil && img != nil && strings.HasPrefix(img.ID, imageName) {
			// It's a truncated version of the ID of an image that's present in local storage;
			// we need to expand it.
			return []string{img.ID}, nil
		}
	}
	// This to prevent any image ID to go through this routine
	_, err := reference.ParseNormalizedNamed(imageName)
	if err != nil {
		if strings.Contains(err.Error(), "cannot specify 64-byte hexadecimal strings") {
			return nil, ErrCannotParseImageID
		}
		return nil, err
	}

	domain, remainder := splitDockerDomain(imageName)
	if domain != "" {
		// this means the image is already fully qualified
		registry, err := sysregistriesv2.FindRegistry(nil, imageName)
		if err != nil {
			return nil, err
		}
		if registry != nil && registry.Blocked {
			return nil, fmt.Errorf("cannot use %q because it's blocked", imageName)
		}
		return []string{imageName}, nil
	}
	// we got an unqualified image here, we can't go ahead w/o registries configured
	// properly.
	if len(svc.unqualifiedSearchRegistries) == 0 {
		return nil, ErrNoRegistriesConfigured
	}
	// this means we got an image in the form of "busybox"
	// we need to use additional registries...
	// normalize the unqualified image to be domain/repo/image...
	images := []string{}
	for _, r := range svc.unqualifiedSearchRegistries {
		rem := remainder
		if r == "docker.io" && !strings.ContainsRune(remainder, '/') {
			rem = "library/" + rem
		}
		image := path.Join(r, rem)
		registry, err := sysregistriesv2.FindRegistry(nil, image)
		if err != nil {
			return nil, err
		}
		if registry != nil && registry.Blocked {
			continue
		}
		images = append(images, image)
	}
	if len(images) == 0 {
		return nil, fmt.Errorf("all search registries for %q are blocked", remainder)
	}
	return images, nil
}
98276
func (r ImageRepos) GetRepositoryMetadata(repo image.Name) image.RepositoryMetadata {
	if metadata, ok := r.imageRepos[repo.CanonicalName()]; ok {
		// copy tags
		tagsCopy := make([]string, len(metadata.Tags))
		copy(tagsCopy, metadata.Tags)
		// copy images
		imagesCopy := make(map[string]image.Info, len(metadata.Images))
		for tag, info := range metadata.Images {
			// The registry (cache) stores metadata with canonical image
			// names (e.g., `index.docker.io/library/alpine`). We rewrite the
			// names based on how we were queried (repo), which could
			// be non-canonical representation (e.g. `alpine`).
			info.ID = repo.ToRef(info.ID.Tag)
			imagesCopy[tag] = info
		}
		return image.RepositoryMetadata{tagsCopy, imagesCopy}
	}
	return image.RepositoryMetadata{}
}
492355
func GetImage(name, registryURL string) (*Image, int, error) {
	if name == "" {
		return nil, -1, errors.New("image name is empty")
	}

	var ru *url.URL
	var err error
	if len(registryURL) != 0 {
		ru, err = url.Parse(registryURL)
	} else {
		ru, err = url.Parse(DockerHubRegistryURL)
		registryURL = DockerHubRegistryURL
	}
	if err != nil {
		return nil, -1, err
	}

	// In order to get layers from Docker CDN we need to hit 'images' endpoint
	// and request the token. Client should also accept and store cookies, as
	// they are needed to fetch the layer data later.
	imagesURL := fmt.Sprintf("%s/v1/repositories/%s/images", registryURL, name)

	req, err := http.NewRequest("GET", imagesURL, nil)
	if err != nil {
		return nil, -1, err
	}

	// FIXME: Send 'Connection: close' header on HTTP requests
	// as reusing the connection is still prone to EOF/Connection reset errors
	// in certain network environments...
	// See: ENGT-9670
	// https://stackoverflow.com/questions/17714494/golang-http-request-results-in-eof-errors
	req.Close = true

	req.Header.Set("X-Docker-Token", "true")

	client := &http.Client{
		Transport: &http.Transport{
			Proxy: http.ProxyFromEnvironment,
		},
	}
	client.Jar, err = cookiejar.New(nil) // Docker repo API sets and uses cookies for CDN.
	if err != nil {
		return nil, -1, err
	}

	res, err := client.Do(req)
	if err != nil {
		return nil, -1, err
	}
	defer res.Body.Close()
	switch res.StatusCode {
	case http.StatusOK:
		// Fall through.
	case http.StatusNotFound:
		return nil, res.StatusCode, fmt.Errorf("image %q not found", name)
	default:
		return nil, res.StatusCode, fmt.Errorf("HTTP %d ", res.StatusCode)
	}

	token := res.Header.Get("X-Docker-Token")
	endpoints := strings.Split(res.Header.Get("X-Docker-Endpoints"), ",")

	if len(endpoints) == 0 {
		return nil, res.StatusCode, errors.New("Docker index response didn't contain any endpoints")
	}
	for i := range endpoints {
		endpoints[i] = strings.Trim(endpoints[i], " ")
	}

	img := &Image{
		Name:      name,
		client:    client,
		endpoints: endpoints,
		token:     token,
		scheme:    ru.Scheme,
	}

	img.tags, err = img.fetchTags()
	if err != nil {
		return nil, res.StatusCode, err
	}

	return img, res.StatusCode, nil
}
1289082
func (i Name) Registry() string {
	switch i.Domain {
	case "", oldDockerHubHost:
		return dockerHubHost
	default:
		return i.Domain
	}
}
1306196
func (i Name) CanonicalName() CanonicalName {
	return CanonicalName{
		Name: Name{
			Domain: i.Registry(),
			Image:  i.Repository(),
		},
	}
}
1315161
func IndexOfImageSignatureByName(signatures []ImageSignature, name string) int {
	for i := range signatures {
		if signatures[i].Name == name {
			return i
		}
	}
	return -1
}
315735
func (r *RegexpNamer) ServiceName(container *docker.APIContainers) string {
	if container == nil {
		log.Warn("ServiceName() called with nil service passed!")
		return ""
	}

	if r.expression == nil {
		log.Errorf("Invalid regex can't match using: %s", r.ServiceNameMatch)
		return container.Image
	}

	var svcName string

	toMatch := []byte(container.Names[0])
	matches := r.expression.FindSubmatch(toMatch)
	if len(matches) < 1 {
		svcName = container.Image
	} else {
		svcName = string(matches[1])
	}

	return svcName
}