diff --git a/docs/spec/api.md b/docs/spec/api.md
index 5196d05c5..483f15f03 100644
--- a/docs/spec/api.md
+++ b/docs/spec/api.md
@@ -120,6 +120,12 @@ indicating what is different. Optionally, we may start marking parts of the
specification to correspond with the versions enumerated here.
+ - 2.0.3
+ -
+
- Allow repository name components to be one character.
+ - Clarified that single component names are allowed.
+
+
- 2.0.2
-
- Added section covering digest format.
@@ -174,12 +180,11 @@ path component is less than 30 characters. The V2 registry API does not
enforce this. The rules for a repository name are as follows:
1. A repository name is broken up into _path components_. A component of a
- repository name must be at least two lowercase, alpha-numeric characters,
+ repository name must be at least one lowercase, alpha-numeric characters,
optionally separated by periods, dashes or underscores. More strictly, it
- must match the regular expression `[a-z0-9]+(?:[._-][a-z0-9]+)*` and the
- matched result must be 2 or more characters in length.
-2. The name of a repository must have at least two path components, separated
- by a forward slash.
+ must match the regular expression `[a-z0-9]+(?:[._-][a-z0-9]+)*`.
+2. If a repository name has two or more path components, they must be
+ separated by a forward slash ("/").
3. The total length of a repository name, including slashes, must be less the
256 characters.
diff --git a/docs/spec/api.md.tmpl b/docs/spec/api.md.tmpl
index 878f0e4da..bc6d6f926 100644
--- a/docs/spec/api.md.tmpl
+++ b/docs/spec/api.md.tmpl
@@ -120,6 +120,12 @@ indicating what is different. Optionally, we may start marking parts of the
specification to correspond with the versions enumerated here.
+ - 2.0.3
+ -
+
- Allow repository name components to be one character.
+ - Clarified that single component names are allowed.
+
+
- 2.0.2
-
- Added section covering digest format.
@@ -174,12 +180,11 @@ path component is less than 30 characters. The V2 registry API does not
enforce this. The rules for a repository name are as follows:
1. A repository name is broken up into _path components_. A component of a
- repository name must be at least two lowercase, alpha-numeric characters,
+ repository name must be at least one lowercase, alpha-numeric characters,
optionally separated by periods, dashes or underscores. More strictly, it
- must match the regular expression `[a-z0-9]+(?:[._-][a-z0-9]+)*` and the
- matched result must be 2 or more characters in length.
-2. The name of a repository must have at least two path components, separated
- by a forward slash.
+ must match the regular expression `[a-z0-9]+(?:[._-][a-z0-9]+)*`.
+2. If a repository name has two or more path components, they must be
+ separated by a forward slash ("/").
3. The total length of a repository name, including slashes, must be less the
256 characters.
diff --git a/registry/api/v2/names.go b/registry/api/v2/names.go
index 19cb72a02..14b7ea60a 100644
--- a/registry/api/v2/names.go
+++ b/registry/api/v2/names.go
@@ -6,19 +6,10 @@ import (
"strings"
)
-// TODO(stevvooe): Move these definitions back to an exported package. While
-// they are used with v2 definitions, their relevance expands beyond.
-// "distribution/names" is a candidate package.
+// TODO(stevvooe): Move these definitions to the future "reference" package.
+// While they are used with v2 definitions, their relevance expands beyond.
const (
- // RepositoryNameComponentMinLength is the minimum number of characters in a
- // single repository name slash-delimited component
- RepositoryNameComponentMinLength = 2
-
- // RepositoryNameMinComponents is the minimum number of slash-delimited
- // components that a repository name must have
- RepositoryNameMinComponents = 1
-
// RepositoryNameTotalLengthMax is the maximum total number of characters in
// a repository name
RepositoryNameTotalLengthMax = 255
@@ -40,17 +31,13 @@ var RepositoryNameRegexp = regexp.MustCompile(`(?:` + RepositoryNameComponentReg
// TagNameRegexp matches valid tag names. From docker/docker:graph/tags.go.
var TagNameRegexp = regexp.MustCompile(`[\w][\w.-]{0,127}`)
-// TODO(stevvooe): Contribute these exports back to core, so they are shared.
+// TagNameAnchoredRegexp matches valid tag names, anchored at the start and
+// end of the matched string.
+var TagNameAnchoredRegexp = regexp.MustCompile("^" + TagNameRegexp.String() + "$")
var (
- // ErrRepositoryNameComponentShort is returned when a repository name
- // contains a component which is shorter than
- // RepositoryNameComponentMinLength
- ErrRepositoryNameComponentShort = fmt.Errorf("repository name component must be %v or more characters", RepositoryNameComponentMinLength)
-
- // ErrRepositoryNameMissingComponents is returned when a repository name
- // contains fewer than RepositoryNameMinComponents components
- ErrRepositoryNameMissingComponents = fmt.Errorf("repository name must have at least %v components", RepositoryNameMinComponents)
+ // ErrRepositoryNameEmpty is returned for empty, invalid repository names.
+ ErrRepositoryNameEmpty = fmt.Errorf("repository name must have at least one component")
// ErrRepositoryNameLong is returned when a repository name is longer than
// RepositoryNameTotalLengthMax
@@ -76,21 +63,17 @@ var (
// The result of the production, known as the "namespace", should be limited
// to 255 characters.
func ValidateRepositoryName(name string) error {
+ if name == "" {
+ return ErrRepositoryNameEmpty
+ }
+
if len(name) > RepositoryNameTotalLengthMax {
return ErrRepositoryNameLong
}
components := strings.Split(name, "/")
- if len(components) < RepositoryNameMinComponents {
- return ErrRepositoryNameMissingComponents
- }
-
for _, component := range components {
- if len(component) < RepositoryNameComponentMinLength {
- return ErrRepositoryNameComponentShort
- }
-
if !RepositoryNameComponentAnchoredRegexp.MatchString(component) {
return ErrRepositoryNameComponentInvalid
}
diff --git a/registry/api/v2/names_test.go b/registry/api/v2/names_test.go
index 0975fb7c8..51e0ba8b3 100644
--- a/registry/api/v2/names_test.go
+++ b/registry/api/v2/names_test.go
@@ -1,6 +1,7 @@
package v2
import (
+ "strconv"
"strings"
"testing"
)
@@ -10,6 +11,10 @@ func TestRepositoryNameRegexp(t *testing.T) {
input string
err error
}{
+ {
+ input: "",
+ err: ErrRepositoryNameEmpty,
+ },
{
input: "short",
},
@@ -30,11 +35,26 @@ func TestRepositoryNameRegexp(t *testing.T) {
},
{
input: "a/a/a/b/b",
- err: ErrRepositoryNameComponentShort,
},
{
input: "a/a/a/a/",
- err: ErrRepositoryNameComponentShort,
+ err: ErrRepositoryNameComponentInvalid,
+ },
+ {
+ input: "a//a/a",
+ err: ErrRepositoryNameComponentInvalid,
+ },
+ {
+ input: "a",
+ },
+ {
+ input: "a/aa",
+ },
+ {
+ input: "aa/a",
+ },
+ {
+ input: "a/aa/a",
},
{
input: "foo.com/bar/baz",
@@ -58,10 +78,6 @@ func TestRepositoryNameRegexp(t *testing.T) {
{
input: "a-a/a-a",
},
- {
- input: "a",
- err: ErrRepositoryNameComponentShort,
- },
{
input: "a-/a/a/a",
err: ErrRepositoryNameComponentInvalid,
@@ -110,9 +126,8 @@ func TestRepositoryNameRegexp(t *testing.T) {
err: ErrRepositoryNameComponentInvalid,
},
} {
-
failf := func(format string, v ...interface{}) {
- t.Logf(testcase.input+": "+format, v...)
+ t.Logf(strconv.Quote(testcase.input)+": "+format, v...)
t.Fail()
}
diff --git a/registry/api/v2/routes_test.go b/registry/api/v2/routes_test.go
index fb268336f..9fd29a4f5 100644
--- a/registry/api/v2/routes_test.go
+++ b/registry/api/v2/routes_test.go
@@ -263,6 +263,7 @@ func checkTestRouter(t *testing.T, testCases []routeTestCase, prefix string, dee
}
if testcase.StatusCode != http.StatusOK {
+ resp.Body.Close()
// We don't care about json response.
continue
}
@@ -291,6 +292,8 @@ func checkTestRouter(t *testing.T, testCases []routeTestCase, prefix string, dee
if deeplyEqual && !reflect.DeepEqual(actualRouteInfo, testcase) {
t.Fatalf("actual does not equal expected: %#v != %#v", actualRouteInfo, testcase)
}
+
+ resp.Body.Close()
}
}