[GH] Migrate playground-plugin to Kotlin
## Proposed Changes
Migrate playground-plugin to Kotlin
## Testing
Test: ./gradlew tasks in activity/
This is an imported pull request from https://github.com/androidx/androidx/pull/286.
Resolves #286
Github-Pr-Head-Sha: 87e4facd13dd102b132e995b2355bce7f52796fe
GitOrigin-RevId: 69b809796452428398b5cd3317a7bbb823173dbd
Change-Id: I0e07b77a71a24b80b1af5f5b30419bcbcbd88d0c
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index ac87caf..6bcb125 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -173,3 +173,6 @@
wireRuntime = { module = "com.squareup.wire:wire-runtime", version.ref = "wire" }
xpp3 = { module = "xpp3:xpp3", version = "1.1.4c" }
xmlpull = { module = "xmlpull:xmlpull", version = "1.1.3.1" }
+
+[plugins]
+kotlinJvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
diff --git a/playground-common/playground-plugin/build.gradle b/playground-common/playground-plugin/build.gradle
index 9fff29a..7b521cf 100644
--- a/playground-common/playground-plugin/build.gradle
+++ b/playground-common/playground-plugin/build.gradle
@@ -13,8 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
- plugins {
+
+plugins {
id "groovy-gradle-plugin"
+ alias(libs.plugins.kotlinJvm)
}
repositories {
@@ -26,6 +28,15 @@
implementation "com.gradle:common-custom-user-data-gradle-plugin:1.5"
}
+// Needed to be able to use Groovy code from Kotlin
+// https://docs.gradle.org/6.1-rc-1/release-notes.html#compilation-order
+tasks.named('compileGroovy') {
+ classpath = sourceSets.main.compileClasspath
+}
+tasks.named('compileKotlin') {
+ classpath += files(sourceSets.main.groovy.classesDirectory)
+}
+
gradlePlugin {
plugins {
playgroundConventions {
diff --git a/playground-common/playground-plugin/settings.gradle b/playground-common/playground-plugin/settings.gradle
index 9c18267..cb8499c 100644
--- a/playground-common/playground-plugin/settings.gradle
+++ b/playground-common/playground-plugin/settings.gradle
@@ -33,3 +33,12 @@
}
}
}
+
+enableFeaturePreview("VERSION_CATALOGS")
+dependencyResolutionManagement {
+ versionCatalogs {
+ libs {
+ from(files("../../gradle/libs.versions.toml"))
+ }
+ }
+}
\ No newline at end of file
diff --git a/playground-common/playground-plugin/src/main/groovy/androidx/playground/GradleEnterpriseConventionsPlugin.groovy b/playground-common/playground-plugin/src/main/groovy/androidx/playground/GradleEnterpriseConventionsPlugin.groovy
deleted file mode 100644
index 566904b..0000000
--- a/playground-common/playground-plugin/src/main/groovy/androidx/playground/GradleEnterpriseConventionsPlugin.groovy
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package androidx.playground
-
-import org.gradle.api.Plugin
-import org.gradle.api.initialization.Settings
-import org.gradle.caching.http.HttpBuildCache
-
-class GradleEnterpriseConventionsPlugin implements Plugin<Settings> {
- void apply(Settings settings) {
- settings.apply(plugin: "com.gradle.enterprise")
- settings.apply(plugin: "com.gradle.common-custom-user-data-gradle-plugin")
-
- // Github Actions always sets a "CI" environment variable
- var isCI = System.getenv("CI") != null
-
- settings.gradleEnterprise {
- server = "https://ge.androidx.dev"
-
- buildScan {
- publishAlways()
- publishIfAuthenticated()
-
- uploadInBackground = !isCI
-
- capture {
- taskInputFiles = true
- }
- obfuscation {
- hostname { host -> "unset" }
- ipAddresses { addresses -> addresses.collect { address -> "0.0.0.0"} }
- }
- }
- }
-
- settings.buildCache {
- remote(HttpBuildCache) {
- url = "https://ge.androidx.dev/cache/"
- var buildCachePassword = System.getenv("GRADLE_BUILD_CACHE_PASSWORD")
- if (isCI && buildCachePassword != null && !buildCachePassword.empty) {
- push = true
- credentials {
- username = "ci"
- password = buildCachePassword
- }
- } else {
- push = false
- }
- }
- }
- }
-}
diff --git a/playground-common/playground-plugin/src/main/groovy/androidx/playground/GradleWorkaround.groovy b/playground-common/playground-plugin/src/main/groovy/androidx/playground/GradleWorkaround.groovy
new file mode 100644
index 0000000..d85061c
--- /dev/null
+++ b/playground-common/playground-plugin/src/main/groovy/androidx/playground/GradleWorkaround.groovy
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.playground
+
+import com.gradle.scan.plugin.BuildScanDataObfuscation
+
+class GradleWorkaround {
+ /**
+ * This is needed because Gradle configuration caching fails to serialize these lambdas
+ * if they are written in Kotlin
+ * https://github.com/gradle/gradle/issues/19047
+ */
+ static void obfuscate(BuildScanDataObfuscation obfuscation) {
+ obfuscation.hostname {"unset" }
+ obfuscation.ipAddresses { addresses -> addresses.collect { address -> "0.0.0.0"} }
+ }
+}
\ No newline at end of file
diff --git a/playground-common/playground-plugin/src/main/groovy/androidx/playground/PlaygroundExtension.groovy b/playground-common/playground-plugin/src/main/groovy/androidx/playground/PlaygroundExtension.groovy
deleted file mode 100644
index ab9daac..0000000
--- a/playground-common/playground-plugin/src/main/groovy/androidx/playground/PlaygroundExtension.groovy
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package androidx.playground
-
-import javax.inject.Inject
-import org.gradle.api.GradleException
-import org.gradle.api.model.ObjectFactory
-import org.gradle.api.initialization.Settings
-
-class PlaygroundExtension {
- private final ObjectFactory objectFactory
- private final Settings settings
-
- private File supportRootDir
-
- @Inject
- PlaygroundExtension(Settings settings, ObjectFactory objectFactory) {
- this.settings = settings
- this.objectFactory = objectFactory
- }
-
- /**
- * Includes the project if it does not already exist.
- * This is invoked from `includeProject` to ensure all parent projects are included. If they are
- * not, gradle will use the root project path to set the projectDir, which might conflict in
- * playground. Instead, this method checks if another project in that path exists and if so,
- * changes the project dir to avoid the conflict.
- * see b/197253160 for details.
- */
- private includeFakeParentProjectIfNotExists(String name, File projectDir) {
- if (name.isEmpty()) return
- if (settings.findProject(name)) {
- return
- }
- if (settings.findProject(projectDir) != null) {
- // Project directory conflicts with an existing project (possibly root). Move it
- // to another directory to avoid the conflict.
- projectDir = new File(projectDir.getParentFile(), ".ignore-${projectDir.name}")
- }
- includeProjectAt(name, projectDir)
- // Set it to a gradle file that does not exist.
- // We must always include projects starting with root, if we are including nested projects.
- settings.project(name).buildFileName = "ignored.gradle"
- }
-
- private includeProjectAt(String name, File projectDir) {
- if (settings.findProject(name) != null) {
- throw new GradleException("Cannot include project twice: $name is already included.")
- }
- def parentPath = name.substring(0, name.lastIndexOf(":"))
- def parentDir = projectDir.getParentFile()
- // Make sure parent is created first. see: b/197253160 for details
- includeFakeParentProjectIfNotExists(
- parentPath,
- parentDir
- )
- settings.include(name)
- settings.project(name).projectDir = projectDir
- }
-
- /**
- * Includes a project by name, with a path relative to the root of AndroidX.
- */
- def includeProject(String name, String filePath) {
- if (supportRootDir == null) {
- throw new GradleException("Must call setupPlayground() first.")
- }
- includeProjectAt(name, new File(supportRootDir, filePath))
- }
-
- /**
- * Initializes the playground project to use public repositories as well as other internal projects
- * that cannot be found in public repositories.
- *
- * @param settings The reference to the settings script
- * @param relativePathToRoot The relative path of the project to the root AndroidX project
- */
- def setupPlayground(String relativePathToRoot) {
- def projectDir = settings.rootProject.getProjectDir()
- def supportRoot = new File(projectDir, relativePathToRoot).getCanonicalFile()
- this.supportRootDir = supportRoot
- def buildFile = new File(supportRoot, "playground-common/playground-build.gradle")
- def relativePathToBuild = projectDir.toPath().relativize(buildFile.toPath()).toString()
-
- Properties playgroundProperties = new Properties()
- File propertiesFile = new File(supportRoot, "playground-common/playground.properties")
- propertiesFile.withInputStream {
- playgroundProperties.load(it)
- }
- settings.gradle.beforeProject { project ->
- // load playground properties. These are not kept in the playground projects to prevent
- // AndroidX build from reading them.
- playgroundProperties.each {
- project.ext[it.key] = it.value
- }
- }
-
- settings.rootProject.buildFileName = relativePathToBuild
- settings.enableFeaturePreview("VERSION_CATALOGS")
-
- def catalogFiles = objectFactory.fileCollection().from("$supportRoot/gradle/libs.versions.toml")
- settings.dependencyResolutionManagement {
- versionCatalogs {
- libs {
- from(catalogFiles)
- }
- }
- }
-
- includeProject(":lint-checks", "lint-checks")
- includeProject(":lint-checks:integration-tests", "lint-checks/integration-tests")
- includeProject(":fakeannotations", "fakeannotations")
- includeProject(":internal-testutils-common", "testutils/testutils-common")
- includeProject(":internal-testutils-gradle-plugin", "testutils/testutils-gradle-plugin")
-
- // allow public repositories
- System.setProperty("ALLOW_PUBLIC_REPOS", "true")
-
- // specify out dir location
- System.setProperty("CHECKOUT_ROOT", supportRoot.path)
- }
-
-
- /**
- * A convenience method to include projects from the main AndroidX build using a filter.
- *
- * @param filter This filter will be called with the project name (project path in gradle).
- * If filter returns true, it will be included in the build.
- */
- def selectProjectsFromAndroidX(filter) {
- if (supportRootDir == null) {
- throw new RuntimeException("Must call setupPlayground() first.")
- }
-
- // Multiline matcher for anything of the form:
- // includeProject(name, path, ...)
- // where '...' is anything except the ')' character.
- def includeProjectPattern = ~/(?m)^[\n\r\s]*includeProject\("(?<name>[a-z0-9-:]*)",[\n\r\s]*"(?<path>[a-z0-9-\/]+)[^)]+\)$/
- def supportSettingsFile = new File(supportRootDir, "settings.gradle")
- def matcher = includeProjectPattern.matcher(supportSettingsFile.text)
-
- while (matcher.find()) {
- // check if is an include project line, if so, extract project gradle path and
- // file system path and call the filter
- def projectGradlePath = matcher.group("name")
- def projectFilePath = matcher.group("path")
- if (filter(projectGradlePath)) {
- includeProject(projectGradlePath, projectFilePath)
- }
- }
- }
-
- /**
- * Checks if a project is necessary for playground projects that involve compose.
- */
- def isNeededForComposePlayground(name) {
- if (name == ":compose:lint:common") return true
- if (name == ":compose:lint:internal-lint-checks") return true
- if (name == ":compose:test-utils") return true
- if (name == ":compose:lint:common-test") return true
- if (name == ":test:screenshot:screenshot") return true
- return false
- }
-}
\ No newline at end of file
diff --git a/playground-common/playground-plugin/src/main/groovy/androidx/playground/PlaygroundPlugin.groovy b/playground-common/playground-plugin/src/main/groovy/androidx/playground/PlaygroundPlugin.groovy
deleted file mode 100644
index 4208b82..0000000
--- a/playground-common/playground-plugin/src/main/groovy/androidx/playground/PlaygroundPlugin.groovy
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package androidx.playground
-
-import org.gradle.api.Plugin
-import org.gradle.api.initialization.Settings
-
-class PlaygroundPlugin implements Plugin<Settings> {
- void apply(Settings settings) {
- settings.apply(plugin: "playground-ge-conventions")
-
- settings.extensions.create("playground", PlaygroundExtension, settings)
-
- validateJvm(settings)
- }
-
- def validateJvm(Settings settings) {
- // validate JVM version to print an understandable error if it is not set to the
- // required value (11)
- def jvmVersion = System.getProperty("java.vm.specification.version")
- if (jvmVersion != "11") {
- def guidance;
- if (settings.gradle.startParameter.projectProperties.containsKey("android.injected.invoked.from.ide")) {
- guidance = "Make sure to set the gradle JDK to JDK 11 in the project settings." +
- "(File -> Other Settings -> Default Project Structure)"
- } else {
- guidance = "Make sure your JAVA_HOME environment variable points to Java 11 JDK."
- }
- throw new IllegalStateException("""
- AndroidX build must be invoked with JDK 11.
- $guidance
- Current version: $jvmVersion
- Current JAVA HOME: ${System.getProperty("java.home")}""".stripIndent());
- }
-
- }
-}
diff --git a/playground-common/playground-plugin/src/main/kotlin/androidx/playground/GradleEnterpriseConventionsPlugin.kt b/playground-common/playground-plugin/src/main/kotlin/androidx/playground/GradleEnterpriseConventionsPlugin.kt
new file mode 100644
index 0000000..ef5a878
--- /dev/null
+++ b/playground-common/playground-plugin/src/main/kotlin/androidx/playground/GradleEnterpriseConventionsPlugin.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.playground
+
+import com.gradle.enterprise.gradleplugin.internal.extension.BuildScanExtensionWithHiddenFeatures
+import org.gradle.api.Plugin
+import org.gradle.api.initialization.Settings
+import org.gradle.caching.http.HttpBuildCache
+import org.gradle.kotlin.dsl.gradleEnterprise
+import java.net.URI
+
+class GradleEnterpriseConventionsPlugin : Plugin<Settings> {
+ override fun apply(settings: Settings) {
+ settings.apply(mapOf("plugin" to "com.gradle.enterprise"))
+ settings.apply(mapOf("plugin" to "com.gradle.common-custom-user-data-gradle-plugin"))
+
+ // Github Actions always sets a "CI" environment variable
+ val isCI = System.getenv("CI") != null
+
+ settings.gradleEnterprise {
+ server = "https://ge.androidx.dev"
+
+ buildScan.apply {
+ publishAlways()
+ (this as BuildScanExtensionWithHiddenFeatures).publishIfAuthenticated()
+ isUploadInBackground = !isCI
+ capture.isTaskInputFiles = true
+
+ GradleWorkaround.obfuscate(obfuscation)
+ }
+ }
+
+ settings.buildCache.remote(HttpBuildCache::class.java) { remote ->
+ remote.url = URI("https://ge.androidx.dev/cache/")
+ val buildCachePassword = System.getenv("GRADLE_BUILD_CACHE_PASSWORD")
+ if (isCI && !buildCachePassword.isNullOrEmpty()) {
+ remote.isPush = true
+ remote.credentials { credentials ->
+ credentials.username = "ci"
+ credentials.password = buildCachePassword
+ }
+ } else {
+ remote.isPush = false
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/playground-common/playground-plugin/src/main/kotlin/androidx/playground/PlaygroundExtension.kt b/playground-common/playground-plugin/src/main/kotlin/androidx/playground/PlaygroundExtension.kt
new file mode 100644
index 0000000..90a699a
--- /dev/null
+++ b/playground-common/playground-plugin/src/main/kotlin/androidx/playground/PlaygroundExtension.kt
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.playground
+
+import org.gradle.api.GradleException
+import org.gradle.api.initialization.Settings
+import org.gradle.api.model.ObjectFactory
+import java.io.File
+import java.util.Properties
+import javax.inject.Inject
+
+open class PlaygroundExtension @Inject constructor(
+ private val settings: Settings,
+ private val objectFactory: ObjectFactory
+) {
+ private var supportRootDir: File? = null
+
+ /**
+ * Includes the project if it does not already exist.
+ * This is invoked from `includeProject` to ensure all parent projects are included. If they are
+ * not, gradle will use the root project path to set the projectDir, which might conflict in
+ * playground. Instead, this method checks if another project in that path exists and if so,
+ * changes the project dir to avoid the conflict.
+ * see b/197253160 for details.
+ */
+ private fun includeFakeParentProjectIfNotExists(name: String, projectDir: File) {
+ if (name.isEmpty()) return
+ if (settings.findProject(name) != null) {
+ return
+ }
+ val actualProjectDir: File = if (settings.findProject(projectDir) != null) {
+ // Project directory conflicts with an existing project (possibly root). Move it
+ // to another directory to avoid the conflict.
+ File(projectDir.parentFile, ".ignore-${projectDir.name}")
+ } else {
+ projectDir
+ }
+ includeProjectAt(name, actualProjectDir)
+ // Set it to a gradle file that does not exist.
+ // We must always include projects starting with root, if we are including nested projects.
+ settings.project(name).buildFileName = "ignored.gradle"
+ }
+
+ private fun includeProjectAt(name: String, projectDir: File) {
+ if (settings.findProject(name) != null) {
+ throw GradleException("Cannot include project twice: $name is already included.")
+ }
+ val parentPath = name.substring(0, name.lastIndexOf(":"))
+ val parentDir = projectDir.parentFile
+ // Make sure parent is created first. see: b/197253160 for details
+ includeFakeParentProjectIfNotExists(
+ parentPath,
+ parentDir
+ )
+ settings.include(name)
+ settings.project(name).projectDir = projectDir
+ }
+
+ /**
+ * Includes a project by name, with a path relative to the root of AndroidX.
+ */
+ fun includeProject(name: String, filePath: String) {
+ if (supportRootDir == null) {
+ throw GradleException("Must call setupPlayground() first.")
+ }
+ includeProjectAt(name, File(supportRootDir, filePath))
+ }
+
+ /**
+ * Initializes the playground project to use public repositories as well as other internal
+ * projects that cannot be found in public repositories.
+ *
+ * @param relativePathToRoot The relative path of the project to the root AndroidX project
+ */
+ fun setupPlayground(relativePathToRoot: String) {
+ val projectDir = settings.rootProject.projectDir
+ val supportRoot = File(projectDir, relativePathToRoot).canonicalFile
+ this.supportRootDir = supportRoot
+ val buildFile = File(supportRoot, "playground-common/playground-build.gradle")
+ val relativePathToBuild = projectDir.toPath().relativize(buildFile.toPath()).toString()
+
+ val playgroundProperties = Properties()
+ val propertiesFile = File(supportRoot, "playground-common/playground.properties")
+ playgroundProperties.load(propertiesFile.inputStream())
+ settings.gradle.beforeProject { project ->
+ // load playground properties. These are not kept in the playground projects to prevent
+ // AndroidX build from reading them.
+ playgroundProperties.forEach {
+ project.extensions.extraProperties[it.key as String] = it.value
+ }
+ }
+
+ settings.rootProject.buildFileName = relativePathToBuild
+ settings.enableFeaturePreview("VERSION_CATALOGS")
+
+ val catalogFiles =
+ objectFactory.fileCollection().from("$supportRoot/gradle/libs.versions.toml")
+ settings.dependencyResolutionManagement {
+ it.versionCatalogs.create("libs").from(catalogFiles)
+ }
+
+ includeProject(":lint-checks", "lint-checks")
+ includeProject(":lint-checks:integration-tests", "lint-checks/integration-tests")
+ includeProject(":fakeannotations", "fakeannotations")
+ includeProject(":internal-testutils-common", "testutils/testutils-common")
+ includeProject(":internal-testutils-gradle-plugin", "testutils/testutils-gradle-plugin")
+
+ // allow public repositories
+ System.setProperty("ALLOW_PUBLIC_REPOS", "true")
+
+ // specify out dir location
+ System.setProperty("CHECKOUT_ROOT", supportRoot.path)
+ }
+
+ /**
+ * A convenience method to include projects from the main AndroidX build using a filter.
+ *
+ * @param filter This filter will be called with the project name (project path in gradle).
+ * If filter returns true, it will be included in the build.
+ */
+ fun selectProjectsFromAndroidX(filter: (String) -> Boolean) {
+ if (supportRootDir == null) {
+ throw RuntimeException("Must call setupPlayground() first.")
+ }
+
+ // Multiline matcher for anything of the form:
+ // includeProject(name, path, ...)
+ // where '...' is anything except the ')' character.
+ /* ktlint-disable max-line-length */
+ val includeProjectPattern = Regex(
+ """[\n\r\s]*includeProject\("(?<name>[a-z0-9-:]*)",[\n\r\s]*"(?<path>[a-z0-9-\/]+)[^)]+\)$""",
+ setOf(RegexOption.MULTILINE, RegexOption.IGNORE_CASE)
+ ).toPattern()
+ val supportSettingsFile = File(supportRootDir, "settings.gradle")
+ val matcher = includeProjectPattern.matcher(supportSettingsFile.readText())
+
+ while (matcher.find()) {
+ // check if is an include project line, if so, extract project gradle path and
+ // file system path and call the filter
+ val projectGradlePath = matcher.group("name")
+ val projectFilePath = matcher.group("path")
+ if (filter(projectGradlePath)) {
+ includeProject(projectGradlePath, projectFilePath)
+ }
+ }
+ }
+
+ /**
+ * Checks if a project is necessary for playground projects that involve compose.
+ */
+ fun isNeededForComposePlayground(name: String): Boolean {
+ if (name == ":compose:lint:common") return true
+ if (name == ":compose:lint:internal-lint-checks") return true
+ if (name == ":compose:test-utils") return true
+ if (name == ":compose:lint:common-test") return true
+ if (name == ":test:screenshot:screenshot") return true
+ return false
+ }
+}
\ No newline at end of file
diff --git a/playground-common/playground-plugin/src/main/kotlin/androidx/playground/PlaygroundPlugin.kt b/playground-common/playground-plugin/src/main/kotlin/androidx/playground/PlaygroundPlugin.kt
new file mode 100644
index 0000000..ff190ae
--- /dev/null
+++ b/playground-common/playground-plugin/src/main/kotlin/androidx/playground/PlaygroundPlugin.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.playground
+
+import org.gradle.api.Plugin
+import org.gradle.api.initialization.Settings
+
+class PlaygroundPlugin : Plugin<Settings> {
+ override fun apply(settings: Settings) {
+ settings.apply(mapOf("plugin" to "playground-ge-conventions"))
+ settings.extensions.create("playground", PlaygroundExtension::class.java, settings)
+ validateJvm(settings)
+ }
+
+ private fun validateJvm(settings: Settings) {
+ // validate JVM version to print an understandable error if it is not set to the
+ // required value (11)
+ val jvmVersion = System.getProperty("java.vm.specification.version")
+ check(jvmVersion == "11") {
+ """
+ AndroidX build must be invoked with JDK 11.
+ ${
+ if (settings.gradle.startParameter.projectProperties.containsKey(
+ "android.injected.invoked.from.ide"
+ )
+ ) {
+ """
+ Make sure to set the Gradle JDK to JDK 11 in the project settings.
+ File -> Settings -> Build, Execution, Deployment -> Build Tools ->
+ Gradle -> Gradle JDK"
+ """
+ } else {
+ "Make sure your JAVA_HOME environment variable points to Java 11 JDK."
+ }
+ }
+ Current version: $jvmVersion
+ Current JAVA HOME: ${System.getProperty("java.home")}
+ """.trimIndent()
+ }
+ }
+}
\ No newline at end of file