Skip to content

Commit 54a11cd

Browse files
committed
port Gradle's VersionNumber to avoid deprecations
1 parent 290b2f4 commit 54a11cd

File tree

4 files changed

+446
-2
lines changed

4 files changed

+446
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
package com.netflix.nebula.lint
2+
3+
4+
import com.google.common.base.Objects
5+
import com.google.common.collect.Ordering
6+
7+
import javax.annotation.Nullable
8+
9+
/**
10+
* Represents, parses, and compares version numbers. Supports a couple of different schemes: <ul> <li>MAJOR.MINOR.MICRO-QUALIFIER (the default).</li> <li>MAJOR.MINOR.MICRO.PATCH-QUALIFIER.</li> </ul>
11+
*
12+
* <p>The {@link #parse} method handles missing parts and allows "." to be used instead of "-", and "_" to be used instead of "." for the patch number.
13+
*
14+
* <p>This class considers missing parts to be 0, so that "1.0" == "1.0.0" == "1.0.0_0".</p>
15+
*
16+
* <p>Note that this class considers "1.2.3-something" less than "1.2.3". Qualifiers are compared lexicographically ("1.2.3-alpha" < "1.2.3-beta") and case-insensitive ("1.2.3-alpha" <
17+
* "1.2.3.RELEASE").
18+
*
19+
* <p>To check if a version number is at least "1.2.3", disregarding a potential qualifier like "beta", use {@code version.getBaseVersion().compareTo(VersionNumber.parse("1.2.3")) >= 0}.
20+
*/
21+
class VersionNumber implements Comparable<VersionNumber> {
22+
private static final DefaultScheme DEFAULT_SCHEME = new VersionNumber.DefaultScheme()
23+
private static final VersionNumber.SchemeWithPatchVersion PATCH_SCHEME = new VersionNumber.SchemeWithPatchVersion()
24+
static final VersionNumber UNKNOWN = version(0)
25+
26+
private final int major
27+
private final int minor
28+
private final int micro
29+
private final int patch
30+
private final String qualifier
31+
private final AbstractScheme scheme
32+
33+
VersionNumber(int major, int minor, int micro, @Nullable String qualifier) {
34+
this(major, minor, micro, 0, qualifier, DEFAULT_SCHEME)
35+
}
36+
37+
VersionNumber(int major, int minor, int micro, int patch, @Nullable String qualifier) {
38+
this(major, minor, micro, patch, qualifier, PATCH_SCHEME)
39+
}
40+
41+
private VersionNumber(int major, int minor, int micro, int patch, @Nullable String qualifier, AbstractScheme scheme) {
42+
this.major = major
43+
this.minor = minor
44+
this.micro = micro
45+
this.patch = patch
46+
this.qualifier = qualifier
47+
this.scheme = scheme
48+
}
49+
50+
int getMajor() {
51+
return major;
52+
}
53+
54+
int getMinor() {
55+
return minor;
56+
}
57+
58+
int getMicro() {
59+
return micro
60+
}
61+
62+
int getPatch() {
63+
return patch
64+
}
65+
66+
@Nullable
67+
String getQualifier() {
68+
return qualifier
69+
}
70+
71+
VersionNumber getBaseVersion() {
72+
return new VersionNumber(major, minor, micro, patch, null, scheme)
73+
}
74+
75+
@Override
76+
int compareTo(VersionNumber other) {
77+
if (major != other.major) {
78+
return major - other.major
79+
}
80+
if (minor != other.minor) {
81+
return minor - other.minor
82+
}
83+
if (micro != other.micro) {
84+
return micro - other.micro
85+
}
86+
if (patch != other.patch) {
87+
return patch - other.patch
88+
}
89+
return Ordering.natural().nullsLast().compare(toLowerCase(qualifier), toLowerCase(other.qualifier))
90+
}
91+
92+
boolean equals(@Nullable Object other) {
93+
return other instanceof VersionNumber && compareTo((VersionNumber) other) == 0
94+
}
95+
96+
int hashCode() {
97+
int result = major
98+
result = 31 * result + minor
99+
result = 31 * result + micro
100+
result = 31 * result + patch
101+
result = 31 * result + Objects.hashCode(qualifier)
102+
return result
103+
}
104+
105+
String toString() {
106+
return scheme.format(this)
107+
}
108+
109+
static VersionNumber version(int major) {
110+
return new VersionNumber(major, 0, 0, 0, null, DEFAULT_SCHEME)
111+
}
112+
113+
/**
114+
* Returns the default MAJOR.MINOR.MICRO-QUALIFIER scheme.
115+
*/
116+
static VersionNumber.Scheme scheme() {
117+
return DEFAULT_SCHEME
118+
}
119+
120+
/**
121+
* Returns the MAJOR.MINOR.MICRO.PATCH-QUALIFIER scheme.
122+
*/
123+
static VersionNumber.Scheme withPatchNumber() {
124+
return PATCH_SCHEME
125+
}
126+
127+
static VersionNumber parse(String versionString) {
128+
return DEFAULT_SCHEME.parse(versionString)
129+
}
130+
131+
@Nullable
132+
private String toLowerCase(@Nullable String string) {
133+
return string == null ? null : string.toLowerCase()
134+
}
135+
136+
interface Scheme {
137+
VersionNumber parse(String value)
138+
139+
String format(VersionNumber versionNumber)
140+
}
141+
142+
private abstract static class AbstractScheme implements VersionNumber.Scheme {
143+
final int depth
144+
145+
protected AbstractScheme(int depth) {
146+
this.depth = depth
147+
}
148+
149+
@Override
150+
VersionNumber parse(@Nullable String versionString) {
151+
if (versionString == null || versionString.length() == 0) {
152+
return UNKNOWN
153+
}
154+
VersionNumber.AbstractScheme.Scanner scanner = new VersionNumber.AbstractScheme.Scanner(versionString)
155+
156+
int major = 0
157+
int minor = 0
158+
int micro = 0
159+
int patch = 0
160+
161+
if (!scanner.hasDigit()) {
162+
return UNKNOWN
163+
}
164+
major = scanner.scanDigit()
165+
if (scanner.isSeparatorAndDigit('.')) {
166+
scanner.skipSeparator()
167+
minor = scanner.scanDigit()
168+
if (scanner.isSeparatorAndDigit('.')) {
169+
scanner.skipSeparator()
170+
micro = scanner.scanDigit()
171+
if (depth > 3 && scanner.isSeparatorAndDigit('.', '_')) {
172+
scanner.skipSeparator()
173+
patch = scanner.scanDigit()
174+
}
175+
}
176+
}
177+
178+
if (scanner.isEnd()) {
179+
return new VersionNumber(major, minor, micro, patch, null, this)
180+
}
181+
182+
if (scanner.isQualifier()) {
183+
scanner.skipSeparator()
184+
return new VersionNumber(major, minor, micro, patch, scanner.remainder(), this)
185+
}
186+
187+
return UNKNOWN
188+
}
189+
190+
private static class Scanner {
191+
int pos
192+
final String str
193+
194+
private Scanner(String string) {
195+
this.str = string
196+
}
197+
198+
boolean hasDigit() {
199+
return pos < str.length() && Character.isDigit(str.charAt(pos))
200+
}
201+
202+
boolean isSeparatorAndDigit(char... separators) {
203+
return pos < str.length() - 1 && oneOf(separators) && Character.isDigit(str.charAt(pos + 1))
204+
}
205+
206+
private boolean oneOf(char... separators) {
207+
char current = str.charAt(pos);
208+
for (int i = 0; i < separators.length; i++) {
209+
char separator = separators[i]
210+
if (current == separator) {
211+
return true
212+
}
213+
}
214+
return false
215+
}
216+
217+
boolean isQualifier() {
218+
return pos < str.length() - 1 && oneOf('.', '-')
219+
}
220+
221+
int scanDigit() {
222+
int start = pos
223+
while (hasDigit()) {
224+
pos++
225+
}
226+
return Integer.parseInt(str.substring(start, pos))
227+
}
228+
229+
boolean isEnd() {
230+
return pos == str.length()
231+
}
232+
233+
void skipSeparator() {
234+
pos++
235+
}
236+
237+
@Nullable
238+
String remainder() {
239+
return pos == str.length() ? null : str.substring(pos)
240+
}
241+
}
242+
}
243+
244+
private static class DefaultScheme extends AbstractScheme {
245+
private static final String VERSION_TEMPLATE = "%d.%d.%d%s"
246+
247+
DefaultScheme() {
248+
super(3)
249+
}
250+
251+
@Override
252+
String format(VersionNumber versionNumber) {
253+
return String.format(VERSION_TEMPLATE, versionNumber.major, versionNumber.minor, versionNumber.micro, versionNumber.qualifier == null ? "" : "-" + versionNumber.qualifier)
254+
}
255+
}
256+
257+
private static class SchemeWithPatchVersion extends AbstractScheme {
258+
private static final String VERSION_TEMPLATE = "%d.%d.%d.%d%s"
259+
260+
private SchemeWithPatchVersion() {
261+
super(4)
262+
}
263+
264+
@Override
265+
String format(VersionNumber versionNumber) {
266+
return String.format(VERSION_TEMPLATE, versionNumber.major, versionNumber.minor, versionNumber.micro, versionNumber.patch, versionNumber.qualifier == null ? "" : "-" + versionNumber.qualifier)
267+
}
268+
}
269+
270+
}
271+

