1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/**
18 * This file was created using the `create_project.py` script located in the
19 * `<AndroidX root>/development/project-creator` directory.
20 *
21 * Please use that script when creating a new project, rather than copying an existing project and
22 * modifying its settings.
23 */
24
25import androidx.build.BuildOnServerKt
26import androidx.build.SoftwareType
27import androidx.build.SdkHelperKt
28import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
29
30import java.util.regex.Matcher
31import java.util.regex.Pattern
32
33plugins {
34    id("AndroidXPlugin")
35    id("AndroidXRepackagePlugin")
36    id("kotlin")
37}
38
39repackage {
40    // Must match what is in room/room-external-antlr/build.gradle
41    addRelocation {
42        sourcePackage = "org.antlr"
43        targetPackage = "androidx.room.jarjarred.org.antlr"
44    }
45    // Must match what is in room/room-external-antlr/build.gradle
46    addRelocation {
47        sourcePackage = "org.stringtemplate"
48        targetPackage =  "androidx.room.jarjarred.org.stringtemplate"
49    }
50}
51
52androidx.configureAarAsJarForConfiguration("testImplementation")
53
54dependencies {
55    implementation(project(":room:room-common"))
56    implementation(project(":room:room-external-antlr"))
57    implementation(project(":room:room-migration"))
58    implementation(project(":room:room-compiler-processing"))
59    implementation(libs.kotlinStdlib)
60    implementation(libs.autoCommon)
61    implementation(libs.autoValueAnnotations)
62    implementation(libs.javapoet)
63    implementation("com.squareup:kotlinpoet:2.0.0")
64    implementation("com.squareup:kotlinpoet-javapoet:2.0.0")
65    implementation(libs.kspApi)
66    // Must be compileOnly to not bring in antlr4 in runtime
67    // Repackaged antlr4 brought in by
68    // project(":room:room-external-antlr") and used at runtime
69    compileOnly(libs.antlr4) {
70        // antlr has dependencies on unrelated projects for its gui stuff, do not include them
71        exclude group: "org.abego.treelayout"
72        exclude group: "com.ibm.icu"
73        exclude group: "org.glassfish"
74    }
75    implementation(libs.sqliteJdbc)
76    implementation(libs.apacheCommonsCodec)
77    implementation(libs.intellijAnnotations)
78    testImplementation(libs.truth)
79    testImplementation(project(":kruth:kruth"))
80    testImplementation(libs.testParameterInjector)
81    testImplementation(libs.autoValue) // to access the processor in tests
82    testImplementation(libs.autoServiceAnnotations)
83    testImplementation(libs.autoService) // to access the processor in tests
84    testImplementation(project(":paging:paging-common"))
85    testImplementation(project(":room:room-compiler-processing-testing"))
86    testImplementation(libs.junit)
87    testImplementation(libs.jsr250)
88    testImplementation(libs.mockitoCore4)
89    testImplementation(libs.antlr4)
90    testImplementation(SdkHelperKt.getSdkDependency(project))
91    testImplementationAarAsJar(project(":room:room-runtime"))
92    testImplementationAarAsJar(project(":sqlite:sqlite"))
93    testImplementation(project(":internal-testutils-common"))
94}
95
96def generateAntlrTask = tasks.register("generateAntlrGrammar", GenerateAntlrGrammar) { task ->
97    def sourceFiles = [
98            "SQLiteLexer.g4",
99            "SQLiteParser.g4"
100    ]
101    task.getSourceFiles().set(sourceFiles.collect { layout.projectDirectory.file(it) })
102    task.getAntlrClasspath().from(configurations.compileClasspath)
103    task.getOutputDirectory().set(layout.buildDirectory.dir("generated/antlr/grammar-gen/"))
104}
105
106sourceSets {
107    main.java.srcDirs += generateAntlrTask.map { it.outputDirectory }
108}
109
110@CacheableTask
111abstract class GenerateAntlrGrammar extends DefaultTask {
112    @PathSensitive(PathSensitivity.NONE)
113    @InputFiles
114    abstract ListProperty<RegularFile> getSourceFiles()
115
116    @Classpath
117    abstract ConfigurableFileCollection getAntlrClasspath()
118
119    @OutputDirectory
120    abstract DirectoryProperty getOutputDirectory()
121
122    @Inject
123    abstract ExecOperations getExecOperations()
124
125    @Inject
126    public GenerateAntlrGrammar() {
127        description = "Generates ANTLR Grammar used by Room"
128        group = "build"
129    }
130
131    @TaskAction
132    void generateAntlrGrammar() {
133        File outputDirectoryFile = getOutputDirectory().asFile.get()
134        outputDirectoryFile.deleteDir()
135        execOperations.javaexec {
136            mainClass.set("org.antlr.v4.Tool")
137            classpath = getAntlrClasspath()
138            args(
139                 *getSourceFiles().get().collect { it.getAsFile().absolutePath },
140                 "-visitor",
141                 "-o", new File(outputDirectoryFile, "androidx/room/parser").path,
142                 "-package", "androidx.room.parser"
143            )
144        }
145    }
146}
147
148/**
149 * This task validates the published artifacts of room compiler to ensure dependencies are properly
150 * specified.
151 */
152abstract class CheckArtifactTask extends DefaultTask {
153    @InputFiles
154    abstract ConfigurableFileCollection getArtifactInputs()
155    @InputFile
156    abstract RegularFileProperty getPomFile()
157    @OutputFile
158    abstract RegularFileProperty getResult()
159
160    /**
161     * Checks the generated pom file to ensure it does not depend on any jarjarred dependencies
162     * but still depends on others.
163     */
164    void validatePomTaskOutputs() {
165        File pom = getPomFile().asFile.get()
166        if (!pom.canRead()) {
167            throw new GradleException("Cannot find the pom file for room-compiler")
168        }
169        def pomContents = pom.newReader().text
170        Pattern antlrDep = Pattern.compile("<dependency>\\s.*antlr(.*\\s)*</dependency>")
171        Matcher matcher = antlrDep.matcher(pomContents)
172        if (matcher.find()) {
173            throw new GradleException("Room-compiler pom file should not depend on antlr.\n" +
174                    "Pom Contents:\n $pomContents")
175        }
176        if(!pomContents.contains("<artifactId>kotlin-stdlib</artifactId>")) {
177            throw new GradleException("room-compiler should depend on kotlin stdlib.\n" +
178                    "Pom Contents:\n $pomContents")
179        }
180    }
181
182    @TaskAction
183    void validate() {
184        getResult().asFile.get().write("fail\n")
185        validatePomTaskOutputs()
186        // have a no-op output to make gradle happy w/ input/output checking.
187        getResult().asFile.get().write("ok\n")
188    }
189}
190
191def checkArtifactContentsTask = tasks.register("checkArtifact", CheckArtifactTask) { task ->
192    task.getResult().set(layout.buildDirectory.file("checkArtifactOutput.txt"))
193    def pomTask = (TaskProvider<GenerateMavenPom>) project.tasks.named("generatePomFileForMavenPublication")
194    task.getPomFile().set(
195            project.objects.fileProperty().fileProvider(
196                    pomTask.map {  it.destination }
197            )
198    )
199}
200
201afterEvaluate {
202    def publishTaskProvider = project.tasks.named("publishMavenPublicationToMavenRepository")
203    checkArtifactContentsTask.configure { checkArtifactTask ->
204        checkArtifactTask.getArtifactInputs().from {
205            publishTaskProvider.map {
206                ((PublishToMavenRepository) it).getPublication().artifacts.matching {
207                    it.classifier == null
208                }.collect {
209                    it.file
210                }
211            }
212        }
213    }
214}
215
216// make sure we validate published artifacts on the build server.
217BuildOnServerKt.addToBuildOnServer(project, checkArtifactContentsTask)
218
219tasks.withType(KotlinCompile).configureEach {
220    kotlinOptions {
221        freeCompilerArgs += [
222                "-opt-in=kotlin.contracts.ExperimentalContracts",
223                "-opt-in=androidx.room.compiler.processing.ExperimentalProcessingApi",
224                "-opt-in=com.squareup.kotlinpoet.javapoet.KotlinPoetJavaPoetPreview"
225        ]
226    }
227}
228
229tasks.withType(Test).configureEach {
230    it.systemProperty("androidx.room.compiler.processing.strict", "true")
231    it.maxParallelForks = 8
232    if (project.providers.environmentVariable("GITHUB_ACTIONS").present) {
233        // limit memory usage to avoid running out of memory in the docker container.
234        it.maxHeapSize = "512m"
235    }
236}
237
238androidx {
239    name = "Room Compiler"
240    type = SoftwareType.ANNOTATION_PROCESSOR
241    inceptionYear = "2017"
242    description = "Android Room annotation processor"
243}
244