IDEA-189463 Setting "Delegate Build Actions to Gradle" should override project output directory

This commit is contained in:
Vladislav.Soroka
2019-02-19 14:16:17 +03:00
parent 5bc3e369c4
commit d776fddb86
13 changed files with 172 additions and 25 deletions
@@ -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();
@@ -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<Pair<Project, String>, 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.
@@ -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) {
}
}
@@ -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) {
}
}
@@ -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) {
@@ -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<File> 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<ModuleData> ideModule, File ideaOutDir) {
ContentRootData excludedContentRootData;
DataNode<ContentRootData> contentRootDataDataNode = ExternalSystemApiUtil.find(ideModule, ProjectKeys.CONTENT_ROOT);
@@ -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();
@@ -60,6 +60,8 @@ public interface ProjectResolverContext extends UserDataHolderEx {
boolean isUseQualifiedModuleNames();
default boolean isDelegatedBuild() { return true; }
@NotNull
ProjectImportAction.AllModels getModels();
@@ -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<ClassHolder<? extends GradleProjectResolverExtension>> getResolverExtensions() {
return myResolverExtensions;
@@ -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<GradleSetting
if (old.getStoreProjectFilesExternally() != storeProjectFilesExternally) {
ExternalProjectsManagerImpl.getInstance(getProject()).setStoreExternally(storeProjectFilesExternally != ThreeState.NO);
}
if (!Comparing.equal(old.getDelegatedBuild(), current.getDelegatedBuild())) {
boolean delegatedBuild = GradleSettingsService.getInstance(getProject()).isDelegatedBuildEnabled(current.getExternalProjectPath());
getPublisher().onBuildDelegationChange(delegatedBuild, current.getExternalProjectPath());
}
if (!Comparing.equal(old.getTestRunner(), current.getTestRunner())) {
TestRunner testRunner = GradleSettingsService.getInstance(getProject()).getTestRunner(current.getExternalProjectPath());
getPublisher().onTestRunnerChange(testRunner, current.getExternalProjectPath());
}
}
@NotNull
@@ -56,4 +56,20 @@ public interface GradleSettingsListener extends ExternalSystemSettingsListener<G
* @param newOptions new option (if any)
*/
void onGradleVmOptionsChange(@Nullable String oldOptions, @Nullable String newOptions);
/**
* Is expected to be called when build delegation setting is changed by end-user.
*
* @param delegatedBuild current value
* @param linkedProjectPath target linked gradle project path
*/
void onBuildDelegationChange(boolean delegatedBuild, @NotNull String linkedProjectPath);
/**
* Is expected to be called when test runner setting is changed by end-user.
*
* @param currentTestRunner current value
* @param linkedProjectPath target linked gradle project path
*/
void onTestRunnerChange(@NotNull TestRunner currentTestRunner, @NotNull String linkedProjectPath);
}
@@ -26,6 +26,7 @@ import com.intellij.util.ThreeState;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.model.java.JavaSourceRootType;
import org.jetbrains.plugins.gradle.service.settings.GradleSettingsService;
import org.jetbrains.plugins.gradle.tooling.annotation.TargetVersions;
import org.junit.Test;
@@ -74,6 +75,23 @@ public class GradleFoldersImportingTest extends GradleImportingTestCase {
getProjectPath() + "/out/test/resources");
assertModuleOutput("project", getProjectPath() + "/out/production/classes", getProjectPath() + "/out/test/classes");
getCurrentExternalProjectSettings().setDelegatedBuild(ThreeState.YES);
importProject();
if (isGradle40orNewer()) {
assertModuleOutputs("project",
getProjectPath() + "/build/classes/java/main",
getProjectPath() + "/build/resources/main",
getProjectPath() + "/build/classes/java/test",
getProjectPath() + "/build/resources/test");
} else {
assertModuleOutputs("project",
getProjectPath() + "/build/classes/main",
getProjectPath() + "/build/resources/main",
getProjectPath() + "/build/classes/test",
getProjectPath() + "/build/resources/test");
}
}
@Test
@@ -95,7 +113,7 @@ public class GradleFoldersImportingTest extends GradleImportingTestCase {
assertDefaultGradleJavaProjectFolders("project");
assertModuleOutput("project.main", getProjectPath() + "/build", "");
String testClassesOutputPath = "/out/test/classes";
String testClassesOutputPath = isGradle40orNewer() ? "/build/classes/java/test" : "/build/classes/test";
assertModuleOutput("project.test", "", getProjectPath() + testClassesOutputPath);
importProjectUsingSingeModulePerGradleProject();
@@ -104,7 +122,7 @@ public class GradleFoldersImportingTest extends GradleImportingTestCase {
assertDefaultGradleJavaProjectFoldersForMergedModule("project");
assertModuleOutput("project", getProjectPath() + "/build", getProjectPath() + "/out/test/classes");
assertModuleOutput("project", getProjectPath() + "/build", getProjectPath() + testClassesOutputPath);
}
@Test
@@ -201,7 +219,7 @@ public class GradleFoldersImportingTest extends GradleImportingTestCase {
assertModules("project", "project.main", "project.test");
assertContentRoots("project", getProjectPath());
assertExcludes("project", ".gradle", "build", "out");
assertExcludes("project", ".gradle", "build");
assertContentRoots("project.main", getProjectPath() + "/src/main");
assertSources("project.main", "java", "src2");
assertResources("project.main", "resources", "resources2");
@@ -214,7 +232,7 @@ public class GradleFoldersImportingTest extends GradleImportingTestCase {
assertModules("project");
assertContentRoots("project", getProjectPath());
assertExcludes("project", ".gradle", "build", "out");
assertExcludes("project", ".gradle", "build");
assertSources("project", "src/main/java", "src/main/src2");
assertResources("project", "src/main/resources", "src/main/resources2");
assertTestSources("project", "src/test/java", "src/test/src2");
@@ -279,7 +297,7 @@ public class GradleFoldersImportingTest extends GradleImportingTestCase {
assertModules("project", "project.main", "project.test");
assertContentRoots("project", getProjectPath());
assertExcludes("project", ".gradle", "build", "out");
assertExcludes("project", ".gradle", "build");
final String mainSourceSetModuleName = "project.main";
assertContentRoots(mainSourceSetModuleName, getProjectPath() + "/src");
assertSources(mainSourceSetModuleName, "", "main/java");
@@ -292,7 +310,7 @@ public class GradleFoldersImportingTest extends GradleImportingTestCase {
importProjectUsingSingeModulePerGradleProject();
assertModules("project");
assertContentRoots("project", getProjectPath());
assertExcludes("project", ".gradle", "build", "out");
assertExcludes("project", ".gradle", "build");
assertSources("project", "src", "src/main/java");
assertResources("project", "src/main/resources", "src/resources");
assertTestSources("project", "src/test/java", "test");
@@ -308,7 +326,7 @@ public class GradleFoldersImportingTest extends GradleImportingTestCase {
);
assertModules("project");
assertExcludes("project", ".gradle", "build", "out");
assertExcludes("project", ".gradle", "build");
assertSources("project", "src/main/java");
assertResources("project");
assertTestSources("project");
@@ -593,7 +611,9 @@ public class GradleFoldersImportingTest extends GradleImportingTestCase {
}
protected void assertDefaultGradleJavaProjectFolders(@NotNull String mainModuleName) {
assertExcludes(mainModuleName, ".gradle", "build", "out");
boolean isDelegatedBuild = GradleSettingsService.getInstance(myProject).isDelegatedBuildEnabled(getProjectPath());
String[] excludes = isDelegatedBuild ? new String[]{".gradle", "build"} : new String[]{".gradle", "build", "out"};
assertExcludes(mainModuleName, excludes);
final String mainSourceSetModuleName = mainModuleName + ".main";
assertContentRoots(mainSourceSetModuleName, getProjectPath() + "/src/main");
assertSources(mainSourceSetModuleName, "java");
@@ -606,7 +626,9 @@ public class GradleFoldersImportingTest extends GradleImportingTestCase {
protected void assertDefaultGradleJavaProjectFoldersForMergedModule(@NotNull String moduleName) {
assertContentRoots(moduleName, getProjectPath());
assertExcludes(moduleName, ".gradle", "build", "out");
boolean isDelegatedBuild = GradleSettingsService.getInstance(myProject).isDelegatedBuildEnabled(getProjectPath());
String[] excludes = isDelegatedBuild ? new String[]{".gradle", "build"} : new String[]{".gradle", "build", "out"};
assertExcludes(moduleName, excludes);
assertSources(moduleName, "src/main/java");
assertResources(moduleName, "src/main/resources");
assertTestSources(moduleName, "src/test/java");
@@ -255,7 +255,12 @@ class ExternalProjectBuilderImpl implements ModelBuilderService {
ExternalSourceDirectorySet resourcesDirectorySet = new DefaultExternalSourceDirectorySet()
resourcesDirectorySet.name = sourceSet.resources.name
resourcesDirectorySet.srcDirs = sourceSet.resources.srcDirs
if(ideaPluginOutDir && SourceSet.MAIN_SOURCE_SET_NAME == sourceSet.name) {
resourcesDirectorySet.addGradleOutputDir(ideaPluginOutDir)
}
if (ideaPluginTestOutDir && SourceSet.TEST_SOURCE_SET_NAME == sourceSet.name) {
resourcesDirectorySet.addGradleOutputDir(ideaPluginTestOutDir)
}
if (is4OrBetter) {
if (sourceSet.output.resourcesDir) {
resourcesDirectorySet.addGradleOutputDir(sourceSet.output.resourcesDir)
@@ -283,6 +288,12 @@ class ExternalProjectBuilderImpl implements ModelBuilderService {
ExternalSourceDirectorySet javaDirectorySet = new DefaultExternalSourceDirectorySet()
javaDirectorySet.name = sourceSet.allJava.name
javaDirectorySet.srcDirs = sourceSet.allJava.srcDirs
if(ideaPluginOutDir && SourceSet.MAIN_SOURCE_SET_NAME == sourceSet.name) {
javaDirectorySet.addGradleOutputDir(ideaPluginOutDir)
}
if (ideaPluginTestOutDir && SourceSet.TEST_SOURCE_SET_NAME == sourceSet.name) {
javaDirectorySet.addGradleOutputDir(ideaPluginTestOutDir)
}
if (is4OrBetter) {
for (File outDir : sourceSet.output.classesDirs.files) {
javaDirectorySet.addGradleOutputDir(outDir)
@@ -321,7 +332,9 @@ class ExternalProjectBuilderImpl implements ModelBuilderService {
generatedDirectorySet = new DefaultExternalSourceDirectorySet()
generatedDirectorySet.name = "generated " + javaDirectorySet.name
generatedDirectorySet.srcDirs = files
generatedDirectorySet.addGradleOutputDir(javaDirectorySet.outputDir)
for (file in javaDirectorySet.gradleOutputDirs) {
generatedDirectorySet.addGradleOutputDir(file)
}
generatedDirectorySet.outputDir = javaDirectorySet.outputDir
generatedDirectorySet.inheritedCompilerOutput = javaDirectorySet.isCompilerOutputPathInherited()
}