2 * Copyright 2000-2009 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
.idea
.devkit
.build
;
18 import com
.intellij
.openapi
.compiler
.CompileContext
;
19 import com
.intellij
.openapi
.compiler
.CompilerMessageCategory
;
20 import com
.intellij
.openapi
.compiler
.make
.BuildConfiguration
;
21 import com
.intellij
.openapi
.compiler
.make
.BuildParticipantBase
;
22 import com
.intellij
.openapi
.compiler
.make
.BuildRecipe
;
23 import com
.intellij
.openapi
.deployment
.DeploymentUtil
;
24 import com
.intellij
.openapi
.deployment
.LibraryLink
;
25 import com
.intellij
.openapi
.deployment
.ModuleLink
;
26 import com
.intellij
.openapi
.deployment
.PackagingMethod
;
27 import com
.intellij
.openapi
.module
.Module
;
28 import com
.intellij
.openapi
.module
.ModuleUtil
;
29 import com
.intellij
.openapi
.projectRoots
.Sdk
;
30 import com
.intellij
.openapi
.roots
.ModuleRootManager
;
31 import com
.intellij
.openapi
.roots
.OrderRootType
;
32 import com
.intellij
.openapi
.roots
.libraries
.Library
;
33 import com
.intellij
.openapi
.vfs
.JarFileSystem
;
34 import com
.intellij
.openapi
.vfs
.VfsUtil
;
35 import com
.intellij
.openapi
.vfs
.VirtualFile
;
36 import com
.intellij
.psi
.xml
.XmlDocument
;
37 import com
.intellij
.psi
.xml
.XmlFile
;
38 import com
.intellij
.psi
.xml
.XmlTag
;
39 import com
.intellij
.util
.descriptors
.ConfigFile
;
40 import com
.intellij
.util
.descriptors
.CustomConfigFile
;
41 import com
.intellij
.util
.xml
.DomElement
;
42 import com
.intellij
.util
.xml
.DomManager
;
43 import org
.jetbrains
.annotations
.NonNls
;
44 import org
.jetbrains
.idea
.devkit
.DevKitBundle
;
45 import org
.jetbrains
.idea
.devkit
.dom
.Dependency
;
46 import org
.jetbrains
.idea
.devkit
.dom
.IdeaPlugin
;
47 import org
.jetbrains
.idea
.devkit
.module
.PluginModuleType
;
48 import org
.jetbrains
.idea
.devkit
.projectRoots
.IdeaJdk
;
49 import org
.jetbrains
.idea
.devkit
.util
.DescriptorUtil
;
51 import java
.util
.ArrayList
;
52 import java
.util
.HashSet
;
57 public class PluginBuildParticipant
extends BuildParticipantBase
{
58 @NonNls private static final String CLASSES
= "/classes";
59 @NonNls private static final String LIB
= "/lib/";
60 @NonNls private static final String LIB_DIRECTORY
= "lib";
61 private final PluginBuildConfiguration myPluginBuildConfiguration
;
63 public PluginBuildParticipant(final Module module
, final PluginBuildConfiguration pluginBuildConfiguration
) {
65 myPluginBuildConfiguration
= pluginBuildConfiguration
;
68 public BuildRecipe
getBuildInstructions(final CompileContext context
) {
70 final BuildRecipe buildRecipe
= DeploymentUtil
.getInstance().createBuildRecipe();
71 registerBuildInstructions(buildRecipe
, context
);
75 protected void registerBuildInstructions(final BuildRecipe instructions
, final CompileContext context
) {
76 Sdk jdk
= IdeaJdk
.findIdeaJdk(ModuleRootManager
.getInstance(getModule()).getSdk());
77 if (jdk
!= null && IdeaJdk
.isFromIDEAProject(jdk
.getHomePath())) {
81 registerDescriptorCopyingInstructions(instructions
, context
);
84 context
.addMessage(CompilerMessageCategory
.ERROR
, DevKitBundle
.message("jdk.type.incorrect", getModule().getName()), null, -1, -1);
88 final Module
[] wrongSetDependencies
= PluginBuildUtil
.getWrongSetDependencies(getModule());
89 if (wrongSetDependencies
.length
!= 0) {
90 boolean realProblems
= false;
91 final String pluginId
= DescriptorUtil
.getPluginId(getModule());
93 for (Module dependency
: wrongSetDependencies
) {
94 if (!PluginModuleType
.isOfType(dependency
)) {
96 context
.addMessage(CompilerMessageCategory
.ERROR
,
97 DevKitBundle
.message("incorrect.dependency.non-plugin-module", dependency
.getName(), getModule().getName()), null,
101 final XmlFile pluginXml
= PluginModuleType
.getPluginXml(dependency
);
102 boolean isDeclared
= false;
103 if (pluginXml
!= null) {
104 final XmlTag rootTag
= pluginXml
.getDocument().getRootTag();
105 final XmlTag
[] dependencies
= rootTag
!= null ? rootTag
.findSubTags("depends") : XmlTag
.EMPTY
;
106 for (XmlTag dep
: dependencies
) {
107 if (dep
.getValue().getTrimmedText().equals(pluginId
)) {
114 // make this a warning instead?
116 context
.addMessage(CompilerMessageCategory
.ERROR
,
117 DevKitBundle
.message("incorrect.dependency.not-declared", dependency
.getName(), getModule().getName()), null, -1,
122 if (realProblems
) return;
125 final String explodedPath
= myPluginBuildConfiguration
.getExplodedPath();
126 if (explodedPath
== null) return; //where to put everything?
127 HashSet
<Module
> modules
= new HashSet
<Module
>();
128 PluginBuildUtil
.getDependencies(getModule(), modules
);
130 ModuleLink
[] containingModules
= new ModuleLink
[modules
.size()];
132 final DeploymentUtil makeUtil
= DeploymentUtil
.getInstance();
133 for (Module dep
: modules
) {
134 ModuleLink link
= makeUtil
.createModuleLink(dep
, getModule());
135 containingModules
[i
++] = link
;
136 link
.setPackagingMethod(PackagingMethod
.COPY_FILES
);
137 link
.setURI(CLASSES
);
140 // output may be excluded, copy it nevertheless
141 makeUtil
.addModuleOutputContents(context
, instructions
, getModule(), getModule(), CLASSES
, explodedPath
, null);
143 // child Java utility modules
144 makeUtil
.addJavaModuleOutputs(getModule(), containingModules
, instructions
, context
, explodedPath
, DevKitBundle
.message("presentable.plugin.module.name",
145 ModuleUtil
.getModuleNameInReadAction(getModule())));
147 HashSet
<Library
> libs
= new HashSet
<Library
>();
148 PluginBuildUtil
.getLibraries(getModule(), libs
);
149 for (Module dependentModule
: modules
) {
150 PluginBuildUtil
.getLibraries(dependentModule
, libs
);
153 final LibraryLink
[] libraryLinks
= new LibraryLink
[libs
.size()];
155 for (Library library
: libs
) {
156 LibraryLink link
= makeUtil
.createLibraryLink(library
, getModule());
157 libraryLinks
[i
++] = link
;
158 link
.setPackagingMethod(PackagingMethod
.COPY_FILES
);
159 final boolean onlyDirs
= link
.hasDirectoriesOnly();
160 if (onlyDirs
) {//todo split one lib into 2 separate libs if there are jars and dirs
161 link
.setURI(CLASSES
);
169 final VirtualFile libDir
= jdk
.getHomeDirectory().findFileByRelativePath(LIB_DIRECTORY
);
170 for (i
= 0; i
< libraryLinks
.length
; i
++) {
171 LibraryLink libraryLink
= libraryLinks
[i
];
172 final Library library
= libraryLink
.getLibrary();
173 if (library
!= null) {
174 VirtualFile
[] files
= library
.getFiles(OrderRootType
.CLASSES
);
175 for (VirtualFile file
: files
) {
176 if (file
.getFileSystem() instanceof JarFileSystem
) {
177 file
= ((JarFileSystem
)file
.getFileSystem()).getVirtualFileForJar(file
);
179 if (libDir
!= null && file
!= null && VfsUtil
.isAncestor(libDir
, file
, false)) {
180 context
.addMessage(CompilerMessageCategory
.ERROR
, DevKitBundle
.message("dont.add.idea.libs.to.classpath", file
.getName()), null,
184 makeUtil
.addLibraryLink(context
, instructions
, libraryLink
, getModule(), explodedPath
);
189 protected CustomConfigFile
[] getCustomDescriptors() {
190 final ConfigFile
[] configFiles
= getDeploymentDescriptors();
191 if (configFiles
.length
== 1) {
192 final ConfigFile configFile
= configFiles
[0];
193 final XmlFile xmlFile
= configFile
.getXmlFile();
194 if (xmlFile
!= null) {
195 final XmlDocument document
= xmlFile
.getDocument();
196 if (document
!= null) {
197 final DomElement domElement
= DomManager
.getDomManager(xmlFile
.getProject()).getDomElement(document
.getRootTag());
198 if (domElement
instanceof IdeaPlugin
) {
199 final ArrayList
<CustomConfigFile
> list
= new ArrayList
<CustomConfigFile
>();
200 for(Dependency dependency
: ((IdeaPlugin
)domElement
).getDependencies()) {
201 final String file
= dependency
.getConfigFile().getValue();
202 final VirtualFile virtualFile
= configFile
.getVirtualFile();
203 assert virtualFile
!= null;
204 final VirtualFile parent
= virtualFile
.getParent();
205 assert parent
!= null;
206 final String url
= parent
.getUrl();
207 list
.add(new CustomConfigFile(url
+ "/" + file
, configFile
.getMetaData().getDirectoryPath()));
209 return list
.toArray(new CustomConfigFile
[list
.size()]);
214 return super.getCustomDescriptors();
217 protected ConfigFile
[] getDeploymentDescriptors() {
218 ConfigFile configFile
= myPluginBuildConfiguration
.getPluginXML();
219 if (configFile
!= null) {
220 return new ConfigFile
[]{configFile
};
222 return ConfigFile
.EMPTY_ARRAY
;
225 public BuildConfiguration
getBuildConfiguration() {
226 return myPluginBuildConfiguration
;