
This package was forked from the https://github.com/distribution/distribution repository in commit901bcb2231
, but that commit did a plain copy of the code (minus tests), and rewrote the code to be in a single file. The same commit also removed some deprecated code for handling "shortid" references (ParseAnyReferenceWithSet() function), in order to avoid the "digestset" dependency from the distribution repo. At the time, containerd used the distribution/distribution package from this commit:0d3efadf01
Since the code was forked, both containerd and distribution have received improvements and fixes, so unfortunately, the code started to diverge. I'm planning to reconcile the packages (potentially by using a shared module), and this is the first commit to assist with that. This patch restructures the reference/docker package to split the code into the same files as are used in the upstream distribution/distribution repository. This makes it easier to compare the implementations in both repositories (to allow synchronizing changes). No changes are applied yet, other than splitting the code (follow-up commits will take care of syncing changes across). Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
155 lines
5.5 KiB
Go
155 lines
5.5 KiB
Go
/*
|
|
Copyright The containerd Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package docker
|
|
|
|
import "regexp"
|
|
|
|
var (
|
|
// alphaNumericRegexp defines the alpha numeric atom, typically a
|
|
// component of names. This only allows lower case characters and digits.
|
|
alphaNumericRegexp = match(`[a-z0-9]+`)
|
|
|
|
// separatorRegexp defines the separators allowed to be embedded in name
|
|
// components. This allow one period, one or two underscore and multiple
|
|
// dashes.
|
|
separatorRegexp = match(`(?:[._]|__|[-]*)`)
|
|
|
|
// nameComponentRegexp restricts registry path component names to start
|
|
// with at least one letter or number, with following parts able to be
|
|
// separated by one period, one or two underscore and multiple dashes.
|
|
nameComponentRegexp = expression(
|
|
alphaNumericRegexp,
|
|
optional(repeated(separatorRegexp, alphaNumericRegexp)))
|
|
|
|
// domainComponentRegexp restricts the registry domain component of a
|
|
// repository name to start with a component as defined by DomainRegexp
|
|
// and followed by an optional port.
|
|
domainComponentRegexp = match(`(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])`)
|
|
|
|
// DomainRegexp defines the structure of potential domain components
|
|
// that may be part of image names. This is purposely a subset of what is
|
|
// allowed by DNS to ensure backwards compatibility with Docker image
|
|
// names.
|
|
DomainRegexp = expression(
|
|
domainComponentRegexp,
|
|
optional(repeated(literal(`.`), domainComponentRegexp)),
|
|
optional(literal(`:`), match(`[0-9]+`)))
|
|
|
|
// TagRegexp matches valid tag names. From docker/docker:graph/tags.go.
|
|
TagRegexp = match(`[\w][\w.-]{0,127}`)
|
|
|
|
// anchoredTagRegexp matches valid tag names, anchored at the start and
|
|
// end of the matched string.
|
|
anchoredTagRegexp = anchored(TagRegexp)
|
|
|
|
// DigestRegexp matches valid digests.
|
|
DigestRegexp = match(`[A-Za-z][A-Za-z0-9]*(?:[-_+.][A-Za-z][A-Za-z0-9]*)*[:][[:xdigit:]]{32,}`)
|
|
|
|
// anchoredDigestRegexp matches valid digests, anchored at the start and
|
|
// end of the matched string.
|
|
anchoredDigestRegexp = anchored(DigestRegexp)
|
|
|
|
// NameRegexp is the format for the name component of references. The
|
|
// regexp has capturing groups for the domain and name part omitting
|
|
// the separating forward slash from either.
|
|
NameRegexp = expression(
|
|
optional(DomainRegexp, literal(`/`)),
|
|
nameComponentRegexp,
|
|
optional(repeated(literal(`/`), nameComponentRegexp)))
|
|
|
|
// anchoredNameRegexp is used to parse a name value, capturing the
|
|
// domain and trailing components.
|
|
anchoredNameRegexp = anchored(
|
|
optional(capture(DomainRegexp), literal(`/`)),
|
|
capture(nameComponentRegexp,
|
|
optional(repeated(literal(`/`), nameComponentRegexp))))
|
|
|
|
// ReferenceRegexp is the full supported format of a reference. The regexp
|
|
// is anchored and has capturing groups for name, tag, and digest
|
|
// components.
|
|
ReferenceRegexp = anchored(capture(NameRegexp),
|
|
optional(literal(":"), capture(TagRegexp)),
|
|
optional(literal("@"), capture(DigestRegexp)))
|
|
|
|
// IdentifierRegexp is the format for string identifier used as a
|
|
// content addressable identifier using sha256. These identifiers
|
|
// are like digests without the algorithm, since sha256 is used.
|
|
IdentifierRegexp = match(`([a-f0-9]{64})`)
|
|
|
|
// ShortIdentifierRegexp is the format used to represent a prefix
|
|
// of an identifier. A prefix may be used to match a sha256 identifier
|
|
// within a list of trusted identifiers.
|
|
ShortIdentifierRegexp = match(`([a-f0-9]{6,64})`)
|
|
|
|
// anchoredIdentifierRegexp is used to check or match an
|
|
// identifier value, anchored at start and end of string.
|
|
anchoredIdentifierRegexp = anchored(IdentifierRegexp)
|
|
)
|
|
|
|
// match compiles the string to a regular expression.
|
|
var match = regexp.MustCompile
|
|
|
|
// literal compiles s into a literal regular expression, escaping any regexp
|
|
// reserved characters.
|
|
func literal(s string) *regexp.Regexp {
|
|
re := match(regexp.QuoteMeta(s))
|
|
|
|
if _, complete := re.LiteralPrefix(); !complete {
|
|
panic("must be a literal")
|
|
}
|
|
|
|
return re
|
|
}
|
|
|
|
// expression defines a full expression, where each regular expression must
|
|
// follow the previous.
|
|
func expression(res ...*regexp.Regexp) *regexp.Regexp {
|
|
var s string
|
|
for _, re := range res {
|
|
s += re.String()
|
|
}
|
|
|
|
return match(s)
|
|
}
|
|
|
|
// optional wraps the expression in a non-capturing group and makes the
|
|
// production optional.
|
|
func optional(res ...*regexp.Regexp) *regexp.Regexp {
|
|
return match(group(expression(res...)).String() + `?`)
|
|
}
|
|
|
|
// repeated wraps the regexp in a non-capturing group to get one or more
|
|
// matches.
|
|
func repeated(res ...*regexp.Regexp) *regexp.Regexp {
|
|
return match(group(expression(res...)).String() + `+`)
|
|
}
|
|
|
|
// group wraps the regexp in a non-capturing group.
|
|
func group(res ...*regexp.Regexp) *regexp.Regexp {
|
|
return match(`(?:` + expression(res...).String() + `)`)
|
|
}
|
|
|
|
// capture wraps the expression in a capturing group.
|
|
func capture(res ...*regexp.Regexp) *regexp.Regexp {
|
|
return match(`(` + expression(res...).String() + `)`)
|
|
}
|
|
|
|
// anchored anchors the regular expression by adding start and end delimiters.
|
|
func anchored(res ...*regexp.Regexp) *regexp.Regexp {
|
|
return match(`^` + expression(res...).String() + `$`)
|
|
}
|