forked from TrueCloudLab/distribution
Add reference.ParseDockerRef utility function
ParseDockerRef normalizes the image reference following the docker convention. This is added mainly for backward compatibility. The reference returned can only be either tagged or digested. For reference contains both tag and digest, the function returns digested reference, e.g. docker.io/library/busybox:latest@sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa will be returned as docker.io/library/busybox@sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa. Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
parent
40b7b5830a
commit
0ac367fd6b
2 changed files with 109 additions and 0 deletions
|
@ -56,6 +56,35 @@ func ParseNormalizedNamed(s string) (Named, error) {
|
||||||
return named, nil
|
return named, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseDockerRef normalizes the image reference following the docker convention. This is added
|
||||||
|
// mainly for backward compatibility.
|
||||||
|
// The reference returned can only be either tagged or digested. For reference contains both tag
|
||||||
|
// and digest, the function returns digested reference, e.g. docker.io/library/busybox:latest@
|
||||||
|
// sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa will be returned as
|
||||||
|
// docker.io/library/busybox@sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa.
|
||||||
|
func ParseDockerRef(ref string) (Named, error) {
|
||||||
|
named, err := ParseNormalizedNamed(ref)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if _, ok := named.(NamedTagged); ok {
|
||||||
|
if canonical, ok := named.(Canonical); ok {
|
||||||
|
// The reference is both tagged and digested, only
|
||||||
|
// return digested.
|
||||||
|
newNamed, err := WithName(canonical.Name())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
newCanonical, err := WithDigest(newNamed, canonical.Digest())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return newCanonical, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TagNameOnly(named), nil
|
||||||
|
}
|
||||||
|
|
||||||
// splitDockerDomain splits a repository name to domain and remotename string.
|
// splitDockerDomain splits a repository name to domain and remotename string.
|
||||||
// If no valid domain is found, the default domain is used. Repository name
|
// If no valid domain is found, the default domain is used. Repository name
|
||||||
// needs to be already validated before.
|
// needs to be already validated before.
|
||||||
|
|
|
@ -623,3 +623,83 @@ func TestMatch(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParseDockerRef(t *testing.T) {
|
||||||
|
testcases := []struct {
|
||||||
|
name string
|
||||||
|
input string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "nothing",
|
||||||
|
input: "busybox",
|
||||||
|
expected: "docker.io/library/busybox:latest",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "tag only",
|
||||||
|
input: "busybox:latest",
|
||||||
|
expected: "docker.io/library/busybox:latest",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "digest only",
|
||||||
|
input: "busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582",
|
||||||
|
expected: "docker.io/library/busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "path only",
|
||||||
|
input: "library/busybox",
|
||||||
|
expected: "docker.io/library/busybox:latest",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "hostname only",
|
||||||
|
input: "docker.io/busybox",
|
||||||
|
expected: "docker.io/library/busybox:latest",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no tag",
|
||||||
|
input: "docker.io/library/busybox",
|
||||||
|
expected: "docker.io/library/busybox:latest",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no path",
|
||||||
|
input: "docker.io/busybox:latest",
|
||||||
|
expected: "docker.io/library/busybox:latest",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no hostname",
|
||||||
|
input: "library/busybox:latest",
|
||||||
|
expected: "docker.io/library/busybox:latest",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "full reference with tag",
|
||||||
|
input: "docker.io/library/busybox:latest",
|
||||||
|
expected: "docker.io/library/busybox:latest",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "gcr reference without tag",
|
||||||
|
input: "gcr.io/library/busybox",
|
||||||
|
expected: "gcr.io/library/busybox:latest",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "both tag and digest",
|
||||||
|
input: "gcr.io/library/busybox:latest@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582",
|
||||||
|
expected: "gcr.io/library/busybox@sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range testcases {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
normalized, err := ParseDockerRef(test.input)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
output := normalized.String()
|
||||||
|
if output != test.expected {
|
||||||
|
t.Fatalf("expected %q to be parsed as %v, got %v", test.input, test.expected, output)
|
||||||
|
}
|
||||||
|
_, err = Parse(output)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("%q should be a valid reference, but got an error: %v", output, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue