blob: 071b2961c8f0c5340f4bd7432a83e381e3eeeda4 [file] [log] [blame]
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.packaging.impl.artifacts;
import com.intellij.CommonBundle;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.OrderEnumerator;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.ui.configuration.ModulesProvider;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.packaging.artifacts.ArtifactTemplate;
import com.intellij.packaging.elements.*;
import com.intellij.packaging.impl.elements.LibraryPackagingElement;
import com.intellij.packaging.impl.elements.ManifestFileUtil;
import com.intellij.packaging.impl.elements.ProductionModuleOutputElementType;
import com.intellij.packaging.impl.elements.TestModuleOutputElementType;
import com.intellij.util.CommonProcessors;
import com.intellij.util.PathUtil;
import com.intellij.util.Processor;
import gnu.trove.THashSet;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.*;
/**
* @author nik
*/
public class JarFromModulesTemplate extends ArtifactTemplate {
private static final Logger LOG = Logger.getInstance("#com.intellij.packaging.impl.artifacts.JarFromModulesTemplate");
private PackagingElementResolvingContext myContext;
public JarFromModulesTemplate(PackagingElementResolvingContext context) {
myContext = context;
}
@Override
public NewArtifactConfiguration createArtifact() {
JarArtifactFromModulesDialog dialog = new JarArtifactFromModulesDialog(myContext);
dialog.show();
if (!dialog.isOK()) {
return null;
}
return doCreateArtifact(dialog.getSelectedModules(), dialog.getMainClassName(), dialog.getDirectoryForManifest(),
dialog.isExtractLibrariesToJar(), dialog.isIncludeTests());
}
@Nullable
public NewArtifactConfiguration doCreateArtifact(final Module[] modules, final String mainClassName,
final String directoryForManifest,
final boolean extractLibrariesToJar,
final boolean includeTests) {
VirtualFile manifestFile = null;
final Project project = myContext.getProject();
if (mainClassName != null && !mainClassName.isEmpty() || !extractLibrariesToJar) {
final VirtualFile directory;
try {
directory = ApplicationManager.getApplication().runWriteAction(new ThrowableComputable<VirtualFile, IOException>() {
@Override
public VirtualFile compute() throws IOException {
return VfsUtil.createDirectoryIfMissing(directoryForManifest);
}
});
}
catch (IOException e) {
LOG.info(e);
Messages.showErrorDialog(project, "Cannot create directory '" + directoryForManifest + "': " + e.getMessage(),
CommonBundle.getErrorTitle());
return null;
}
if (directory == null) return null;
manifestFile = ManifestFileUtil.createManifestFile(directory, project);
if (manifestFile == null) {
return null;
}
ManifestFileUtil.updateManifest(manifestFile, mainClassName, null, true);
}
String name = modules.length == 1 ? modules[0].getName() : project.getName();
final PackagingElementFactory factory = PackagingElementFactory.getInstance();
final CompositePackagingElement<?> archive = factory.createArchive(ArtifactUtil.suggestArtifactFileName(name) + ".jar");
OrderEnumerator orderEnumerator = ProjectRootManager.getInstance(project).orderEntries(Arrays.asList(modules));
final Set<Library> libraries = new THashSet<Library>();
if (!includeTests) {
orderEnumerator = orderEnumerator.productionOnly();
}
final ModulesProvider modulesProvider = myContext.getModulesProvider();
final OrderEnumerator enumerator = orderEnumerator.using(modulesProvider).withoutSdk().runtimeOnly().recursively();
enumerator.forEachLibrary(new CommonProcessors.CollectProcessor<Library>(libraries));
enumerator.forEachModule(new Processor<Module>() {
@Override
public boolean process(Module module) {
if (ProductionModuleOutputElementType.ELEMENT_TYPE.isSuitableModule(modulesProvider, module)) {
archive.addOrFindChild(factory.createModuleOutput(module));
}
if (includeTests && TestModuleOutputElementType.ELEMENT_TYPE.isSuitableModule(modulesProvider, module)) {
archive.addOrFindChild(factory.createTestModuleOutput(module));
}
return true;
}
});
final JarArtifactType jarArtifactType = JarArtifactType.getInstance();
if (manifestFile != null && !manifestFile.equals(ManifestFileUtil.findManifestFile(archive, myContext, jarArtifactType))) {
archive.addFirstChild(factory.createFileCopyWithParentDirectories(manifestFile.getPath(), ManifestFileUtil.MANIFEST_DIR_NAME));
}
final String artifactName = name + ":jar";
if (extractLibrariesToJar) {
addExtractedLibrariesToJar(archive, factory, libraries);
return new NewArtifactConfiguration(archive, artifactName, jarArtifactType);
}
else {
final ArtifactRootElement<?> root = factory.createArtifactRootElement();
List<String> classpath = new ArrayList<String>();
root.addOrFindChild(archive);
addLibraries(libraries, root, archive, classpath);
ManifestFileUtil.updateManifest(manifestFile, mainClassName, classpath, true);
return new NewArtifactConfiguration(root, artifactName, PlainArtifactType.getInstance());
}
}
private void addLibraries(Set<Library> libraries, ArtifactRootElement<?> root, CompositePackagingElement<?> archive,
List<String> classpath) {
PackagingElementFactory factory = PackagingElementFactory.getInstance();
for (Library library : libraries) {
if (LibraryPackagingElement.getKindForLibrary(library).containsDirectoriesWithClasses()) {
for (VirtualFile classesRoot : library.getFiles(OrderRootType.CLASSES)) {
if (classesRoot.isInLocalFileSystem()) {
archive.addOrFindChild(factory.createDirectoryCopyWithParentDirectories(classesRoot.getPath(), "/"));
}
else {
final PackagingElement<?> child = factory.createFileCopyWithParentDirectories(PathUtil.getLocalFile(classesRoot).getPath(), "/");
root.addOrFindChild(child);
classpath.addAll(ManifestFileUtil.getClasspathForElements(Collections.singletonList(child), myContext, PlainArtifactType.getInstance()));
}
}
}
else {
final List<? extends PackagingElement<?>> children = factory.createLibraryElements(library);
classpath.addAll(ManifestFileUtil.getClasspathForElements(children, myContext, PlainArtifactType.getInstance()));
root.addOrFindChildren(children);
}
}
}
private static void addExtractedLibrariesToJar(CompositePackagingElement<?> archive, PackagingElementFactory factory, Set<Library> libraries) {
for (Library library : libraries) {
if (LibraryPackagingElement.getKindForLibrary(library).containsJarFiles()) {
for (VirtualFile classesRoot : library.getFiles(OrderRootType.CLASSES)) {
if (classesRoot.isInLocalFileSystem()) {
archive.addOrFindChild(factory.createDirectoryCopyWithParentDirectories(classesRoot.getPath(), "/"));
}
else {
archive.addOrFindChild(factory.createExtractedDirectory(classesRoot));
}
}
}
else {
archive.addOrFindChildren(factory.createLibraryElements(library));
}
}
}
@Override
public String getPresentableName() {
return "From modules with dependencies...";
}
}