PY-40120 Preserve additional data for SDKs of unknown types

Fixes the problem when disabling a language plugin causes SDKs associated with it loose their additional data. F.e. the problem affected Python interpreters based on SSH, Docker or Docker Compose.

GitOrigin-RevId: 1e73426241bc443318d3230804154e0752c7793b
This commit is contained in:
Alexander Koshevoy
2020-01-28 13:40:33 +03:00
committed by intellij-monorepo-bot
parent cb702185b5
commit 9f311cfce4
4 changed files with 63 additions and 39 deletions

View File

@@ -4,6 +4,7 @@ package com.intellij.openapi.projectRoots.impl;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.project.ProjectBundle;
import com.intellij.openapi.projectRoots.*;
import com.intellij.openapi.util.JDOMUtil;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -14,9 +15,10 @@ import java.util.concurrent.ConcurrentHashMap;
/**
* Used as a plug for all SDKs which type cannot be determined (for example, plugin that registered a custom type has been deinstalled)
*
* @author Eugene Zhuravlev
*/
public class UnknownSdkType extends SdkType{
public class UnknownSdkType extends SdkType {
private static final Map<String, UnknownSdkType> ourTypeNameToInstanceMap = new ConcurrentHashMap<>();
/**
@@ -71,6 +73,15 @@ public class UnknownSdkType extends SdkType{
@Override
public void saveAdditionalData(@NotNull SdkAdditionalData additionalData, @NotNull Element additional) {
if (additionalData instanceof UnknownSdkAdditionalData) {
((UnknownSdkAdditionalData)additionalData).save(additional);
}
}
@Nullable
@Override
public SdkAdditionalData loadAdditionalData(@NotNull Element additional) {
return new UnknownSdkAdditionalData(additional);
}
@NotNull
@@ -88,4 +99,17 @@ public class UnknownSdkType extends SdkType{
public boolean allowCreationByUser() {
return false;
}
private static class UnknownSdkAdditionalData implements SdkAdditionalData {
@NotNull
private final Element myAdditionalElement;
UnknownSdkAdditionalData(@NotNull Element element) {
myAdditionalElement = element.clone();
}
void save(@NotNull Element additional) {
JDOMUtil.copyMissingContent(myAdditionalElement, additional);
}
}
}

View File

@@ -1,37 +0,0 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
@file:JvmName("ElementUtil")
package com.intellij.remote.ext
import org.jdom.Content
import org.jdom.Element
/**
* Copies attributes and elements from [source] node to [target] node if they
* are not present in the latter one.
*
* Preservers [target] element name.
*
* @param source the source element to copy from
* @param target the target element to copy to
*/
fun copyMissingContent(source: Element, target: Element) {
val targetClone = target.clone()
for (attribute in source.attributes) {
if (!targetClone.hasAttribute(attribute.name)) {
target.setAttribute(attribute.clone())
}
}
for (content in source.content) {
if (!targetClone.hasContent(content)) {
target.addContent(content.clone())
}
}
}
private fun Element.hasAttribute(name: String) = getAttribute(name) != null
private fun Element.hasContent(content: Content): Boolean = when (content) {
is Element -> getChildren(content.name).isNotEmpty()
else -> false
}

View File

@@ -15,6 +15,7 @@
*/
package com.intellij.remote.ext;
import com.intellij.openapi.util.JDOMUtil;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -44,7 +45,7 @@ public class UnknownCredentialsHolder {
public void save(@NotNull Element element) {
if (myElement != null) {
ElementUtil.copyMissingContent(myElement, element);
JDOMUtil.copyMissingContent(myElement, element);
}
}

View File

@@ -993,4 +993,40 @@ public final class JDOMUtil {
.setAttribute(width, Integer.toString(bounds.width))
.setAttribute(height, Integer.toString(bounds.height));
}
/**
* Copies attributes and elements from {@code source} node to {@code target}
* node if they are not present in the latter one.
* <p>
* Preserves {@code target} element's name.
*
* @param source the source element to copy from
* @param target the target element to copy to
*/
public static void copyMissingContent(@NotNull Element source, @NotNull Element target) {
Element targetClone = target.clone();
for (Attribute attribute : source.getAttributes()) {
if (!hasAttribute(targetClone, attribute.getName())) {
target.setAttribute(attribute.clone());
}
}
for (Content content : source.getContent()) {
if (!hasContent(targetClone, content)) {
target.addContent(content.clone());
}
}
}
private static boolean hasAttribute(@NotNull Element element, @NotNull String name) {
return element.getAttribute(name) != null;
}
private static boolean hasContent(@NotNull Element element, @NotNull Content content) {
if (content instanceof Element) {
return !element.getChildren(((Element)content).getName()).isEmpty();
}
else {
return false;
}
}
}