Merge branch 'slava/plugin-incompatible-with'
authorVyacheslav Karpukhin <Vyacheslav.Karpukhin@jetbrains.com>
Tue, 12 May 2020 18:09:41 +0000 (20:09 +0200)
committerintellij-monorepo-bot <intellij-monorepo-bot-no-reply@jetbrains.com>
Tue, 12 May 2020 18:09:41 +0000 (18:09 +0000)
# Conflicts:
# community/platform/core-impl/src/com/intellij/ide/plugins/IdeaPluginDescriptorImpl.java
# community/platform/core-impl/src/com/intellij/ide/plugins/PluginManagerCore.java
# community/platform/extensions/src/com/intellij/openapi/extensions/PluginDescriptor.java
# community/platform/platform-tests/testData/plugins/sort/simplePluginSort.txt

GitOrigin-RevId: 4ad7f001037c5c3c30e3f185971d3075702bfc41

1  2 
platform/core-impl/src/com/intellij/ide/plugins/IdeaPluginDescriptorImpl.java
platform/core-impl/src/com/intellij/ide/plugins/PluginManagerCore.java
platform/extensions/src/com/intellij/openapi/extensions/DefaultPluginDescriptor.java
platform/extensions/src/com/intellij/openapi/extensions/PluginDescriptor.java
platform/platform-impl/src/com/intellij/ide/plugins/PluginNode.java
platform/platform-tests/testData/plugins/sort/simplePluginSort.txt
platform/platform-tests/testData/plugins/sort/simplePluginSort.xml

index 5ba3259827f0a3345d57f8704e1ebf7fb2113f77,e74df8b156097c3281f1c0c4e652ed97ed19e44f..521e1d1d37d3391373302961566e7e45f267e83f
@@@ -10,9 -19,19 +10,10 @@@ import com.intellij.openapi.util.JDOMUt
  import com.intellij.openapi.util.io.FileUtil;
  import com.intellij.openapi.util.text.StringUtil;
  import com.intellij.openapi.util.text.StringUtilRt;
 -import com.intellij.util.SmartList;
+ import com.intellij.util.containers.ContainerUtil;
 -import com.intellij.util.containers.ContainerUtilRt;
 -import com.intellij.util.containers.Interner;
 -import com.intellij.util.messages.ListenerDescriptor;
  import com.intellij.util.ref.GCWatcher;
 -import gnu.trove.THashMap;
 -import org.jdom.Attribute;
  import org.jdom.Content;
  import org.jdom.Element;
 -import org.jdom.JDOMException;
  import org.jetbrains.annotations.ApiStatus;
  import org.jetbrains.annotations.NotNull;
  import org.jetbrains.annotations.Nullable;
@@@ -56,9 -75,14 +57,10 @@@ public final class IdeaPluginDescriptor
    private String myVendorEmail;
    private String myVendorUrl;
    private String myCategory;
 -  private String myUrl;
 -  private PluginId[] myDependencies = PluginId.EMPTY_ARRAY;
 -  private PluginId[] myOptionalDependencies = PluginId.EMPTY_ARRAY;
 -  private List<PluginId> myIncompatibilities;
 -  private List<PluginDependency> myPluginDependencies;
 -
 -  // used only during initializing
 -  transient Map<PluginId, List<IdeaPluginDescriptorImpl>> optionalConfigs;
 +  String myUrl;
 +  @Nullable List<PluginDependency> pluginDependencies;
++  @Nullable private List<PluginId> myIncompatibilities;
 +
    transient List<Path> jarFiles;
  
    private @Nullable List<Element> myActionElements;
            break;
  
          case "depends":
 -          if (!readPluginDependency(basePath, context, child)) return false;
 +          if (!readPluginDependency(basePath, context, child)) {
 +            return true;
 +          }
            break;
  
