Allow single character repository names

The main goal of this changeset is to allow repository name components to
consist of a single character. The number of components allowed and the slash
separation requirements have also been clarified.

To go along with this simplification, errant constants and unneeded error types
have been removed.

Signed-off-by: Stephen J Day <stephen.day@docker.com>
This commit is contained in:
Stephen J Day 2015-07-10 12:00:06 -06:00
parent 5ea13fc549
commit a58848a0b7
3 changed files with 37 additions and 36 deletions

View file

@ -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
}

View file

@ -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()
}

View file

@ -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()
}
}