// Package imageref splits container image references into repository, tag // and digest. package imageref import ( "regexp" "strings" ) // Ref is an image reference split into its parts. Tag and Digest are empty // when the reference has none. type Ref struct { Repo string Tag string Digest string } // Parse splits ref into repository, tag and digest. A colon before the last // "/" belongs to a registry host and port ("localhost:5000/foo"), not a tag. func Parse(ref string) Ref { var r Ref if at := strings.Index(ref, "@"); at >= 0 { r.Digest = ref[at+1:] ref = ref[:at] } slash := strings.LastIndex(ref, "/") last := ref[slash+1:] if colon := strings.Index(last, ":"); colon >= 0 { r.Tag = last[colon+1:] ref = ref[:slash+1+colon] } r.Repo = ref return r } // IsRegistryHost reports whether the first path segment of a repository names // a registry: it contains a "." or ":" or is "localhost". func IsRegistryHost(segment string) bool { return strings.ContainsAny(segment, ".:") || segment == "localhost" } // String reassembles the reference as repo[:tag][@digest]. func (r Ref) String() string { s := r.Repo if r.Tag != "" { s += ":" + r.Tag } if r.Digest != "" { s += "@" + r.Digest } return s } var digestPattern = regexp.MustCompile(`^sha256:[0-9a-f]{64}$`) // IsDigest reports whether d is a well-formed sha256 digest. func IsDigest(d string) bool { return digestPattern.MatchString(d) }