1
+ package com.apollographql.apollo.compiler
2
+
3
+ import com.apollographql.apollo.annotations.ApolloInternal
4
+ import com.apollographql.apollo.compiler.codegen.SchemaAndOperationsLayout
5
+ import com.apollographql.apollo.compiler.codegen.writeTo
6
+ import com.apollographql.apollo.compiler.internal.GradleCompilerPluginLogger
7
+ import com.apollographql.apollo.compiler.operationoutput.OperationDescriptor
8
+ import com.apollographql.apollo.compiler.operationoutput.OperationId
9
+ import com.apollographql.apollo.compiler.operationoutput.OperationOutput
10
+ import java.io.File
11
+ import java.util.ServiceLoader
12
+ import java.util.function.Consumer
13
+
14
+ /* *
15
+ * EntryPoints contains code that is called using reflection from the Gradle plugin.
16
+ * This is so that the classloader can be isolated, and we can use our preferred version of
17
+ * Kotlin and other dependencies without risking conflicts.
18
+ */
19
+ @Suppress(" UNUSED" ) // Used from reflection
20
+ @ApolloInternal
21
+ class EntryPoints {
22
+ fun buildCodegenSchema (
23
+ arguments : Map <String , Any ?>,
24
+ logLevel : Int ,
25
+ warnIfNotFound : Boolean = false,
26
+ normalizedSchemaFiles : List <Any >,
27
+ warning : Consumer <String >,
28
+ codegenSchemaOptionsFile : File ,
29
+ codegenSchemaFile : File ,
30
+ ) {
31
+ val plugin = apolloCompilerPlugin(
32
+ arguments,
33
+ logLevel,
34
+ warnIfNotFound
35
+ )
36
+
37
+ ApolloCompiler .buildCodegenSchema(
38
+ schemaFiles = normalizedSchemaFiles.toInputFiles(),
39
+ logger = warning.toLogger(),
40
+ codegenSchemaOptions = codegenSchemaOptionsFile.toCodegenSchemaOptions(),
41
+ foreignSchemas = plugin?.foreignSchemas().orEmpty()
42
+ ).writeTo(codegenSchemaFile)
43
+ }
44
+
45
+ fun buildIr (
46
+ arguments : Map <String , Any ?>,
47
+ logLevel : Int ,
48
+ graphqlFiles : List <Any >,
49
+ codegenSchemaFiles : List <Any >,
50
+ upstreamIrOperations : List <Any >,
51
+ irOptionsFile : File ,
52
+ warning : Consumer <String >,
53
+ irOperationsFile : File ,
54
+ ) {
55
+ val plugin = apolloCompilerPlugin(arguments, logLevel)
56
+
57
+ val upstream = upstreamIrOperations.toInputFiles().map { it.file.toIrOperations() }
58
+ ApolloCompiler .buildIrOperations(
59
+ executableFiles = graphqlFiles.toInputFiles(),
60
+ codegenSchema = codegenSchemaFiles.toInputFiles().map { it.file }.findCodegenSchemaFile().toCodegenSchema(),
61
+ upstreamCodegenModels = upstream.map { it.codegenModels },
62
+ upstreamFragmentDefinitions = upstream.flatMap { it.fragmentDefinitions },
63
+ documentTransform = plugin?.documentTransform(),
64
+ options = irOptionsFile.toIrOptions(),
65
+ logger = warning.toLogger(),
66
+ ).writeTo(irOperationsFile)
67
+ }
68
+
69
+ fun buildSourcesFromIr (
70
+ arguments : Map <String , Any ?>,
71
+ logLevel : Int ,
72
+ warnIfNotFound : Boolean = false,
73
+ codegenSchemaFiles : List <Any >,
74
+ upstreamMetadata : List <Any >,
75
+ irOperations : File ,
76
+ downstreamUsedCoordinates : Map <String , Map <String , Set <String >>>,
77
+ codegenOptions : File ,
78
+ operationManifestFile : File ? ,
79
+ outputDir : File ,
80
+ metadataOutputFile : File ?
81
+ ) {
82
+ val plugin = apolloCompilerPlugin(
83
+ arguments,
84
+ logLevel,
85
+ warnIfNotFound
86
+ )
87
+ val codegenSchemaFile = codegenSchemaFiles.toInputFiles().map { it.file }.findCodegenSchemaFile()
88
+
89
+ val codegenSchema = codegenSchemaFile.toCodegenSchema()
90
+
91
+ val upstreamCodegenMetadata = upstreamMetadata.toInputFiles().map { it.file.toCodegenMetadata() }
92
+ ApolloCompiler .buildSchemaAndOperationsSourcesFromIr(
93
+ codegenSchema = codegenSchema,
94
+ irOperations = irOperations.toIrOperations(),
95
+ downstreamUsedCoordinates = downstreamUsedCoordinates.toUsedCoordinates(),
96
+ upstreamCodegenMetadata = upstreamCodegenMetadata,
97
+ codegenOptions = codegenOptions.toCodegenOptions(),
98
+ layout = plugin?.layout(codegenSchema),
99
+ irOperationsTransform = plugin?.irOperationsTransform(),
100
+ javaOutputTransform = plugin?.javaOutputTransform(),
101
+ kotlinOutputTransform = plugin?.kotlinOutputTransform(),
102
+ operationManifestFile = operationManifestFile,
103
+ operationOutputGenerator = plugin?.toOperationOutputGenerator(),
104
+ ).writeTo(outputDir, true , metadataOutputFile)
105
+
106
+ if (upstreamCodegenMetadata.isEmpty()) {
107
+ plugin?.schemaListener()?.onSchema(codegenSchema.schema, outputDir)
108
+ }
109
+ }
110
+
111
+ fun buildSources (
112
+ arguments : Map <String , Any ?>,
113
+ logLevel : Int ,
114
+ warnIfNotFound : Boolean = false,
115
+ schemaFiles : List <Any >,
116
+ graphqlFiles : List <Any >,
117
+ codegenSchemaOptions : File ,
118
+ codegenOptions : File ,
119
+ irOptions : File ,
120
+ warning : Consumer <String >,
121
+ operationManifestFile : File ? ,
122
+ outputDir : File
123
+ ) {
124
+ val plugin = apolloCompilerPlugin(
125
+ arguments,
126
+ logLevel,
127
+ warnIfNotFound
128
+ )
129
+
130
+ val codegenSchema = ApolloCompiler .buildCodegenSchema(
131
+ schemaFiles = schemaFiles.toInputFiles(),
132
+ codegenSchemaOptions = codegenSchemaOptions.toCodegenSchemaOptions(),
133
+ foreignSchemas = plugin?.foreignSchemas().orEmpty(),
134
+ logger = warning.toLogger()
135
+ )
136
+
137
+ ApolloCompiler .buildSchemaAndOperationsSources(
138
+ codegenSchema,
139
+ executableFiles = graphqlFiles.toInputFiles(),
140
+ codegenOptions = codegenOptions.toCodegenOptions(),
141
+ irOptions = irOptions.toIrOptions(),
142
+ logger = warning.toLogger(),
143
+ layoutFactory = object : LayoutFactory {
144
+ override fun create (codegenSchema : CodegenSchema ): SchemaAndOperationsLayout ? {
145
+ return plugin?.layout(codegenSchema)
146
+ }
147
+ },
148
+ operationOutputGenerator = plugin?.toOperationOutputGenerator(),
149
+ irOperationsTransform = plugin?.irOperationsTransform(),
150
+ javaOutputTransform = plugin?.javaOutputTransform(),
151
+ kotlinOutputTransform = plugin?.kotlinOutputTransform(),
152
+ documentTransform = plugin?.documentTransform(),
153
+ operationManifestFile = operationManifestFile,
154
+ ).writeTo(outputDir, true , null )
155
+
156
+ plugin?.schemaListener()?.onSchema(codegenSchema.schema, outputDir)
157
+ }
158
+ }
159
+
160
+ internal fun ApolloCompilerPlugin.toOperationOutputGenerator (): OperationOutputGenerator {
161
+ return object : OperationOutputGenerator {
162
+ override fun generate (operationDescriptorList : Collection <OperationDescriptor >): OperationOutput {
163
+ var operationIds = operationIds(operationDescriptorList.toList())
164
+ if (operationIds == null ) {
165
+ operationIds = operationDescriptorList.map { OperationId (OperationIdGenerator .Sha256 .apply (it.source, it.name), it.name) }
166
+ }
167
+ return operationDescriptorList.associateBy { descriptor ->
168
+ val operationId = operationIds.firstOrNull { it.name == descriptor.name } ? : error(" No id found for operation ${descriptor.name} " )
169
+ operationId.id
170
+ }
171
+ }
172
+ }
173
+ }
174
+
175
+ internal fun Consumer<String>.toLogger (): ApolloCompiler .Logger {
176
+ return object : ApolloCompiler .Logger {
177
+ override fun warning (message : String ) {
178
+ accept(message)
179
+ }
180
+ }
181
+ }
182
+
183
+ @ApolloInternal
184
+ fun Iterable<File>.findCodegenSchemaFile (): File {
185
+ return firstOrNull {
186
+ it.length() > 0
187
+ } ? : error(" Cannot find CodegenSchema in $this " )
188
+ }
189
+
190
+ internal fun apolloCompilerPlugin (
191
+ arguments : Map <String , Any ?>,
192
+ logLevel : Int ,
193
+ warnIfNotFound : Boolean = false,
194
+ ): ApolloCompilerPlugin ? {
195
+ val plugins = ServiceLoader .load(ApolloCompilerPlugin ::class .java, ApolloCompilerPlugin ::class .java.classLoader).toList()
196
+
197
+ if (plugins.size > 1 ) {
198
+ error(" Apollo: only a single compiler plugin is allowed" )
199
+ }
200
+
201
+ val plugin = plugins.singleOrNull()
202
+ if (plugin != null ) {
203
+ error(" Apollo: use ApolloCompilerPluginProvider instead of ApolloCompilerPlugin directly. ApolloCompilerPluginProvider allows arguments and logging" )
204
+ }
205
+
206
+ val pluginProviders = ServiceLoader .load(ApolloCompilerPluginProvider ::class .java, ApolloCompilerPlugin ::class .java.classLoader).toList()
207
+
208
+ if (pluginProviders.size > 1 ) {
209
+ error(" Apollo: only a single compiler plugin provider is allowed" )
210
+ }
211
+
212
+ if (pluginProviders.isEmpty() && warnIfNotFound) {
213
+ println (" Apollo: a compiler plugin was added with `Service.plugin()` but could not be loaded by the ServiceLoader. Check your META-INF/services/com.apollographql.apollo.compiler.ApolloCompilerPluginProvider file." )
214
+ }
215
+
216
+ val provider = pluginProviders.singleOrNull()
217
+ if (provider != null ) {
218
+ return provider.create(
219
+ ApolloCompilerPluginEnvironment (
220
+ arguments,
221
+ GradleCompilerPluginLogger (logLevel)
222
+ )
223
+ )
224
+ }
225
+
226
+ return plugins.singleOrNull()
227
+ }
228
+
229
+
230
+ internal fun List<Any>.toInputFiles (): List <InputFile > = buildList {
231
+ val iterator = this @toInputFiles.iterator()
232
+ while (iterator.hasNext()) {
233
+ add(InputFile (normalizedPath = iterator.next() as String , file = iterator.next() as File ))
234
+ }
235
+ }
0 commit comments