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>
			
			
				master
			
			
		
							parent
							
								
									40b7b5830a
								
							
						
					
					
						commit
						0ac367fd6b
					
				|  | @ -56,6 +56,35 @@ func ParseNormalizedNamed(s string) (Named, error) { | |||
| 	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.
 | ||||
| // If no valid domain is found, the default domain is used. Repository name
 | ||||
| // 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 New Issue