src/main/groovy/com/netflix/nebula/lint/rule/dependency/DependencyService.groovy

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.netflix.nebula.lint.rule.dependency
22

33
import com.netflix.nebula.interop.GradleKt
44
import com.netflix.nebula.lint.SourceSetUtils
5+
import com.netflix.nebula.lint.VersionNumber
56
import groovy.transform.Memoized
67
import groovyx.gpars.GParsPool
78
import org.gradle.api.Project
@@ -15,7 +16,6 @@ import org.gradle.api.file.FileCollection
1516
import org.gradle.api.internal.artifacts.DefaultModuleIdentifier
1617
import org.gradle.api.tasks.SourceSet
1718
import org.gradle.api.tasks.SourceSetContainer
18-
import org.gradle.util.VersionNumber
1919
import org.objectweb.asm.ClassReader
2020
import org.slf4j.Logger
2121
import org.slf4j.LoggerFactory

src/main/groovy/com/netflix/nebula/lint/rule/dependency/MinimumDependencyVersionRule.groovy

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.netflix.nebula.lint.rule.dependency
22

3+
import com.netflix.nebula.lint.VersionNumber
34
import com.netflix.nebula.lint.rule.GradleDependency
45
import com.netflix.nebula.lint.rule.GradleLintRule
56
import com.netflix.nebula.lint.rule.GradleModelAware
@@ -10,7 +11,6 @@ import org.codehaus.groovy.ast.expr.Expression
1011
import org.codehaus.groovy.ast.expr.MethodCallExpression
1112
import org.gradle.api.Incubating
1213
import org.gradle.api.artifacts.Configuration
13-
import org.gradle.util.VersionNumber
1414

1515
/**
1616
* This is like a declarative form of the use of a Substitute Nebula Resolution Rule:

0 commit comments

Comments
 (0)