1 package com.aragost.javahg;
2
3 import com.google.common.collect.ComparisonChain;
4 import com.google.common.collect.Ordering;
5
6
7
8
9
10
11
12
13
14
15 public class HgVersion implements Comparable<HgVersion> {
16
17 private static final HgVersion UNKNOWN = new HgVersion(null);
18
19 private final String versionString;
20
21 private final byte major;
22
23 private final byte minor;
24
25 private final Integer release;
26
27 private final boolean releaseCandidate;
28
29 private final String suffix;
30
31
32
33
34
35
36 private HgVersion(String versionString) {
37 if (versionString == null) {
38 this.versionString = "unknown";
39 this.major = 0;
40 this.minor = 0;
41 this.release = 0;
42 this.releaseCandidate = false;
43 this.suffix = null;
44 } else {
45 this.versionString = versionString;
46 int pos = versionString.indexOf('.');
47
48
49
50 if (pos != 1 && pos != 2) {
51 throw new IllegalArgumentException();
52 }
53 this.major = parseInt(versionString.substring(0, pos));
54
55 String rest = versionString.substring(pos + 1);
56 pos = indexOfFirstNonDigit(rest);
57 this.minor = parseInt(rest.substring(0, pos));
58 if (rest.length() > pos && rest.charAt(pos) == '.') {
59 rest = rest.substring(pos + 1);
60 pos = indexOfFirstNonDigit(rest);
61 this.release = Integer.valueOf(parseInt(rest.substring(0, pos)));
62 } else {
63 this.release = null;
64 }
65 rest = rest.substring(pos);
66
67 this.releaseCandidate = rest.startsWith("-rc+") || rest.equals("-rc");
68
69 if (this.releaseCandidate) {
70 rest = rest.substring(3);
71 }
72 if (rest.length() != 0) {
73 if (rest.charAt(0) != '+') {
74 throw new IllegalArgumentException();
75 }
76 this.suffix = rest.substring(1);
77 } else {
78 this.suffix = null;
79 }
80 }
81 }
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97 public static HgVersion fromString(String versionString) {
98 if (versionString == null) {
99 throw new IllegalArgumentException();
100 }
101 return new HgVersion(versionString);
102 }
103
104
105
106
107 public static HgVersion unknown() {
108 return UNKNOWN;
109 }
110
111
112
113
114 public String getVersionString() {
115 return versionString;
116 }
117
118
119
120
121
122 public int getMajor() {
123 return major;
124 }
125
126
127
128
129
130 public int getMinor() {
131 return minor;
132 }
133
134
135
136
137
138 public Integer getRelease() {
139 return release;
140 }
141
142
143
144
145
146
147 public boolean isReleaseCandidate() {
148 return releaseCandidate;
149 }
150
151
152
153
154
155 public String getSuffix() {
156 return suffix;
157 }
158
159
160
161
162
163 public boolean isUnknown() {
164 return this.equals(UNKNOWN);
165 }
166
167
168
169
170
171
172 public int compareTo(HgVersion that) {
173 if (that.equals(UNKNOWN) || this.equals(UNKNOWN)) {
174 throw new IllegalArgumentException();
175 }
176
177
178 return ComparisonChain.start().compare(this.major, that.major).compare(this.minor, that.minor).compare(
179 this.release, that.release, Ordering.natural().nullsFirst()).compare(that.releaseCandidate,
180 this.releaseCandidate).result();
181 }
182
183
184
185
186
187
188
189 public boolean isBefore(HgVersion ver) {
190 return this.compareTo(ver) < 0;
191 }
192
193 @Override
194 public String toString() {
195 return this.versionString;
196 }
197
198
199
200
201
202
203
204
205
206 private int indexOfFirstNonDigit(String s) {
207 int length = s.length();
208 for (int i = 0; i < length; i++) {
209 if (!Character.isDigit(s.charAt(i))) {
210 return i;
211 }
212 }
213 return length;
214 }
215
216
217
218
219
220
221
222
223
224
225 private byte parseInt(String s) {
226 int length = s.length();
227 if (length == 0 || length > 2) {
228 throw new IllegalArgumentException();
229 }
230 int result = 0;
231 for (int i = 0; i < length; i++) {
232 if (Character.isDigit(s.charAt(i))) {
233 result = result * 10 + s.charAt(i) - '0';
234 } else {
235 throw new IllegalArgumentException();
236 }
237 }
238 return (byte) result;
239 }
240
241 }