Added initial support for Python code coverage. Ruby coverage refactored.
authorDmitry Trofimov <dmitry.trofimov@jetbrains.com>
Fri, 23 Sep 2011 10:27:33 +0000 (14:27 +0400)
committerDmitry Trofimov <dmitry.trofimov@jetbrains.com>
Fri, 23 Sep 2011 10:27:33 +0000 (14:27 +0400)
platform/lang-api/src/com/intellij/execution/configuration/AbstractRunConfiguration.java [new file with mode: 0644]
platform/lang-api/src/com/intellij/execution/configuration/RunConfigurationExtension.java [new file with mode: 0644]
platform/lang-api/src/com/intellij/execution/configuration/RunConfigurationExtensionsManager.java [new file with mode: 0644]
platform/platform-api/platform-api.iml
platform/platform-api/src/com/intellij/execution/configurations/ParametersList.java

diff --git a/platform/lang-api/src/com/intellij/execution/configuration/AbstractRunConfiguration.java b/platform/lang-api/src/com/intellij/execution/configuration/AbstractRunConfiguration.java
new file mode 100644 (file)
index 0000000..8401725
--- /dev/null
@@ -0,0 +1,41 @@
+package com.intellij.execution.configuration;
+
+import com.intellij.execution.configurations.ConfigurationFactory;
+import com.intellij.execution.configurations.ModuleBasedConfiguration;
+import com.intellij.execution.configurations.RunConfigurationModule;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * @author traff
+ */
+public abstract class AbstractRunConfiguration extends ModuleBasedConfiguration<RunConfigurationModule> {
+  private Map<String, String> myEnvs = new LinkedHashMap<String, String>();
+  private boolean myPassParentEnvs = true;
+
+  public AbstractRunConfiguration(String name, RunConfigurationModule configurationModule, ConfigurationFactory factory) {
+    super(name, configurationModule, factory);
+  }
+
+  public Map<String, String> getEnvs() {
+    return myEnvs;
+  }
+
+  public void setEnvs(final Map<String, String> envs) {
+    myEnvs = envs;
+  }
+
+  public boolean isPassParentEnvs() {
+    return myPassParentEnvs;
+  }
+
+  public void setPassParentEnvs(final boolean passParentEnvs) {
+    myPassParentEnvs = passParentEnvs;
+  }
+
+  public enum RunnerType {
+    RUN,
+    DEBUG
+  }
+}
diff --git a/platform/lang-api/src/com/intellij/execution/configuration/RunConfigurationExtension.java b/platform/lang-api/src/com/intellij/execution/configuration/RunConfigurationExtension.java
new file mode 100644 (file)
index 0000000..c205aa6
--- /dev/null
@@ -0,0 +1,78 @@
+package com.intellij.execution.configuration;
+
+import com.intellij.execution.Location;
+import com.intellij.execution.configurations.GeneralCommandLine;
+import com.intellij.execution.process.ProcessHandler;
+import com.intellij.openapi.options.SettingsEditor;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.WriteExternalException;
+import org.jdom.Element;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+
+/**
+ * @author traff
+ */
+public abstract class RunConfigurationExtension<T extends AbstractRunConfiguration> {
+  @NotNull
+  protected abstract String getSerializationId();
+
+  protected abstract void readExternal(@NotNull final T runConfiguration,
+                                       @NotNull final Element element) throws InvalidDataException;
+
+  protected abstract void writeExternal(@NotNull final T runConfiguration,
+                                        @NotNull final Element element) throws WriteExternalException;
+
+  @Nullable
+  protected abstract Icon getIcon(@NotNull final T configuration);
+
+  @Nullable
+  protected abstract <P extends T> SettingsEditor<P> createEditor(@NotNull final P configuration);
+  
+  @Nullable
+  protected abstract String getEditorTitle();
+
+  /**
+   * @param configuration Run configuration
+   * @return True if extension in general applicable to given run configuration - just to attach settings tab, etc. But extension may be
+   * turned off in it's settings. E.g. RCov in general available for given run configuration, but may be turned off.
+   */
+  protected abstract boolean isApplicableFor(@NotNull final T configuration);
+
+  /**
+   * @param applicableConfiguration Applicable run configuration
+   * @return True if extension is tuned on in configuration extension settings.
+   * E.g. RCov is turned on for given run configuration.
+   */
+  protected abstract boolean isEnabledFor(@NotNull final T applicableConfiguration);
+
+  protected abstract void patchCommandLine(@NotNull final T configuration,
+                                             @NotNull final GeneralCommandLine cmdLine,
+                                             @NotNull final AbstractRunConfiguration.RunnerType type);
+
+  /**
+   * Validate extensions after general configuration validation passed
+   * @param configuration
+   * @param isExecution
+   * @param <T>
+   * @throws com.intellij.execution.ExecutionException
+   */
+  protected abstract void validateConfiguration(@NotNull final T configuration,
+                                                                                        final boolean isExecution) throws Exception;
+
+  /**
+   * Setup extension settings for created run configuration
+   * @param configuration Configuration
+   * @param location
+   */
+  protected abstract void extendCreatedConfiguration(@NotNull final T configuration,
+                                                                                              @NotNull final Location location);
+
+  protected abstract void extendTemplateConfiguration(@NotNull final T configuration);
+
+  protected abstract void attachToProcess(@NotNull final T configuration,
+                                          @NotNull final ProcessHandler handler,
+                                          @NotNull final AbstractRunConfiguration.RunnerType type);
+}
diff --git a/platform/lang-api/src/com/intellij/execution/configuration/RunConfigurationExtensionsManager.java b/platform/lang-api/src/com/intellij/execution/configuration/RunConfigurationExtensionsManager.java
new file mode 100644 (file)
index 0000000..cb1b1ff
--- /dev/null
@@ -0,0 +1,166 @@
+package com.intellij.execution.configuration;
+
+import com.google.common.collect.Maps;
+import com.intellij.execution.Location;
+import com.intellij.execution.configurations.GeneralCommandLine;
+import com.intellij.execution.process.ProcessHandler;
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.openapi.extensions.Extensions;
+import com.intellij.openapi.options.SettingsEditor;
+import com.intellij.openapi.options.SettingsEditorGroup;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.ui.LayeredIcon;
+import org.jdom.Element;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * @author traff
+ */
+public class RunConfigurationExtensionsManager<U extends AbstractRunConfiguration, T extends RunConfigurationExtension<U>> {
+  public static final Key<List<Element>> RUN_EXTENSIONS = Key.create("run.extension.elements");
+  private static final String EXT_ID_ATTR = "ID";
+  private static final String EXTENSION_ROOT_ATTR = "EXTENSION";
+  protected final ExtensionPointName<T> myExtensionPointName;
+
+  public RunConfigurationExtensionsManager(ExtensionPointName<T> extensionPointName) {
+    myExtensionPointName = extensionPointName;
+  }
+
+  public void readExternal(@NotNull final U configuration,
+                           @NotNull final Element parentNode) throws InvalidDataException {
+    final List<Element> children = parentNode.getChildren(EXTENSION_ROOT_ATTR);
+    final Map<String, T> extensions = Maps.newHashMap();
+    for (T extension : getApplicableExtensions(configuration)) {
+      extensions.put(extension.getSerializationId(), extension);
+    }
+
+    // if some of extensions settings weren't found we should just keep it because some plugin with extension
+    // may be turned off
+    boolean found = true;
+    for (Object o : children) {
+      final Element element = (Element)o;
+      final String extensionName = element.getAttributeValue(EXT_ID_ATTR);
+      final T extension = extensions.remove(extensionName);
+      if (extension != null) {
+        extension.readExternal(configuration, element);
+      }
+      else {
+        found = false;
+      }
+    }
+    if (!found) {
+      configuration.putCopyableUserData(RUN_EXTENSIONS, children);
+    }
+  }
+
+  public void writeExternal(@NotNull final U configuration,
+                            @NotNull final Element parentNode) throws WriteExternalException {
+    final TreeMap<String, Element> map = Maps.newTreeMap();
+    final List<Element> elements = configuration.getCopyableUserData(RUN_EXTENSIONS);
+    if (elements != null) {
+      for (Element el : elements) {
+        final String name = el.getAttributeValue(EXT_ID_ATTR);
+        map.put(name, (Element)el.clone());
+      }
+    }
+
+    for (T extension : getApplicableExtensions(configuration)) {
+      Element el = new Element(EXTENSION_ROOT_ATTR);
+      el.setAttribute(EXT_ID_ATTR, extension.getSerializationId());
+      extension.writeExternal(configuration, el);
+      map.put(extension.getSerializationId(), el);
+    }
+
+    for (Element val : map.values()) {
+      parentNode.addContent(val);
+    }
+  }
+
+  public Icon getIcon(@NotNull final U configuration, @NotNull final Icon icon) {
+    for (T extension : getApplicableExtensions(configuration)) {
+      final Icon extIcon = extension.getIcon(configuration);
+      if (extIcon != null) {
+        return LayeredIcon.create(icon, extIcon);
+      }
+    }
+    return icon;
+  }
+
+  public <V extends U> void appendEditors(@NotNull final U configuration,
+                            @NotNull final SettingsEditorGroup<V> group) {
+    for (T extension : getApplicableExtensions(configuration)) {
+      @SuppressWarnings("unchecked")
+      final SettingsEditor<V> editor = extension.createEditor((V)configuration);
+      if (editor != null) {
+        group.addEditor(extension.getEditorTitle(), editor);
+      }
+    }
+  }
+
+  public void validateConfiguration(@NotNull final U configuration,
+                                    final boolean isExecution) throws Exception {
+    // only for enabled extensions
+    for (T extension : getEnabledExtensions(configuration)) {
+      extension.validateConfiguration(configuration, isExecution);
+    }
+  }
+
+  public void extendCreatedConfiguration(@NotNull final U configuration,
+                                         @NotNull final Location location) {
+    for (T extension : getApplicableExtensions(configuration)) {
+      extension.extendCreatedConfiguration(configuration, location);
+    }
+  }
+
+  public void extendTemplateConfiguration(@NotNull final U configuration) {
+    for (T extension : getApplicableExtensions(configuration)) {
+      extension.extendTemplateConfiguration(configuration);
+    }
+  }
+
+  public void patchCommandLine(@NotNull final U configuration,
+                               @NotNull final GeneralCommandLine cmdLine,
+                               @NotNull final AbstractRunConfiguration.RunnerType type) {
+    // only for enabled extensions
+    for (T extension : getEnabledExtensions(configuration)) {
+      extension.patchCommandLine(configuration, cmdLine, type);
+    }
+  }
+
+  public void attachExtensionsToProcess(@NotNull final U configuration,
+                                        @NotNull final ProcessHandler handler,
+                                        @NotNull final AbstractRunConfiguration.RunnerType type) {
+    // only for enabled extensions
+    for (T extension : getEnabledExtensions(configuration)) {
+      extension.attachToProcess(configuration, handler, type);
+    }
+  }
+
+  private List<T> getApplicableExtensions(@NotNull final U configuration) {
+    final List<T> extensions = new ArrayList<T>();
+    for (T extension : Extensions.getExtensions(myExtensionPointName)) {
+      if (extension.isApplicableFor(configuration)) {
+        extensions.add(extension);
+      }
+    }
+    return extensions;
+  }
+
+  private List<T> getEnabledExtensions(@NotNull final U configuration) {
+    final List<T> extensions = new ArrayList<T>();
+    for (T extension : Extensions.getExtensions(myExtensionPointName)) {
+      if (extension.isApplicableFor(configuration) && extension.isEnabledFor(configuration)) {
+        extensions.add(extension);
+      }
+    }
+    return extensions;
+  }
+}
index 414c5495b8703a7cc236c0382e73a3a231ddbf46..5f7e717d2212370bea1b1f2176114efbdc27a296 100644 (file)
@@ -30,6 +30,7 @@
       </library>
     </orderEntry>
     <orderEntry type="library" scope="TEST" name="Mocks" level="project" />
