1
1
task japicc {
2
2
group ' verification'
3
- description ' Checks for binary and source incompatibility.'
4
3
5
- def japiccVersion = ' 2.4'
6
- def workingDir = new File (project. buildDir, ' japicc' )
7
- def executable = new File (workingDir, ' japi-compliance-checker-' + japiccVersion + ' /japi-compliance-checker.pl' )
8
-
9
- def mavenRepo = " ${ project.repositories.mavenCentral().url} "
10
-
11
- def lastSemVer = project. prevVersion == null ? lastSemVer() : project. prevVersion
12
- def shadedName = project. name + ' -' + project. shadedAppendix
13
- def lastJar = new File (workingDir, project. name + ' -' + lastSemVer + ' .jar' )
14
- def lastShadedJar = new File (workingDir, shadedName + ' -' + lastSemVer + ' .jar' )
4
+ ext {
5
+ japiccVersion = ' 2.4'
6
+ workingDir = new File (project. buildDir, ' japicc' )
7
+ executable = new File (workingDir, ' japi-compliance-checker-' + japiccVersion + ' /japi-compliance-checker.pl' )
8
+ }
9
+ }
10
+ project. tasks. check. dependsOn(japicc)
15
11
16
- def nonImplFile = new File (workingDir, ' non-impl' )
12
+ if (rootProject. tasks. findByName(' japiccDownload' ) == null ) {
13
+ rootProject. tasks. create(' japiccDownload' ) {
14
+ group ' japicc'
15
+ description ' Download Java API Compliance Checker'
17
16
18
- def reportDir = new File (workingDir, ' compat_reports' )
19
- def versions = lastSemVer + ' _to_' + project. version
20
- def report = new File (new File (new File (reportDir, project. name), versions), ' compat_report.html' )
21
- def shadedReport = new File (new File (new File (reportDir, shadedName), versions), ' compat_report.html' )
17
+ outputs. files japicc. executable
22
18
23
- inputs. files jar, shadowJar
24
- outputs. files report, shadedReport
19
+ File archive = new File (japicc. workingDir, ' japi-compliance-checker-' + japicc. japiccVersion + ' .zip' )
25
20
26
- doFirst {
27
- description ' Check if last semantic version is available'
28
- println (description)
21
+ doLast {
22
+ archive. parentFile. mkdirs()
23
+ if (! archive. exists()) {
24
+ new URL (' https://github.com/lvc/japi-compliance-checker/archive/' + japicc. japiccVersion + ' .zip' )
25
+ .withInputStream { i -> archive. withOutputStream { it << i } }
26
+ }
27
+ }
29
28
30
- if (project. version == lastSemVer) {
31
- throw new StopExecutionException (' No last semantic version available' )
29
+ doLast {
30
+ copy {
31
+ from zipTree(archive)
32
+ into japicc. workingDir
33
+ }
32
34
}
33
35
}
36
+ }
34
37
35
- doLast {
38
+ if (rootProject. tasks. findByName(' japiccNonImpl' ) == null ) {
39
+ rootProject. tasks. create(' japiccNonImpl' ) {
40
+ group ' japicc'
36
41
description ' List non impl interfaces'
37
- println (description)
38
-
39
- nonImplFile. delete()
40
- nonImplFile. createNewFile()
41
-
42
- sourceSets. main. java. visit { FileTreeElement f ->
43
- if (f. file. isFile()) {
44
- def packageName = f. relativePath. parent. pathString. replace(' /' , ' .' ). replace(' \\ ' , ' .' )
45
-
46
- def content = f. file. getText(" UTF-8" )
47
- content = content. replaceAll(' //.*\n ' , ' ' ) // remove line comments
48
- content = content. replaceAll(' \n ' , ' ' ) // remove new lines
49
- content = content. replaceAll(' /\\ *.*?\\ */' , ' ' ) // remove multi line comments
50
- content = content. replaceAll(' +' , ' ' ) // remove unnecessary spaces
51
-
52
- def index = 0
53
- def classNames = []
54
- while (true ) {
55
- def start = content. indexOf(' interface ' , index)
56
- if (start == -1 ) break
57
-
58
- def sub = content. substring(0 , start)
59
- def level = sub. count(' {' ) - sub. count(' }' )
60
- while (level < classNames. size()) {
61
- classNames. remove(classNames. size() - 1 )
62
- }
63
42
64
- start + = ' interface ' . length()
65
- def end = content. indexOf(' {' , start)
66
- if (end == -1 ) break
67
-
68
- def interfaceDef = content. substring(start, end)
69
- def className = interfaceDef. split(' [ <{]' , 2 )[0 ]
70
- classNames. add(className)
71
-
72
- def annotationIndex = content. indexOf(' @DoNotImplement' , index)
73
- if (annotationIndex == -1 ) break
74
-
75
- if (annotationIndex < start) {
76
- def qualifiedName = packageName + " ." + classNames. join(' .' )
77
-
78
- def rest = interfaceDef. substring(className. length()). trim()
79
- if (rest. startsWith(' <' )) {
80
- rest = rest. replaceAll(' extends [^ <,]+' , ' ' ) // remove all extends ...
81
- rest = rest. replaceAll(' @.*? ' , ' ' ) // remove all annotations
82
- def generics = ' <'
83
- def nesting = 0
84
- for (def c : rest. chars) {
85
- if (c == ' <' ) {
86
- nesting++
87
- } else if (c == ' >' ) {
88
- nesting--
89
- } else if (nesting == 1 ) {
90
- generics + = c
91
- } else if (nesting == 0 ) {
92
- break
43
+ ext {
44
+ nonImplFile = new File (japicc. workingDir, ' non-impl' )
45
+ }
46
+
47
+ inputs. files sourceSets. main. java
48
+ outputs. files nonImplFile
49
+
50
+ doLast {
51
+ nonImplFile. delete()
52
+ nonImplFile. parentFile. mkdirs()
53
+ nonImplFile. createNewFile()
54
+
55
+ sourceSets. main. java. visit { FileTreeElement f ->
56
+ if (f. file. isFile()) {
57
+ def packageName = f. relativePath. parent. pathString. replace(' /' , ' .' ). replace(' \\ ' , ' .' )
58
+
59
+ def content = f. file. getText(" UTF-8" )
60
+ content = content. replaceAll(' //.*\n ' , ' ' ) // remove line comments
61
+ content = content. replaceAll(' \n ' , ' ' ) // remove new lines
62
+ content = content. replaceAll(' /\\ *.*?\\ */' , ' ' ) // remove multi line comments
63
+ content = content. replaceAll(' +' , ' ' ) // remove unnecessary spaces
64
+
65
+ def index = 0
66
+ def classNames = []
67
+ while (true ) {
68
+ def start = content. indexOf(' interface ' , index)
69
+ if (start == -1 ) break
70
+
71
+ def sub = content. substring(0 , start)
72
+ def level = sub. count(' {' ) - sub. count(' }' )
73
+ while (level < classNames. size()) {
74
+ classNames. remove(classNames. size() - 1 )
75
+ }
76
+
77
+ start + = ' interface ' . length()
78
+ def end = content. indexOf(' {' , start)
79
+ if (end == -1 ) break
80
+
81
+ def interfaceDef = content. substring(start, end)
82
+ def className = interfaceDef. split(' [ <{]' , 2 )[0 ]
83
+ classNames. add(className)
84
+
85
+ def annotationIndex = content. indexOf(' @DoNotImplement' , index)
86
+ if (annotationIndex == -1 ) break
87
+
88
+ if (annotationIndex < start) {
89
+ def qualifiedName = packageName + " ." + classNames. join(' .' )
90
+
91
+ def rest = interfaceDef. substring(className. length()). trim()
92
+ if (rest. startsWith(' <' )) {
93
+ rest = rest. replaceAll(' extends [^ <,]+' , ' ' ) // remove all extends ...
94
+ rest = rest. replaceAll(' @.*? ' , ' ' ) // remove all annotations
95
+ def generics = ' <'
96
+ def nesting = 0
97
+ for (def c : rest. chars) {
98
+ if (c == ' <' ) {
99
+ nesting++
100
+ } else if (c == ' >' ) {
101
+ nesting--
102
+ } else if (nesting == 1 ) {
103
+ generics + = c
104
+ } else if (nesting == 0 ) {
105
+ break
106
+ }
93
107
}
108
+ generics + = ' >'
109
+ generics = generics. replace(' ' , ' ' )
110
+ qualifiedName + = generics
94
111
}
95
- generics + = ' >'
96
- generics = generics. replace(' ' , ' ' )
97
- qualifiedName + = generics
112
+
113
+ nonImplFile. append(qualifiedName + ' \n ' )
98
114
}
99
115
100
- nonImplFile . append(qualifiedName + ' \n ' )
116
+ index = end + 1
101
117
}
102
-
103
- index = end + 1
104
118
}
105
119
}
106
120
}
107
121
}
122
+ }
108
123
109
- doLast {
110
- description ' Download Java API Compliance Checker'
111
- println (description)
124
+ def addCheck (Jar jarTask ) {
125
+ String archiveBaseName = jarTask. archiveBaseName. get()
126
+ String archiveAppendix = jarTask. archiveAppendix. getOrElse(' ' )
127
+ String taskName = ' japiccCheck' + archiveAppendix. capitalize()
112
128
113
- def archive = new File (workingDir, ' japi-compliance-checker-' + japiccVersion + ' .zip' )
114
- archive. parentFile. mkdirs()
115
- if (! archive. exists()) {
116
- new URL (' https://github.com/lvc/japi-compliance-checker/archive/' + japiccVersion + ' .zip' )
117
- .withInputStream { i -> archive. withOutputStream { it << i } }
129
+ def task = project. tasks. create(taskName) {
118
130
119
- copy {
120
- from zipTree(archive)
121
- into workingDir
122
- }
131
+ group ' japicc'
132
+ description ' Checks for binary and source incompatibility.'
133
+ dependsOn rootProject. tasks. japiccDownload, rootProject. tasks. japiccNonImpl
134
+
135
+ File taskDir = new File (japicc. workingDir, taskName)
136
+ String archiveName = archiveBaseName
137
+ if (archiveAppendix == ' -' ) {
138
+ archiveName + = ' -' + archiveAppendix
123
139
}
124
- }
125
140
126
- doLast {
127
- description ' Download last version '
128
- println (description )
141
+ String lastSemVer = project . prevVersion == null ? lastSemVer() : project . prevVersion
142
+ String lastJarName = archiveName + ' - ' + lastSemVer + ' .jar '
143
+ File lastJar = new File (taskDir, lastJarName )
129
144
130
- lastJar. parentFile. mkdirs()
131
- if (! lastJar. exists()) {
132
- String path = project. group. replace(' .' , ' /' )
133
- path + = ' /' + project. name + ' /' + lastSemVer + ' /'
134
- path + = project. name + ' -' + lastSemVer + ' .jar'
135
- new URL (mavenRepo + path). withInputStream { i -> lastJar. withOutputStream { it << i } }
136
- }
137
- }
145
+ File reportDir = new File (taskDir, ' compat_reports' )
146
+ File report = new File (new File (reportDir, lastSemVer + ' _to_' + project. version), ' compat_report.html' )
138
147
139
- doLast {
140
- description ' Download last shaded version'
141
- println (description)
148
+ inputs. files jarTask
149
+ outputs. files report
142
150
143
- lastShadedJar. parentFile. mkdirs()
144
- if (! lastShadedJar. exists()) {
145
- String path = project. group. replace(' .' , ' /' )
146
- path + = ' /' + shadedName + ' /' + lastSemVer + ' /'
147
- path + = shadedName + ' -' + lastSemVer + ' .jar'
148
- new URL (mavenRepo + path). withInputStream { i -> lastShadedJar. withOutputStream { it << i } }
149
- }
150
- }
151
+ doFirst {
152
+ description ' Check if last semantic version is available'
153
+ println (description)
151
154
152
- doLast {
153
- description ' Check binary and source compatibility for last version'
154
- println (description)
155
+ if (project. version == lastSemVer) {
156
+ throw new StopExecutionException (' No last semantic version available' )
157
+ }
158
+ }
155
159
156
- def command = [' perl' , executable. getPath(), ' -lib' , project. name,
157
- ' -skip-internal-packages' , ' com.hivemq.client.internal' ,
158
- ' -non-impl' , nonImplFile. getPath(),
159
- ' -check-annotations' , ' -s' ,
160
- lastJar. getPath(), jar. archiveFile. get(). getAsFile(). getPath()]
160
+ doLast {
161
+ description ' Download last version'
162
+ println (description)
161
163
162
- def process = new ProcessBuilder (command). directory(workingDir). start()
163
- def returnCode = process. waitFor()
164
- if (returnCode != 0 ) {
165
- throw new GradleException (' Binary or source incompatibilities, code ' + returnCode)
164
+ lastJar. parentFile. mkdirs()
165
+ if (! lastJar. exists()) {
166
+ String path = project. group. replace(' .' , ' /' ) + ' /' + archiveName + ' /' + lastSemVer + ' /' + lastJarName
167
+ new URL (project. repositories. mavenCentral(). url. toString() + path)
168
+ .withInputStream { i -> lastJar. withOutputStream { it << i } }
169
+ }
166
170
}
167
- }
168
171
169
- doLast {
170
- description ' Check binary and source compatibility for last shaded version'
171
- println (description)
172
-
173
- def command = [' perl' , executable. getPath(), ' -lib' , shadedName,
174
- ' -skip-internal-packages' , ' com.hivemq.client.internal' ,
175
- ' -skip-internal-packages' , ' com.hivemq.shaded' ,
176
- ' -non-impl' , nonImplFile. getPath(),
177
- ' -check-annotations' , ' -s' ,
178
- lastShadedJar. getPath(), shadowJar. archiveFile. get(). getAsFile(). getPath()]
179
-
180
- def process = new ProcessBuilder (command). directory(workingDir). start()
181
- def returnCode = process. waitFor()
182
- if (returnCode != 0 ) {
183
- throw new GradleException (' Binary or source incompatibilities in shaded, code ' + returnCode)
172
+ doLast {
173
+ description ' Check binary and source compatibility for last version'
174
+ println (description)
175
+
176
+ def command = [' perl' , japicc. executable. getPath(), ' -lib' , archiveName,
177
+ ' -skip-internal-packages' , ' com.hivemq.client.internal' ,
178
+ ' -skip-internal-packages' , ' com.hivemq.shaded' ,
179
+ ' -non-impl' , japiccNonImpl. nonImplFile. getPath(),
180
+ ' -check-annotations' , ' -s' ,
181
+ lastJar. getPath(), jarTask. archiveFile. get(). getAsFile(). getPath()]
182
+
183
+ Process process = new ProcessBuilder (command). directory(taskDir). start()
184
+ int returnCode = process. waitFor()
185
+ if (returnCode != 0 ) {
186
+ throw new GradleException (' Binary or source incompatibilities, code ' + returnCode)
187
+ }
184
188
}
185
189
}
190
+ project. tasks. japicc. dependsOn(task)
186
191
}
187
192
188
- project. tasks. check. dependsOn(japicc)
189
-
190
193
String lastSemVer () {
191
194
String version = project. version
192
195
def split = version. split(' -' )[0 ]. split(' \\ .' )
@@ -200,3 +203,8 @@ String lastSemVer() {
200
203
}
201
204
return major + ' .' + minor + ' .' + patch
202
205
}
206
+
207
+ addCheck(project. tasks. jar)
208
+ if (project. plugins. hasPlugin(' com.github.johnrengelman.shadow' )) {
209
+ addCheck(project. tasks. shadowJar)
210
+ }
0 commit comments