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