214dad27db0ec0ea99b43c8dbbdaddd2910b99de
[idea/community.git] / plugins / gradle / tooling-extension-impl / src / org / jetbrains / plugins / gradle / tooling / builder / ModuleExtendedModelBuilderImpl.java
1 /*
2  * Copyright 2000-2014 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package org.jetbrains.plugins.gradle.tooling.builder;
17
18 import org.gradle.api.Project;
19 import org.gradle.api.Task;
20 import org.gradle.api.tasks.SourceSet;
21 import org.gradle.api.tasks.SourceSetContainer;
22 import org.gradle.api.tasks.SourceSetOutput;
23 import org.gradle.api.tasks.bundling.Jar;
24 import org.gradle.api.tasks.testing.Test;
25 import org.gradle.plugins.ide.idea.IdeaPlugin;
26 import org.gradle.plugins.ide.idea.model.IdeaModel;
27 import org.gradle.util.GradleVersion;
28 import org.jetbrains.annotations.NotNull;
29 import org.jetbrains.annotations.Nullable;
30 import org.jetbrains.plugins.gradle.model.ExtIdeaContentRoot;
31 import org.jetbrains.plugins.gradle.model.ModuleExtendedModel;
32 import org.jetbrains.plugins.gradle.tooling.ErrorMessageBuilder;
33 import org.jetbrains.plugins.gradle.tooling.ModelBuilderService;
34 import org.jetbrains.plugins.gradle.tooling.internal.IdeaCompilerOutputImpl;
35 import org.jetbrains.plugins.gradle.tooling.internal.IdeaContentRootImpl;
36 import org.jetbrains.plugins.gradle.tooling.internal.IdeaSourceDirectoryImpl;
37 import org.jetbrains.plugins.gradle.tooling.internal.ModuleExtendedModelImpl;
38
39 import java.io.File;
40 import java.io.IOException;
41 import java.util.*;
42
43 /**
44  * @author Vladislav.Soroka
45  * @since 11/5/13
46  */
47 public class ModuleExtendedModelBuilderImpl implements ModelBuilderService {
48
49   private static final String SOURCE_SETS_PROPERTY = "sourceSets";
50   private static final String TEST_SRC_DIRS_PROPERTY = "testSrcDirs";
51
52   @Override
53   public boolean canBuild(String modelName) {
54     return ModuleExtendedModel.class.getName().equals(modelName);
55   }
56
57   @Nullable
58   @Override
59   public Object buildAll(String modelName, Project project) {
60
61     final String moduleName = project.getName();
62     final String moduleGroup = project.getGroup().toString();
63     final String moduleVersion = project.getVersion().toString();
64     final File buildDir = project.getBuildDir();
65
66     final ModuleExtendedModelImpl moduleVersionModel = new ModuleExtendedModelImpl(moduleName, moduleGroup, moduleVersion, buildDir);
67
68     final List<File> artifacts = new ArrayList<File>();
69     for (Task task : project.getTasks()) {
70       if (task instanceof Jar) {
71         Jar jar = (Jar)task;
72         artifacts.add(jar.getArchivePath());
73       }
74     }
75
76     moduleVersionModel.setArtifacts(artifacts);
77
78     final Set<String> sourceDirectories = new HashSet<String>();
79     final Set<String> testDirectories = new HashSet<String>();
80     final Set<String> resourceDirectories = new HashSet<String>();
81     final Set<String> testResourceDirectories = new HashSet<String>();
82
83     final List<File> testClassesDirs = new ArrayList<File>();
84     for (Task task : project.getTasks()) {
85       if (task instanceof Test) {
86         Test test = (Test)task;
87         testClassesDirs.add(test.getTestClassesDir());
88
89         if (test.hasProperty(TEST_SRC_DIRS_PROPERTY)) {
90           Object testSrcDirs = test.property(TEST_SRC_DIRS_PROPERTY);
91           if (testSrcDirs instanceof Iterable) {
92             for (Object dir : Iterable.class.cast(testSrcDirs)) {
93               addFilePath(testDirectories, dir);
94             }
95           }
96         }
97       }
98     }
99
100     IdeaCompilerOutputImpl compilerOutput = new IdeaCompilerOutputImpl();
101
102     if (project.hasProperty(SOURCE_SETS_PROPERTY)) {
103       Object sourceSets = project.property(SOURCE_SETS_PROPERTY);
104       if (sourceSets instanceof SourceSetContainer) {
105         SourceSetContainer sourceSetContainer = (SourceSetContainer)sourceSets;
106         for (SourceSet sourceSet : sourceSetContainer) {
107
108           SourceSetOutput output = sourceSet.getOutput();
109           if (SourceSet.TEST_SOURCE_SET_NAME.equals(sourceSet.getName())) {
110             compilerOutput.setTestClassesDir(output.getClassesDir());
111             compilerOutput.setTestResourcesDir(output.getResourcesDir());
112           }
113           if (SourceSet.MAIN_SOURCE_SET_NAME.equals(sourceSet.getName())) {
114             compilerOutput.setMainClassesDir(output.getClassesDir());
115             compilerOutput.setMainResourcesDir(output.getResourcesDir());
116           }
117
118           for (File javaSrcDir : sourceSet.getAllJava().getSrcDirs()) {
119             boolean isTestDir = isTestDir(sourceSet, testClassesDirs);
120             addFilePath(isTestDir ? testDirectories : sourceDirectories, javaSrcDir);
121           }
122           for (File resourcesSrcDir : sourceSet.getResources().getSrcDirs()) {
123             boolean isTestDir = isTestDir(sourceSet, testClassesDirs);
124             addFilePath(isTestDir ? testResourceDirectories : resourceDirectories, resourcesSrcDir);
125           }
126         }
127       }
128     }
129
130     File projectDir = project.getProjectDir();
131     IdeaContentRootImpl contentRoot = new IdeaContentRootImpl(projectDir);
132
133     final Set<String> ideaSourceDirectories = new HashSet<String>();
134     final Set<String> ideaTestDirectories = new HashSet<String>();
135     final Set<String> ideaGeneratedDirectories = new HashSet<String>();
136     final Set<File> excludeDirectories = new HashSet<File>();
137
138     enrichDataFromIdeaPlugin(project, excludeDirectories, ideaSourceDirectories, ideaTestDirectories, ideaGeneratedDirectories);
139
140     if (ideaSourceDirectories.isEmpty()) {
141       sourceDirectories.clear();
142       resourceDirectories.clear();
143     }
144     if (ideaTestDirectories.isEmpty()) {
145       testDirectories.clear();
146       testResourceDirectories.clear();
147     }
148
149     ideaSourceDirectories.removeAll(resourceDirectories);
150     sourceDirectories.removeAll(ideaTestDirectories);
151     sourceDirectories.addAll(ideaSourceDirectories);
152     ideaTestDirectories.removeAll(testResourceDirectories);
153     testDirectories.addAll(ideaTestDirectories);
154
155     // ensure disjoint directories with different type
156     resourceDirectories.removeAll(sourceDirectories);
157     testDirectories.removeAll(sourceDirectories);
158     testResourceDirectories.removeAll(testDirectories);
159
160     for (String javaDir : sourceDirectories) {
161       contentRoot.addSourceDirectory(new IdeaSourceDirectoryImpl(new File(javaDir), ideaGeneratedDirectories.contains(javaDir)));
162     }
163     for (String testDir : testDirectories) {
164       contentRoot.addTestDirectory(new IdeaSourceDirectoryImpl(new File(testDir), ideaGeneratedDirectories.contains(testDir)));
165     }
166     for (String resourceDir : resourceDirectories) {
167       contentRoot.addResourceDirectory(new IdeaSourceDirectoryImpl(new File(resourceDir)));
168     }
169     for (String testResourceDir : testResourceDirectories) {
170       contentRoot.addTestResourceDirectory(new IdeaSourceDirectoryImpl(new File(testResourceDir)));
171     }
172     for (File excludeDir : excludeDirectories) {
173       contentRoot.addExcludeDirectory(excludeDir);
174     }
175
176     moduleVersionModel.setContentRoots(Collections.<ExtIdeaContentRoot>singleton(contentRoot));
177     moduleVersionModel.setCompilerOutput(compilerOutput);
178     return moduleVersionModel;
179   }
180
181   @NotNull
182   @Override
183   public ErrorMessageBuilder getErrorMessageBuilder(@NotNull Project project, @NotNull Exception e) {
184     return ErrorMessageBuilder.create(
185       project, e, "Other"
186     ).withDescription("Unable to resolve all content root directories");
187   }
188
189   private static boolean isTestDir(SourceSet sourceSet, List<File> testClassesDirs) {
190     if (SourceSet.TEST_SOURCE_SET_NAME.equals(sourceSet.getName())) return true;
191     if (SourceSet.MAIN_SOURCE_SET_NAME.equals(sourceSet.getName())) return false;
192
193     File sourceSetClassesDir = sourceSet.getOutput().getClassesDir();
194     for (File testClassesDir : testClassesDirs) {
195       do {
196         if (sourceSetClassesDir.getPath().equals(testClassesDir.getPath())) return true;
197       }
198       while ((testClassesDir = testClassesDir.getParentFile()) != null);
199     }
200
201     return false;
202   }
203
204   private static void addFilePath(Set<String> filePathSet, Object file) {
205     if (file instanceof File) {
206       try {
207         filePathSet.add(((File)file).getCanonicalPath());
208       }
209       catch (IOException ignore) {
210       }
211     }
212   }
213
214   private static void enrichDataFromIdeaPlugin(Project project,
215                                                Set<File> excludeDirectories,
216                                                Set<String> javaDirectories,
217                                                Set<String> testDirectories,
218                                                Set<String> ideaGeneratedDirectories) {
219
220     IdeaPlugin ideaPlugin = project.getPlugins().getPlugin(IdeaPlugin.class);
221     if (ideaPlugin == null) return;
222
223     IdeaModel ideaModel = ideaPlugin.getModel();
224     if (ideaModel == null || ideaModel.getModule() == null) return;
225
226     for (File excludeDir : ideaModel.getModule().getExcludeDirs()) {
227       excludeDirectories.add(excludeDir);
228     }
229     for (File file : ideaModel.getModule().getSourceDirs()) {
230       javaDirectories.add(file.getPath());
231     }
232     for (File file : ideaModel.getModule().getTestSourceDirs()) {
233       testDirectories.add(file.getPath());
234     }
235
236     if(GradleVersion.current().compareTo(GradleVersion.version("2.2")) >=0) {
237       for (File file : ideaModel.getModule().getGeneratedSourceDirs()) {
238         ideaGeneratedDirectories.add(file.getPath());
239       }
240     }
241   }
242 }