+         case "incompatible-with":
+           readPluginIncompatibility(child);
+           break;
          case "category":
            myCategory = StringUtil.nullize(child.getTextTrim());
            break;
          child.getContent().clear();
        }
      }
 +    return false;
 +  }
  
 -    if (myVersion == null) {
 -      myVersion = context.parentContext.getDefaultVersion();
 -    }
 -
 -    if (myPluginDependencies != null) {
 -      XmlReader.readDependencies(rootDescriptor, this, context, pathResolver);
 -    }
 -
 -    return true;
 +  private void readProduct(@NotNull DescriptorListLoadingContext context, @NotNull Element child) {
 +    myProductCode = StringUtil.nullize(child.getAttributeValue("code"));
 +    myReleaseDate = parseReleaseDate(child.getAttributeValue("release-date"), context);
 +    myReleaseVersion = StringUtil.parseInt(child.getAttributeValue("release-version"), 0);
 +    myIsLicenseOptional = Boolean.parseBoolean(child.getAttributeValue("optional", "false"));
    }
  
 -  private boolean readPluginDependency(@NotNull Path basePath, @NotNull DescriptorLoadingContext context, Element child) {
+   private void readPluginIncompatibility(@NotNull Element child) {
+     String pluginId = child.getTextTrim();
+     if (pluginId.isEmpty()) return;
+     if (myIncompatibilities == null) {
+       myIncompatibilities = new ArrayList<>();
+     }
+     myIncompatibilities.add(PluginId.getId(pluginId));
+   }
 +  private boolean readPluginDependency(@NotNull Path basePath, @NotNull DescriptorListLoadingContext context, @NotNull Element child) {
      String dependencyIdString = child.getTextTrim();
      if (dependencyIdString.isEmpty()) {
        return true;
      return myIsLicenseOptional;
    }
  
+   @Override
+   public @NotNull List<PluginId> getIncompatibleModuleIds() {
+     return ContainerUtil.notNullize(myIncompatibilities);
+   }
 +  @SuppressWarnings("deprecation")
    @Override
    public PluginId @NotNull [] getDependentPluginIds() {
 -    return myDependencies;
 +    if (pluginDependencies == null || pluginDependencies.isEmpty()) {
 +      return PluginId.EMPTY_ARRAY;
 +    }
 +    int size = pluginDependencies.size();
 +    PluginId[] result = new PluginId[size];
 +    for (int i = 0; i < size; i++) {
 +      result[i] = pluginDependencies.get(i).id;
 +    }
 +    return result;
    }
  
    @Override
index 7e94f21dc8a4149f60f5ea345a52a93fb726eefb,b38cc052fb555d36ce0819aeb836bbd4150c01a8..82170b2d19e4cccc7d00b64e60a56a851bee026a
@@@ -596,20 -720,11 +596,21 @@@ public final class PluginManagerCore 
      boolean hasAllModules = idToDescriptorMap.containsKey(ALL_MODULES_MARKER);
      Set<IdeaPluginDescriptorImpl> uniqueCheck = new HashSet<>();
      return new CachingSemiGraph<>(descriptors, rootDescriptor -> {
-       List<PluginDependency> dependencies = rootDescriptor.pluginDependencies;
 -      List<PluginId> dependentPluginIds = ContainerUtil.newArrayList(rootDescriptor.getDependentPluginIds());
++      List<PluginDependency> dependencies = rootDescriptor.pluginDependencies; //ContainerUtil.newArrayList(rootDescriptor.getDependentPluginIds())
+       List<PluginId> incompatibleModuleIds = rootDescriptor.getIncompatibleModuleIds();
 +      if (dependencies == null) {
 +        dependencies = Collections.emptyList();
 +      }
 +
        IdeaPluginDescriptorImpl implicitDep = getImplicitDependency(rootDescriptor, javaDep, hasAllModules);
-       int capacity = dependencies.size();
 -      PluginId[] optionalDependentPluginIds = withOptional ? rootDescriptor.getOptionalDependentPluginIds() : PluginId.EMPTY_ARRAY;
 -      int capacity = dependentPluginIds.size() - (withOptional ? 0 : optionalDependentPluginIds.length) + incompatibleModuleIds.size();
++      int capacity = dependencies.size() + incompatibleModuleIds.size();
 +      if (!withOptional) {
 +        for (PluginDependency dependency : dependencies) {
 +          if (dependency.isOptional) {
 +            capacity--;
 +          }
 +        }
 +      }
        if (capacity == 0) {
          return implicitDep == null ? Collections.emptyList() : Collections.singletonList(implicitDep);
        }
          }
        }
  
 -      boolean excludeOptional = !withOptional && optionalDependentPluginIds.length > 0 && optionalDependentPluginIds.length != dependentPluginIds.size();
 -
 -      dependentPluginIds.addAll(incompatibleModuleIds);
 -
 -      loop:
 -      for (PluginId dependentPluginId : dependentPluginIds) {
 -        if (excludeOptional) {
 -          for (PluginId id : optionalDependentPluginIds) {
 -            if (id == dependentPluginId) {
 -              continue loop;
 -            }
 -          }
++      //dependencies.addAll(incompatibleModuleIds);
 +      for (PluginDependency dependency : dependencies) {
 +        if (!withOptional && dependency.isOptional) {
 +          continue;
          }
  
          // check for missing optional dependency
    }
  
    private static boolean computePluginEnabled(@NotNull IdeaPluginDescriptorImpl descriptor,
-                                               @NotNull Set<PluginId> loadedIds,
+                                               @NotNull Set<PluginId> loadedPluginIds,
+                                               @NotNull Set<PluginId> loadedModuleIds,
                                                @NotNull Map<PluginId, IdeaPluginDescriptorImpl> idMap,
 -                                              @NotNull Set<? super PluginId> disabledRequiredIds,
 +                                              @NotNull Set<PluginId> disabledRequiredIds,
                                                @NotNull Set<PluginId> disabledPlugins,
 -                                              @NotNull List<? super String> errors) {
 +                                              @NotNull List<PluginError> errors) {
      if (descriptor.getPluginId() == CORE_ID || descriptor.isImplementationDetail()) {
        return true;
      }
  
 -    // no deps at all or all are optional
 -    if (result && descriptor.getDependentPluginIds().length == descriptor.getOptionalDependentPluginIds().length) {
+     boolean result = true;
+     for (PluginId incompatibleId : descriptor.getIncompatibleModuleIds()) {
+       if (!loadedModuleIds.contains(incompatibleId) || disabledPlugins.contains(incompatibleId)) continue;
+       result = false;
+       String presentableName = toPresentableName(incompatibleId.getIdString());
+       errors.add(descriptor.formatErrorMessage("is incompatible with the IDE containing module " + presentableName));
+     }
-     if (descriptor.pluginDependencies == null) {
 +    // no deps at all
++    if (result && descriptor.pluginDependencies == null) {
        return true;
      }
  
-     boolean result = true;
 -    for (PluginId depId : descriptor.getDependentPluginIds()) {
 -      if (loadedPluginIds.contains(depId) || loadedModuleIds.contains(depId) || isOptional(descriptor, depId)) {
 +    for (PluginDependency dependency : descriptor.pluginDependencies) {
 +      PluginId depId = dependency.id;
-       if (dependency.isOptional || loadedIds.contains(depId)) {
++      if (dependency.isOptional || loadedPluginIds.contains(depId)) {
          continue;
        }
  
index 90eaf10fdd53dd3dd8b15535778147ee2e100cb0,f4c79181bcdd66773772b9d569778492437e53ae..db3ac7201e839db1bb95044c12f174897d86a201
@@@ -5,11 -5,17 +5,12 @@@ import com.intellij.ide.plugins.IdeaPlu
  import org.jetbrains.annotations.NotNull;
  import org.jetbrains.annotations.Nullable;
  
 -import java.io.File;
  import java.nio.file.Path;
+ import java.util.Collections;
  import java.util.Date;
 -import java.util.List;
  
  public final class DefaultPluginDescriptor implements IdeaPluginDescriptor {
 -  @NotNull
 -  private final PluginId myPluginId;
 +  private final @NotNull PluginId myPluginId;
    private final ClassLoader myPluginClassLoader;
  
    public DefaultPluginDescriptor(@NotNull String pluginId) {
index 6c679a7e199088d6f52c1530bd1d93379624c13c,f9b7a320a3d345ae8dcae78207dd6abc4beda75b..e199072e5a00bfa6e04f02a9a685ac590e204388
@@@ -8,8 -10,10 +8,9 @@@ import org.jetbrains.annotations.Nullab
  import java.io.File;
  import java.nio.file.Path;
  import java.util.Date;
+ import java.util.List;
  
  public interface PluginDescriptor {
 -
    /**
     * @return plugin id or null if the descriptor is the nested (optional dependency) descriptor
     */
  
    boolean isLicenseOptional();
  
 -  PluginId @NotNull [] getDependentPluginIds();
+   @NotNull
+   List<PluginId> getIncompatibleModuleIds();
 +  /**
 +   * @deprecated Do not use.
 +   */
 +  @Deprecated
 +  default PluginId @NotNull [] getDependentPluginIds() {
 +    return PluginId.EMPTY_ARRAY;
 +  }
  
 +  /**
 +   * @deprecated Do not use.
 +   */
 +  @Deprecated
    PluginId @NotNull [] getOptionalDependentPluginIds();
  
    String getVendor();
index c9cce1357126947347ef1ec7ce13d4eb569d9f0c,c0029ef414fe69795c54b349a9b425d5d55376ed..3a7245b7085157ea219ab5bce9890950b65bdfcf
@@@ -5,8 -6,11 +5,9 @@@ import com.intellij.openapi.extensions.
  import org.jetbrains.annotations.NotNull;
  import org.jetbrains.annotations.Nullable;
  
 -import java.io.File;
  import java.nio.file.Path;
  import java.util.ArrayList;
+ import java.util.Collections;
  import java.util.Date;
  import java.util.List;
  
index bde33953db4a953938405a3a3181c21e3ff4294e,b2493ef6e7ca7b78e72c54923c06f4242175d950..6a98a5ca6a0f692b13c679fb2d51ac8d3c0d945b
@@@ -29,10 -31,11 +31,11 @@@ Plugin "missing4" is incompatible (supp
  Module com.intellij.modules.duplicate is declared by plugins:
    PluginDescriptor(name=duplicate0, id=duplicate0, path=file:/duplicate0.xml)
    PluginDescriptor(name=duplicate, id=duplicate, path=file:/duplicate1.xml).
 -Plugins should not have cyclic dependencies: optional_cycle1 <-> optional_cycle2 <-> optional_cycle0, optional_config_cycle2 <-> optional_config_cycle0, cycle5 <-> cycle4, cycle2 <-> cycle3 <-> cycle1.
 -The missing2 (id=missing2, path=file:/missing2.xml) plugin requires "com.intellij.missing" plugin to be installed.
 -The missing3 (id=missing3, path=file:/missing3.xml) plugin requires "missing2" plugin to be enabled.
 -The missing1 (id=missing1, path=file:/missing1.xml) plugin requires "com.intellij.modules.missing" plugin to be installed.
 -The cycle0 (id=cycle0, path=file:/cycle0.xml) plugin requires "cycle1" plugin to be enabled.
 +Plugins should not have cyclic dependencies: optional_cycle1 <-> optional_cycle2 <-> optional_cycle0, cycle5 <-> cycle4, cycle2 <-> cycle3 <-> cycle1.
 +Plugin "missing2" requires "com.intellij.missing" plugin to be installed.
 +Plugin "missing3" requires "missing2" plugin to be enabled.
 +Plugin "missing1" requires "com.intellij.modules.missing" plugin to be installed.
 +Plugin "cycle0" requires "cycle1" plugin to be enabled.
+ The incompatible_with_enabled_module (id=incompatible_with_enabled_module, path=file:/incompatible_with_enabled_module.xml) plugin is incompatible with the IDE containing module "com.intellij.modules.plugin0".
  <br><a href="disable">Disable not loaded plugins</a>
  <a href="edit">Open plugin manager</a>