-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
DockerImageName.java
181 lines (153 loc) · 5.22 KB
/
DockerImageName.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
package org.testcontainers.utility;
import com.google.common.net.HostAndPort;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.regex.Pattern;
@EqualsAndHashCode
public final class DockerImageName {
/* Regex patterns used for validation */
private static final String ALPHA_NUMERIC = "[a-z0-9]+";
private static final String SEPARATOR = "([\\.]{1}|_{1,2}|-+)";
private static final String REPO_NAME_PART = ALPHA_NUMERIC + "(" + SEPARATOR + ALPHA_NUMERIC + ")*";
private static final Pattern REPO_NAME = Pattern.compile(REPO_NAME_PART + "(/" + REPO_NAME_PART + ")*");
private final String rawName;
private final String registry;
private final String repo;
private final Versioning versioning;
public DockerImageName(String name) {
this.rawName = name;
final int slashIndex = name.indexOf('/');
String remoteName;
if (slashIndex == -1 ||
(!name.substring(0, slashIndex).contains(".") &&
!name.substring(0, slashIndex).contains(":") &&
!name.substring(0, slashIndex).equals("localhost"))) {
registry = "";
remoteName = name;
} else {
registry = name.substring(0, slashIndex);
remoteName = name.substring(slashIndex + 1);
}
if (remoteName.contains("@sha256:")) {
repo = remoteName.split("@sha256:")[0];
versioning = new Sha256Versioning(remoteName.split("@sha256:")[1]);
} else if (remoteName.contains(":")) {
repo = remoteName.split(":")[0];
versioning = new TagVersioning(remoteName.split(":")[1]);
} else {
repo = remoteName;
versioning = new TagVersioning("latest");
}
}
public DockerImageName(String name, String tag) {
this.rawName = name;
final int slashIndex = name.indexOf('/');
String remoteName;
if (slashIndex == -1 ||
(!name.substring(0, slashIndex).contains(".") &&
!name.substring(0, slashIndex).contains(":") &&
!name.substring(0, slashIndex).equals("localhost"))) {
registry = "";
remoteName = name;
} else {
registry = name.substring(0, slashIndex - 1);
remoteName = name.substring(slashIndex + 1);
}
if (tag.startsWith("sha256:")) {
repo = remoteName;
versioning = new Sha256Versioning(tag);
} else {
repo = remoteName;
versioning = new TagVersioning(tag);
}
}
/**
* @return the unversioned (non 'tag') part of this name
*/
public String getUnversionedPart() {
if (!"".equals(registry)) {
return registry + "/" + repo;
} else {
return repo;
}
}
/**
* @return the versioned part of this name (tag or sha256)
*/
public String getVersionPart() {
return versioning.toString();
}
@Override
public String toString() {
if (versioning == null) {
return getUnversionedPart();
} else {
return getUnversionedPart() + versioning.getSeparator() + versioning.toString();
}
}
/**
* Is the image name valid?
*
* @throws IllegalArgumentException if not valid
*/
public void assertValid() {
HostAndPort.fromString(registry);
if (!REPO_NAME.matcher(repo).matches()) {
throw new IllegalArgumentException(repo + " is not a valid Docker image name (in " + rawName + ")");
}
if (versioning == null) {
throw new IllegalArgumentException("No image tag was specified in docker image name " +
"(" + rawName + "). Please provide a tag; this may be 'latest' or a specific version");
}
if (!versioning.isValid()) {
throw new IllegalArgumentException(versioning + " is not a valid image versioning identifier (in " + rawName + ")");
}
}
public String getRegistry() {
return registry;
}
private interface Versioning {
boolean isValid();
String getSeparator();
}
@Data
private static class TagVersioning implements Versioning {
public static final String TAG_REGEX = "[\\w][\\w\\.\\-]{0,127}";
private final String tag;
TagVersioning(String tag) {
this.tag = tag;
}
@Override
public boolean isValid() {
return tag.matches(TAG_REGEX);
}
@Override
public String getSeparator() {
return ":";
}
@Override
public String toString() {
return tag;
}
}
@Data
private class Sha256Versioning implements Versioning {
public static final String HASH_REGEX = "[0-9a-fA-F]{32,}";
private final String hash;
Sha256Versioning(String hash) {
this.hash = hash;
}
@Override
public boolean isValid() {
return hash.matches(HASH_REGEX);
}
@Override
public String getSeparator() {
return "@";
}
@Override
public String toString() {
return "sha256:" + hash;
}
}
}