2 * Copyright 2000-2013 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.jetbrains.plugins.gradle.service.project;
18 import com.google.common.collect.Multimap;
19 import com.google.gson.GsonBuilder;
20 import com.intellij.execution.ExecutionException;
21 import com.intellij.execution.configurations.SimpleJavaParameters;
22 import com.intellij.externalSystem.JavaProjectData;
23 import com.intellij.openapi.application.PathManager;
24 import com.intellij.openapi.diagnostic.Logger;
25 import com.intellij.openapi.externalSystem.model.DataNode;
26 import com.intellij.openapi.externalSystem.model.ExternalSystemException;
27 import com.intellij.openapi.externalSystem.model.ProjectKeys;
28 import com.intellij.openapi.externalSystem.model.project.*;
29 import com.intellij.openapi.externalSystem.model.task.TaskData;
30 import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
31 import com.intellij.openapi.externalSystem.util.Order;
32 import com.intellij.openapi.module.EmptyModuleType;
33 import com.intellij.openapi.module.JavaModuleType;
34 import com.intellij.openapi.module.ModuleType;
35 import com.intellij.openapi.module.StdModuleTypes;
36 import com.intellij.openapi.roots.DependencyScope;
37 import com.intellij.openapi.util.KeyValue;
38 import com.intellij.openapi.util.Pair;
39 import com.intellij.openapi.util.io.FileFilters;
40 import com.intellij.openapi.util.io.FileUtil;
41 import com.intellij.openapi.util.io.FileUtilRt;
42 import com.intellij.openapi.util.text.StringUtil;
43 import com.intellij.pom.java.LanguageLevel;
44 import com.intellij.util.*;
45 import com.intellij.util.containers.ContainerUtil;
46 import com.intellij.util.containers.ContainerUtilRt;
47 import com.intellij.util.net.HttpConfigurable;
48 import com.intellij.util.text.CharArrayUtil;
49 import groovy.lang.GroovyObject;
50 import org.codehaus.groovy.runtime.typehandling.ShortTypeHandling;
51 import org.gradle.tooling.ProjectConnection;
52 import org.gradle.tooling.model.DomainObjectSet;
53 import org.gradle.tooling.model.GradleModuleVersion;
54 import org.gradle.tooling.model.GradleTask;
55 import org.gradle.tooling.model.UnsupportedMethodException;
56 import org.gradle.tooling.model.gradle.GradleBuild;
57 import org.gradle.tooling.model.idea.*;
58 import org.jetbrains.annotations.NonNls;
59 import org.jetbrains.annotations.NotNull;
60 import org.jetbrains.annotations.Nullable;
61 import org.jetbrains.plugins.gradle.model.*;
62 import org.jetbrains.plugins.gradle.model.data.BuildScriptClasspathData;
63 import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData;
64 import org.jetbrains.plugins.gradle.service.project.data.ExternalProjectDataService;
65 import org.jetbrains.plugins.gradle.tooling.builder.ModelBuildScriptClasspathBuilderImpl;
66 import org.jetbrains.plugins.gradle.tooling.internal.init.Init;
67 import org.jetbrains.plugins.gradle.util.GradleBundle;
68 import org.jetbrains.plugins.gradle.util.GradleConstants;
69 import org.slf4j.impl.Log4jLoggerFactory;
72 import java.lang.reflect.Field;
73 import java.lang.reflect.Method;
74 import java.lang.reflect.Proxy;
77 import java.util.regex.Matcher;
78 import java.util.regex.Pattern;
80 import static org.jetbrains.plugins.gradle.service.project.GradleProjectResolverUtil.*;
83 * {@link BaseGradleProjectResolverExtension} provides base implementation of Gradle project resolver.
85 * @author Vladislav.Soroka
88 @Order(Integer.MAX_VALUE)
89 public class BaseGradleProjectResolverExtension implements GradleProjectResolverExtension {
90 private static final Logger LOG = Logger.getInstance(BaseGradleProjectResolverExtension.class);
92 @NotNull @NonNls private static final String UNRESOLVED_DEPENDENCY_PREFIX = "unresolved dependency - ";
94 @NotNull private ProjectResolverContext resolverCtx;
95 @NotNull private final BaseProjectImportErrorHandler myErrorHandler = new BaseProjectImportErrorHandler();
98 public void setProjectResolverContext(@NotNull ProjectResolverContext projectResolverContext) {
99 resolverCtx = projectResolverContext;
103 public void setNext(@NotNull GradleProjectResolverExtension next) {
104 // should be the last extension in the chain
109 public GradleProjectResolverExtension getNext() {
115 public ProjectData createProject() {
116 final String projectDirPath = resolverCtx.getProjectPath();
117 final IdeaProject ideaProject = resolverCtx.getModels().getIdeaProject();
118 return new ProjectData(GradleConstants.SYSTEM_ID, ideaProject.getName(), projectDirPath, projectDirPath);
123 public JavaProjectData createJavaProjectData() {
124 final String projectDirPath = resolverCtx.getProjectPath();
125 final IdeaProject ideaProject = resolverCtx.getModels().getIdeaProject();
127 // Gradle API doesn't expose gradleProject compile output path yet.
128 JavaProjectData javaProjectData = new JavaProjectData(GradleConstants.SYSTEM_ID, projectDirPath + "/build/classes");
129 javaProjectData.setJdkVersion(ideaProject.getJdkName());
130 LanguageLevel resolvedLanguageLevel = null;
131 // org.gradle.tooling.model.idea.IdeaLanguageLevel.getLevel() returns something like JDK_1_6
132 final String languageLevel = ideaProject.getLanguageLevel().getLevel();
133 for (LanguageLevel level : LanguageLevel.values()) {
134 if (level.name().equals(languageLevel)) {
135 resolvedLanguageLevel = level;
139 if (resolvedLanguageLevel != null) {
140 javaProjectData.setLanguageLevel(resolvedLanguageLevel);
143 javaProjectData.setLanguageLevel(languageLevel);
145 return javaProjectData;
149 public void populateProjectExtraModels(@NotNull IdeaProject gradleProject, @NotNull DataNode<ProjectData> ideProject) {
150 final ExternalProject externalProject = resolverCtx.getExtraProject(ExternalProject.class);
151 if (externalProject != null) {
152 ideProject.createChild(ExternalProjectDataService.KEY, externalProject);
153 ideProject.getData().setDescription(externalProject.getDescription());
159 public DataNode<ModuleData> createModule(@NotNull IdeaModule gradleModule, @NotNull DataNode<ProjectData> projectDataNode) {
160 DataNode<ModuleData> mainModuleNode = createMainModule(resolverCtx, gradleModule, projectDataNode);
161 final ModuleData mainModuleData = mainModuleNode.getData();
162 final String mainModuleConfigPath = mainModuleData.getLinkedExternalProjectPath();
163 final String mainModuleFileDirectoryPath = mainModuleData.getModuleFileDirectoryPath();
165 ExternalProject externalProject = resolverCtx.getExtraProject(gradleModule, ExternalProject.class);
166 if (externalProject != null) {
167 String gradlePath = gradleModule.getGradleProject().getPath();
168 final boolean isRootModule = StringUtil.isEmpty(gradlePath) || ":".equals(gradlePath);
169 final String[] moduleGroup;
171 moduleGroup = new String[]{mainModuleData.getInternalName()};
174 moduleGroup = ArrayUtil.remove(gradlePath.split(":"), 0);
176 mainModuleData.setIdeModuleGroup(isRootModule ? null : moduleGroup);
178 for (ExternalSourceSet sourceSet : externalProject.getSourceSets().values()) {
179 final String moduleId = getModuleId(externalProject, sourceSet);
180 final String moduleExternalName = gradleModule.getName() + ":" + sourceSet.getName();
181 final String moduleInternalName = getInternalModuleName(gradleModule, sourceSet.getName());
183 GradleSourceSetData sourceSetData = new GradleSourceSetData(
184 moduleId, moduleExternalName, moduleInternalName, mainModuleFileDirectoryPath, mainModuleConfigPath);
186 sourceSetData.setGroup(externalProject.getGroup());
187 sourceSetData.setVersion(externalProject.getVersion());
188 sourceSetData.setIdeModuleGroup(moduleGroup);
190 sourceSetData.setSourceCompatibility(sourceSet.getSourceCompatibility());
191 sourceSetData.setTargetCompatibility(sourceSet.getTargetCompatibility());
193 final Set<File> artifacts = ContainerUtil.newTroveSet(FileUtil.FILE_HASHING_STRATEGY);
194 if ("main".equals(sourceSet.getName())) {
195 final Set<File> defaultArtifacts = externalProject.getArtifactsByConfiguration().get("default");
196 if (defaultArtifacts != null) {
197 artifacts.addAll(defaultArtifacts);
199 if (externalProject.getArtifactsByConfiguration().get("archives") != null) {
200 final Set<File> archivesArtifacts = ContainerUtil.newHashSet(externalProject.getArtifactsByConfiguration().get("archives"));
201 final Set<File> testsArtifacts = externalProject.getArtifactsByConfiguration().get("tests");
202 if (testsArtifacts != null) {
203 archivesArtifacts.removeAll(testsArtifacts);
205 artifacts.addAll(archivesArtifacts);
209 sourceSetData.setProductionModuleId(getInternalModuleName(gradleModule, "main"));
210 if ("test".equals(sourceSet.getName())) {
211 final Set<File> testsArtifacts = externalProject.getArtifactsByConfiguration().get("tests");
212 if (testsArtifacts != null) {
213 artifacts.addAll(testsArtifacts);
217 sourceSetData.setArtifacts(ContainerUtil.newArrayList(artifacts));
219 DataNode<GradleSourceSetData> sourceSetDataNode = mainModuleNode.createChild(GradleSourceSetData.KEY, sourceSetData);
220 final Map<String, Pair<DataNode<GradleSourceSetData>, ExternalSourceSet>> sourceSetMap =
221 projectDataNode.getUserData(GradleProjectResolver.RESOLVED_SOURCE_SETS);
222 assert sourceSetMap != null;
223 sourceSetMap.put(moduleId, Pair.create(sourceSetDataNode, sourceSet));
227 final ProjectData projectData = projectDataNode.getData();
228 if (StringUtil.equals(mainModuleData.getLinkedExternalProjectPath(), projectData.getLinkedExternalProjectPath())) {
229 projectData.setGroup(mainModuleData.getGroup());
230 projectData.setVersion(mainModuleData.getVersion());
233 return mainModuleNode;
237 public String getInternalModuleName(@NotNull IdeaModule gradleModule, @NotNull String sourceSetName) {
238 return gradleModule.getName() + "_" + sourceSetName;
242 public void populateModuleExtraModels(@NotNull IdeaModule gradleModule, @NotNull DataNode<ModuleData> ideModule) {
243 final BuildScriptClasspathModel buildScriptClasspathModel = resolverCtx.getExtraProject(gradleModule, BuildScriptClasspathModel.class);
244 final List<BuildScriptClasspathData.ClasspathEntry> classpathEntries;
245 if (buildScriptClasspathModel != null) {
246 classpathEntries = ContainerUtil
247 .map(buildScriptClasspathModel.getClasspath(), new Function<ClasspathEntryModel, BuildScriptClasspathData.ClasspathEntry>() {
249 public BuildScriptClasspathData.ClasspathEntry fun(ClasspathEntryModel model) {
250 return new BuildScriptClasspathData.ClasspathEntry(model.getClasses(), model.getSources(), model.getJavadoc());
255 classpathEntries = ContainerUtil.emptyList();
257 BuildScriptClasspathData buildScriptClasspathData = new BuildScriptClasspathData(GradleConstants.SYSTEM_ID, classpathEntries);
258 ideModule.createChild(BuildScriptClasspathData.KEY, buildScriptClasspathData);
262 public void populateModuleContentRoots(@NotNull IdeaModule gradleModule,
263 @NotNull DataNode<ModuleData> ideModule) {
264 ExternalProject externalProject = resolverCtx.getExtraProject(gradleModule, ExternalProject.class);
265 if (externalProject != null) {
266 processSourceSets(externalProject, ideModule, new SourceSetsProcessor() {
268 public void process(@NotNull DataNode<GradleSourceSetData> dataNode, @NotNull ExternalSourceSet sourceSet) {
269 for (Map.Entry<IExternalSystemSourceType, ExternalSourceDirectorySet> directorySetEntry : sourceSet.getSources().entrySet()) {
270 ExternalSystemSourceType sourceType = ExternalSystemSourceType.from(directorySetEntry.getKey());
271 ExternalSourceDirectorySet sourceDirectorySet = directorySetEntry.getValue();
273 for (File file : sourceDirectorySet.getSrcDirs()) {
274 ContentRootData ideContentRoot = new ContentRootData(GradleConstants.SYSTEM_ID, file.getAbsolutePath());
275 ideContentRoot.storePath(sourceType, file.getAbsolutePath());
276 dataNode.createChild(ProjectKeys.CONTENT_ROOT, ideContentRoot);
283 DomainObjectSet<? extends IdeaContentRoot> contentRoots = gradleModule.getContentRoots();
284 if (contentRoots == null) {
287 for (IdeaContentRoot gradleContentRoot : contentRoots) {
288 if (gradleContentRoot == null) continue;
290 File rootDirectory = gradleContentRoot.getRootDirectory();
291 if (rootDirectory == null) continue;
293 ContentRootData ideContentRoot = new ContentRootData(GradleConstants.SYSTEM_ID, rootDirectory.getAbsolutePath());
294 if (externalProject == null) {
295 populateContentRoot(ideContentRoot, ExternalSystemSourceType.SOURCE, gradleContentRoot.getSourceDirectories());
296 populateContentRoot(ideContentRoot, ExternalSystemSourceType.TEST, gradleContentRoot.getTestDirectories());
298 if (gradleContentRoot instanceof ExtIdeaContentRoot) {
299 ExtIdeaContentRoot extIdeaContentRoot = (ExtIdeaContentRoot)gradleContentRoot;
300 populateContentRoot(ideContentRoot, ExternalSystemSourceType.RESOURCE, extIdeaContentRoot.getResourceDirectories());
301 populateContentRoot(ideContentRoot, ExternalSystemSourceType.TEST_RESOURCE, extIdeaContentRoot.getTestResourceDirectories());
305 Set<File> excluded = gradleContentRoot.getExcludeDirectories();
306 if (excluded != null) {
307 for (File file : excluded) {
308 ideContentRoot.storePath(ExternalSystemSourceType.EXCLUDED, file.getAbsolutePath());
311 ideModule.createChild(ProjectKeys.CONTENT_ROOT, ideContentRoot);
315 private static void processSourceSets(@NotNull ExternalProject externalProject,
316 @NotNull DataNode<ModuleData> ideModule,
317 @NotNull SourceSetsProcessor processor) {
318 Map<String, DataNode<GradleSourceSetData>> sourceSetsMap = ContainerUtil.newHashMap();
319 for (DataNode<GradleSourceSetData> dataNode : ExternalSystemApiUtil.findAll(ideModule, GradleSourceSetData.KEY)) {
320 sourceSetsMap.put(dataNode.getData().getId(), dataNode);
323 for (ExternalSourceSet sourceSet : externalProject.getSourceSets().values()) {
324 if (sourceSet == null || sourceSet.getSources().isEmpty()) continue;
326 final String moduleId = getModuleId(externalProject, sourceSet);
327 final DataNode<GradleSourceSetData> sourceSetDataNode = sourceSetsMap.get(moduleId);
328 if (sourceSetDataNode == null) continue;
330 processor.process(sourceSetDataNode, sourceSet);
336 public void populateModuleCompileOutputSettings(@NotNull IdeaModule gradleModule,
337 @NotNull DataNode<ModuleData> ideModule) {
338 ExternalProject externalProject = resolverCtx.getExtraProject(gradleModule, ExternalProject.class);
339 if (externalProject != null) {
340 processSourceSets(externalProject, ideModule, new SourceSetsProcessor() {
342 public void process(@NotNull DataNode<GradleSourceSetData> dataNode, @NotNull ExternalSourceSet sourceSet) {
343 for (Map.Entry<IExternalSystemSourceType, ExternalSourceDirectorySet> directorySetEntry : sourceSet.getSources().entrySet()) {
344 ExternalSystemSourceType sourceType = ExternalSystemSourceType.from(directorySetEntry.getKey());
345 ExternalSourceDirectorySet sourceDirectorySet = directorySetEntry.getValue();
346 final GradleSourceSetData sourceSetData = dataNode.getData();
347 sourceSetData.setCompileOutputPath(sourceType, sourceDirectorySet.getOutputDir().getAbsolutePath());
348 sourceSetData.setInheritProjectCompileOutputPath(sourceDirectorySet.isCompilerOutputPathInherited());
356 IdeaCompilerOutput moduleCompilerOutput = gradleModule.getCompilerOutput();
358 File buildDir = null;
360 buildDir = gradleModule.getGradleProject().getBuildDirectory();
362 catch (UnsupportedMethodException ignore) {
363 // see org.gradle.tooling.model.GradleProject.getBuildDirectory method supported only since Gradle 2.0
364 // will use com.intellij.openapi.externalSystem.model.ExternalProject.getBuildDir() instead
367 Map<ExternalSystemSourceType, File> compileOutputPaths = ContainerUtil.newHashMap();
369 boolean inheritOutputDirs = false;
371 ModuleData moduleData = ideModule.getData();
372 if (moduleCompilerOutput != null) {
373 compileOutputPaths.put(ExternalSystemSourceType.SOURCE, moduleCompilerOutput.getOutputDir());
374 compileOutputPaths.put(ExternalSystemSourceType.RESOURCE, moduleCompilerOutput.getOutputDir());
375 compileOutputPaths.put(ExternalSystemSourceType.TEST, moduleCompilerOutput.getTestOutputDir());
376 compileOutputPaths.put(ExternalSystemSourceType.TEST_RESOURCE, moduleCompilerOutput.getTestOutputDir());
378 inheritOutputDirs = moduleCompilerOutput.getInheritOutputDirs();
381 for (Map.Entry<ExternalSystemSourceType, File> sourceTypeFileEntry : compileOutputPaths.entrySet()) {
382 final File outputPath = ObjectUtils.chooseNotNull(sourceTypeFileEntry.getValue(), buildDir);
383 if (outputPath != null) {
384 moduleData.setCompileOutputPath(sourceTypeFileEntry.getKey(), outputPath.getAbsolutePath());
388 moduleData.setInheritProjectCompileOutputPath(inheritOutputDirs);
392 public void populateModuleDependencies(@NotNull IdeaModule gradleModule,
393 @NotNull DataNode<ModuleData> ideModule,
394 @NotNull final DataNode<ProjectData> ideProject) {
396 ExternalProject externalProject = resolverCtx.getExtraProject(gradleModule, ExternalProject.class);
397 if (externalProject != null) {
398 final Map<String, Pair<DataNode<GradleSourceSetData>, ExternalSourceSet>> sourceSetMap =
399 ideProject.getUserData(GradleProjectResolver.RESOLVED_SOURCE_SETS);
400 assert sourceSetMap != null;
402 processSourceSets(externalProject, ideModule, new SourceSetsProcessor() {
404 public void process(@NotNull DataNode<GradleSourceSetData> dataNode, @NotNull ExternalSourceSet sourceSet) {
405 buildDependencies(sourceSetMap, dataNode, sourceSet.getDependencies(), ideProject);
412 final List<? extends IdeaDependency> dependencies = gradleModule.getDependencies().getAll();
414 if (dependencies == null) return;
416 for (IdeaDependency dependency : dependencies) {
417 if (dependency == null) {
420 DependencyScope scope = parseScope(dependency.getScope());
422 if (dependency instanceof IdeaModuleDependency) {
423 ModuleDependencyData d = buildDependency(ideModule, (IdeaModuleDependency)dependency, ideProject);
424 d.setExported(dependency.getExported());
428 ideModule.createChild(ProjectKeys.MODULE_DEPENDENCY, d);
430 else if (dependency instanceof IdeaSingleEntryLibraryDependency) {
431 LibraryDependencyData d = buildDependency(gradleModule, ideModule, (IdeaSingleEntryLibraryDependency)dependency, ideProject);
432 d.setExported(dependency.getExported());
436 ideModule.createChild(ProjectKeys.LIBRARY_DEPENDENCY, d);
443 public Collection<TaskData> populateModuleTasks(@NotNull IdeaModule gradleModule,
444 @NotNull DataNode<ModuleData> ideModule,
445 @NotNull DataNode<ProjectData> ideProject)
446 throws IllegalArgumentException, IllegalStateException {
448 final Collection<TaskData> tasks = ContainerUtil.newArrayList();
449 final String moduleConfigPath = ideModule.getData().getLinkedExternalProjectPath();
451 ExternalProject externalProject = resolverCtx.getExtraProject(gradleModule, ExternalProject.class);
452 final String rootProjectPath = ideProject.getData().getLinkedExternalProjectPath();
453 final boolean isFlatProject = !FileUtil.isAncestor(rootProjectPath, moduleConfigPath, false);
454 if (externalProject != null) {
455 for (ExternalTask task : externalProject.getTasks().values()) {
456 String taskName = isFlatProject ? task.getQName() : task.getName();
457 String taskGroup = task.getGroup();
458 if (taskName.trim().isEmpty() || isIdeaTask(taskName, taskGroup)) {
461 final String taskPath = isFlatProject ? rootProjectPath : moduleConfigPath;
462 TaskData taskData = new TaskData(GradleConstants.SYSTEM_ID, taskName, taskPath, task.getDescription());
463 taskData.setGroup(taskGroup);
464 taskData.setType(task.getType());
465 ideModule.createChild(ProjectKeys.TASK, taskData);
466 taskData.setInherited(StringUtil.equals(task.getName(), task.getQName()));
473 for (GradleTask task : gradleModule.getGradleProject().getTasks()) {
474 String taskName = task.getName();
475 String taskGroup = getTaskGroup(task);
476 if (taskName == null || taskName.trim().isEmpty() || isIdeaTask(taskName, taskGroup)) {
479 TaskData taskData = new TaskData(GradleConstants.SYSTEM_ID, taskName, moduleConfigPath, task.getDescription());
480 taskData.setGroup(taskGroup);
481 ideModule.createChild(ProjectKeys.TASK, taskData);
489 private static String getTaskGroup(GradleTask task) {
492 taskGroup = task.getGroup();
494 catch (UnsupportedMethodException e) {
502 public Set<Class> getExtraProjectModelClasses() {
503 Set<Class> result = ContainerUtil.<Class>set(GradleBuild.class, ModuleExtendedModel.class);
504 result.add(BuildScriptClasspathModel.class);
505 result.add(ExternalProject.class);
511 public Set<Class> getToolingExtensionsClasses() {
512 return ContainerUtil.<Class>set(
513 // external-system-rt.jar
514 ExternalSystemSourceType.class,
515 // gradle-tooling-extension-api jar
516 ProjectImportAction.class,
517 // gradle-tooling-extension-impl jar
518 ModelBuildScriptClasspathBuilderImpl.class,
521 ShortTypeHandling.class
527 public List<KeyValue<String, String>> getExtraJvmArgs() {
528 if (ExternalSystemApiUtil.isInProcessMode(GradleConstants.SYSTEM_ID)) {
529 final List<KeyValue<String, String>> extraJvmArgs = ContainerUtil.newArrayList();
530 final HttpConfigurable httpConfigurable = HttpConfigurable.getInstance();
531 if (!StringUtil.isEmpty(httpConfigurable.PROXY_EXCEPTIONS)) {
532 List<String> hosts = StringUtil.split(httpConfigurable.PROXY_EXCEPTIONS, ",");
533 if (!hosts.isEmpty()) {
534 final String nonProxyHosts = StringUtil.join(hosts, StringUtil.TRIMMER, "|");
535 extraJvmArgs.add(KeyValue.create("http.nonProxyHosts", nonProxyHosts));
536 extraJvmArgs.add(KeyValue.create("https.nonProxyHosts", nonProxyHosts));
539 if (httpConfigurable.USE_HTTP_PROXY && StringUtil.isNotEmpty(httpConfigurable.PROXY_LOGIN)) {
540 extraJvmArgs.add(KeyValue.create("http.proxyUser", httpConfigurable.PROXY_LOGIN));
541 extraJvmArgs.add(KeyValue.create("https.proxyUser", httpConfigurable.PROXY_LOGIN));
542 final String plainProxyPassword = httpConfigurable.getPlainProxyPassword();
543 extraJvmArgs.add(KeyValue.create("http.proxyPassword", plainProxyPassword));
544 extraJvmArgs.add(KeyValue.create("https.proxyPassword", plainProxyPassword));
546 extraJvmArgs.addAll(HttpConfigurable.getJvmPropertiesList(false, null));
550 return Collections.emptyList();
555 public List<String> getExtraCommandLineArgs() {
556 return Collections.emptyList();
561 public ExternalSystemException getUserFriendlyError(@NotNull Throwable error,
562 @NotNull String projectPath,
563 @Nullable String buildFilePath) {
564 return myErrorHandler.getUserFriendlyError(error, projectPath, buildFilePath);
568 public void preImportCheck() {
572 public void enhanceTaskProcessing(@NotNull List<String> taskNames,
573 @Nullable String debuggerSetup,
574 @NotNull Consumer<String> initScriptConsumer) {
575 if (!StringUtil.isEmpty(debuggerSetup)) {
576 final String[] lines = {
577 "gradle.taskGraph.beforeTask { Task task ->",
578 " if (task instanceof JavaForkOptions) {",
579 " def jvmArgs = task.jvmArgs.findAll{!it?.startsWith('-agentlib') && !it?.startsWith('-Xrunjdwp')}",
580 " jvmArgs << '" + debuggerSetup.trim() + '\'',
581 " task.jvmArgs jvmArgs",
585 final String script = StringUtil.join(lines, SystemProperties.getLineSeparator());
586 initScriptConsumer.consume(script);
591 public void enhanceRemoteProcessing(@NotNull SimpleJavaParameters parameters) throws ExecutionException {
592 PathsList classPath = parameters.getClassPath();
594 // Gradle i18n bundle.
595 ExternalSystemApiUtil.addBundle(classPath, GradleBundle.PATH_TO_BUNDLE, GradleBundle.class);
598 String toolingApiPath = PathManager.getJarPathForClass(ProjectConnection.class);
599 if (toolingApiPath == null) {
600 LOG.warn(GradleBundle.message("gradle.generic.text.error.jar.not.found"));
601 throw new ExecutionException("Can't find gradle libraries");
603 File gradleJarsDir = new File(toolingApiPath).getParentFile();
604 File[] gradleJars = gradleJarsDir.listFiles(FileFilters.filesWithExtension("jar"));
605 if (gradleJars == null) {
606 LOG.warn(GradleBundle.message("gradle.generic.text.error.jar.not.found"));
607 throw new ExecutionException("Can't find gradle libraries at " + gradleJarsDir.getAbsolutePath());
609 for (File jar : gradleJars) {
610 classPath.add(jar.getAbsolutePath());
613 List<String> additionalEntries = ContainerUtilRt.newArrayList();
614 ContainerUtilRt.addIfNotNull(additionalEntries, PathUtil.getJarPathForClass(GroovyObject.class));
615 ContainerUtilRt.addIfNotNull(additionalEntries, PathUtil.getJarPathForClass(GsonBuilder.class));
616 ContainerUtilRt.addIfNotNull(additionalEntries, PathUtil.getJarPathForClass(ExternalProject.class));
617 ContainerUtilRt.addIfNotNull(additionalEntries, PathUtil.getJarPathForClass(JavaProjectData.class));
618 ContainerUtilRt.addIfNotNull(additionalEntries, PathUtil.getJarPathForClass(LanguageLevel.class));
619 ContainerUtilRt.addIfNotNull(additionalEntries, PathUtil.getJarPathForClass(StdModuleTypes.class));
620 ContainerUtilRt.addIfNotNull(additionalEntries, PathUtil.getJarPathForClass(JavaModuleType.class));
621 ContainerUtilRt.addIfNotNull(additionalEntries, PathUtil.getJarPathForClass(ModuleType.class));
622 ContainerUtilRt.addIfNotNull(additionalEntries, PathUtil.getJarPathForClass(EmptyModuleType.class));
623 ContainerUtilRt.addIfNotNull(additionalEntries, PathUtil.getJarPathForClass(ProjectImportAction.class));
624 ContainerUtilRt.addIfNotNull(additionalEntries, PathUtil.getJarPathForClass(Init.class));
625 ContainerUtilRt.addIfNotNull(additionalEntries, PathUtil.getJarPathForClass(org.slf4j.Logger.class));
626 ContainerUtilRt.addIfNotNull(additionalEntries, PathUtil.getJarPathForClass(Log4jLoggerFactory.class));
627 for (String entry : additionalEntries) {
628 classPath.add(entry);
633 public void enhanceLocalProcessing(@NotNull List<URL> urls) {
637 * Stores information about given directories at the given content root
639 * @param contentRoot target paths info holder
640 * @param type type of data located at the given directories
641 * @param dirs directories which paths should be stored at the given content root
642 * @throws IllegalArgumentException if specified by {@link ContentRootData#storePath(ExternalSystemSourceType, String)}
644 private static void populateContentRoot(@NotNull final ContentRootData contentRoot,
645 @NotNull final ExternalSystemSourceType type,
646 @Nullable final Iterable<? extends IdeaSourceDirectory> dirs)
647 throws IllegalArgumentException {
651 for (IdeaSourceDirectory dir : dirs) {
652 ExternalSystemSourceType dirSourceType = type;
654 if (dir.isGenerated() && !dirSourceType.isGenerated()) {
655 final ExternalSystemSourceType generatedType = ExternalSystemSourceType.from(
656 dirSourceType.isTest(), dir.isGenerated(), dirSourceType.isResource(), dirSourceType.isExcluded()
658 dirSourceType = generatedType != null ? generatedType : dirSourceType;
661 catch (UnsupportedMethodException e) {
662 // org.gradle.tooling.model.idea.IdeaSourceDirectory.isGenerated method supported only since Gradle 2.2
663 LOG.warn(e.getMessage());
664 printToolingProxyDiagnosticInfo(dir);
666 catch (Throwable e) {
668 printToolingProxyDiagnosticInfo(dir);
670 contentRoot.storePath(dirSourceType, dir.getDirectory().getAbsolutePath());
674 private static void printToolingProxyDiagnosticInfo(@Nullable Object obj) {
675 if (!LOG.isDebugEnabled() || obj == null) return;
677 LOG.debug(String.format("obj: %s", obj));
678 final Class<?> aClass = obj.getClass();
679 LOG.debug(String.format("obj class: %s", aClass));
680 LOG.debug(String.format("classloader: %s", aClass.getClassLoader()));
681 for (Method m : aClass.getDeclaredMethods()) {
682 LOG.debug(String.format("obj m: %s", m));
685 if (obj instanceof Proxy) {
687 final Field hField = ReflectionUtil.findField(obj.getClass(), null, "h");
688 hField.setAccessible(true);
689 final Object h = hField.get(obj);
690 final Field delegateField = ReflectionUtil.findField(h.getClass(), null, "delegate");
691 delegateField.setAccessible(true);
692 final Object delegate = delegateField.get(h);
693 LOG.debug(String.format("delegate: %s", delegate));
694 LOG.debug(String.format("delegate class: %s", delegate.getClass()));
695 LOG.debug(String.format("delegate classloader: %s", delegate.getClass().getClassLoader()));
696 for (Method m : delegate.getClass().getDeclaredMethods()) {
697 LOG.debug(String.format("delegate m: %s", m));
700 catch (NoSuchFieldException e) {
703 catch (IllegalAccessException e) {
710 private static DependencyScope parseScope(@Nullable IdeaDependencyScope scope) {
714 String scopeAsString = scope.getScope();
715 if (scopeAsString == null) {
718 for (DependencyScope dependencyScope : DependencyScope.values()) {
719 if (scopeAsString.equalsIgnoreCase(dependencyScope.toString())) {
720 return dependencyScope;
727 private static ModuleDependencyData buildDependency(@NotNull DataNode<ModuleData> ownerModule,
728 @NotNull IdeaModuleDependency dependency,
729 @NotNull DataNode<ProjectData> ideProject)
730 throws IllegalStateException {
731 IdeaModule module = dependency.getDependencyModule();
732 if (module == null) {
733 throw new IllegalStateException(
734 String.format("Can't parse gradle module dependency '%s'. Reason: referenced module is null", dependency)
738 String moduleName = module.getName();
739 if (moduleName == null) {
740 throw new IllegalStateException(String.format(
741 "Can't parse gradle module dependency '%s'. Reason: referenced module name is undefined (module: '%s') ", dependency, module
745 Set<String> registeredModuleNames = ContainerUtilRt.newHashSet();
746 Collection<DataNode<ModuleData>> modulesDataNode = ExternalSystemApiUtil.getChildren(ideProject, ProjectKeys.MODULE);
747 for (DataNode<ModuleData> moduleDataNode : modulesDataNode) {
748 String name = moduleDataNode.getData().getExternalName();
749 registeredModuleNames.add(name);
750 if (name.equals(moduleName)) {
751 return new ModuleDependencyData(ownerModule.getData(), moduleDataNode.getData());
754 throw new IllegalStateException(String.format(
755 "Can't parse gradle module dependency '%s'. Reason: no module with such name (%s) is found. Registered modules: %s",
756 dependency, moduleName, registeredModuleNames
761 private LibraryDependencyData buildDependency(@NotNull IdeaModule gradleModule,
762 @NotNull DataNode<ModuleData> ownerModule,
763 @NotNull IdeaSingleEntryLibraryDependency dependency,
764 @NotNull DataNode<ProjectData> ideProject)
765 throws IllegalStateException {
766 File binaryPath = dependency.getFile();
767 if (binaryPath == null) {
768 throw new IllegalStateException(String.format(
769 "Can't parse external library dependency '%s'. Reason: it doesn't specify path to the binaries", dependency
774 final GradleModuleVersion moduleVersion = dependency.getGradleModuleVersion();
775 final LibraryLevel level;
777 // Gradle API doesn't explicitly provide information about unresolved libraries (http://issues.gradle.org/browse/GRADLE-1995).
778 // That's why we use this dirty hack here.
779 boolean unresolved = binaryPath.getPath().startsWith(UNRESOLVED_DEPENDENCY_PREFIX);
781 if (moduleVersion == null) {
782 // use module library level if the dependency does not originate from a remote repository.
783 level = LibraryLevel.MODULE;
785 if (binaryPath.isFile()) {
786 libraryName = FileUtil.getNameWithoutExtension(binaryPath);
793 // Gradle uses names like 'unresolved dependency - commons-collections commons-collections 3.2' for unresolved dependencies.
794 libraryName = binaryPath.getPath().substring(UNRESOLVED_DEPENDENCY_PREFIX.length());
795 int i = libraryName.indexOf(' ');
797 i = CharArrayUtil.shiftForward(libraryName, i + 1, " ");
800 if (i >= 0 && i < libraryName.length()) {
801 int dependencyNameIndex = i;
802 i = libraryName.indexOf(' ', dependencyNameIndex);
804 libraryName = String.format("%s-%s", libraryName.substring(dependencyNameIndex, i), libraryName.substring(i + 1));
810 level = LibraryLevel.PROJECT;
811 libraryName = String.format("%s:%s:%s", moduleVersion.getGroup(), moduleVersion.getName(), moduleVersion.getVersion());
812 if (binaryPath.isFile()) {
813 String libraryFileName = FileUtil.getNameWithoutExtension(binaryPath);
814 final String mavenLibraryFileName = String.format("%s-%s", moduleVersion.getName(), moduleVersion.getVersion());
815 if (!mavenLibraryFileName.equals(libraryFileName)) {
816 Pattern pattern = Pattern.compile(moduleVersion.getName() + "-" + moduleVersion.getVersion() + "-(.*)");
817 Matcher matcher = pattern.matcher(libraryFileName);
818 if (matcher.matches()) {
819 final String classifier = matcher.group(1);
820 libraryName += (":" + classifier);
823 final String artifactId = StringUtil.trimEnd(StringUtil.trimEnd(libraryFileName, moduleVersion.getVersion()), "-");
824 libraryName = String.format("%s:%s:%s",
825 moduleVersion.getGroup(),
827 moduleVersion.getVersion());
833 // add packaging type to distinguish different artifact dependencies with same groupId:artifactId:version
834 if (StringUtil.isNotEmpty(libraryName) && !FileUtilRt.extensionEquals(binaryPath.getPath(), "jar")) {
835 libraryName += (":" + FileUtilRt.getExtension(binaryPath.getPath()));
838 final LibraryData library = new LibraryData(GradleConstants.SYSTEM_ID, libraryName, unresolved);
840 library.addPath(LibraryPathType.BINARY, binaryPath.getAbsolutePath());
843 File sourcePath = dependency.getSource();
844 if (!unresolved && sourcePath != null) {
845 library.addPath(LibraryPathType.SOURCE, sourcePath.getAbsolutePath());
848 if (!unresolved && sourcePath == null) {
849 attachGradleSdkSources(gradleModule, binaryPath, library, resolverCtx);
852 File javadocPath = dependency.getJavadoc();
853 if (!unresolved && javadocPath != null) {
854 library.addPath(LibraryPathType.DOC, javadocPath.getAbsolutePath());
857 if (level == LibraryLevel.PROJECT) {
858 linkProjectLibrary(ideProject, library);
861 return new LibraryDependencyData(ownerModule.getData(), library, level);
864 private interface SourceSetsProcessor {
865 void process(@NotNull DataNode<GradleSourceSetData> dataNode, @NotNull ExternalSourceSet sourceSet);