mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-390110 [gradle] new: add suppressFailures option to GradleModelFetchRequest
(cherry picked from commit bb602a8ad4a96558f6e10d60d6b8ea8edc5c8ea7) IJ-CR-214557 GitOrigin-RevId: d0066d771c112b24a2e5017e307c6e3c45e89692
This commit is contained in:
committed by
intellij-monorepo-bot
parent
715a95f180
commit
dd487f45e3
+13
@@ -4,6 +4,7 @@ package com.intellij.gradle.toolingExtension.modelAction
|
||||
import org.gradle.api.Action
|
||||
import org.gradle.tooling.model.gradle.BasicGradleProject
|
||||
import org.gradle.tooling.model.gradle.GradleBuild
|
||||
import org.jetbrains.annotations.ApiStatus.Experimental
|
||||
import org.jetbrains.annotations.ApiStatus.NonExtendable
|
||||
import org.jetbrains.plugins.gradle.model.ProjectImportModelProvider.GradleModelConsumer
|
||||
import org.gradle.tooling.model.Model as GradleModel
|
||||
@@ -81,6 +82,18 @@ interface GradleModelController {
|
||||
parameterInitializer: Action<in Parameter>,
|
||||
): GradleModelFetchRequest<Model>
|
||||
|
||||
/**
|
||||
* Suppresses failures for this model fetch request.
|
||||
*
|
||||
* When suppressed:
|
||||
* - With the resilient Gradle API: failures returned by [org.gradle.tooling.BuildController.fetch] are not forwarded.
|
||||
* - Without the resilient Gradle API: exceptions thrown by [org.gradle.tooling.BuildController.getModel] are caught and discarded.
|
||||
*
|
||||
* Use this when the model may not be available in all Gradle configurations.
|
||||
*/
|
||||
@Experimental
|
||||
fun suppressFailures(): GradleModelFetchRequest<Model>
|
||||
|
||||
fun execute(modelConsumer: GradleModelConsumer)
|
||||
|
||||
enum class GradleExecutionMode {
|
||||
|
||||
+70
-51
@@ -54,7 +54,7 @@ class GradleModelControllerImpl(
|
||||
error("Strict Gradle model fetch unexpectedly returned invalid model for ${modelClass.name}")
|
||||
}
|
||||
|
||||
sendModelFetchFailures(null, result)
|
||||
sendModelFetchFailures(null, result, false)
|
||||
return model
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ class GradleModelControllerImpl(
|
||||
return buildController.findModel(modelClass)
|
||||
}
|
||||
return buildController.fetch(modelClass)
|
||||
.also { sendModelFetchFailures(null, it) }
|
||||
.also { sendModelFetchFailures(null, it, false) }
|
||||
.getModel()
|
||||
}
|
||||
|
||||
@@ -71,23 +71,19 @@ class GradleModelControllerImpl(
|
||||
target: Target,
|
||||
modelClass: Class<Model>,
|
||||
modelParameter: GradleModelParameter<*>?,
|
||||
suppressFailures: Boolean,
|
||||
): Model? {
|
||||
if (modelParameter != null) {
|
||||
return fetchModelOrNull(target, modelClass, modelParameter.parameterClass, modelParameter.parameterInitializer)
|
||||
return fetchModelOrNull(target, modelClass, modelParameter.parameterClass, modelParameter.parameterInitializer, suppressFailures)
|
||||
}
|
||||
return fetchModelOrNull(target, modelClass)
|
||||
return fetchModelOrNull(target, modelClass, suppressFailures)
|
||||
}
|
||||
|
||||
override fun <Target : GradleModel, Model : Any> fetchModelOrNull(
|
||||
target: Target,
|
||||
modelClass: Class<Model>,
|
||||
): Model? {
|
||||
if (!isResilientModelFetchApiUsed()) {
|
||||
return buildController.findModel(target, modelClass)
|
||||
}
|
||||
return buildController.fetch(target, modelClass)
|
||||
.also { sendModelFetchFailures(target, it) }
|
||||
.getModel()
|
||||
return fetchModelOrNull(target, modelClass, false)
|
||||
}
|
||||
|
||||
override fun <Target : GradleModel, Model : Any, Parameter : Any> fetchModelOrNull(
|
||||
@@ -95,12 +91,39 @@ class GradleModelControllerImpl(
|
||||
modelClass: Class<Model>,
|
||||
modelParameterClass: Class<Parameter>,
|
||||
modelParameterInitializer: Action<in Parameter>,
|
||||
): Model? {
|
||||
return fetchModelOrNull(target, modelClass, modelParameterClass, modelParameterInitializer, false)
|
||||
}
|
||||
|
||||
private fun <Target : GradleModel, Model : Any> fetchModelOrNull(
|
||||
target: Target,
|
||||
modelClass: Class<Model>,
|
||||
suppressFailures: Boolean,
|
||||
): Model? {
|
||||
if (!isResilientModelFetchApiUsed()) {
|
||||
return buildController.findModel(target, modelClass, modelParameterClass, modelParameterInitializer)
|
||||
return handleModelFetchFailures(suppressFailures) {
|
||||
buildController.findModel(target, modelClass)
|
||||
}
|
||||
}
|
||||
return buildController.fetch(target, modelClass)
|
||||
.also { sendModelFetchFailures(target, it, suppressFailures) }
|
||||
.getModel()
|
||||
}
|
||||
|
||||
private fun <Target : GradleModel, Model : Any, Parameter : Any> fetchModelOrNull(
|
||||
target: Target,
|
||||
modelClass: Class<Model>,
|
||||
modelParameterClass: Class<Parameter>,
|
||||
modelParameterInitializer: Action<in Parameter>,
|
||||
suppressFailures: Boolean,
|
||||
): Model? {
|
||||
if (!isResilientModelFetchApiUsed()) {
|
||||
return handleModelFetchFailures(suppressFailures) {
|
||||
buildController.findModel(target, modelClass, modelParameterClass, modelParameterInitializer)
|
||||
}
|
||||
}
|
||||
return buildController.fetch(target, modelClass, modelParameterClass, modelParameterInitializer)
|
||||
.also { sendModelFetchFailures(target, it) }
|
||||
.also { sendModelFetchFailures(target, it, suppressFailures) }
|
||||
.getModel()
|
||||
}
|
||||
|
||||
@@ -109,14 +132,35 @@ class GradleModelControllerImpl(
|
||||
|
||||
private fun <Model : Any> fetchModels(request: GradleModelFetchRequestImpl<Model>, modelConsumer: GradleModelConsumer) {
|
||||
|
||||
fun <Target : GradleModel> fetchTargetModelsInParallel(targets: Collection<Target>, consumer: (Target, Model, Class<Model>) -> Unit) {
|
||||
val buildActions = targets.map { target ->
|
||||
BuildAction { innerBuildController ->
|
||||
val innerController = GradleModelControllerImpl(innerBuildController)
|
||||
val model = innerController.fetchModelOrNull(target, request.modelClass, request.modelParameter, request.suppressFailures)
|
||||
target to model
|
||||
}
|
||||
}
|
||||
val models = buildController.run(buildActions)
|
||||
for ((target, model) in models) {
|
||||
consumer(target, model ?: continue, request.modelClass)
|
||||
}
|
||||
}
|
||||
|
||||
fun <Target : GradleModel> fetchTargetModelsInSequence(targets: Collection<Target>, consumer: (Target, Model, Class<Model>) -> Unit) {
|
||||
for (target in targets) {
|
||||
val model = fetchModelOrNull(target, request.modelClass, request.modelParameter, request.suppressFailures)
|
||||
consumer(target, model ?: continue, request.modelClass)
|
||||
}
|
||||
}
|
||||
|
||||
fun <Target : GradleModel> fetchModels(targets: Collection<Target>, consumer: (Target, Model, Class<Model>) -> Unit) {
|
||||
when (request.executionMode) {
|
||||
GradleExecutionMode.DEFAULT -> when (isParallelModelFetchEnabled()) {
|
||||
true -> fetchTargetModelsInParallel(targets, request.modelClass, request.modelParameter, consumer)
|
||||
else -> fetchTargetModelsInSequence(targets, request.modelClass, request.modelParameter, consumer)
|
||||
true -> fetchTargetModelsInParallel(targets, consumer)
|
||||
else -> fetchTargetModelsInSequence(targets, consumer)
|
||||
}
|
||||
GradleExecutionMode.PARALLEL -> fetchTargetModelsInParallel(targets, request.modelClass, request.modelParameter, consumer)
|
||||
GradleExecutionMode.SEQUENTIAL -> fetchTargetModelsInSequence(targets, request.modelClass, request.modelParameter, consumer)
|
||||
GradleExecutionMode.PARALLEL -> fetchTargetModelsInParallel(targets, consumer)
|
||||
GradleExecutionMode.SEQUENTIAL -> fetchTargetModelsInSequence(targets, consumer)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,39 +178,6 @@ class GradleModelControllerImpl(
|
||||
}
|
||||
}
|
||||
|
||||
private fun <Target : GradleModel, Model : Any> fetchTargetModelsInParallel(
|
||||
targets: Collection<Target>,
|
||||
modelClass: Class<Model>,
|
||||
modelParameter: GradleModelParameter<*>?,
|
||||
modelConsumer: (Target, Model, Class<Model>) -> Unit,
|
||||
) {
|
||||
val buildActions = targets.map { target ->
|
||||
BuildAction { innerBuildController ->
|
||||
val innerController = GradleModelControllerImpl(innerBuildController)
|
||||
val model = innerController.fetchModelOrNull(target, modelClass, modelParameter)
|
||||
target to (model ?: return@BuildAction null)
|
||||
}
|
||||
}
|
||||
val models = buildController.run(buildActions)
|
||||
for (model in models) {
|
||||
if (model != null) {
|
||||
modelConsumer(model.first, model.second, modelClass)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun <Target : GradleModel, Model : Any> fetchTargetModelsInSequence(
|
||||
targets: Collection<Target>,
|
||||
modelClass: Class<Model>,
|
||||
modelParameter: GradleModelParameter<*>?,
|
||||
modelConsumer: (Target, Model, Class<Model>) -> Unit,
|
||||
) {
|
||||
for (target in targets) {
|
||||
val model = fetchModelOrNull(target, modelClass, modelParameter) ?: continue
|
||||
modelConsumer(target, model, modelClass)
|
||||
}
|
||||
}
|
||||
|
||||
private fun collectAllProjectModels(buildModels: Collection<GradleBuild>): Collection<BasicGradleProject> {
|
||||
val projectModels = ArrayList<BasicGradleProject>()
|
||||
for (buildModel in buildModels) {
|
||||
@@ -196,8 +207,12 @@ class GradleModelControllerImpl(
|
||||
return buildModel.projects.filter { it.parent == null }
|
||||
}
|
||||
|
||||
private fun sendModelFetchFailures(target: GradleModel?, result: FetchModelResult<*>) {
|
||||
val failures = result.failures.takeIf { it.isNotEmpty() } ?: return
|
||||
private fun <Model : Any> handleModelFetchFailures(suppressFailures: Boolean, action: () -> Model?): Model? {
|
||||
return runCatching(action).getOrElse { if (!suppressFailures) throw it else null }
|
||||
}
|
||||
|
||||
private fun sendModelFetchFailures(target: GradleModel?, result: FetchModelResult<*>, suppressFailures: Boolean) {
|
||||
val failures = result.failures.takeIf { it.isNotEmpty() && !suppressFailures } ?: return
|
||||
val targetPath = when (target) {
|
||||
is BasicGradleProject -> target.projectDirectory
|
||||
is GradleBuild -> target.buildIdentifier.rootDir
|
||||
@@ -215,6 +230,7 @@ class GradleModelControllerImpl(
|
||||
val executionMode: GradleExecutionMode = GradleExecutionMode.DEFAULT,
|
||||
val targetLevel: GradleModelLevel = GradleModelLevel.PROJECT,
|
||||
val projectTraversal: GradleTraversalMode = GradleTraversalMode.DIRECT,
|
||||
val suppressFailures: Boolean = false,
|
||||
) : GradleModelFetchRequest<Model> {
|
||||
|
||||
override fun modelLevel(targetLevel: GradleModelLevel): GradleModelFetchRequest<Model> =
|
||||
@@ -232,6 +248,9 @@ class GradleModelControllerImpl(
|
||||
): GradleModelFetchRequest<Model> =
|
||||
copy(modelParameter = GradleModelParameter(parameterClass, parameterInitializer))
|
||||
|
||||
override fun suppressFailures(): GradleModelFetchRequest<Model> =
|
||||
copy(suppressFailures = true)
|
||||
|
||||
override fun execute(modelConsumer: GradleModelConsumer): Unit =
|
||||
modelController.fetchModels(this, modelConsumer)
|
||||
}
|
||||
|
||||
+26
@@ -283,6 +283,32 @@ class GradleModelControllerTest(val isResilientSyncEnabled: Boolean) {
|
||||
modelConsumer.assertProjectModels(emptyList())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `suppressed model fetch request suppresses all failures`() {
|
||||
val rootProject = MockGradleProject("root")
|
||||
val subProject = MockGradleProject("sub-project", rootProject)
|
||||
val projectModels = listOf(rootProject, subProject)
|
||||
val buildModel = MockGradleBuild(rootProject, projectModels)
|
||||
|
||||
val buildController = TestBuildController().apply {
|
||||
registerModelFailure(rootProject, TestModel::class.java, TestModelFetchException())
|
||||
}
|
||||
val modelConsumer = TestModelConsumer()
|
||||
|
||||
GradleModelControllerImpl(buildController)
|
||||
.fetchRequest(listOf(buildModel), TestModel::class.java)
|
||||
.suppressFailures()
|
||||
.execute(modelConsumer)
|
||||
|
||||
buildController.assertRunActionCounts(emptyList())
|
||||
buildController.assertModelRequests(projectModels.map {
|
||||
TestModelRequest(it, TestModel::class.java)
|
||||
})
|
||||
|
||||
modelConsumer.assertBuildModels(emptyList())
|
||||
modelConsumer.assertProjectModels(emptyList())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `resilient model fetch api propagates project directory as target path in failure result`() {
|
||||
val projectDirectory = File("root-dir")
|
||||
|
||||
+21
-18
@@ -53,21 +53,34 @@ internal class TestBuildController : BuildController by notImplemented(BuildCont
|
||||
assertEqualsOrdered(expectedTargetPaths, actualTargetPaths)
|
||||
}
|
||||
|
||||
override fun <T> findModel(target: Model?, modelType: Class<T>): T? {
|
||||
modelRequests.add(TestModelRequest(target!!, modelType))
|
||||
override fun <T> getModel(target: Model, modelType: Class<T>): T {
|
||||
return findModel(target, modelType) ?: error("No model of type ${modelType.name} for $target")
|
||||
}
|
||||
|
||||
override fun <T, P : Any> getModel(
|
||||
target: Model,
|
||||
modelType: Class<T>,
|
||||
parameterType: Class<P>,
|
||||
parameterInitializer: Action<in P>,
|
||||
): T {
|
||||
return findModel(target, modelType, parameterType, parameterInitializer) ?: error("No model of type ${modelType.name} for $target")
|
||||
}
|
||||
|
||||
override fun <T> findModel(target: Model, modelType: Class<T>): T? {
|
||||
modelRequests.add(TestModelRequest(target, modelType))
|
||||
throwModelFailure(target, modelType)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return models[target to modelType] as T?
|
||||
}
|
||||
|
||||
override fun <T, P : Any> findModel(
|
||||
target: Model?,
|
||||
target: Model,
|
||||
modelType: Class<T>,
|
||||
parameterType: Class<P>?,
|
||||
parameterInitializer: Action<in P>?,
|
||||
parameterType: Class<P>,
|
||||
parameterInitializer: Action<in P>,
|
||||
): T? {
|
||||
val parameter = createParameter(parameterType!!, parameterInitializer!!)
|
||||
modelRequests.add(TestModelRequest(target!!, modelType, parameterType, parameter))
|
||||
val parameter = createParameter(parameterType, parameterInitializer)
|
||||
modelRequests.add(TestModelRequest(target, modelType, parameterType, parameter))
|
||||
throwModelFailure(target, modelType)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return models[target to modelType] as T?
|
||||
@@ -87,26 +100,16 @@ internal class TestBuildController : BuildController by notImplemented(BuildCont
|
||||
return parameter
|
||||
}
|
||||
|
||||
override fun <T : Any> fetch(modelType: Class<T>): FetchModelResult<T> =
|
||||
fetchModelResult { findModel(modelType) }
|
||||
|
||||
override fun <T : Any> fetch(target: Model, modelType: Class<T>): FetchModelResult<T> =
|
||||
fetchModelResult { findModel(target, modelType) }
|
||||
|
||||
override fun <T : Any, P : Any> fetch(
|
||||
modelType: Class<T>,
|
||||
parameterType: Class<P>?,
|
||||
parameterInitializer: Action<in P>?,
|
||||
): FetchModelResult<T> =
|
||||
fetchModelResult { findModel(modelType, parameterType, parameterInitializer) }
|
||||
|
||||
override fun <T : Any, P : Any> fetch(
|
||||
target: Model?,
|
||||
modelType: Class<T>,
|
||||
parameterType: Class<P>?,
|
||||
parameterInitializer: Action<in P>?,
|
||||
): FetchModelResult<T> =
|
||||
fetchModelResult { findModel(target, modelType, parameterType, parameterInitializer) }
|
||||
fetchModelResult { findModel(target!!, modelType, parameterType!!, parameterInitializer!!) }
|
||||
|
||||
override fun <T> run(actions: Collection<BuildAction<out T>>): List<T> {
|
||||
runActionCounts.add(actions.size)
|
||||
|
||||
Reference in New Issue
Block a user