2f10c5eba8f982076737543002b9a3f0176596e2
[nikiroo-utils.git] / src / be / nikiroo / utils / Version.java
1 package be.nikiroo.utils;
2
3 import java.io.ByteArrayOutputStream;
4 import java.io.IOException;
5 import java.io.InputStream;
6
7 /**
8 * This class describe a program {@link Version}.
9 *
10 * @author niki
11 */
12 public class Version implements Comparable<Version> {
13 private String version;
14 private int major;
15 private int minor;
16 private int patch;
17 private String tag;
18 private int tagVersion;
19
20 /**
21 * Create a new, empty {@link Version}.
22 *
23 */
24 public Version() {
25 }
26
27 /**
28 * Create a new {@link Version} with the given values.
29 *
30 * @param major
31 * the major version
32 * @param minor
33 * the minor version
34 * @param patch
35 * the patch version
36 */
37 public Version(int major, int minor, int patch) {
38 this(major, minor, patch, null, -1);
39 }
40
41 /**
42 * Create a new {@link Version} with the given values.
43 *
44 * @param major
45 * the major version
46 * @param minor
47 * the minor version
48 * @param patch
49 * the patch version
50 * @param tag
51 * a tag name for this version
52 */
53 public Version(int major, int minor, int patch, String tag) {
54 this(major, minor, patch, tag, -1);
55 }
56
57 /**
58 * Create a new {@link Version} with the given values.
59 *
60 * @param major
61 * the major version
62 * @param minor
63 * the minor version
64 * @param patch
65 * the patch version the patch version
66 * @param tag
67 * a tag name for this version
68 * @param tagVersion
69 * the version of the tagged version
70 */
71 public Version(int major, int minor, int patch, String tag, int tagVersion) {
72 if (tagVersion >= 0 && tag == null) {
73 throw new java.lang.IllegalArgumentException(
74 "A tag version cannot be used without a tag");
75 }
76
77 this.major = major;
78 this.minor = minor;
79 this.patch = patch;
80 this.tag = tag;
81 this.tagVersion = tagVersion;
82
83 String tagSuffix = "";
84 if (tag != null) {
85 tagSuffix = "-" + tag
86 + (tagVersion >= 0 ? Integer.toString(tagVersion) : "");
87 }
88
89 this.version = String.format("%d.%d.%d%s", major, minor, patch,
90 tagSuffix);
91 }
92
93 /**
94 * Create a new {@link Version} with the given value, which must be in the
95 * form <tt>MAJOR.MINOR.PATCH(-TAG(TAG_VERSION))</tt>.
96 *
97 * @param version
98 * the version (<tt>MAJOR.MINOR.PATCH</tt>,
99 * <tt>MAJOR.MINOR.PATCH-TAG</tt> or
100 * <tt>MAJOR.MINOR.PATCH-TAGVERSIONTAG</tt>)
101 */
102 public Version(String version) {
103 try {
104 String[] tab = version.split("\\.");
105 this.major = Integer.parseInt(tab[0]);
106 this.minor = Integer.parseInt(tab[1]);
107 if (tab[2].contains("-")) {
108 int posInVersion = version.indexOf('.');
109 posInVersion = version.indexOf('.', posInVersion + 1);
110 String rest = version.substring(posInVersion + 1);
111
112 int posInRest = rest.indexOf('-');
113 this.patch = Integer.parseInt(rest.substring(0, posInRest));
114
115 posInVersion = version.indexOf('-');
116 this.tag = version.substring(posInVersion + 1);
117 this.tagVersion = -1;
118
119 StringBuilder str = new StringBuilder();
120 while (!tag.isEmpty() && tag.charAt(tag.length() - 1) >= '0'
121 && tag.charAt(tag.length() - 1) <= '9') {
122 str.insert(0, tag.charAt(tag.length() - 1));
123 tag = tag.substring(0, tag.length() - 1);
124 }
125
126 if (str.length() > 0) {
127 this.tagVersion = Integer.parseInt(str.toString());
128 }
129 } else {
130 this.patch = Integer.parseInt(tab[2]);
131 this.tag = null;
132 this.tagVersion = -1;
133 }
134
135 this.version = toString();
136 } catch (Exception e) {
137 this.major = 0;
138 this.minor = 0;
139 this.patch = 0;
140 this.tag = null;
141 this.tagVersion = -1;
142 this.version = null;
143 }
144 }
145
146 /**
147 * The 'major' version.
148 * <p>
149 * This version should only change when API-incompatible changes are made to
150 * the program.
151 *
152 * @return the major version
153 */
154 public int getMajor() {
155 return major;
156 }
157
158 /**
159 * The 'minor' version.
160 * <p>
161 * This version should only change when new, backwards-compatible
162 * functionality has been added to the program.
163 *
164 * @return the minor version
165 */
166 public int getMinor() {
167 return minor;
168 }
169
170 /**
171 * The 'patch' version.
172 * <p>
173 * This version should change when backwards-compatible bugfixes have been
174 * added to the program.
175 *
176 * @return the patch version
177 */
178 public int getPatch() {
179 return patch;
180 }
181
182 /**
183 * A tag name for this version.
184 *
185 * @return the tag
186 */
187 public String getTag() {
188 return tag;
189 }
190
191 /**
192 * The version of the tag.
193 *
194 * @return the tag version
195 */
196 public int getTagVersion() {
197 return tagVersion;
198 }
199
200 /**
201 * Check if this {@link Version} is "empty" (i.e., the version was not
202 * parse-able or not given).
203 * <p>
204 * An empty {@link Version} is always <tt>0.0.0</tt>.
205 *
206 * @return TRUE if it is empty
207 */
208 public boolean isEmpty() {
209 return major == 0 && minor == 0 && patch == 0 && tag == null;
210 }
211
212 /**
213 * Check if we are more recent than the given {@link Version}.
214 * <p>
215 * Note that a tagged version is considered newer than a non-tagged version,
216 * but two tagged versions with different tags are not comparable.
217 *
218 * @param o
219 * the other {@link Version}
220 * @return TRUE if this {@link Version} is more recent than the given one
221 */
222 public boolean isNewerThan(Version o) {
223 if (major > o.major) {
224 return true;
225 }
226
227 if (major == o.major && minor > o.minor) {
228 return true;
229 }
230
231 if (major == o.major && minor == o.minor && patch > o.patch) {
232 return true;
233 }
234
235 // a tagged version is considered newer than a non-tagged one
236 if (major == o.major && minor == o.minor && patch == o.patch
237 && tag != null && o.tag == null) {
238 return true;
239 }
240
241 // 2 <> tagged versions are not comparable
242 boolean sameTag = (tag == null && o.tag == null)
243 || (tag != null && tag.equals(o.tag));
244 if (major == o.major && minor == o.minor && patch == o.patch && sameTag
245 && tagVersion > o.tagVersion) {
246 return true;
247 }
248
249 return false;
250 }
251
252 /**
253 * Check if we are older than the given {@link Version}.
254 *
255 * @param o
256 * the other {@link Version}
257 * @return TRUE if this {@link Version} is older than the given one
258 */
259 public boolean isOlderThan(Version o) {
260 // 2 <> tagged versions are not comparable
261 boolean sameTag = (tag == null && o.tag == null)
262 || (tag != null && tag.equals(o.tag));
263 if (major == o.major && minor == o.minor && patch == o.patch
264 && !sameTag) {
265 return false;
266 }
267
268 return !equals(o) && !isNewerThan(o);
269 }
270
271 /**
272 * Return the version of the running program if it follows the VERSION
273 * convention (i.e., if it has a file called VERSION containing the version
274 * as a {@link String} in its binary root, and if this {@link String}
275 * follows the Major/Minor/Patch convention).
276 * <p>
277 * If it does not, return an empty {@link Version} object.
278 *
279 * @return the {@link Version} of the program, or an empty {@link Version}
280 * (does not return NULL)
281 */
282 public static Version getCurrentVersion() {
283 String version = null;
284
285 InputStream in = IOUtils.openResource("VERSION");
286 if (in != null) {
287 try {
288 ByteArrayOutputStream ba = new ByteArrayOutputStream();
289 IOUtils.write(in, ba);
290 in.close();
291
292 version = ba.toString("UTF-8").trim();
293 } catch (IOException e) {
294 }
295 }
296
297 return new Version(version);
298 }
299
300 public int compareTo(Version o) {
301 if (equals(o)) {
302 return 0;
303 } else if (isNewerThan(o)) {
304 return 1;
305 } else {
306 return -1;
307 }
308 }
309
310 @Override
311 public boolean equals(Object obj) {
312 if (obj instanceof Version) {
313 Version o = (Version) obj;
314 boolean sameTag = (tag == null && o.tag == null)
315 || (tag != null && tag.equals(o.tag));
316 return o.major == major && o.minor == minor && o.patch == patch
317 && sameTag && o.tagVersion == tagVersion;
318 }
319
320 return false;
321 }
322
323 @Override
324 public int hashCode() {
325 return version == null ? 0 : version.hashCode();
326 }
327
328 /**
329 * Return a user-readable form of this {@link Version}.
330 */
331 @Override
332 public String toString() {
333 return version == null ? "[unknown]" : version;
334 }
335 }