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