+    <orderEntry type="library" name="Guava" level="project" />
   </component>
 </module>
 
index 6735bbbc86a4568789d72e6dea6a1b7b8dd68efb..ee4ee2e78e7dbe522d6277173b294041b91a62c5 100644 (file)
@@ -84,10 +84,21 @@ public class ParametersList implements Cloneable {
     return Collections.unmodifiableList(params);
   }
 
+  public void clearAll() {
+    myParameters.clear();
+    myGroups.clear();
+  }
+
   public void prepend(@NonNls final String parameter) {
     addAt(0, parameter);
   }
 
+  public void prependAll(@NonNls final String... parameter) {
+    for (int i = parameter.length - 1; i >= 0; i--) {
+      addAt(0, parameter[i]);
+    }
+  }
+
   public void addParametersString(final String parameters) {
     if (parameters != null) {
       final String[] split = parse(parameters);
@@ -163,7 +174,7 @@ public class ParametersList implements Cloneable {
   }
 
   private void replaceOrAdd(final @NonNls String parameterPrefix, final @NonNls String replacement, final int position) {
-    for (ListIterator<String> iterator = myParameters.listIterator(); iterator.hasNext();) {
+    for (ListIterator<String> iterator = myParameters.listIterator(); iterator.hasNext(); ) {
       final String param = iterator.next();
       if (param.startsWith(parameterPrefix)) {
         if ("".equals(replacement)) {
@@ -175,7 +186,7 @@ public class ParametersList implements Cloneable {
         return;
       }
     }
-    if(!"".equals(replacement)) {
+    if (!"".equals(replacement)) {
       myParameters.add(position, replacement);
     }
   }
@@ -216,20 +227,20 @@ public class ParametersList implements Cloneable {
 
   /**
    * <p>Joins list of parameters into single string, which may be then parsed back into list by {@link #parse(String)}.</p>
-   *
+   * <p/>
    * <p>
-   *   <strong>Conversion rules:</strong>
-   *   <ul>
-   *     <li>double quotes are escaped by backslash (<code>&#92;</code>);</li>
-   *     <li>empty parameters parameters and parameters with spaces inside are surrounded with double quotes (<code>"</code>);</li>
-   *     <li>parameters are separated by single whitespace.</li>
-   *   </ul>
+   * <strong>Conversion rules:</strong>
+   * <ul>
+   * <li>double quotes are escaped by backslash (<code>&#92;</code>);</li>
+   * <li>empty parameters parameters and parameters with spaces inside are surrounded with double quotes (<code>"</code>);</li>
+   * <li>parameters are separated by single whitespace.</li>
+   * </ul>
    * </p>
-   *
+   * <p/>
    * <p><strong>Examples:</strong></p>
    * <p>
-   *   <code>['a', 'b'] => 'a  b'</code><br/>
-   *   <code>['a="1 2"', 'b'] => '"a &#92;"1 2&#92;"" b'</code>
+   * <code>['a', 'b'] => 'a  b'</code><br/>
+   * <code>['a="1 2"', 'b'] => '"a &#92;"1 2&#92;"" b'</code>
    * </p>
    *
    * @param parameters a list of parameters to join.
@@ -247,23 +258,23 @@ public class ParametersList implements Cloneable {
 
   /**
    * <p>Converts single parameter string (as created by {@link #join(java.util.List)}) into list of parameters.</p>
-   *
+   * <p/>
    * <p>
-   *   <strong>Conversion rules:</strong>
-   *   <ul>
-   *     <li>starting/whitespaces are trimmed;</li>
-   *     <li>parameters are split by whitespaces, whitespaces itself are dropped</li>
-   *     <li>parameters inside double quotes (<code>"a b"</code>) are kept as single one;</li>
-   *     <li>double quotes are dropped, escaped double quotes (<code>&#92;"</code>) are un-escaped.</li>
-   *   </ul>
+   * <strong>Conversion rules:</strong>
+   * <ul>
+   * <li>starting/whitespaces are trimmed;</li>
+   * <li>parameters are split by whitespaces, whitespaces itself are dropped</li>
+   * <li>parameters inside double quotes (<code>"a b"</code>) are kept as single one;</li>
+   * <li>double quotes are dropped, escaped double quotes (<code>&#92;"</code>) are un-escaped.</li>
+   * </ul>
    * </p>
-   *
+   * <p/>
    * <p><strong>Examples:</strong></p>
    * <p>
-   *   <code>' a  b ' => ['a', 'b']</code><br/>
-   *   <code>'a="1 2" b' => ['a=1 2', 'b']</code><br/>
-   *   <code>'a " " b' => ['a', ' ', 'b']</code><br/>
-   *   <code>'"a &#92;"1 2&#92;"" b' => ['a="1 2"', 'b']</code>
+   * <code>' a  b ' => ['a', 'b']</code><br/>
+   * <code>'a="1 2" b' => ['a=1 2', 'b']</code><br/>
+   * <code>'a " " b' => ['a', ' ', 'b']</code><br/>
+   * <code>'"a &#92;"1 2&#92;"" b' => ['a="1 2"', 'b']</code>
    * </p>
    *
    * @param string parameter string to split.
@@ -277,11 +288,11 @@ public class ParametersList implements Cloneable {
 
   public String expandMacros(String text) {
     final Map<String, String> macroMap = getMacroMap();
-      final Set<String> set = macroMap.keySet();
-      for (final String from : set) {
-          final String to = macroMap.get(from);
-          text = StringUtil.replace(text, from, to, true);
-      }
+    final Set<String> set = macroMap.keySet();
+    for (final String from : set) {
+      final String to = macroMap.get(from);
+      text = StringUtil.replace(text, from, to, true);
+    }
     return text;
   }
 
@@ -296,7 +307,7 @@ public class ParametersList implements Cloneable {
         final PathMacros pathMacros = PathMacros.getInstance();
         final Set<String> names = pathMacros.getAllMacroNames();
         for (String name : names) {
-            myMacroMap.put("${" + name + "}", pathMacros.getValue(name));
+          myMacroMap.put("${" + name + "}", pathMacros.getValue(name));
         }
         final Map<String, String> env = EnvironmentUtil.getEnviromentProperties();
         for (String name : env.keySet()) {
@@ -316,7 +327,8 @@ public class ParametersList implements Cloneable {
   }
 
   private static class ParametersTokenizer {
-    private ParametersTokenizer() { }
+    private ParametersTokenizer() {
+    }
 
     @NotNull
     public static String encode(@NotNull final List<String> parameters) {