From d776fddb8625cfe8e44c534c92e784391f7199e8 Mon Sep 17 00:00:00 2001 From: "Vladislav.Soroka" Date: Tue, 19 Feb 2019 14:13:43 +0300 Subject: [PATCH] IDEA-189463 Setting "Delegate Build Actions to Gradle" should override project output directory --- .../compiler/GradleCompilingTestCase.java | 10 ++++ .../plugins/gradle/GradleManager.java | 19 +++++-- ...legatingGradleSettingsListenerAdapter.java | 9 ++++ .../config/GradleSettingsListenerAdapter.java | 9 ++++ .../GradleOrderEnumeratorHandler.java | 2 +- .../BaseGradleProjectResolverExtension.java | 50 ++++++++++++++++--- .../DefaultProjectResolverContext.java | 5 ++ .../project/ProjectResolverContext.java | 2 + .../settings/GradleExecutionSettings.java | 9 ++++ .../gradle/settings/GradleSettings.java | 9 ++++ .../settings/GradleSettingsListener.java | 16 ++++++ .../importing/GradleFoldersImportingTest.java | 40 +++++++++++---- .../builder/ExternalProjectBuilderImpl.groovy | 17 ++++++- 13 files changed, 172 insertions(+), 25 deletions(-) diff --git a/plugins/gradle/java/testSources/compiler/GradleCompilingTestCase.java b/plugins/gradle/java/testSources/compiler/GradleCompilingTestCase.java index ea276ea99aa4..20a2e6e02a5c 100644 --- a/plugins/gradle/java/testSources/compiler/GradleCompilingTestCase.java +++ b/plugins/gradle/java/testSources/compiler/GradleCompilingTestCase.java @@ -10,8 +10,10 @@ import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VfsUtilCore; +import com.intellij.util.ThreeState; import org.jetbrains.plugins.gradle.config.GradleResourceCompilerConfigurationGenerator; import org.jetbrains.plugins.gradle.importing.GradleImportingTestCase; +import org.junit.Before; import java.io.File; @@ -19,6 +21,14 @@ import java.io.File; * @author Vladislav.Soroka */ public abstract class GradleCompilingTestCase extends GradleImportingTestCase { + + @Before + @Override + public void setUp() throws Exception { + super.setUp(); + getCurrentExternalProjectSettings().setDelegatedBuild(ThreeState.NO); + } + @Override protected void setUpInWriteAction() throws Exception { super.setUpInWriteAction(); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/GradleManager.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/GradleManager.java index abe0510726f1..e9fde60a5c2d 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/GradleManager.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/GradleManager.java @@ -76,6 +76,7 @@ import org.jetbrains.plugins.gradle.service.project.GradleAutoImportAware; import org.jetbrains.plugins.gradle.service.project.GradleProjectResolver; import org.jetbrains.plugins.gradle.service.project.GradleProjectResolverExtension; import org.jetbrains.plugins.gradle.service.settings.GradleConfigurable; +import org.jetbrains.plugins.gradle.service.settings.GradleSettingsService; import org.jetbrains.plugins.gradle.service.task.GradleTaskManager; import org.jetbrains.plugins.gradle.settings.*; import org.jetbrains.plugins.gradle.util.GradleConstants; @@ -173,8 +174,9 @@ public class GradleManager public Function, GradleExecutionSettings> getExecutionSettingsProvider() { return pair -> { final Project project = pair.first; + final String projectPath = pair.second; GradleSettings settings = GradleSettings.getInstance(project); - File gradleHome = myInstallationManager.getGradleHome(project, pair.second); + File gradleHome = myInstallationManager.getGradleHome(project, projectPath); String localGradlePath = null; if (gradleHome != null) { try { @@ -186,11 +188,11 @@ public class GradleManager } } - GradleProjectSettings projectLevelSettings = settings.getLinkedProjectSettings(pair.second); + GradleProjectSettings projectLevelSettings = settings.getLinkedProjectSettings(projectPath); final DistributionType distributionType; if (projectLevelSettings == null) { distributionType = - GradleUtil.isGradleDefaultWrapperFilesExist(pair.second) ? DistributionType.DEFAULT_WRAPPED : DistributionType.BUNDLED; + GradleUtil.isGradleDefaultWrapperFilesExist(projectPath) ? DistributionType.DEFAULT_WRAPPED : DistributionType.BUNDLED; } else { distributionType = @@ -206,7 +208,7 @@ public class GradleManager result.addResolverExtensionClass(ClassHolder.from(extension.getClass())); } - final String rootProjectPath = projectLevelSettings != null ? projectLevelSettings.getExternalProjectPath() : pair.second; + final String rootProjectPath = projectLevelSettings != null ? projectLevelSettings.getExternalProjectPath() : projectPath; final Sdk gradleJdk = myInstallationManager.getGradleJdk(project, rootProjectPath); final String javaHome = gradleJdk != null ? gradleJdk.getHomePath() : null; if (!StringUtil.isEmpty(javaHome)) { @@ -226,8 +228,10 @@ public class GradleManager result.setResolveModulePerSourceSet(projectLevelSettings.isResolveModulePerSourceSet()); result.setUseQualifiedModuleNames(projectLevelSettings.isUseQualifiedModuleNames()); } + boolean delegatedBuildEnabled = GradleSettingsService.getInstance(project).isDelegatedBuildEnabled(projectPath); + result.setDelegatedBuild(delegatedBuildEnabled); - configureExecutionWorkspace(projectLevelSettings, settings, result, project, pair.second); + configureExecutionWorkspace(projectLevelSettings, settings, result, project, projectPath); return result; }; } @@ -434,6 +438,11 @@ public class GradleManager public void onGradleDistributionTypeChange(DistributionType currentValue, @NotNull String linkedProjectPath) { ExternalProjectsManager.getInstance(project).getExternalProjectsWatcher().markDirty(linkedProjectPath); } + + @Override + public void onBuildDelegationChange(boolean delegatedBuild, @NotNull String linkedProjectPath) { + ExternalProjectsManager.getInstance(project).getExternalProjectsWatcher().markDirty(linkedProjectPath); + } }); // We used to assume that gradle scripts are always named 'build.gradle' and kept path to that build.gradle file at ide settings. diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/DelegatingGradleSettingsListenerAdapter.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/DelegatingGradleSettingsListenerAdapter.java index 0e5e2b6333da..01d644050216 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/DelegatingGradleSettingsListenerAdapter.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/DelegatingGradleSettingsListenerAdapter.java @@ -22,6 +22,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.settings.DistributionType; import org.jetbrains.plugins.gradle.settings.GradleProjectSettings; import org.jetbrains.plugins.gradle.settings.GradleSettingsListener; +import org.jetbrains.plugins.gradle.settings.TestRunner; /** * @author Denis Zhdanov @@ -49,4 +50,12 @@ public class DelegatingGradleSettingsListenerAdapter extends DelegatingExternalS @Override public void onGradleVmOptionsChange(@Nullable String oldOptions, @Nullable String newOptions) { } + + @Override + public void onBuildDelegationChange(boolean delegatedBuild, @NotNull String linkedProjectPath) { + } + + @Override + public void onTestRunnerChange(@NotNull TestRunner currentTestRunner, @NotNull String linkedProjectPath) { + } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleSettingsListenerAdapter.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleSettingsListenerAdapter.java index 2090120169fd..07f31797772d 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleSettingsListenerAdapter.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleSettingsListenerAdapter.java @@ -6,6 +6,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.settings.DistributionType; import org.jetbrains.plugins.gradle.settings.GradleProjectSettings; import org.jetbrains.plugins.gradle.settings.GradleSettingsListener; +import org.jetbrains.plugins.gradle.settings.TestRunner; /** * @author Denis Zhdanov @@ -29,4 +30,12 @@ public abstract class GradleSettingsListenerAdapter extends ExternalSystemSettin @Override public void onGradleVmOptionsChange(@Nullable String oldOptions, @Nullable String newOptions) { } + + @Override + public void onBuildDelegationChange(boolean delegatedBuild, @NotNull String linkedProjectPath) { + } + + @Override + public void onTestRunnerChange(@NotNull TestRunner currentTestRunner, @NotNull String linkedProjectPath) { + } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/GradleOrderEnumeratorHandler.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/GradleOrderEnumeratorHandler.java index 9861535700c4..9abd54efa153 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/GradleOrderEnumeratorHandler.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/GradleOrderEnumeratorHandler.java @@ -127,7 +127,7 @@ public class GradleOrderEnumeratorHandler extends OrderEnumerationHandler { externalProjectDataCache.findExternalProject(externalRootProject, rootModel.getModule()); if (externalSourceSets.isEmpty()) return false; - boolean isDelegatedBuildEnabled = GradleSettingsService.getInstance(project).isDelegatedBuildEnabled(rootModel.getModule()); + boolean isDelegatedBuildEnabled = GradleSettingsService.isDelegatedBuildEnabled(rootModel.getModule()); for (ExternalSourceSet sourceSet : externalSourceSets.values()) { if (includeTests) { if (isDelegatedBuildEnabled) { diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java index 5cd252c8e0bb..bf523489c2da 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java @@ -74,6 +74,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.*; +import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -459,16 +460,18 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver ExternalSystemSourceType sourceType = ExternalSystemSourceType.from(directorySetEntry.getKey()); ExternalSourceDirectorySet sourceDirectorySet = directorySetEntry.getValue(); final ModuleData moduleData = dataNode.getData(); - File outputDir = sourceDirectorySet.getOutputDir(); - outputDirs.add(outputDir.getPath()); - moduleData.setCompileOutputPath(sourceType, outputDir.getAbsolutePath()); + File outputDir = getOutputDir(sourceDirectorySet); + moduleData.setCompileOutputPath(sourceType, outputDir == null ? null : outputDir.getAbsolutePath()); moduleData.setInheritProjectCompileOutputPath(sourceDirectorySet.isCompilerOutputPathInherited()); - for (File gradleOutputDir : sourceDirectorySet.getGradleOutputDirs()) { - String gradleOutputPath = ExternalSystemApiUtil.toCanonicalPath(gradleOutputDir.getAbsolutePath()); - gradleOutputMap.putValue(sourceType, gradleOutputPath); - if (!gradleOutputDir.getPath().equals(outputDir.getPath())) { - moduleOutputsMap.put(gradleOutputPath, Pair.create(moduleData.getId(), sourceType)); + if (outputDir != null) { + outputDirs.add(outputDir.getPath()); + for (File gradleOutputDir : sourceDirectorySet.getGradleOutputDirs()) { + String gradleOutputPath = ExternalSystemApiUtil.toCanonicalPath(gradleOutputDir.getAbsolutePath()); + gradleOutputMap.putValue(sourceType, gradleOutputPath); + if (!gradleOutputDir.getPath().equals(outputDir.getPath())) { + moduleOutputsMap.put(gradleOutputPath, Pair.create(moduleData.getId(), sourceType)); + } } } } @@ -486,12 +489,18 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver if (moduleCompilerOutput != null) { File outputDir = moduleCompilerOutput.getOutputDir(); + if (outputDir == null && resolverCtx.isDelegatedBuild() && externalProject != null) { + outputDir = getOutputDir(externalProject, "main", ExternalSystemSourceType.SOURCE); + } File classesOutputDir = ObjectUtils.chooseNotNull(outputDir, new File(ideaOutDir, "production/classes")); compileOutputPaths.put(ExternalSystemSourceType.SOURCE, classesOutputDir); File resourcesOutputDir = ObjectUtils.chooseNotNull(outputDir, new File(ideaOutDir, "production/resources")); compileOutputPaths.put(ExternalSystemSourceType.RESOURCE, resourcesOutputDir); File testOutputDir = moduleCompilerOutput.getTestOutputDir(); + if (testOutputDir == null && resolverCtx.isDelegatedBuild() && externalProject != null) { + testOutputDir = getOutputDir(externalProject, "test", ExternalSystemSourceType.TEST); + } File testClassesOutputDir = ObjectUtils.chooseNotNull(testOutputDir, new File(ideaOutDir, "test/classes")); compileOutputPaths.put(ExternalSystemSourceType.TEST, testClassesOutputDir); File testResourcesOutputDir = ObjectUtils.chooseNotNull(testOutputDir, new File(ideaOutDir, "test/resources")); @@ -512,6 +521,31 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver moduleData.setInheritProjectCompileOutputPath(inheritOutputDirs); } + @Nullable + private File getOutputDir(@NotNull ExternalProject externalProject, + @NotNull String sourceSetName, + @NotNull ExternalSystemSourceType sourceType) { + ExternalSourceSet sourceSet = externalProject.getSourceSets().get(sourceSetName); + if (sourceSet == null) return null; + return getOutputDir(sourceSet.getSources().get(sourceType)); + } + + @Nullable + private File getOutputDir(@Nullable ExternalSourceDirectorySet sourceDirectorySet) { + if (sourceDirectorySet == null) return null; + + AtomicReference result = new AtomicReference<>(); + if (resolverCtx.isDelegatedBuild()) { + sourceDirectorySet.getGradleOutputDirs().stream() + .findFirst() + .ifPresent(file -> result.set(file)); + } + else { + result.set(sourceDirectorySet.getOutputDir()); + } + return result.get(); + } + private static void excludeOutDir(@NotNull DataNode ideModule, File ideaOutDir) { ContentRootData excludedContentRootData; DataNode contentRootDataDataNode = ExternalSystemApiUtil.find(ideModule, ProjectKeys.CONTENT_ROOT); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/DefaultProjectResolverContext.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/DefaultProjectResolverContext.java index 9e8f5746b5f1..a4941bc71a17 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/DefaultProjectResolverContext.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/DefaultProjectResolverContext.java @@ -135,6 +135,11 @@ public class DefaultProjectResolverContext extends UserDataHolderBase implements return mySettings != null && mySettings.isUseQualifiedModuleNames(); } + @Override + public boolean isDelegatedBuild() { + return mySettings == null || mySettings.isDelegatedBuild(); + } + public File getGradleUserHome() { if (myGradleUserHome == null) { String serviceDirectory = mySettings == null ? null : mySettings.getServiceDirectory(); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/ProjectResolverContext.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/ProjectResolverContext.java index 1f16b05fc47e..c6baf4364912 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/ProjectResolverContext.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/ProjectResolverContext.java @@ -60,6 +60,8 @@ public interface ProjectResolverContext extends UserDataHolderEx { boolean isUseQualifiedModuleNames(); + default boolean isDelegatedBuild() { return true; } + @NotNull ProjectImportAction.AllModels getModels(); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/settings/GradleExecutionSettings.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/settings/GradleExecutionSettings.java index 65d2c8ead00e..29ea6feb1002 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/settings/GradleExecutionSettings.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/settings/GradleExecutionSettings.java @@ -49,6 +49,7 @@ public class GradleExecutionSettings extends ExternalSystemExecutionSettings { private String myIdeProjectPath; private boolean resolveModulePerSourceSet = true; private boolean useQualifiedModuleNames = false; + private boolean delegatedBuild = true; public GradleExecutionSettings(@Nullable String gradleHome, @Nullable String serviceDirectory, @@ -124,6 +125,14 @@ public class GradleExecutionSettings extends ExternalSystemExecutionSettings { this.useQualifiedModuleNames = useQualifiedModuleNames; } + public boolean isDelegatedBuild() { + return delegatedBuild; + } + + public void setDelegatedBuild(boolean delegatedBuild) { + this.delegatedBuild = delegatedBuild; + } + @NotNull public List> getResolverExtensions() { return myResolverExtensions; diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/settings/GradleSettings.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/settings/GradleSettings.java index faae77e71a3d..27096cc03955 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/settings/GradleSettings.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/settings/GradleSettings.java @@ -18,6 +18,7 @@ import com.intellij.util.xmlb.annotations.XCollection; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.config.DelegatingGradleSettingsListenerAdapter; +import org.jetbrains.plugins.gradle.service.settings.GradleSettingsService; import java.util.Collection; import java.util.Set; @@ -121,6 +122,14 @@ public class GradleSettings extends AbstractExternalSystemSettings