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.ArrayList;
22 import java.util.Arrays;
23 import java.util.List;
24 import java.util.Locale;
25 import java.util.Objects;
26 import java.util.regex.Matcher;
27 import java.util.regex.Pattern;
28
29 import org.apache.maven.artifact.Artifact;
30 import org.apache.maven.artifact.ArtifactUtils;
31 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
32 import org.codehaus.plexus.util.StringUtils;
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 public class DefaultVersionInfo implements VersionInfo {
58 private final String strVersion;
59
60 private final List<String> digits;
61
62 private String annotation;
63
64 private String annotationRevision;
65
66 private final String buildSpecifier;
67
68 private String annotationSeparator;
69
70 private String annotationRevSeparator;
71
72 private final String buildSeparator;
73
74 private static final int DIGITS_INDEX = 1;
75
76 private static final int ANNOTATION_SEPARATOR_INDEX = 2;
77
78 private static final int ANNOTATION_INDEX = 3;
79
80 private static final int ANNOTATION_REV_SEPARATOR_INDEX = 4;
81
82 private static final int ANNOTATION_REVISION_INDEX = 5;
83
84 private static final int BUILD_SEPARATOR_INDEX = 6;
85
86 private static final int BUILD_SPECIFIER_INDEX = 7;
87
88 private static final String SNAPSHOT_IDENTIFIER = "SNAPSHOT";
89
90 private static final String DIGIT_SEPARATOR_STRING = ".";
91
92
93 public static final Pattern STANDARD_PATTERN = Pattern.compile(
94 "^((?:\\d+\\.)*\\d+)"
95 + "([-_])?"
96 + "([a-zA-Z]*)"
97 + "([-_])?"
98 + "(\\d*)"
99 + "(?:([-_])?(.*?))?$");
100
101
102
103
104
105
106
107
108
109
110
111 public static final Pattern ALTERNATE_PATTERN = Pattern.compile("^(SNAPSHOT|[a-zA-Z]+[_-]SNAPSHOT)");
112
113
114
115
116
117
118
119 public DefaultVersionInfo(String version) throws VersionParseException {
120 strVersion = version;
121
122
123 Matcher matcher = ALTERNATE_PATTERN.matcher(strVersion);
124
125 if (matcher.matches()) {
126 annotation = null;
127 digits = null;
128 buildSpecifier = version;
129 buildSeparator = null;
130 return;
131 }
132
133 Matcher m = STANDARD_PATTERN.matcher(strVersion);
134 if (m.matches()) {
135 digits = parseDigits(m.group(DIGITS_INDEX));
136 if (!SNAPSHOT_IDENTIFIER.equals(m.group(ANNOTATION_INDEX))) {
137 annotationSeparator = m.group(ANNOTATION_SEPARATOR_INDEX);
138 annotation = nullIfEmpty(m.group(ANNOTATION_INDEX));
139
140 if (StringUtils.isNotEmpty(m.group(ANNOTATION_REV_SEPARATOR_INDEX))
141 && StringUtils.isEmpty(m.group(ANNOTATION_REVISION_INDEX))) {
142
143 buildSeparator = m.group(ANNOTATION_REV_SEPARATOR_INDEX);
144 buildSpecifier = nullIfEmpty(m.group(BUILD_SPECIFIER_INDEX));
145 } else {
146 annotationRevSeparator = m.group(ANNOTATION_REV_SEPARATOR_INDEX);
147 annotationRevision = nullIfEmpty(m.group(ANNOTATION_REVISION_INDEX));
148
149 buildSeparator = m.group(BUILD_SEPARATOR_INDEX);
150 buildSpecifier = nullIfEmpty(m.group(BUILD_SPECIFIER_INDEX));
151 }
152 } else {
153
154 buildSeparator = m.group(ANNOTATION_SEPARATOR_INDEX);
155 buildSpecifier = nullIfEmpty(m.group(ANNOTATION_INDEX));
156 }
157 } else {
158 throw new VersionParseException("Unable to parse the version string: \"" + version + "\"");
159 }
160 }
161
162
163
164
165
166
167
168
169
170
171
172
173 public DefaultVersionInfo(
174 List<String> digits,
175 String annotation,
176 String annotationRevision,
177 String buildSpecifier,
178 String annotationSeparator,
179 String annotationRevSeparator,
180 String buildSeparator) {
181 this.digits = digits;
182 this.annotation = annotation;
183 this.annotationRevision = annotationRevision;
184 this.buildSpecifier = buildSpecifier;
185 this.annotationSeparator = annotationSeparator;
186 this.annotationRevSeparator = annotationRevSeparator;
187 this.buildSeparator = buildSeparator;
188 this.strVersion = getVersionString(this, buildSpecifier, buildSeparator);
189 }
190
191 @Override
192 public boolean isSnapshot() {
193 return ArtifactUtils.isSnapshot(strVersion);
194 }
195
196 @Override
197 public VersionInfo getNextVersion() {
198 DefaultVersionInfo version = null;
199 if (digits != null) {
200 List<String> digits = new ArrayList<>(this.digits);
201 String annotationRevision = this.annotationRevision;
202 if (StringUtils.isNumeric(annotationRevision)) {
203 annotationRevision = incrementVersionString(annotationRevision);
204 } else {
205 digits.set(digits.size() - 1, incrementVersionString(digits.get(digits.size() - 1)));
206 }
207
208 version = new DefaultVersionInfo(
209 digits,
210 annotation,
211 annotationRevision,
212 buildSpecifier,
213 annotationSeparator,
214 annotationRevSeparator,
215 buildSeparator);
216 }
217 return version;
218 }
219
220
221
222
223
224
225
226 @Override
227 public int compareTo(VersionInfo obj) {
228 DefaultVersionInfo that = (DefaultVersionInfo) obj;
229
230 int result;
231
232 if (strVersion.startsWith(that.strVersion)
233 && !strVersion.equals(that.strVersion)
234 && strVersion.charAt(that.strVersion.length()) != '-') {
235 result = 1;
236 } else if (that.strVersion.startsWith(strVersion)
237 && !strVersion.equals(that.strVersion)
238 && that.strVersion.charAt(strVersion.length()) != '-') {
239 result = -1;
240 } else {
241
242
243
244 String thisVersion = strVersion.toUpperCase(Locale.ENGLISH).toLowerCase(Locale.ENGLISH);
245 String thatVersion = that.strVersion.toUpperCase(Locale.ENGLISH).toLowerCase(Locale.ENGLISH);
246
247 result = new DefaultArtifactVersion(thisVersion).compareTo(new DefaultArtifactVersion(thatVersion));
248 }
249 return result;
250 }
251
252 @Override
253 public boolean equals(Object obj) {
254 if (!(obj instanceof DefaultVersionInfo)) {
255 return false;
256 }
257
258 return compareTo((VersionInfo) obj) == 0;
259 }
260
261 @Override
262 public int hashCode() {
263 return strVersion.toLowerCase(Locale.ENGLISH).hashCode();
264 }
265
266
267
268
269
270
271
272
273
274 protected String incrementVersionString(String s) {
275 int n = Integer.valueOf(s).intValue() + 1;
276 String value = String.valueOf(n);
277 if (value.length() < s.length()) {
278
279 value = StringUtils.leftPad(value, s.length(), "0");
280 }
281 return value;
282 }
283
284 @Override
285 public String getSnapshotVersionString() {
286 if (strVersion.equals(Artifact.SNAPSHOT_VERSION)) {
287 return strVersion;
288 }
289
290 String baseVersion = getReleaseVersionString();
291
292 if (baseVersion.length() > 0) {
293 baseVersion += "-";
294 }
295
296 return baseVersion + Artifact.SNAPSHOT_VERSION;
297 }
298
299 @Override
300 public String getReleaseVersionString() {
301 String baseVersion = strVersion;
302
303 Matcher m = Artifact.VERSION_FILE_PATTERN.matcher(baseVersion);
304 if (m.matches()) {
305 baseVersion = m.group(1);
306 }
307
308 else if (StringUtils.right(baseVersion, 9).equalsIgnoreCase("-" + Artifact.SNAPSHOT_VERSION)) {
309 baseVersion = baseVersion.substring(0, baseVersion.length() - Artifact.SNAPSHOT_VERSION.length() - 1);
310 } else if (baseVersion.equals(Artifact.SNAPSHOT_VERSION)) {
311 baseVersion = "1.0";
312 }
313 return baseVersion;
314 }
315
316 @Override
317 public String toString() {
318 return strVersion;
319 }
320
321
322
323
324
325
326
327
328
329 protected static String getVersionString(DefaultVersionInfo info, String buildSpecifier, String buildSeparator) {
330 StringBuilder sb = new StringBuilder();
331
332 if (info.digits != null) {
333 sb.append(joinDigitString(info.digits));
334 }
335
336 if (info.annotation != null && !info.annotation.isEmpty()) {
337 sb.append(Objects.toString(info.annotationSeparator, ""));
338 sb.append(info.annotation);
339 }
340
341 if (info.annotationRevision != null && !info.annotationRevision.isEmpty()) {
342 if (info.annotation == null || info.annotation.isEmpty()) {
343 sb.append(Objects.toString(info.annotationSeparator, ""));
344 } else {
345 sb.append(Objects.toString(info.annotationRevSeparator, ""));
346 }
347 sb.append(info.annotationRevision);
348 }
349
350 if (buildSpecifier != null && !buildSpecifier.isEmpty()) {
351 sb.append(Objects.toString(buildSeparator, ""));
352 sb.append(buildSpecifier);
353 }
354
355 return sb.toString();
356 }
357
358
359
360
361
362
363
364 protected static String joinDigitString(List<String> digits) {
365 return digits != null ? StringUtils.join(digits.iterator(), DIGIT_SEPARATOR_STRING) : null;
366 }
367
368
369
370
371
372
373
374 private List<String> parseDigits(String strDigits) {
375 return Arrays.asList(StringUtils.split(strDigits, DIGIT_SEPARATOR_STRING));
376 }
377
378
379
380
381
382 private static String nullIfEmpty(String s) {
383 return (s == null || s.isEmpty()) ? null : s;
384 }
385
386
387
388
389
390
391 public List<String> getDigits() {
392 return digits;
393 }
394
395
396
397
398
399
400 public String getAnnotation() {
401 return annotation;
402 }
403
404
405
406
407
408
409 public String getAnnotationRevision() {
410 return annotationRevision;
411 }
412
413
414
415
416
417
418 public String getBuildSpecifier() {
419 return buildSpecifier;
420 }
421 }