From ef2aae41f3af018c5983c6d873dad55ce3cb3964 Mon Sep 17 00:00:00 2001 From: Daz DeBoer Date: Thu, 18 Jun 2020 13:38:16 -0600 Subject: [PATCH 1/3] Do not eagerly create format-specific spotless tasks Previously applying the Spotless plugin resulted in a many tasks to be created per subproject, even for an invocation like `gradle help`. Using "Task configuration avoidance" APIs means that these tasks will not be constructed if they will not be required in the task graph. --- .../spotless/SpotlessExtensionModern.java | 56 ++++++++++--------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtensionModern.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtensionModern.java index 3398024b2d..0d9ac7fd2d 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtensionModern.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtensionModern.java @@ -19,6 +19,8 @@ import org.gradle.api.Task; import org.gradle.api.plugins.BasePlugin; import org.gradle.api.plugins.JavaBasePlugin; +import org.gradle.api.tasks.TaskContainer; +import org.gradle.api.tasks.TaskProvider; public class SpotlessExtensionModern extends SpotlessExtensionBase { public SpotlessExtensionModern(Project project) { @@ -47,46 +49,50 @@ protected void createFormatTasks(String name, FormatExtension formatExtension) { // TODO level 1: implement SpotlessExtension::createFormatTasks, but using config avoidance // TODO level 2: override configure(String name, Class clazz, Action configure) so that it is lazy + boolean isIdeHook = project.hasProperty(IdeHook.PROPERTY); + TaskContainer tasks = project.getTasks(); + // create the SpotlessTask String taskName = EXTENSION + SpotlessPlugin.capitalize(name); - SpotlessTaskModern spotlessTask = project.getTasks().create(taskName, SpotlessTaskModern.class); - project.afterEvaluate(unused -> formatExtension.setupTask(spotlessTask)); + TaskProvider spotlessTask = tasks.register(taskName, SpotlessTaskModern.class, task -> { + task.setEnabled(!isIdeHook); + // clean removes the SpotlessCache, so we have to run after clean + task.mustRunAfter(BasePlugin.CLEAN_TASK_NAME); + }); - // clean removes the SpotlessCache, so we have to run after clean - Task clean = project.getTasks().getByName(BasePlugin.CLEAN_TASK_NAME); - spotlessTask.mustRunAfter(clean); + project.afterEvaluate(unused -> spotlessTask.configure(formatExtension::setupTask)); // create the check and apply control tasks - SpotlessCheck checkTask = project.getTasks().create(taskName + CHECK, SpotlessCheck.class); - checkTask.setSpotlessOutDirectory(spotlessTask.getOutputDirectory()); - checkTask.source = spotlessTask; - checkTask.dependsOn(spotlessTask); - - SpotlessApply applyTask = project.getTasks().create(taskName + APPLY, SpotlessApply.class); - applyTask.setSpotlessOutDirectory(spotlessTask.getOutputDirectory()); - applyTask.linkSource(spotlessTask); - applyTask.dependsOn(spotlessTask); + TaskProvider applyTask = tasks.register(taskName + APPLY, SpotlessApply.class, task -> { + task.setEnabled(!isIdeHook); + task.dependsOn(spotlessTask); + task.setSpotlessOutDirectory(spotlessTask.get().getOutputDirectory()); + task.linkSource(spotlessTask.get()); + }); + TaskProvider checkTask = tasks.register(taskName + CHECK, SpotlessCheck.class, task -> { + task.setEnabled(!isIdeHook); + task.dependsOn(spotlessTask); + task.setSpotlessOutDirectory(spotlessTask.get().getOutputDirectory()); + task.source = spotlessTask.get(); - // if the user runs both, make sure that apply happens first, - checkTask.mustRunAfter(applyTask); + // if the user runs both, make sure that apply happens first, + task.mustRunAfter(applyTask); + }); // the root tasks depend on the control tasks rootCheckTask.dependsOn(checkTask); rootApplyTask.dependsOn(applyTask); // create the diagnose task - SpotlessDiagnoseTask diagnoseTask = project.getTasks().create(taskName + DIAGNOSE, SpotlessDiagnoseTask.class); - diagnoseTask.source = spotlessTask; + TaskProvider diagnoseTask = tasks.register(taskName + DIAGNOSE, SpotlessDiagnoseTask.class, task -> { + task.source = spotlessTask.get(); + task.mustRunAfter(BasePlugin.CLEAN_TASK_NAME); + }); rootDiagnoseTask.dependsOn(diagnoseTask); - diagnoseTask.mustRunAfter(clean); - if (project.hasProperty(IdeHook.PROPERTY)) { - // disable the normal tasks, to disable their up-to-date checking - spotlessTask.setEnabled(false); - checkTask.setEnabled(false); - applyTask.setEnabled(false); + if (isIdeHook) { // the rootApplyTask is no longer just a marker task, now it does a bit of work itself - rootApplyTask.doLast(unused -> IdeHook.performHook(spotlessTask)); + rootApplyTask.doLast(unused -> IdeHook.performHook(spotlessTask.get())); } } } From 621af486c82027e38daeba702d6e97d5cf148660 Mon Sep 17 00:00:00 2001 From: Daz DeBoer Date: Thu, 18 Jun 2020 14:55:24 -0600 Subject: [PATCH 2/3] Do not eagerly create per-project spotless tasks With this commit, running `./gradlew help -PspotlessModern=true` will no longer the `spotless`, `spotlessCheck` or `spotlessApply` tasks if they are not required for task execution. The only remaining task that is eagerly constructed is "spotlessInternalRegisterDependencies". --- .../spotless/SpotlessExtensionModern.java | 48 ++++++++++--------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtensionModern.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtensionModern.java index 0d9ac7fd2d..d77b2de7e6 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtensionModern.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtensionModern.java @@ -16,7 +16,6 @@ package com.diffplug.gradle.spotless; import org.gradle.api.Project; -import org.gradle.api.Task; import org.gradle.api.plugins.BasePlugin; import org.gradle.api.plugins.JavaBasePlugin; import org.gradle.api.tasks.TaskContainer; @@ -25,14 +24,17 @@ public class SpotlessExtensionModern extends SpotlessExtensionBase { public SpotlessExtensionModern(Project project) { super(project); - rootCheckTask = project.task(EXTENSION + CHECK); - rootCheckTask.setGroup(TASK_GROUP); - rootCheckTask.setDescription(CHECK_DESCRIPTION); - rootApplyTask = project.task(EXTENSION + APPLY); - rootApplyTask.setGroup(TASK_GROUP); - rootApplyTask.setDescription(APPLY_DESCRIPTION); - rootDiagnoseTask = project.task(EXTENSION + DIAGNOSE); - rootDiagnoseTask.setGroup(TASK_GROUP); // no description on purpose + rootCheckTask = project.getTasks().register(EXTENSION + CHECK, task -> { + task.setGroup(TASK_GROUP); + task.setDescription(CHECK_DESCRIPTION); + }); + rootApplyTask = project.getTasks().register(EXTENSION + APPLY, task -> { + task.setGroup(TASK_GROUP); + task.setDescription(APPLY_DESCRIPTION); + }); + rootDiagnoseTask = project.getTasks().register(EXTENSION + DIAGNOSE, task -> { + task.setGroup(TASK_GROUP); // no description on purpose + }); project.afterEvaluate(unused -> { if (enforceCheck) { @@ -42,7 +44,7 @@ public SpotlessExtensionModern(Project project) { }); } - final Task rootCheckTask, rootApplyTask, rootDiagnoseTask; + final TaskProvider rootCheckTask, rootApplyTask, rootDiagnoseTask; @Override protected void createFormatTasks(String name, FormatExtension formatExtension) { @@ -51,13 +53,14 @@ protected void createFormatTasks(String name, FormatExtension formatExtension) { boolean isIdeHook = project.hasProperty(IdeHook.PROPERTY); TaskContainer tasks = project.getTasks(); + TaskProvider cleanTask = tasks.named(BasePlugin.CLEAN_TASK_NAME); // create the SpotlessTask String taskName = EXTENSION + SpotlessPlugin.capitalize(name); TaskProvider spotlessTask = tasks.register(taskName, SpotlessTaskModern.class, task -> { task.setEnabled(!isIdeHook); // clean removes the SpotlessCache, so we have to run after clean - task.mustRunAfter(BasePlugin.CLEAN_TASK_NAME); + task.mustRunAfter(cleanTask); }); project.afterEvaluate(unused -> spotlessTask.configure(formatExtension::setupTask)); @@ -69,6 +72,15 @@ protected void createFormatTasks(String name, FormatExtension formatExtension) { task.setSpotlessOutDirectory(spotlessTask.get().getOutputDirectory()); task.linkSource(spotlessTask.get()); }); + rootApplyTask.configure(task -> { + task.dependsOn(applyTask); + + if (isIdeHook) { + // the rootApplyTask is no longer just a marker task, now it does a bit of work itself + task.doLast(unused -> IdeHook.performHook(spotlessTask.get())); + } + }); + TaskProvider checkTask = tasks.register(taskName + CHECK, SpotlessCheck.class, task -> { task.setEnabled(!isIdeHook); task.dependsOn(spotlessTask); @@ -78,21 +90,13 @@ protected void createFormatTasks(String name, FormatExtension formatExtension) { // if the user runs both, make sure that apply happens first, task.mustRunAfter(applyTask); }); - - // the root tasks depend on the control tasks - rootCheckTask.dependsOn(checkTask); - rootApplyTask.dependsOn(applyTask); + rootCheckTask.configure(task -> task.dependsOn(checkTask)); // create the diagnose task TaskProvider diagnoseTask = tasks.register(taskName + DIAGNOSE, SpotlessDiagnoseTask.class, task -> { task.source = spotlessTask.get(); - task.mustRunAfter(BasePlugin.CLEAN_TASK_NAME); + task.mustRunAfter(cleanTask); }); - rootDiagnoseTask.dependsOn(diagnoseTask); - - if (isIdeHook) { - // the rootApplyTask is no longer just a marker task, now it does a bit of work itself - rootApplyTask.doLast(unused -> IdeHook.performHook(spotlessTask.get())); - } + rootDiagnoseTask.configure(task -> task.dependsOn(diagnoseTask)); } } From 78cfd654f9caa1f4ce722c37f22be8b5a90e44ad Mon Sep 17 00:00:00 2001 From: Daz DeBoer Date: Thu, 18 Jun 2020 15:30:26 -0600 Subject: [PATCH 3/3] Update TODO items in code --- .../com/diffplug/gradle/spotless/SpotlessExtensionModern.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtensionModern.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtensionModern.java index d77b2de7e6..263becb54b 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtensionModern.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/SpotlessExtensionModern.java @@ -48,8 +48,7 @@ public SpotlessExtensionModern(Project project) { @Override protected void createFormatTasks(String name, FormatExtension formatExtension) { - // TODO level 1: implement SpotlessExtension::createFormatTasks, but using config avoidance - // TODO level 2: override configure(String name, Class clazz, Action configure) so that it is lazy + // TODO override configure(String name, Class clazz, Action configure) so that it is lazy boolean isIdeHook = project.hasProperty(IdeHook.PROPERTY); TaskContainer tasks = project.getTasks();