xref: /OpenGrok/opengrok-indexer/src/main/java/org/opengrok/indexer/util/Version.java (revision 5d9f3aa0ca3da3a714233f987fa732f62c0965f6)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * See LICENSE.txt included in this distribution for the specific
9  * language governing permissions and limitations under the License.
10  *
11  * When distributing Covered Code, include this CDDL HEADER in each
12  * file and include the License file at LICENSE.txt.
13  * If applicable, add the following below this CDDL HEADER, with the
14  * fields enclosed by brackets "[]" replaced with your own identifying
15  * information: Portions Copyright [yyyy] [name of copyright owner]
16  *
17  * CDDL HEADER END
18  */
19 
20 /*
21  * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
22  * Portions Copyright (c) 2019, Krystof Tulinger (tulinkry).
23  */
24 package org.opengrok.indexer.util;
25 
26 import java.util.Arrays;
27 import java.util.stream.Stream;
28 
29 /**
30  * This class implements portions of semantic versioning from version noted as
31  * <pre>
32  *     a.b.c.d.e.f
33  * </pre>
34  * where
35  * <pre>
36  *     a - major
37  *     b - minor
38  *     c - patch
39  *     d ... - others
40  * </pre>
41  *
42  * @author Krystof Tulinger (tulinkry)
43  * @see <a href="https://semver.org/">https://semver.org/</a>
44  */
45 public class Version implements Comparable<Version> {
46     private final Integer[] versions;
47 
48     /**
49      * Construct the version from integer parts.
50      * The order is:
51      * <ol>
52      * <li>major</li>
53      * <li>minor</li>
54      * <li>patch</li>
55      * <li>... others</li>
56      * </ol>
57      *
58      * @param parts integer values for version partials
59      */
Version(Integer... parts)60     public Version(Integer... parts) {
61         // cut off trailing zeros
62         int cutOffLength = parts.length;
63         for (int i = parts.length - 1; i >= 0; i--) {
64             if (parts[i] != 0) {
65                 break;
66             }
67             cutOffLength--;
68         }
69         versions = Arrays.copyOf(parts, cutOffLength);
70     }
71 
72     /**
73      * Construct the version from a string.
74      *
75      * @param string string representing the version (e. g. 1.2.1)
76      * @return the new instance of version from the string
77      * @throws NumberFormatException when parts can not be converted to integers
78      */
from(String string)79     public static Version from(String string) throws NumberFormatException {
80         return new Version(
81                 Stream.of(string.trim().split("\\."))
82                       .map(String::trim)
83                       .map(Integer::parseInt)
84                       .toArray(Integer[]::new)
85         );
86     }
87 
88     @Override
equals(Object o)89     public boolean equals(Object o) {
90         if (this == o) {
91             return true;
92         }
93         if (o == null || getClass() != o.getClass()) {
94             return false;
95         }
96         Version version = (Version) o;
97         return Arrays.equals(versions, version.versions);
98     }
99 
100     @Override
hashCode()101     public int hashCode() {
102         return Arrays.hashCode(versions);
103     }
104 
105     @Override
compareTo(Version o)106     public int compareTo(Version o) {
107         if (o == null) {
108             return 1;
109         }
110 
111         // first different number determines the result
112         for (int i = 0; i < Math.min(versions.length, o.versions.length); i++) {
113             if (!versions[i].equals(o.versions[i])) {
114                 return Integer.compare(versions[i], o.versions[i]);
115             }
116         }
117 
118         // the comparable parts are the same, the longer has some trailing non-null element which
119         // makes it greater then the shorter
120         // e. g. 1.0.0.0.1 vs. 1.0.0
121         return Integer.compare(versions.length, o.versions.length);
122     }
123 }
124