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