Merge remote-tracking branch 'origin/master'

This commit is contained in:
Dmitry Trofimov
2014-12-17 17:49:16 +01:00
26 changed files with 352 additions and 203 deletions
@@ -27,6 +27,8 @@ import java.util.List;
import static org.jetbrains.jps.api.CmdlineRemoteProto.Message.ControllerMessage.ParametersMessage.TargetTypeBuildScope;
/**
* Allows to control the list of build targets which are compiled when the Make action is invoked for a specific scope.
*
* @author nik
*/
public abstract class BuildTargetScopeProvider {
@@ -25,13 +25,24 @@ import java.util.Collections;
import java.util.Set;
/**
* Describes a source root of a build target.
*
* @author nik
*/
public abstract class BuildRootDescriptor {
/**
* Returns the serializable ID of the root, used for writing caches. May return simply the file path.
*/
public abstract String getRootId();
/**
* Returns the directory of the source root.
*/
public abstract File getRootFile();
/**
* Returns the target to which this source root belongs.
*/
public abstract BuildTarget<?> getTarget();
/**
@@ -41,13 +52,16 @@ public abstract class BuildRootDescriptor {
return null;
}
/**
* Creates the file filter specifying which files under the specified root belong to this build target.
*/
@NotNull
public FileFilter createFileFilter() {
return FileUtilRt.ALL_FILES;
}
/**
* @return the set of excluded directories under this root
* @return the set of excluded directories under this root.
*/
@NotNull
public Set<File> getExcludedRoots() {
@@ -30,6 +30,14 @@ import java.util.Collection;
import java.util.List;
/**
* A single unit of the compilation process of a specific project. Has a number of inputs (individual files or directories with
* filter support). Places its output in a specific set of output roots. Can have dependencies on other build targets.
* E.g. any Java module has two build targets: production output and test output. Custom build targets (not based on a module)
* cannot have cyclic dependencies on each other.
* <p>
* When parallel compilation is enabled, build targets that don't have any dependencies on each other may be built at the same
* time in different threads.
*
* @author nik
*/
public abstract class BuildTarget<R extends BuildRootDescriptor> {
@@ -45,23 +53,63 @@ public abstract class BuildTarget<R extends BuildRootDescriptor> {
return myTargetType;
}
/**
* Calculates the dependencies of this build target.
*
* @param targetRegistry the registry of all targets existing in the project.
* @param outputIndex the index of output files by target.
* @return
*/
public abstract Collection<BuildTarget<?>> computeDependencies(BuildTargetRegistry targetRegistry, TargetOutputIndex outputIndex);
/**
* Allows the build target to tag the current project settings relevant to the build of this target
* (e.g the language level of a Java module) so that the target is fully recompiled when those settings
* change.
*
* @param pd the complete state of a compilation invocation
* @param out the print writer to which the project settings can be written (the settings are compared with the ones
* written during the invocation of the same method in a previous compilation).
*/
public void writeConfiguration(ProjectDescriptor pd, PrintWriter out) {
}
/**
* Returns the list of source roots for this target.
*
* @param model the JPS project model.
* @param index the index of exclude roots.
* @param ignoredFileIndex the index of ignore patterns.
* @param dataPaths the index of paths that can be used to serialize data related to build targets.
* @return
*/
@NotNull
public abstract List<R> computeRootDescriptors(JpsModel model,
ModuleExcludeIndex index,
IgnoredFileIndex ignoredFileIndex,
BuildDataPaths dataPaths);
/**
* Finds a source root by its serialized ID.
*
* @param rootId the serialized root ID.
* @param rootIndex the index of build roots.
* @return the build root or null if no root with this ID exists.
*/
@Nullable
public abstract R findRootDescriptor(String rootId, BuildRootIndex rootIndex);
@NotNull
public abstract String getPresentableName();
/**
* Returns the list of output directories in which this target is going to produce its output. (The specific
* files produced need to be reported by {@link org.jetbrains.jps.incremental.TargetBuilder#build} through
*
* {@link org.jetbrains.jps.builders.BuildOutputConsumer#registerOutputFile}.)
* @param context the compilation context.
* @return the collection of output roots.
*/
@NotNull
public abstract Collection<File> getOutputRoots(CompileContext context);
@@ -22,14 +22,22 @@ import java.util.Collection;
import java.util.List;
/**
* Allows to enumerate all build targets existing in a project.
*
* @author Eugene Zhuravlev
* Date: 10/27/12
* @since 10/27/12
*/
public interface BuildTargetRegistry {
/**
* Returns all build targets of a specified type.
*/
@NotNull
<T extends BuildTarget<?>>
List<T> getAllTargets(@NotNull BuildTargetType<T> type);
/**
* Returns all build targets existing in the project.
*/
@NotNull
List<BuildTarget<?>> getAllTargets();
@@ -37,6 +45,9 @@ public interface BuildTargetRegistry {
PRODUCTION, TEST, ALL
}
/**
* Returns the module-based targets of the specified module that have the specified type.
*/
@NotNull
Collection<ModuleBasedTarget<?>> getModuleBasedTargets(@NotNull JpsModule module, @NotNull ModuleTargetSelector selector);
}
@@ -21,7 +21,10 @@ import org.jetbrains.jps.model.JpsModel;
import java.util.List;
/**
* The type of a build target. For example, there is a build target type for Java production and another for Java tests.
*
* @author nik
* @see org.jetbrains.jps.incremental.BuilderService#getTargetTypes()
*/
public abstract class BuildTargetType<T extends BuildTarget<?>> {
private final String myTypeId;
@@ -44,6 +47,11 @@ public abstract class BuildTargetType<T extends BuildTarget<?>> {
return myTypeId.hashCode();
}
/**
* Finds all targets of the given type that need to be built in the given project.
* @param model the model instance representing a project.
* @return the list of targets.
*/
@NotNull
public abstract List<T> computeAllTargets(@NotNull JpsModel model);
@@ -21,8 +21,17 @@ import java.io.File;
import java.util.Collection;
/**
* Indexes the output roots of individual build targets.
*
* @author nik
*/
public interface TargetOutputIndex {
/**
* Returns the list of targets that contain the specified output file in their output roots.
*
* @param file a build output file.
* @return a collection of targets to the output roots of which this file belongs, or an empty collection
* if no such targets exist.
*/
Collection<BuildTarget<?>> getTargetsByOutputFile(@NotNull File file);
}
@@ -16,8 +16,11 @@
package org.jetbrains.jps.incremental;
/**
* The category of a module-level builder. Determines the order of executing builders when compiling a module.
*
* @author Eugene Zhuravlev
* Date: 9/17/11
* @since 9/17/11
* @see ModuleLevelBuilder#getCategory()
*/
public enum BuilderCategory {
INITIAL,
@@ -29,16 +29,26 @@ import java.util.List;
* @author nik
*/
public abstract class BuilderService {
/**
* Returns the list of build target types contributed by this plugin. If it only participates in the compilation
* of regular Java modules, you don't need to return anything here.
*/
@NotNull
public List<? extends BuildTargetType<?>> getTargetTypes() {
return Collections.emptyList();
}
/**
* Returns the list of Java module builder extensions contributed by this plugin.
*/
@NotNull
public List<? extends ModuleLevelBuilder> createModuleLevelBuilders() {
return Collections.emptyList();
}
/**
* Returns the list of non-module target builders contributed by this plugin.
*/
@NotNull
public List<? extends TargetBuilder<?,?>> createBuilders() {
return Collections.emptyList();
@@ -29,10 +29,14 @@ import java.util.List;
import java.util.Map;
/**
* Use {@link BuilderService} to register implementations of this class
* Allows to extend the compilation process for Java modules compiled to .class files. Use {@link BuilderService} to register
* implementations of this class. The order of execution of different module-level builders is determined by their category
* (they're executed in the order of constants in the {@code BuilderCategory}; the order of executing different builders of
* the same category is not determined).
*
* @author Eugene Zhuravlev
* Date: 9/17/11
* @since 9/17/11
* @see BuilderService#createModuleLevelBuilders()
*/
public abstract class ModuleLevelBuilder extends Builder {
private final BuilderCategory myCategory;
@@ -59,6 +63,17 @@ public abstract class ModuleLevelBuilder extends Builder {
BinaryContent lookupClassBytes(String className);
}
/**
* Performs the compilation actions for a single module or a chunk of cyclically dependent modules.
*
* @param context compilation context (can be used to report compiler errors/warnings and to check whether the build
* has been cancelled and needs to be stopped).
* @param chunk target to build.
* @param dirtyFilesHolder can be used to enumerate the source files from the inputs of this target that have been modified
* or deleted since the previous compilation run.
* @param outputConsumer receives the output files and classes produced by the build. (All output files produced by the build
* need to be reported here.)
*/
public abstract ExitCode build(CompileContext context,
ModuleChunk chunk,
DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget> dirtyFilesHolder,
@@ -22,8 +22,10 @@ import java.io.IOException;
import java.util.Collection;
/**
* Use {@link BuilderService} to register implementations of this class
* Produced the output of a single build target. Use {@link BuilderService} to register implementations of this class.
*
* @author nik
* @see BuilderService#createBuilders()
*/
public abstract class TargetBuilder<R extends BuildRootDescriptor, T extends BuildTarget<R>> extends Builder {
private final Collection<? extends BuildTargetType<? extends T>> myTargetTypes;
@@ -36,6 +38,17 @@ public abstract class TargetBuilder<R extends BuildRootDescriptor, T extends Bui
return myTargetTypes;
}
/**
* Builds a single build target.
*
* @param target target to build.
* @param holder can be used to enumerate the source files from the inputs of this target that have been modified
* or deleted since the previous compilation run.
* @param outputConsumer receives the output files produced by the build. (All output files produced by the build need
* to be reported here.)
* @param context compilation context (can be used to report compiler errors/warnings and to check whether the build
* has been cancelled and needs to be stopped).
*/
public abstract void build(@NotNull T target, @NotNull DirtyFilesHolder<R, T> holder, @NotNull BuildOutputConsumer outputConsumer,
@NotNull CompileContext context) throws ProjectBuildException, IOException;
@@ -16,8 +16,13 @@
package org.jetbrains.jps.indices;
/**
* Indexes the ignored files in a project.
*
* @author nik
*/
public interface IgnoredFileIndex {
/**
* Checks if the specified filename is ignored (listed under Settings | File Types | Files and folders to ignore).
*/
boolean isIgnored(String fileName);
}
@@ -21,12 +21,23 @@ import java.io.File;
import java.util.Collection;
/**
* Allows to check whether a particular file is in the content or under an exclude root of a module.
*
* @author nik
*/
public interface ModuleExcludeIndex {
/**
* Checks if the specified file is under an exclude root of a module.
*/
boolean isExcluded(File file);
/**
* Returns the list of exclude roots for a specified module.
*/
Collection<File> getModuleExcludes(JpsModule module);
/**
* Checks if the specified file is under the content of any module in the project and not under an exclude root.
*/
boolean isInContent(File file);
}
@@ -22,7 +22,10 @@ import org.jetbrains.jps.model.library.sdk.JpsSdk;
import org.jetbrains.jps.model.library.sdk.JpsSdkType;
/**
* Represents the application-level settings (JDKs and global libraries) required for an external build.
*
* @author nik
* @see org.jetbrains.jps.model.JpsModel#getGlobal()
*/
public interface JpsGlobal extends JpsCompositeElement, JpsReferenceableElement<JpsGlobal> {
@NotNull
@@ -18,6 +18,8 @@ package org.jetbrains.jps.model;
import org.jetbrains.annotations.NotNull;
/**
* Represents an IntelliJ IDEA project and a set of relevant application-level settings (e.g. the JDK configuration) in JPS.
*
* @author nik
*/
public interface JpsModel {
@@ -556,23 +556,27 @@ public class PluginManagerCore {
@Nullable
static IdeaPluginDescriptorImpl loadDescriptorFromDir(@NotNull File file, @NotNull String fileName) {
IdeaPluginDescriptorImpl descriptor = null;
File descriptorFile = new File(file, META_INF + File.separator + fileName);
if (descriptorFile.exists()) {
descriptor = new IdeaPluginDescriptorImpl(file);
try {
IdeaPluginDescriptorImpl descriptor = new IdeaPluginDescriptorImpl(file);
descriptor.readExternal(descriptorFile.toURI().toURL());
return descriptor;
}
catch (Exception e) {
System.err.println("Cannot load: " + descriptorFile.getAbsolutePath());
e.printStackTrace();
catch (XmlSerializationException e) {
getLogger().info("Cannot load " + file, e);
prepareLoadingPluginsErrorMessage("File '" + file.getName() + "' contains invalid plugin descriptor.");
}
catch (Throwable e) {
getLogger().info("Cannot load " + file, e);
}
}
return descriptor;
return null;
}
@Nullable
static IdeaPluginDescriptorImpl loadDescriptorFromJar(@NotNull File file, @NotNull @NonNls String fileName) {
static IdeaPluginDescriptorImpl loadDescriptorFromJar(@NotNull File file, @NotNull String fileName) {
try {
String fileURL = StringUtil.replace(file.toURI().toASCIIString(), "!", "%21");
URL jarURL = new URL("jar:" + fileURL + "!/META-INF/" + fileName);
@@ -593,7 +597,7 @@ public class PluginManagerCore {
}
catch (XmlSerializationException e) {
getLogger().info("Cannot load " + file, e);
prepareLoadingPluginsErrorMessage("Plugin file " + file.getName() + " contains invalid plugin descriptor file.");
prepareLoadingPluginsErrorMessage("File '" + file.getName() + "' contains invalid plugin descriptor.");
}
catch (Throwable e) {
getLogger().info("Cannot load " + file, e);
@@ -607,65 +611,65 @@ public class PluginManagerCore {
return loadDescriptorFromJar(file, PLUGIN_XML);
}
@SuppressWarnings({"HardCodedStringLiteral"})
@Nullable
public static IdeaPluginDescriptorImpl loadDescriptor(final File file, @NonNls final String fileName) {
public static IdeaPluginDescriptorImpl loadDescriptor(@NotNull final File file, @NotNull String fileName) {
IdeaPluginDescriptorImpl descriptor = null;
if (file.isDirectory()) {
descriptor = loadDescriptorFromDir(file, fileName);
if (descriptor == null) {
File libDir = new File(file, "lib");
if (!libDir.isDirectory()) {
return null;
}
final File[] files = libDir.listFiles();
if (files == null || files.length == 0) {
return null;
}
Arrays.sort(files, new Comparator<File>() {
@Override
public int compare(@NotNull File o1, @NotNull File o2) {
if (o2.getName().startsWith(file.getName())) return Integer.MAX_VALUE;
if (o1.getName().startsWith(file.getName())) return -Integer.MAX_VALUE;
if (o2.getName().startsWith("resources")) return -Integer.MAX_VALUE;
if (o1.getName().startsWith("resources")) return Integer.MAX_VALUE;
return 0;
}
});
for (final File f : files) {
if (FileUtil.isJarOrZip(f)) {
descriptor = loadDescriptorFromJar(f, fileName);
if (descriptor != null) {
descriptor.setPath(file);
break;
}
// getLogger().warn("Cannot load descriptor from " + f.getName() + "");
}
else if (f.isDirectory()) {
IdeaPluginDescriptorImpl descriptor1 = loadDescriptorFromDir(f, fileName);
if (descriptor1 != null) {
if (descriptor != null) {
getLogger().info("Cannot load " + file + " because two or more plugin.xml's detected");
return null;
}
descriptor = descriptor1;
descriptor.setPath(file);
}
}
}
}
File libDir = new File(file, "lib");
if (!libDir.isDirectory()) {
return null;
}
final File[] files = libDir.listFiles();
if (files == null || files.length == 0) {
return null;
}
Arrays.sort(files, new Comparator<File>() {
@Override
public int compare(@NotNull File o1, @NotNull File o2) {
if (o2.getName().startsWith(file.getName())) return Integer.MAX_VALUE;
if (o1.getName().startsWith(file.getName())) return -Integer.MAX_VALUE;
if (o2.getName().startsWith("resources")) return -Integer.MAX_VALUE;
if (o1.getName().startsWith("resources")) return Integer.MAX_VALUE;
return 0;
}
});
for (final File f : files) {
if (FileUtil.isJarOrZip(f)) {
descriptor = loadDescriptorFromJar(f, fileName);
if (descriptor != null) {
descriptor.setPath(file);
break;
}
// getLogger().warn("Cannot load descriptor from " + f.getName() + "");
}
else if (f.isDirectory()) {
IdeaPluginDescriptorImpl descriptor1 = loadDescriptorFromDir(f, fileName);
if (descriptor1 != null) {
if (descriptor != null) {
getLogger().info("Cannot load " + file + " because two or more plugin.xml's detected");
return null;
}
descriptor = descriptor1;
descriptor.setPath(file);
}
}
}
}
}
else if (StringUtil.endsWithIgnoreCase(file.getName(), ".jar") && file.exists()) {
descriptor = loadDescriptorFromJar(file, fileName);
}
if (descriptor != null && descriptor.getOptionalConfigs() != null && !descriptor.getOptionalConfigs().isEmpty()) {
final Map<PluginId, IdeaPluginDescriptorImpl> descriptors = new THashMap<PluginId, IdeaPluginDescriptorImpl>(descriptor.getOptionalConfigs().size());
for (Map.Entry<PluginId, String> entry: descriptor.getOptionalConfigs().entrySet()) {
final Map<PluginId, IdeaPluginDescriptorImpl> descriptors =
new THashMap<PluginId, IdeaPluginDescriptorImpl>(descriptor.getOptionalConfigs().size());
for (Map.Entry<PluginId, String> entry : descriptor.getOptionalConfigs().entrySet()) {
String optionalDescriptorName = entry.getValue();
assert !Comparing.equal(fileName, optionalDescriptorName) : "recursive dependency: "+ fileName;
assert !Comparing.equal(fileName, optionalDescriptorName) : "recursive dependency: " + fileName;
IdeaPluginDescriptorImpl optionalDescriptor = loadDescriptor(file, optionalDescriptorName);
if (optionalDescriptor == null && !FileUtil.isJarOrZip(file)) {
@@ -687,6 +691,7 @@ public class PluginManagerCore {
}
descriptor.setOptionalDescriptors(descriptors);
}
return descriptor;
}
@@ -27,6 +27,7 @@ import com.intellij.psi.codeStyle.arrangement.model.ArrangementAtomMatchConditio
import com.intellij.psi.codeStyle.arrangement.std.ArrangementStandardSettingsManager;
import com.intellij.psi.codeStyle.arrangement.std.ArrangementUiComponent;
import com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens;
import com.intellij.ui.IdeBorderFactory;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.table.JBTable;
import com.intellij.util.ui.AbstractTableCellEditor;
@@ -79,6 +80,7 @@ public class ArrangementMatchingRulesControl extends JBTable {
setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
setShowColumns(false);
setShowGrid(false);
setBorder(IdeBorderFactory.createBorder());
setSurrendersFocusOnKeystroke(true);
putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
@@ -77,12 +77,15 @@ public class ArrangementRuleIndexControl extends JPanel {
return;
}
g.setColor(myIsError ? JBColor.red : UIUtil.getBorderColor());
g.setColor(myIsError ? JBColor.red : JBColor.border());
Rectangle bounds = getBounds();
((Graphics2D)g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int y = Math.max(0, myBaseLine - myHeight - (myDiameter - myHeight) / 2);
g.drawOval(0, y, myDiameter, myDiameter);
if (UIUtil.isUnderDarcula()) {
g.setColor(UIUtil.getLabelForeground());
}
g.drawChars(myChars, 0, myChars.length, (bounds.width - myIndexWidth) / 2, myBaseLine);
}
@@ -130,7 +130,7 @@ public class ProjectViewDirectoryHelper {
}
else { // source directory in "flatten packages" mode
final PsiDirectory parentDir = psiDirectory.getParentDirectory();
if (parentDir == null || skipDirectory(parentDir) /*|| !rootDirectoryFound(parentDir)*/ && withSubDirectories) {
if (parentDir == null || skipDirectory(parentDir) && withSubDirectories) {
addAllSubpackages(children, psiDirectory, moduleFileIndex, settings);
}
PsiDirectory[] subdirs = psiDirectory.getSubdirectories();
@@ -218,20 +218,22 @@ public class ProjectViewDirectoryHelper {
}
// used only for non-flatten packages mode
public void processPsiDirectoryChildren(final PsiDirectory psiDir,
PsiElement[] children,
List<AbstractTreeNode> container,
ProjectFileIndex projectFileIndex,
ModuleFileIndex moduleFileIndex,
ViewSettings viewSettings,
boolean withSubDirectories) {
public void processPsiDirectoryChildren(final PsiDirectory psiDir,
PsiElement[] children,
List<AbstractTreeNode> container,
ProjectFileIndex projectFileIndex,
@Nullable ModuleFileIndex moduleFileIndex,
ViewSettings viewSettings,
boolean withSubDirectories) {
for (PsiElement child : children) {
LOG.assertTrue(child.isValid());
final VirtualFile vFile;
if (child instanceof PsiFile) {
vFile = ((PsiFile)child).getVirtualFile();
addNode(moduleFileIndex, projectFileIndex, psiDir, vFile, container, PsiFileNode.class, child, viewSettings);
if (vFile != null) {
addNode(moduleFileIndex, vFile, container, PsiFileNode.class, child, viewSettings);
}
}
else if (child instanceof PsiDirectory) {
if (withSubDirectories) {
@@ -244,7 +246,7 @@ public class ProjectViewDirectoryHelper {
continue;
}
}
addNode(moduleFileIndex, projectFileIndex, psiDir, vFile, container, PsiDirectoryNode.class, child, viewSettings);
addNode(moduleFileIndex, vFile, container, PsiDirectoryNode.class, child, viewSettings);
}
}
else {
@@ -254,36 +256,15 @@ public class ProjectViewDirectoryHelper {
}
public void addNode(ModuleFileIndex moduleFileIndex,
ProjectFileIndex projectFileIndex,
PsiDirectory psiDir,
VirtualFile vFile,
List<AbstractTreeNode> container,
Class<? extends AbstractTreeNode> nodeClass,
PsiElement element,
final ViewSettings settings) {
if (vFile == null) {
return;
}
VirtualFile vFile,
List<AbstractTreeNode> container,
Class<? extends AbstractTreeNode> nodeClass,
PsiElement element,
final ViewSettings settings) {
// this check makes sense for classes not in library content only
if (moduleFileIndex != null && !moduleFileIndex.isInContent(vFile)) {
return;
}
/*
final boolean childInLibraryClasses = projectFileIndex.isInLibraryClasses(vFile);
if (!projectFileIndex.isInSourceContent(vFile)) {
if (childInLibraryClasses) {
final VirtualFile psiDirVFile = psiDir.getVirtualFile();
final boolean parentInLibraryContent =
projectFileIndex.isInLibraryClasses(psiDirVFile) || projectFileIndex.isInLibrarySource(psiDirVFile);
if (!parentInLibraryContent) {
return;
}
}
}
if (childInLibraryClasses && !projectFileIndex.isInContent(vFile) && !showFileInLibClasses(vFile)) {
return; // skip java sources in classpath
}
*/
try {
container.add(ProjectViewNode.createTreeNode(nodeClass, element.getProject(), element, settings));
@@ -295,20 +276,18 @@ public class ProjectViewDirectoryHelper {
// used only in flatten packages mode
public void addAllSubpackages(List<AbstractTreeNode> container,
PsiDirectory dir,
ModuleFileIndex moduleFileIndex,
ViewSettings viewSettings) {
PsiDirectory dir,
@Nullable ModuleFileIndex moduleFileIndex,
ViewSettings viewSettings) {
final Project project = dir.getProject();
PsiDirectory[] subdirs = dir.getSubdirectories();
for (PsiDirectory subdir : subdirs) {
if (skipDirectory(subdir)) {
continue;
}
if (moduleFileIndex != null) {
if (!moduleFileIndex.isInContent(subdir.getVirtualFile())) {
container.add(new PsiDirectoryNode(project, subdir, viewSettings));
continue;
}
if (moduleFileIndex != null && !moduleFileIndex.isInContent(subdir.getVirtualFile())) {
container.add(new PsiDirectoryNode(project, subdir, viewSettings));
continue;
}
if (viewSettings.isHideEmptyMiddlePackages()) {
if (!isEmptyMiddleDirectory(subdir, false)) {
@@ -1,21 +1,50 @@
/*
* Copyright 2000-2014 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.ide.plugins;
import com.intellij.openapi.application.ex.PathManagerEx;
import junit.framework.TestCase;
import org.junit.Test;
import java.io.File;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
/**
* @author Dmitry Avdeev
* Date: 7/14/11
*/
public class PluginDescriptorTest extends TestCase {
public class PluginDescriptorTest {
private static String getTestDataPath() {
return PathManagerEx.getTestDataPath() + "/ide/plugins/pluginDescriptor";
}
public void testDescriptorLoading() throws Exception {
String path = PathManagerEx.getTestDataPath().replace(File.separatorChar, '/') + "/ide/plugins/pluginDescriptor";
File file = new File(path + "/asp.jar");
@Test
public void testDescriptorLoading() {
File file = new File(getTestDataPath(), "asp.jar");
assertTrue(file + " not exist", file.exists());
IdeaPluginDescriptorImpl descriptor = PluginManager.loadDescriptorFromJar(file);
IdeaPluginDescriptorImpl descriptor = PluginManagerCore.loadDescriptorFromJar(file);
assertNotNull(descriptor);
}
@Test
public void testInvalidFileDescriptor() {
File file = new File(getTestDataPath(), "malformed");
assertTrue(file + " not exist", file.exists());
IdeaPluginDescriptorImpl descriptor = PluginManagerCore.loadDescriptorFromDir(file, PluginManagerCore.PLUGIN_XML);
assertNull(descriptor);
}
}
@@ -144,14 +144,14 @@ public class JavaCoverageAnnotator extends BaseCoverageAnnotator {
}
@Nullable
public static String getCoverageInformationString(PackageAnnotator.PackageCoverageInfo info, boolean subCoverageActive) {
public static String getCoverageInformationString(PackageAnnotator.SummaryCoverageInfo info, boolean subCoverageActive) {
if (info == null) return null;
if (info.totalClassCount == 0 || info.totalLineCount == 0) return null;
if (subCoverageActive) {
return info.coveredClassCount + info.coveredLineCount > 0 ? "covered" : null;
return info.coveredClassCount + info.getCoveredLineCount() > 0 ? "covered" : null;
}
return (int)((double)info.coveredClassCount / info.totalClassCount * 100) + "% classes, " +
(int)((double)info.coveredLineCount / info.totalLineCount * 100) + "% lines covered";
(int)((double)info.getCoveredLineCount() / info.totalLineCount * 100) + "% lines covered";
}
/**
@@ -184,10 +184,9 @@ public class JavaCoverageAnnotator extends BaseCoverageAnnotator {
boolean flatten) {
if (psiPackage == null) return null;
final boolean subCoverageActive = coverageDataManager.isSubCoverageActive();
PackageAnnotator.PackageCoverageInfo info;
if (module != null) {
final PsiDirectory[] directories = psiPackage.getDirectories(GlobalSearchScope.moduleScope(module));
PackageAnnotator.PackageCoverageInfo result = null;
PackageAnnotator.SummaryCoverageInfo result = null;
for (PsiDirectory directory : directories) {
final VirtualFile virtualFile = directory.getVirtualFile();
result = merge(result, myDirCoverageInfos.get(virtualFile));
@@ -196,49 +195,27 @@ public class JavaCoverageAnnotator extends BaseCoverageAnnotator {
return getCoverageInformationString(result, subCoverageActive);
}
else {
info = getPackageCoverageInfo(psiPackage, flatten);
PackageAnnotator.PackageCoverageInfo info = getPackageCoverageInfo(psiPackage, flatten);
return getCoverageInformationString(info, subCoverageActive);
}
return getCoverageInformationString(info, subCoverageActive);
}
public PackageAnnotator.PackageCoverageInfo getPackageCoverageInfo(@NotNull PsiPackage psiPackage, boolean flattenPackages) {
final String qualifiedName = psiPackage.getQualifiedName();
return flattenPackages ? myFlattenPackageCoverageInfos.get(qualifiedName) : myPackageCoverageInfos.get(qualifiedName);
}
public String getPackageClassPercentage(@NotNull final PsiPackage psiPackage, boolean flatten) {
final PackageAnnotator.PackageCoverageInfo packageCoverageInfo = getPackageCoverageInfo(psiPackage, flatten);
if (packageCoverageInfo == null) return null;
return getPercentage(packageCoverageInfo.coveredClassCount, packageCoverageInfo.totalClassCount);
}
public String getPackageMethodPercentage(PsiPackage psiPackage, boolean flatten) {
final PackageAnnotator.PackageCoverageInfo packageCoverageInfo = getPackageCoverageInfo(psiPackage, flatten);
if (packageCoverageInfo == null) return null;
return getPercentage(packageCoverageInfo.coveredMethodCount, packageCoverageInfo.totalMethodCount);
}
public String getPackageLinePercentage(final PsiPackage psiPackage, boolean flatten) {
final PackageAnnotator.PackageCoverageInfo packageCoverageInfo = getPackageCoverageInfo(psiPackage, flatten);
if (packageCoverageInfo == null) return null;
return getPercentage(packageCoverageInfo.coveredLineCount, packageCoverageInfo.totalLineCount);
}
public String getClassLinePercentage(String classFQName) {
final PackageAnnotator.ClassCoverageInfo info = myClassCoverageInfos.get(classFQName);
public String getLineCoveredPercentage(@Nullable PackageAnnotator.SummaryCoverageInfo info) {
if (info == null) return null;
final int coveredLines = info.fullyCoveredLineCount + info.partiallyCoveredLineCount;
return getPercentage(coveredLines, info.totalLineCount);
return getPercentage(info.getCoveredLineCount(), info.totalLineCount);
}
public String getClassMethodPercentage(String classFQName) {
final PackageAnnotator.ClassCoverageInfo info = myClassCoverageInfos.get(classFQName);
public String getMethodCoveredPercentage(@Nullable PackageAnnotator.SummaryCoverageInfo info) {
if (info == null) return null;
return getPercentage(info.coveredMethodCount, info.totalMethodCount);
}
public String getClassCoveredPercentage(String classFQName) {
final PackageAnnotator.ClassCoverageInfo info = myClassCoverageInfos.get(classFQName);
public String getClassCoveredPercentage(@Nullable PackageAnnotator.SummaryCoverageInfo info) {
if (info == null) return null;
return getPercentage(info.coveredClassCount, info.totalClassCount);
}
@@ -247,8 +224,8 @@ public class JavaCoverageAnnotator extends BaseCoverageAnnotator {
return (int)((double)covered /total * 100) +"% (" + covered + "/" + total + ")";
}
public static PackageAnnotator.PackageCoverageInfo merge(final PackageAnnotator.PackageCoverageInfo info,
final PackageAnnotator.PackageCoverageInfo testInfo) {
public static PackageAnnotator.SummaryCoverageInfo merge(@Nullable final PackageAnnotator.SummaryCoverageInfo info,
@Nullable final PackageAnnotator.SummaryCoverageInfo testInfo) {
if (info == null) return testInfo;
if (testInfo == null) return info;
final PackageAnnotator.PackageCoverageInfo coverageInfo = new PackageAnnotator.PackageCoverageInfo();
@@ -256,7 +233,7 @@ public class JavaCoverageAnnotator extends BaseCoverageAnnotator {
coverageInfo.coveredClassCount = info.coveredClassCount + testInfo.coveredClassCount;
coverageInfo.totalLineCount = info.totalLineCount + testInfo.totalLineCount;
coverageInfo.coveredLineCount = info.coveredLineCount + testInfo.coveredLineCount;
coverageInfo.coveredLineCount = info.getCoveredLineCount() + testInfo.getCoveredLineCount();
return coverageInfo;
}
@@ -64,25 +64,39 @@ public class PackageAnnotator {
void annotateClass(String classQualifiedName, ClassCoverageInfo classCoverageInfo);
}
public static class ClassCoverageInfo {
public int totalLineCount;
public int fullyCoveredLineCount;
public int partiallyCoveredLineCount;
public int totalMethodCount;
public int coveredMethodCount;
public int totalClassCount = 1;
public int coveredClassCount;
}
public static class PackageCoverageInfo {
public static abstract class SummaryCoverageInfo {
public int totalClassCount;
public int coveredClassCount;
public int totalMethodCount;
public int coveredMethodCount;
public int totalLineCount;
public abstract int getCoveredLineCount();
}
public static class ClassCoverageInfo extends SummaryCoverageInfo {
public int fullyCoveredLineCount;
public int partiallyCoveredLineCount;
public ClassCoverageInfo() {
totalClassCount = 1;
}
@Override
public int getCoveredLineCount() {
return fullyCoveredLineCount + partiallyCoveredLineCount;
}
}
public static class PackageCoverageInfo extends SummaryCoverageInfo {
public int coveredLineCount;
public int coveredMethodCount;
public int totalMethodCount;
@Override
public int getCoveredLineCount() {
return coveredLineCount;
}
}
public static class DirCoverageInfo extends PackageCoverageInfo {
@@ -32,6 +32,7 @@ public class JavaCoverageViewExtension extends CoverageViewExtension {
@Override
public String getSummaryForNode(AbstractTreeNode node) {
if (!myCoverageViewManager.isReady()) return "Loading...";
final String coverageInformationString = myAnnotator
.getPackageCoverageInformationString((PsiPackage)node.getValue(), null, myCoverageDataManager, myStateBean.myFlattenPackages);
return getNotCoveredMessage(coverageInformationString) + " in package \'" + node.toString() + "\'";
@@ -44,28 +45,12 @@ public class JavaCoverageViewExtension extends CoverageViewExtension {
myCoverageDataManager);
if (coverageInformationString == null) {
if (!myCoverageViewManager.isReady()) return "Loading...";
PackageAnnotator.PackageCoverageInfo info = new PackageAnnotator.PackageCoverageInfo();
PackageAnnotator.SummaryCoverageInfo info = new PackageAnnotator.PackageCoverageInfo();
final Collection children = childNode.getChildren();
for (Object child : children) {
final Object childValue = ((CoverageListNode)child).getValue();
if (childValue instanceof PsiPackage) {
final PackageAnnotator.PackageCoverageInfo coverageInfo = myAnnotator.getPackageCoverageInfo((PsiPackage)childValue, myStateBean.myFlattenPackages);
if (coverageInfo != null) {
info = JavaCoverageAnnotator.merge(info, coverageInfo);
}
} else {
final PackageAnnotator.ClassCoverageInfo classCoverageInfo = getClassCoverageInfo(((PsiClass)childValue));
if (classCoverageInfo != null) {
info.coveredClassCount += classCoverageInfo.coveredMethodCount > 0 ? 1 : 0;
info.totalClassCount ++;
info.coveredMethodCount += classCoverageInfo.coveredMethodCount;
info.totalMethodCount += classCoverageInfo.totalMethodCount;
info.coveredLineCount += classCoverageInfo.partiallyCoveredLineCount + classCoverageInfo.fullyCoveredLineCount;
info.totalLineCount += classCoverageInfo.totalLineCount;
}
}
PackageAnnotator.SummaryCoverageInfo childInfo = getSummaryCoverageForNodeValue(childValue);
info = JavaCoverageAnnotator.merge(info, childInfo);
}
coverageInformationString = JavaCoverageAnnotator.getCoverageInformationString(info, false);
}
@@ -82,30 +67,30 @@ public class JavaCoverageViewExtension extends CoverageViewExtension {
@Override
public String getPercentage(int columnIndex, AbstractTreeNode node) {
final Object value = node.getValue();
PackageAnnotator.SummaryCoverageInfo info = getSummaryCoverageForNodeValue(value);
if (columnIndex == 1) {
return myAnnotator.getClassCoveredPercentage(info);
} else if (columnIndex == 2){
return myAnnotator.getMethodCoveredPercentage(info);
}
return myAnnotator.getLineCoveredPercentage(info);
}
public PackageAnnotator.SummaryCoverageInfo getSummaryCoverageForNodeValue(Object value) {
PackageAnnotator.SummaryCoverageInfo info = null;
if (value instanceof PsiClass) {
//no coverage gathered
if (((PsiClass)value).isInterface()) return null;
final String qualifiedName = ((PsiClass)value).getQualifiedName();
if (columnIndex == 1) {
return myAnnotator.getClassCoveredPercentage(qualifiedName);
} else if (columnIndex == 2){
return myAnnotator.getClassMethodPercentage(qualifiedName);
if (!((PsiClass)value).isInterface()) {
final String qualifiedName = ((PsiClass)value).getQualifiedName();
info = myAnnotator.getClassCoverageInfo(qualifiedName);
}
return myAnnotator.getClassLinePercentage(qualifiedName);
}
if (value instanceof PsiPackage) {
final boolean flatten = myStateBean.myFlattenPackages;
if (columnIndex == 1) {
return myAnnotator.getPackageClassPercentage((PsiPackage)value, flatten);
} else if (columnIndex == 2) {
return myAnnotator.getPackageMethodPercentage((PsiPackage)value, flatten);
}
return myAnnotator.getPackageLinePercentage((PsiPackage)value, flatten);
info = myAnnotator.getPackageCoverageInfo((PsiPackage)value, myStateBean.myFlattenPackages);
}
return null;
return info;
}
@Override
@@ -1,7 +1,7 @@
<idea-plugin version="2">
<id>org.jetbrains.plugins.coursecreator</id>
<name>Course Creator for PyCharm Educational</name>
<version>1.1</version>
<version>1.2</version>
<description><![CDATA[
Plugin allows you to create new course for PyCharm Education Edition.
@@ -2,7 +2,7 @@
<idea-plugin version="2">
<id>com.jetbrains.python.edu.learn-python</id>
<name>Educational plugin for PyCharm</name>
<version>1.1</version>
<version>1.2</version>
<description><![CDATA[
Educational plugin for students. This plugin allows to learn Python
@@ -1,6 +1,6 @@
<component>
<company name="JetBrains s.r.o." url="http://www.jetbrains.com/?fromIDE"/>
<version major="1" minor="0" eap="true"/>
<version major="1" minor="0.1" eap="false"/>
<build number="__BUILD_NUMBER__" date="__BUILD_DATE__"/>
<logo url="/pycharm_edu_logo.png" textcolor="5a8179" progressColor="ffaa16" progressY="230" progressTailIcon="/community_progress_tail.png"/>
<about url="/pycharm_edu_about.png" logoX="300" logoY="265" logoW="75" logoH="30" foreground="ffffff" linkColor="fca11a"/>