@@ -6,10 +6,14 @@ package util.tasks
6
6
7
7
import org.gradle.api.DefaultTask
8
8
import org.gradle.api.Project
9
+ import org.gradle.api.file.FileTree
10
+ import org.gradle.api.provider.ListProperty
9
11
import org.gradle.api.provider.Property
10
12
import org.gradle.api.tasks.Copy
13
+ import org.gradle.api.tasks.Exec
11
14
import org.gradle.api.tasks.Input
12
15
import org.gradle.api.tasks.InputFile
16
+ import org.gradle.api.tasks.InputFiles
13
17
import org.gradle.api.tasks.OutputFile
14
18
import org.gradle.api.tasks.TaskAction
15
19
import org.gradle.kotlin.dsl.accessors.runtime.addExternalModuleDependencyTo
@@ -21,8 +25,40 @@ import util.other.libs
21
25
import java.io.File
22
26
23
27
const val CONFORMANCE_TEST_RUNNER_CONFIGURATION = " conformanceTestRunner"
28
+ const val PROTOC_TESTING_CONFIGURATION = " protoc_internalTesting"
24
29
const val UNZIP_PROTOBUF_CONFORMANCE_TASK = " unzipProtobufConformance"
25
30
const val WRITE_CONFORMANCE_EXECUTABLE_PATH_TASK = " writeConformanceExecutablePath"
31
+ const val PAYLOAD_PB = " payload.pb"
32
+ const val CONFORMANCE_PB = " conformance.pb"
33
+
34
+ private fun Project.getBinFrom (configuration : String ): File {
35
+ return configurations.getByName(configuration).map {
36
+ zipTree(it).matching { include(" bin/**" ) }.files.first()
37
+ }.single()
38
+ }
39
+
40
+ private fun Project.getIncludeFrom (configuration : String ): List <FileTree > {
41
+ return configurations.getByName(configuration).map {
42
+ zipTree(it).matching { include(" include/**" ) }
43
+ }
44
+ }
45
+
46
+ private fun List<String>.commonPrefix (): String {
47
+ return fold(first()) { acc, s -> acc.commonPrefixWith(s) }
48
+ }
49
+
50
+ private fun Project.pbFile (name : String ): File {
51
+ return layout.buildDirectory.get()
52
+ .dir(" protobuf-conformance" )
53
+ .file(name)
54
+ .asFile
55
+ .apply {
56
+ if (! exists()) {
57
+ parentFile.mkdirs()
58
+ createNewFile()
59
+ }
60
+ }
61
+ }
26
62
27
63
abstract class ConformanceExecutablePathWriter : DefaultTask () {
28
64
@get:Input
@@ -64,6 +100,48 @@ abstract class ConformanceExecutablePathWriter : DefaultTask() {
64
100
}
65
101
}
66
102
103
+ abstract class GenerateConformanceFileDescriptorSet : Exec () {
104
+ @get:InputFiles
105
+ abstract val wktFilesCollection: ListProperty <File >
106
+
107
+ @get:InputFiles
108
+ abstract val conformanceFilesCollection: ListProperty <File >
109
+
110
+ @get:InputFile
111
+ abstract val bin: Property <File >
112
+
113
+ @get:OutputFile
114
+ abstract val outputFile: Property <File >
115
+
116
+ @TaskAction
117
+ fun generate () {
118
+ val wktFiles = wktFilesCollection.get().map { it.absolutePath }
119
+ val conformanceFiles = conformanceFilesCollection.get().map { it.absolutePath }
120
+
121
+ val wktProtoPath = if (wktFiles.isEmpty()) {
122
+ emptyList()
123
+ } else {
124
+ listOf (" --proto_path=${wktFiles.commonPrefix().substringBefore(" /google/protobuf/" )} " )
125
+ }
126
+
127
+ val conformanceIncludeDir = conformanceFiles
128
+ .commonPrefix()
129
+ .substringBefore(" /google/protobuf/" )
130
+ .substringBefore(" /conformance/" )
131
+
132
+ val conformanceProtoPath = " --proto_path=$conformanceIncludeDir "
133
+
134
+ commandLine(
135
+ bin.get().absolutePath,
136
+ * wktProtoPath.toTypedArray(),
137
+ conformanceProtoPath,
138
+ " -o" , outputFile.get().absolutePath,
139
+ * wktFiles.toTypedArray(),
140
+ * conformanceFiles.toTypedArray(),
141
+ )
142
+ }
143
+ }
144
+
67
145
fun Project.setupProtobufConformanceResources () {
68
146
val os = System .getProperty(" os.name" ).lowercase()
69
147
val osPart = when {
@@ -79,7 +157,7 @@ fun Project.setupProtobufConformanceResources() {
79
157
80
158
// https://stackoverflow.com/questions/23023069/gradle-download-and-unzip-file-from-url
81
159
repositories.ivy {
82
- name = " protobuf-conformance- github"
160
+ name = " github"
83
161
url = uri(" https://github.com" )
84
162
85
163
patternLayout {
@@ -93,6 +171,7 @@ fun Project.setupProtobufConformanceResources() {
93
171
}
94
172
95
173
configurations.create(CONFORMANCE_TEST_RUNNER_CONFIGURATION )
174
+ configurations.create(PROTOC_TESTING_CONFIGURATION )
96
175
97
176
// https://docs.gradle.org/current/javadoc/org/gradle/api/artifacts/dsl/DependencyHandler.html
98
177
dependencies {
@@ -115,10 +194,28 @@ fun Project.setupProtobufConformanceResources() {
115
194
}
116
195
}
117
196
197
+ dependencies {
198
+ addExternalModuleDependencyTo(
199
+ this ,
200
+ PROTOC_TESTING_CONFIGURATION ,
201
+ group = " protocolbuffers" ,
202
+ name = " protobuf" ,
203
+ version = libs.versions.protobuf.asProvider().get().substringAfter(" ." ),
204
+ classifier = null ,
205
+ ext = null ,
206
+ configuration = null ,
207
+ ) {
208
+ artifact {
209
+ name = " protoc"
210
+ type = " zip"
211
+ extension = " zip"
212
+ classifier = " $osPart -$archPart "
213
+ }
214
+ }
215
+ }
216
+
118
217
val unzipProtobufConformance = tasks.register<Copy >(UNZIP_PROTOBUF_CONFORMANCE_TASK ) {
119
- from(configurations.getByName(CONFORMANCE_TEST_RUNNER_CONFIGURATION ).map {
120
- zipTree(it).matching { include(" include/**" ) }
121
- })
218
+ from(getIncludeFrom(CONFORMANCE_TEST_RUNNER_CONFIGURATION ))
122
219
123
220
val destDir = project.layout.projectDirectory
124
221
.dir(" src" )
@@ -140,6 +237,34 @@ fun Project.setupProtobufConformanceResources() {
140
237
}
141
238
}
142
239
240
+ tasks.register<GenerateConformanceFileDescriptorSet >(" generateConformanceFileDescriptorSet_conformance" ) {
241
+ wktFilesCollection.set(emptyList())
242
+
243
+ val conformanceFiles = project.getIncludeFrom(CONFORMANCE_TEST_RUNNER_CONFIGURATION ).flatMap { it.files }
244
+ .filter { it.name == " conformance.proto" }
245
+
246
+ conformanceFilesCollection.set(conformanceFiles)
247
+
248
+ bin.set(getBinFrom(PROTOC_TESTING_CONFIGURATION ))
249
+
250
+ outputFile.set(project.pbFile(CONFORMANCE_PB ))
251
+ }
252
+
253
+ tasks.register<GenerateConformanceFileDescriptorSet >(" generateConformanceFileDescriptorSet_payload" ) {
254
+ val wktFiles = project.getIncludeFrom(PROTOC_TESTING_CONFIGURATION ).flatMap { it.files }
255
+ wktFilesCollection.set(wktFiles)
256
+
257
+ // editions are not supported in protoscope and proto2 fails
258
+ val conformanceFiles = project.getIncludeFrom(CONFORMANCE_TEST_RUNNER_CONFIGURATION ).flatMap { it.files }
259
+ .filter { it.name == " test_messages_proto3.proto" }
260
+
261
+ conformanceFilesCollection.set(conformanceFiles)
262
+
263
+ bin.set(getBinFrom(PROTOC_TESTING_CONFIGURATION ))
264
+
265
+ outputFile.set(project.pbFile(PAYLOAD_PB ))
266
+ }
267
+
143
268
val writeConformanceExecutablePath =
144
269
tasks.register<ConformanceExecutablePathWriter >(WRITE_CONFORMANCE_EXECUTABLE_PATH_TASK ) {
145
270
outputDir.set(
@@ -156,11 +281,7 @@ fun Project.setupProtobufConformanceResources() {
156
281
.asFile
157
282
)
158
283
159
- executable.set(
160
- configurations.getByName(CONFORMANCE_TEST_RUNNER_CONFIGURATION ).map {
161
- zipTree(it).matching { include(" bin/**" ) }.files.first()
162
- }.single()
163
- )
284
+ executable.set(getBinFrom(CONFORMANCE_TEST_RUNNER_CONFIGURATION ))
164
285
165
286
destination.set(
166
287
project.layout.buildDirectory.get()
0 commit comments