summaryrefslogtreecommitdiff
path: root/project-system-gradle/src/com/android/tools/idea/gradle/project/importing/InitialImportExcludeDirectoryPolicy.kt
diff options
context:
space:
mode:
Diffstat (limited to 'project-system-gradle/src/com/android/tools/idea/gradle/project/importing/InitialImportExcludeDirectoryPolicy.kt')
-rw-r--r--project-system-gradle/src/com/android/tools/idea/gradle/project/importing/InitialImportExcludeDirectoryPolicy.kt88
1 files changed, 88 insertions, 0 deletions
diff --git a/project-system-gradle/src/com/android/tools/idea/gradle/project/importing/InitialImportExcludeDirectoryPolicy.kt b/project-system-gradle/src/com/android/tools/idea/gradle/project/importing/InitialImportExcludeDirectoryPolicy.kt
new file mode 100644
index 00000000000..fb6435ef538
--- /dev/null
+++ b/project-system-gradle/src/com/android/tools/idea/gradle/project/importing/InitialImportExcludeDirectoryPolicy.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2022 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 com.android.tools.idea.gradle.project.importing
+
+import com.android.tools.idea.gradle.project.GradleProjectInfo
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.roots.ProjectRootManager
+import com.intellij.openapi.roots.impl.DirectoryIndexExcludePolicy
+import com.intellij.openapi.util.Key
+import com.intellij.openapi.vfs.VfsUtilCore
+import org.jetbrains.plugins.gradle.settings.GradleSettings
+import java.io.File
+
+/**
+ * A [DirectoryIndexExcludePolicy] that temporarily excludes all directories under a Gradle root from the project while the initial sync
+ * runs.
+ *
+ * This is needed to prevent directories that are normally excluded from the project after sync from being indexed or included in the VFS
+ * before the initial sync completes. Otherwise, indexing itself may take much time and any file included in the VFS stays there and is
+ * updated when the VFS area containing this file is refreshed. This in turn may result it massive VFS updates after building a project if
+ * its build directories end up in the VFS.
+ *
+ * [InitialImportExcludeDirectoryPolicy] reports any directories directly under the project's Gradle roots as excluded while there is no
+ * source roots yet in the project (i.e. sync has not yet succeeded).
+ */
+class InitialImportExcludeDirectoryPolicy(private val project: Project) : DirectoryIndexExcludePolicy {
+ override fun getExcludeUrlsForProject(): Array<out String> {
+ if (project.getUserData(EXCLUDE_DIRS_KEY) == false) return emptyArray()
+ // Stop returning any exclude directories when sync succeeds. A successful sync sets up some source roots unless all modules are empty.
+ // Note: We cannot rely on listeners here to clear the flag as roots are enumerated just after committing project model changes and
+ // listeners run too late.
+ if (!project.isGradleProject() || project.projectHasSourceRoots()) {
+ project.putUserData(EXCLUDE_DIRS_KEY, false)
+ return emptyArray()
+ }
+
+ return project
+ .getGradleRoots()
+ // TODO(b/242440055): Multiple Gradle roots are not yet supported here.
+ .flatMap { getDirectoriesToExcludeUnderGradleRoot(it) }
+ .map { VfsUtilCore.pathToUrl(it.path) }
+ .toTypedArray()
+ }
+}
+
+private fun Project.isGradleProject(): Boolean {
+ return GradleProjectInfo.getInstance(this).isBuildWithGradle
+}
+
+private fun Project.projectHasSourceRoots(): Boolean {
+ return ProjectRootManager.getInstance(this).orderEntries().withoutLibraries().withoutSdk().sources().urls.isNotEmpty()
+}
+
+private fun Project.getGradleRoots(): List<File> {
+ return GradleSettings.getInstance(this)
+ .linkedProjectsSettings
+ .mapNotNull { File(it.externalProjectPath) }
+}
+
+private fun getDirectoriesToExcludeUnderGradleRoot(gradleRoot: File): List<File> {
+ val existingDirectoryNames =
+ gradleRoot
+ .listFiles()
+ .orEmpty()
+ .filter { it.isDirectory }
+ .map { it.name }
+ .toSet()
+
+ val wellKnownDirectoryNames = setOf("build", ".gradle")
+
+ return (existingDirectoryNames + wellKnownDirectoryNames)
+ .map { gradleRoot.resolve(it) }
+}
+
+private val EXCLUDE_DIRS_KEY: Key<Boolean> = Key.create("temporary_excluded_dirs") \ No newline at end of file