1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.shared.release.versions;
20
21 import java.util.Arrays;
22 import java.util.List;
23 import java.util.Objects;
24 import java.util.regex.Matcher;
25 import java.util.regex.Pattern;
26
27 import org.apache.maven.artifact.ArtifactUtils;
28 import org.codehaus.plexus.util.StringUtils;
29
30
31
32
33 public class Version implements Comparable<Version>, Cloneable {
34 private final AetherVersion aetherVersion;
35
36 private final MavenArtifactVersion mavenArtifactVersion;
37
38 private final String strVersion;
39
40 private final List<String> digits;
41
42 private String annotation;
43
44 private String annotationRevision;
45
46 private final String buildSpecifier;
47
48 private String annotationSeparator;
49
50 private String annotationRevSeparator;
51
52 private String buildSeparator;
53
54 private static final int DIGITS_INDEX = 1;
55
56 private static final int ANNOTATION_SEPARATOR_INDEX = 2;
57
58 private static final int ANNOTATION_INDEX = 3;
59
60 private static final int ANNOTATION_REV_SEPARATOR_INDEX = 4;
61
62 private static final int ANNOTATION_REVISION_INDEX = 5;
63
64 private static final int BUILD_SEPARATOR_INDEX = 6;
65
66 private static final int BUILD_SPECIFIER_INDEX = 7;
67
68 private static final String SNAPSHOT_IDENTIFIER = "SNAPSHOT";
69
70 private static final String DIGIT_SEPARATOR_STRING = ".";
71
72 private static final String DEFAULT_ANNOTATION_REV_SEPARATOR = "-";
73
74 private static final String DEFAULT_BUILD_SEPARATOR = "-";
75
76
77 public static final Pattern STANDARD_PATTERN = Pattern.compile(
78 "^((?:\\d+\\.)*\\d+)"
79
80
81 + "([-_])?"
82 + "([a-zA-Z]*)"
83 + "([-_])?"
84 + "(\\d*)"
85 + "(?:([-_])?(.*?))?$");
86
87
88
89
90
91
92
93 public static final Pattern ALTERNATE_PATTERN = Pattern.compile("^(SNAPSHOT|[a-zA-Z]+[_-]SNAPSHOT)");
94
95 private Version(
96 List<String> digits,
97 String annotation,
98 String annotationRevision,
99 String buildSpecifier,
100 String annotationSeparator,
101 String annotationRevSeparator,
102 String buildSeparator) {
103 this.digits = digits;
104 this.annotation = annotation;
105 this.annotationRevision = annotationRevision;
106 this.buildSpecifier = buildSpecifier;
107 this.annotationSeparator = annotationSeparator;
108 this.annotationRevSeparator = annotationRevSeparator;
109 this.buildSeparator = buildSeparator;
110 this.strVersion = getVersionString(this, buildSpecifier, buildSeparator);
111
112
113 this.aetherVersion = null;
114 this.mavenArtifactVersion = null;
115 }
116
117
118
119
120
121
122
123 public Version(String version) throws VersionParseException {
124 this.strVersion = version;
125 this.aetherVersion = new AetherVersion(version);
126 this.mavenArtifactVersion = new MavenArtifactVersion(version);
127
128
129 Matcher matcher = ALTERNATE_PATTERN.matcher(strVersion);
130
131 if (matcher.matches()) {
132 annotation = null;
133 digits = null;
134 buildSpecifier = version;
135 buildSeparator = null;
136 return;
137 }
138
139 Matcher m = STANDARD_PATTERN.matcher(strVersion);
140 if (m.matches()) {
141 digits = parseDigits(m.group(DIGITS_INDEX));
142 if (!SNAPSHOT_IDENTIFIER.equals(m.group(ANNOTATION_INDEX))) {
143 annotationSeparator = m.group(ANNOTATION_SEPARATOR_INDEX);
144 annotation = nullIfEmpty(m.group(ANNOTATION_INDEX));
145
146 if (StringUtils.isNotEmpty(m.group(ANNOTATION_REV_SEPARATOR_INDEX))
147 && StringUtils.isEmpty(m.group(ANNOTATION_REVISION_INDEX))) {
148
149 buildSeparator = m.group(ANNOTATION_REV_SEPARATOR_INDEX);
150 buildSpecifier = nullIfEmpty(m.group(BUILD_SPECIFIER_INDEX));
151 } else {
152 annotationRevSeparator = m.group(ANNOTATION_REV_SEPARATOR_INDEX);
153 annotationRevision = nullIfEmpty(m.group(ANNOTATION_REVISION_INDEX));
154
155 buildSeparator = m.group(BUILD_SEPARATOR_INDEX);
156 buildSpecifier = nullIfEmpty(m.group(BUILD_SPECIFIER_INDEX));
157 }
158 } else {
159
160 buildSeparator = m.group(ANNOTATION_SEPARATOR_INDEX);
161 buildSpecifier = nullIfEmpty(m.group(ANNOTATION_INDEX));
162 }
163 } else {
164 throw new VersionParseException("Unable to parse the version string: \"" + version + "\"");
165 }
166 }
167
168
169
170
171
172
173 public boolean isSnapshot() {
174 return ArtifactUtils.isSnapshot(strVersion);
175 }
176
177
178
179
180
181
182 public String toString() {
183 return strVersion;
184 }
185
186
187
188
189
190
191
192
193
194 protected static String getVersionString(Version info, String buildSpecifier, String buildSeparator) {
195 StringBuilder sb = new StringBuilder();
196
197 if (info.digits != null) {
198 sb.append(joinDigitString(info.digits));
199 }
200
201 if (info.annotation != null && !info.annotation.isEmpty()) {
202 sb.append(StringUtils.defaultString(info.annotationSeparator));
203 sb.append(info.annotation);
204 }
205
206 if (info.annotationRevision != null && !info.annotationRevision.isEmpty()) {
207 if (info.annotation == null || info.annotation.isEmpty()) {
208 sb.append(StringUtils.defaultString(info.annotationSeparator));
209 } else {
210 sb.append(StringUtils.defaultString(info.annotationRevSeparator));
211 }
212 sb.append(info.annotationRevision);
213 }
214
215 if (buildSpecifier != null && !buildSpecifier.isEmpty()) {
216 sb.append(StringUtils.defaultString(buildSeparator));
217 sb.append(buildSpecifier);
218 }
219
220 return sb.toString();
221 }
222
223
224
225
226
227
228
229 protected static String joinDigitString(List<String> digits) {
230 return digits != null ? StringUtils.join(digits.iterator(), DIGIT_SEPARATOR_STRING) : null;
231 }
232
233
234
235
236
237
238 private List<String> parseDigits(String strDigits) {
239 return Arrays.asList(StringUtils.split(strDigits, DIGIT_SEPARATOR_STRING));
240 }
241
242 private static String nullIfEmpty(String s) {
243 return (s == null || s.isEmpty()) ? null : s;
244 }
245
246
247
248
249
250
251 public List<String> getDigits() {
252 return digits;
253 }
254
255
256
257
258
259
260 public String getAnnotation() {
261 return annotation;
262 }
263
264
265
266
267
268
269 public String getAnnotationRevSeparator() {
270 return annotationRevSeparator;
271 }
272
273
274
275
276
277
278 public String getAnnotationRevision() {
279 return annotationRevision;
280 }
281
282
283
284
285
286
287 public String getBuildSeparator() {
288 return buildSeparator;
289 }
290
291
292
293
294
295
296 public String getBuildSpecifier() {
297 return buildSpecifier;
298 }
299
300
301
302
303
304
305
306 public Version setDigits(List<String> newDigits) {
307 return new Version(
308 newDigits,
309 this.annotation,
310 this.annotationRevision,
311 this.buildSpecifier,
312 this.annotationSeparator,
313 this.annotationRevSeparator,
314 this.buildSeparator);
315 }
316
317
318
319
320
321
322
323 public Version setAnnotationRevision(String newAnnotationRevision) {
324 return new Version(
325 this.digits,
326 this.annotation,
327 newAnnotationRevision,
328 this.buildSpecifier,
329 this.annotationSeparator,
330 Objects.toString(this.annotationRevSeparator, DEFAULT_ANNOTATION_REV_SEPARATOR),
331 this.buildSeparator);
332 }
333
334
335
336
337
338
339
340 public Version setBuildSpecifier(String newBuildSpecifier) {
341 return new Version(
342 this.digits,
343 this.annotation,
344 this.annotationRevision,
345 newBuildSpecifier,
346 this.annotationSeparator,
347 this.annotationRevSeparator,
348 Objects.toString(this.buildSeparator, DEFAULT_BUILD_SEPARATOR));
349 }
350
351
352
353
354
355
356
357
358
359
360 public int compareTo(Version other) throws VersionComparisonConflictException {
361 int aetherComparisonResult = this.aetherVersion.compareTo(other.aetherVersion);
362 int mavenComparisonResult = this.mavenArtifactVersion.compareTo(other.mavenArtifactVersion);
363
364 if (aetherComparisonResult < 0 && mavenComparisonResult < 0) {
365 return -1;
366 } else if (aetherComparisonResult == 0 && mavenComparisonResult == 0) {
367 return 0;
368 } else if (aetherComparisonResult > 0 && mavenComparisonResult > 0) {
369 return 1;
370 } else {
371 throw new VersionComparisonConflictException(
372 this.strVersion, other.strVersion, aetherComparisonResult, mavenComparisonResult);
373 }
374 }
375 }