move Docker to extension point
authorMichael Golubev <michael.golubev@jetbrains.com>
Fri, 15 Jan 2016 01:50:24 +0000 (02:50 +0100)
committerMichael Golubev <michael.golubev@jetbrains.com>
Fri, 15 Jan 2016 01:50:24 +0000 (02:50 +0100)
28 files changed:
platform/platform-impl/src/com/intellij/remote/CredentialsType.java
platform/platform-impl/src/com/intellij/remote/DockerCredentialsHolder.java [deleted file]
platform/platform-impl/src/com/intellij/remote/DockerMachineCommandException.java [deleted file]
platform/platform-impl/src/com/intellij/remote/DockerSupport.java [deleted file]
platform/platform-impl/src/com/intellij/remote/ExceptionFix.java [moved from platform/platform-impl/src/com/intellij/remote/DockerMachineException.java with 64% similarity]
platform/platform-impl/src/com/intellij/remote/RemoteConnectionCredentialsWrapper.java
platform/platform-impl/src/com/intellij/remote/RemoteSdkCredentialsHolder.java
platform/platform-impl/src/com/intellij/remote/ext/CaseCollector.java [new file with mode: 0644]
platform/platform-impl/src/com/intellij/remote/ext/CredentialsCase.java
platform/platform-impl/src/com/intellij/remote/ext/CredentialsEditor.java [new file with mode: 0644]
platform/platform-impl/src/com/intellij/remote/ext/CredentialsLanguageContribution.java [moved from platform/platform-impl/src/com/intellij/remote/DockerMachineNotStartedException.java with 54% similarity]
platform/platform-impl/src/com/intellij/remote/ext/CredentialsManager.java [new file with mode: 0644]
platform/platform-impl/src/com/intellij/remote/ext/CredentialsManagerImpl.java [new file with mode: 0644]
platform/platform-impl/src/com/intellij/remote/ext/CredentialsTypeEx.java [new file with mode: 0644]
platform/platform-impl/src/com/intellij/remote/ext/DockerCredentialsHandler.java [deleted file]
platform/platform-impl/src/com/intellij/remote/ext/LanguageCaseCollector.java [new file with mode: 0644]
platform/platform-impl/src/com/intellij/remote/ext/RemoteCredentialsHandler.java
platform/platform-impl/src/com/intellij/remote/ext/SshCredentialsHandler.java
platform/platform-impl/src/com/intellij/remote/ext/VagrantCredentialsHandler.java
platform/platform-impl/src/com/intellij/remote/ext/WebDeploymentCredentialsHandler.java
platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml
platform/platform-resources/src/META-INF/PlatformExtensions.xml
python/src/com/jetbrains/python/packaging/PyPackageUtil.java
python/src/com/jetbrains/python/packaging/PyRemotePackageManagerImpl.java
python/src/com/jetbrains/python/remote/PyCredentialsContribution.java [new file with mode: 0644]
python/src/com/jetbrains/python/sdk/CredentialsTypeExChecker.java [new file with mode: 0644]
python/src/com/jetbrains/python/sdk/PythonSdkType.java
python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java

index 702234aa3af1751ff9367b01a3c0d029780de464..43e09f02b057ff5f7339ecd3140c44242985fe95 100644 (file)
@@ -18,11 +18,6 @@ package com.intellij.remote;
 import com.intellij.openapi.util.Key;
 import com.intellij.openapi.util.UserDataHolderBase;
 import com.intellij.remote.ext.*;
-import org.jdom.Element;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.Arrays;
-import java.util.List;
 
 /**
  * @author traff
@@ -31,16 +26,13 @@ public abstract class CredentialsType<T> {
 
   public static final String VAGRANT_PREFIX = "vagrant://";
   public static final String SFTP_DEPLOYMENT_PREFIX = "sftp://";
-  public static final String DOCKER_PREFIX = "docker://";
-
 
   public static final Key<VagrantBasedCredentialsHolder> VAGRANT_BASED_CREDENTIALS = Key.create("VAGRANT_BASED_CREDENTIALS");
   public static final Key<WebDeploymentCredentialsHolder> WEB_DEPLOYMENT_BASED_CREDENTIALS = Key.create("WEB_DEPLOYMENT_BASED_CREDENTIALS");
   public static final Key<RemoteCredentialsHolder> PLAIN_SSH_CREDENTIALS = Key.create("PLAIN_SSH_CREDENTIALS");
-  public static final Key<DockerCredentialsHolder> DOCKER_CREDENTIALS = Key.create("DOCKER_CREDENTIALS");
 
   public static final CredentialsType<RemoteCredentialsHolder> SSH_HOST
-    = new CredentialsType<RemoteCredentialsHolder>("SSH Credentials") {
+    = new CredentialsType<RemoteCredentialsHolder>("SSH Credentials", RemoteCredentialsHolder.SSH_PREFIX) {
 
     @Override
     public Key<RemoteCredentialsHolder> getCredentialsKey() {
@@ -52,18 +44,13 @@ public abstract class CredentialsType<T> {
       return new SshCredentialsHandler(credentials);
     }
 
-    @Override
-    public String getPrefix() {
-      return RemoteCredentialsHolder.SSH_PREFIX;
-    }
-
     @Override
     public RemoteCredentialsHolder createCredentials() {
       return new RemoteCredentialsHolder();
     }
   };
   public static final CredentialsType<VagrantBasedCredentialsHolder> VAGRANT
-    = new CredentialsType<VagrantBasedCredentialsHolder>("Vagrant") {
+    = new CredentialsType<VagrantBasedCredentialsHolder>("Vagrant", VAGRANT_PREFIX) {
 
     @Override
     public Key<VagrantBasedCredentialsHolder> getCredentialsKey() {
@@ -75,11 +62,6 @@ public abstract class CredentialsType<T> {
       return new VagrantCredentialsHandler(credentials);
     }
 
-    @Override
-    public String getPrefix() {
-      return VAGRANT_PREFIX;
-    }
-
     @Override
     public VagrantBasedCredentialsHolder createCredentials() {
       return new VagrantBasedCredentialsHolder();
@@ -87,7 +69,7 @@ public abstract class CredentialsType<T> {
   };
 
   public static final CredentialsType<WebDeploymentCredentialsHolder> WEB_DEPLOYMENT
-    = new CredentialsType<WebDeploymentCredentialsHolder>("Web Deployment") {
+    = new CredentialsType<WebDeploymentCredentialsHolder>("Web Deployment", SFTP_DEPLOYMENT_PREFIX) {
 
     @Override
     public Key<WebDeploymentCredentialsHolder> getCredentialsKey() {
@@ -99,53 +81,18 @@ public abstract class CredentialsType<T> {
       return new WebDeploymentCredentialsHandler(credentials);
     }
 
-    @Override
-    public String getPrefix() {
-      return SFTP_DEPLOYMENT_PREFIX;
-    }
-
     @Override
     public WebDeploymentCredentialsHolder createCredentials() {
       return new WebDeploymentCredentialsHolder();
     }
   };
 
-  // TODO: contribute
-  public static final CredentialsType<DockerCredentialsHolder> DOCKER
-    = new CredentialsType<DockerCredentialsHolder>("Docker") {
-
-    @Override
-    public Key<DockerCredentialsHolder> getCredentialsKey() {
-      return DOCKER_CREDENTIALS;
-    }
-
-    @Override
-    public RemoteCredentialsHandler getHandler(DockerCredentialsHolder credentials) {
-      return new DockerCredentialsHandler(credentials);
-    }
-
-    @Override
-    public String getPrefix() {
-      return DOCKER_PREFIX;
-    }
-
-    @Override
-    public DockerCredentialsHolder createCredentials() {
-      return new DockerCredentialsHolder();
-    }
-  };
-
-  public static final List<CredentialsType> TYPES = Arrays.<CredentialsType>asList(
-    SSH_HOST,
-    VAGRANT,
-    WEB_DEPLOYMENT,
-    DOCKER);
-
-
   private final String myName;
+  private final String myPrefix;
 
-  protected CredentialsType(String name) {
+  protected CredentialsType(String name, String prefix) {
     myName = name;
+    myPrefix = prefix;
   }
 
   public String getName() {
@@ -164,20 +111,12 @@ public abstract class CredentialsType<T> {
 
   public abstract RemoteCredentialsHandler getHandler(T credentials);
 
-  public abstract String getPrefix();
+  public boolean hasPrefix(String path) {
+    return path.startsWith(myPrefix);
+  }
 
   public abstract T createCredentials();
 
-  public static void loadCredentials(String interpreterPath, @Nullable Element element, RemoteSdkAdditionalData data) {
-    for (CredentialsType type : TYPES) {
-      if (interpreterPath.startsWith(type.getPrefix())) {
-        Object credentials = type.createCredentials();
-        type.getHandler(credentials).load(element);
-        data.setCredentials(type.getCredentialsKey(), credentials);
-      }
-    }
-  }
-
   public void saveCredentials(RemoteSdkAdditionalData data, CredentialsCase... cases) {
     for (CredentialsCase credentialsCase : cases) {
       if (credentialsCase.getType() == this) {
diff --git a/platform/platform-impl/src/com/intellij/remote/DockerCredentialsHolder.java b/platform/platform-impl/src/com/intellij/remote/DockerCredentialsHolder.java
deleted file mode 100644 (file)
index a597db3..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright 2000-2015 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.remote;
-
-import com.intellij.openapi.util.text.StringUtil;
-import org.jdom.Element;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * @author Alexander Koshevoy
- */
-public class DockerCredentialsHolder {
-  public static final String DOCKER_ACCOUNT_NAME = "DOCKER_ACCOUNT_NAME";
-  public static final String DOCKER_IMAGE_NAME = "DOCKER_IMAGE_NAME";
-  public static final String DOCKER_CONTAINER_NAME = "DOCKER_CONTAINER_NAME";
-  public static final String DOCKER_REMOTE_PROJECT_PATH = "DOCKER_REMOTE_PROJECT_PATH";
-
-  private String myAccountName;
-
-  private String myImageName;
-
-  private String myContainerName;
-
-  private String myRemoteProjectPath;
-
-  public DockerCredentialsHolder() {
-  }
-
-  public DockerCredentialsHolder(String accountName,
-                                 String imageName,
-                                 String containerName,
-                                 String remoteProjectPath) {
-    myAccountName = accountName;
-    myImageName = imageName;
-    myContainerName = containerName;
-    myRemoteProjectPath = remoteProjectPath;
-  }
-
-  public String getAccountName() {
-    return myAccountName;
-  }
-
-  public String getImageName() {
-    return myImageName;
-  }
-
-  public String getContainerName() {
-    return myContainerName;
-  }
-
-  public String getRemoteProjectPath() {
-    return myRemoteProjectPath;
-  }
-
-  public void setAccountName(String accountName) {
-    myAccountName = accountName;
-  }
-
-  public void setImageName(String imageName) {
-    myImageName = imageName;
-  }
-
-  public void setContainerName(String containerName) {
-    myContainerName = containerName;
-  }
-
-  public void setRemoteProjectPath(String remoteProjectPath) {
-    myRemoteProjectPath = remoteProjectPath;
-  }
-
-  public void save(@NotNull Element element) {
-    if (StringUtil.isNotEmpty(myAccountName)) {
-      element.setAttribute(DOCKER_ACCOUNT_NAME, myAccountName);
-    }
-    element.setAttribute(DOCKER_IMAGE_NAME, myImageName);
-    if (StringUtil.isNotEmpty(myContainerName)) {
-      element.setAttribute(DOCKER_CONTAINER_NAME, myContainerName);
-    }
-    element.setAttribute(DOCKER_REMOTE_PROJECT_PATH, myRemoteProjectPath);
-  }
-
-  public void load(@NotNull Element element) {
-    myAccountName = element.getAttributeValue(DOCKER_ACCOUNT_NAME);
-    myImageName = element.getAttributeValue(DOCKER_IMAGE_NAME);
-    myContainerName = element.getAttributeValue(DOCKER_CONTAINER_NAME);
-    myRemoteProjectPath = element.getAttributeValue(DOCKER_REMOTE_PROJECT_PATH);
-  }
-}
diff --git a/platform/platform-impl/src/com/intellij/remote/DockerMachineCommandException.java b/platform/platform-impl/src/com/intellij/remote/DockerMachineCommandException.java
deleted file mode 100644 (file)
index d6e7303..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2000-2015 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.remote;
-
-import com.intellij.openapi.util.text.StringUtil;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * @author Alexander Koshevoy
- */
-public class DockerMachineCommandException extends RuntimeException {
-  public DockerMachineCommandException(int exitCode, @Nullable String stderr) {
-    super(buildErrorMessage(exitCode, stderr));
-  }
-
-  public DockerMachineCommandException(String message) {
-    super(message);
-  }
-
-  @NotNull
-  private static String buildErrorMessage(int exitCode, String stderr) {
-    StringBuilder sb = new StringBuilder()
-      .append("Docker Machine exited with error code ")
-      .append(exitCode);
-    if (StringUtil.isNotEmpty(stderr)) {
-      sb.append(": ").append(stderr);
-    }
-    return sb.toString();
-  }
-}
diff --git a/platform/platform-impl/src/com/intellij/remote/DockerSupport.java b/platform/platform-impl/src/com/intellij/remote/DockerSupport.java
deleted file mode 100644 (file)
index fe9674e..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright 2000-2015 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.remote;
-
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.progress.ProgressManager;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.ThrowableComputable;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.List;
-
-/**
- * @author Alexander Koshevoy
- */
-public abstract class DockerSupport {
-  @Nullable
-  public static DockerSupport getInstance() {
-    return ServiceManager.getService(DockerSupport.class);
-  }
-
-  public abstract boolean hasDockerMachine();
-
-  /**
-   * @deprecated should be moved to application settings
-   */
-  @Deprecated
-  @Nullable
-  public abstract String getDockerMachineExecutable();
-
-  /**
-   * @deprecated should be moved to application settings
-   */
-  @Deprecated
-  public abstract void setDockerMachineExecutable(String executable);
-
-  @NotNull
-  public abstract List<String> getVMs() throws DockerMachineException, DockerMachineCommandException;
-
-  @NotNull
-  public abstract String getStatus(@NotNull String machineName);
-
-  public abstract void startMachine(@NotNull String machineName);
-
-  @NotNull
-  public abstract ConnectionInfo getConnectionInfo(@NotNull String machineName) throws DockerMachineException, DockerMachineCommandException;
-
-  @NotNull
-  public abstract ConnectionInfo getConnectionInfo();
-
-  /**
-   * Returns list of set of repository tags for every available (built and pulled) image. E.g.:
-   * <pre>
-   * {
-   *    ["django:1.8.5", "django:python3", "django:latest"],
-   *    ["python:2", "python:2.7"],
-   *    ["python:3", "python:3.4.3", "python:latest"]
-   * }
-   * </pre>
-   *
-   * @param machineName Docker machine name
-   * @return list of set of repository tags for every available (built and pulled) image
-   */
-  @NotNull
-  public abstract List<String[]> getImages(@NotNull String accountName);
-  // TODO: alternative would require docker-support, so need to move first
-  //public abstract List<String[]> getImages(@NotNull RemoteServer<DockerCloudConfiguration> account);
-
-  public static class ConnectionInfo {
-    @NotNull private final String myApiUrl;
-    @Nullable private final String myCertificatesPath;
-
-    public ConnectionInfo(@NotNull String apiUrl, @Nullable String certificatesPath) {
-      myApiUrl = apiUrl;
-      myCertificatesPath = certificatesPath;
-    }
-
-    @NotNull
-    public String getApiUrl() {
-      return myApiUrl;
-    }
-
-    @Nullable
-    public String getCertificatesPath() {
-      return myCertificatesPath;
-    }
-  }
-
-  public final void startMachineWithProgressIndicator(@Nullable Project project, @NotNull final String machineName) {
-    ProgressManager.getInstance().runProcessWithProgressSynchronously(new ThrowableComputable<Void, RuntimeException>() {
-      @Override
-      public Void compute() {
-        ProgressManager.progress("Starting Docker Machine \'" + machineName + "\'");
-        startMachine(machineName);
-        return null;
-      }
-    }, "Starting Docker Machine", true, project);
-  }
-}
similarity index 64%
rename from platform/platform-impl/src/com/intellij/remote/DockerMachineException.java
rename to platform/platform-impl/src/com/intellij/remote/ExceptionFix.java
index 296fecdbfa03c19a19e85ade792fe0d13c55469e..09e3695dbbd524f73d5a18872fbe40ae0045d255 100644 (file)
  */
 package com.intellij.remote;
 
-/**
- * @author Alexander Koshevoy
- */
-public class DockerMachineException extends RuntimeException {
-  public DockerMachineException(String message) {
-    super(message);
-  }
+public interface ExceptionFix {
 
-  public DockerMachineException(String message, Throwable cause) {
-    super(message, cause);
-  }
+  void apply();
 
-  public DockerMachineException(Throwable cause) {
-    super(cause);
-  }
+  String getNotificationMessage(String message);
 }
index 6be42f46549e46f642e3406fbd43d6968664aa39..5a714e0856fbd155f5da246dc379f5fe0e7e11bd 100644 (file)
@@ -19,6 +19,7 @@ import com.intellij.openapi.util.Key;
 import com.intellij.openapi.util.Pair;
 import com.intellij.openapi.util.UserDataHolderBase;
 import com.intellij.remote.ext.CredentialsCase;
+import com.intellij.remote.ext.CredentialsManager;
 import com.intellij.remote.ext.RemoteCredentialsHandler;
 import org.jdom.Element;
 import org.jetbrains.annotations.NotNull;
@@ -26,7 +27,7 @@ import org.jetbrains.annotations.NotNull;
 /**
  * @author traff
  */
-// TODO: rename to 'RemoteSdkDataDelegate' ?
+// TODO: (next) rename to 'RemoteSdkDataDelegate' ?
 public class RemoteConnectionCredentialsWrapper {
 
   private UserDataHolderBase myCredentialsTypeHolder = new UserDataHolderBase();
@@ -36,7 +37,6 @@ public class RemoteConnectionCredentialsWrapper {
     myCredentialsTypeHolder.putUserData(key, credentials);
   }
 
-  // TODO: may just call instead
   public Object getConnectionKey() {
     return getCredentials();
   }
@@ -76,7 +76,7 @@ public class RemoteConnectionCredentialsWrapper {
   }
 
   private Pair<Object, CredentialsType> getCredentialsAndType() {
-    for (CredentialsType type : CredentialsType.TYPES) {
+    for (CredentialsType type : CredentialsManager.getInstance().getAllTypes()) {
       Object credentials = type.getCredentials(myCredentialsTypeHolder);
       if (credentials != null) {
         return Pair.create(credentials, type);
index 28820f61127a2d6c50e25f983fe3dc1e08247244..8e330162f0e84b7440d88c8bc7729e0a9b687927 100644 (file)
@@ -1,5 +1,6 @@
 package com.intellij.remote;
 
+import com.intellij.remote.ext.CredentialsManager;
 import com.intellij.util.PathMappingSettings;
 import org.jdom.Element;
 import org.jetbrains.annotations.NotNull;
@@ -156,8 +157,8 @@ public class RemoteSdkCredentialsHolder extends RemoteCredentialsHolder implemen
 
   public static boolean isRemoteSdk(@Nullable String path) {
     if (path != null) {
-      for (CredentialsType type : CredentialsType.TYPES) {
-        if (path.startsWith(type.getPrefix())) { // TODO: may encapsulate
+      for (CredentialsType type : CredentialsManager.getInstance().getAllTypes()) {
+        if (type.hasPrefix(path)) {
           return true;
         }
       }
diff --git a/platform/platform-impl/src/com/intellij/remote/ext/CaseCollector.java b/platform/platform-impl/src/com/intellij/remote/ext/CaseCollector.java
new file mode 100644 (file)
index 0000000..72764c2
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2000-2016 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.remote.ext;
+
+import com.intellij.openapi.util.Ref;
+import com.intellij.remote.CredentialsType;
+import com.intellij.remote.RemoteSdkAdditionalData;
+import com.intellij.util.ArrayUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class CaseCollector {
+
+  public static boolean useRemoteCredentials(RemoteSdkAdditionalData data) {
+    final Ref<Boolean> result = Ref.create(true);
+    data.switchOnConnectionType(new CaseCollector() {
+
+      @Override
+      protected void processWithType(CredentialsTypeEx typeEx, Object credentials) {
+        result.set(typeEx.useRemoteCredentials());
+      }
+    }.collectCases());
+    return result.get();
+  }
+
+  public CredentialsCase[] collectCases(CredentialsCase... cases) {
+    List<CredentialsCase> exCases = new ArrayList<CredentialsCase>();
+    for (final CredentialsTypeEx typeEx : CredentialsManager.getInstance().getExTypes()) {
+      exCases.add(new CredentialsCase() {
+        @Override
+        public CredentialsType getType() {
+          return typeEx;
+        }
+
+        @Override
+        public void process(Object credentials) {
+          processWithType(typeEx, credentials);
+        }
+      });
+    }
+    return ArrayUtil.mergeArrays(cases, exCases.toArray(new CredentialsCase[exCases.size()]));
+  }
+
+  protected abstract void processWithType(CredentialsTypeEx typeEx, Object credentials);
+}
index 57182f4f4fb1fd0528538b9d57299d69b0a8f365..0ba971451e5d5a5ebb5512fdabe41d62ed8c9399 100644 (file)
  */
 package com.intellij.remote.ext;
 
-import com.intellij.remote.*;
+import com.intellij.remote.CredentialsType;
+import com.intellij.remote.RemoteCredentialsHolder;
+import com.intellij.remote.VagrantBasedCredentialsHolder;
+import com.intellij.remote.WebDeploymentCredentialsHolder;
 
 public interface CredentialsCase<T> {
 
@@ -47,13 +50,4 @@ public interface CredentialsCase<T> {
       return CredentialsType.WEB_DEPLOYMENT;
     }
   }
-
-  // TODO: ! contribute
-  abstract class Docker implements CredentialsCase<DockerCredentialsHolder> {
-
-    @Override
-    public CredentialsType<DockerCredentialsHolder> getType() {
-      return CredentialsType.DOCKER;
-    }
-  }
 }
diff --git a/platform/platform-impl/src/com/intellij/remote/ext/CredentialsEditor.java b/platform/platform-impl/src/com/intellij/remote/ext/CredentialsEditor.java
new file mode 100644 (file)
index 0000000..656071b
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2000-2016 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.remote.ext;
+
+import com.intellij.openapi.ui.ValidationInfo;
+
+import javax.swing.*;
+
+public interface CredentialsEditor<T> {
+
+  JPanel getMainPanel();
+
+  void onSelected();
+
+  ValidationInfo validate();
+
+  void saveCredentials(T credentials);
+
+  void init(T credentials);
+}
similarity index 54%
rename from platform/platform-impl/src/com/intellij/remote/DockerMachineNotStartedException.java
rename to platform/platform-impl/src/com/intellij/remote/ext/CredentialsLanguageContribution.java
index d239657dfd1077cb653640cb2e175f898fcc1a5a..5fae91891c4ddb9ab6f0d2039d0eeb3a3a72a918 100644 (file)
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.intellij.remote;
+package com.intellij.remote.ext;
 
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
+import com.intellij.openapi.extensions.ExtensionPointName;
 
-/**
- */
-public class DockerMachineNotStartedException extends DockerMachineCommandException {
-  @NotNull private final String myMachineName;
+public abstract class CredentialsLanguageContribution<T> {
+
+  public static final ExtensionPointName<CredentialsLanguageContribution> EP_NAME
+    = ExtensionPointName.create("com.intellij.remote.credentialsLanguageContribution");
+
+  public abstract CredentialsTypeEx getType();
 
-  public DockerMachineNotStartedException(@NotNull String machineName, int exitCode, @Nullable String stderr) {
-    super(exitCode, stderr);
-    this.myMachineName = machineName;
-  }
+  public abstract Class<T> getLanguageContributionClass();
 
-  @NotNull
-  public String getMachineName() {
-    return myMachineName;
-  }
+  public abstract T getLanguageContribution();
 }
diff --git a/platform/platform-impl/src/com/intellij/remote/ext/CredentialsManager.java b/platform/platform-impl/src/com/intellij/remote/ext/CredentialsManager.java
new file mode 100644 (file)
index 0000000..e78c934
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2000-2016 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.remote.ext;
+
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.remote.CredentialsType;
+import com.intellij.remote.RemoteSdkAdditionalData;
+import org.jdom.Element;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
+public abstract class CredentialsManager {
+
+  public static CredentialsManager getInstance() {
+    return ServiceManager.getService(CredentialsManager.class);
+  }
+
+  public abstract List<CredentialsType> getAllTypes();
+
+  public abstract List<CredentialsTypeEx> getExTypes();
+
+  public abstract void loadCredentials(String interpreterPath, @Nullable Element element, RemoteSdkAdditionalData data);
+}
diff --git a/platform/platform-impl/src/com/intellij/remote/ext/CredentialsManagerImpl.java b/platform/platform-impl/src/com/intellij/remote/ext/CredentialsManagerImpl.java
new file mode 100644 (file)
index 0000000..58c59c2
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2000-2016 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.remote.ext;
+
+import com.intellij.remote.CredentialsType;
+import com.intellij.remote.RemoteSdkAdditionalData;
+import org.jdom.Element;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class CredentialsManagerImpl extends CredentialsManager {
+
+  @Override
+  public List<CredentialsType> getAllTypes() {
+    List<CredentialsType> result = new ArrayList<CredentialsType>();
+    result.add(CredentialsType.SSH_HOST);
+    result.add(CredentialsType.VAGRANT);
+    result.add(CredentialsType.WEB_DEPLOYMENT);
+    result.addAll(getExTypes());
+    return result;
+  }
+
+  @Override
+  public List<CredentialsTypeEx> getExTypes() {
+    return Arrays.asList(CredentialsTypeEx.EP_NAME.getExtensions());
+  }
+
+  @Override
+  public void loadCredentials(String interpreterPath, @Nullable Element element, RemoteSdkAdditionalData data) {
+    for (CredentialsType type : getAllTypes()) {
+      if (type.hasPrefix(interpreterPath)) {
+        Object credentials = type.createCredentials();
+        type.getHandler(credentials).load(element);
+        data.setCredentials(type.getCredentialsKey(), credentials);
+      }
+    }
+  }
+}
diff --git a/platform/platform-impl/src/com/intellij/remote/ext/CredentialsTypeEx.java b/platform/platform-impl/src/com/intellij/remote/ext/CredentialsTypeEx.java
new file mode 100644 (file)
index 0000000..ada3197
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2000-2015 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.remote.ext;
+
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.remote.CredentialsType;
+import com.intellij.remote.RemoteCredentials;
+
+public abstract class CredentialsTypeEx<T> extends CredentialsType<T> {
+
+  public static final ExtensionPointName<CredentialsTypeEx> EP_NAME = ExtensionPointName.create("com.intellij.remote.credentialsType");
+
+  protected CredentialsTypeEx(String name, String prefix) {
+    super(name, prefix);
+  }
+
+  public abstract RemoteCredentials createRemoteCredentials(T credentials);
+
+  public abstract boolean useRemoteCredentials();
+
+  public abstract boolean isBrowsingAvailable();
+}
diff --git a/platform/platform-impl/src/com/intellij/remote/ext/DockerCredentialsHandler.java b/platform/platform-impl/src/com/intellij/remote/ext/DockerCredentialsHandler.java
deleted file mode 100644 (file)
index d9cdae2..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2000-2016 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.remote.ext;
-
-import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.remote.DockerCredentialsHolder;
-import org.jdom.Element;
-import org.jetbrains.annotations.Nullable;
-
-public class DockerCredentialsHandler extends RemoteCredentialsHandlerBase<DockerCredentialsHolder> {
-
-  public static final String DOCKER_PREFIX = "docker://";
-
-  public DockerCredentialsHandler(DockerCredentialsHolder credentials) {
-    super(credentials);
-  }
-
-  @Override
-  public String getId() {
-    // TODO [Docker] review
-    DockerCredentialsHolder cred = getCredentials();
-    String name = StringUtil.isNotEmpty(cred.getContainerName()) ? cred.getContainerName() : cred.getImageName();
-    return DOCKER_PREFIX + name + "/";
-  }
-
-  @Override
-  public void save(Element rootElement) {
-    getCredentials().save(rootElement);
-  }
-
-  @Override
-  public String getPresentableDetails(String interpreterPath) {
-    DockerCredentialsHolder credentials = getCredentials();
-    String containerName = StringUtil.isNotEmpty(credentials.getContainerName())
-                           ? credentials.getContainerName() + " " : "";
-    return "Docker " + containerName + "(" + credentials.getImageName() + ")";
-  }
-
-  @Override
-  public void load(@Nullable Element rootElement) {
-    if (rootElement != null) {
-      getCredentials().load(rootElement);
-    }
-  }
-}
diff --git a/platform/platform-impl/src/com/intellij/remote/ext/LanguageCaseCollector.java b/platform/platform-impl/src/com/intellij/remote/ext/LanguageCaseCollector.java
new file mode 100644 (file)
index 0000000..b174901
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2000-2016 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.remote.ext;
+
+import com.intellij.remote.CredentialsType;
+import com.intellij.util.ArrayUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class LanguageCaseCollector<T> {
+
+  public CredentialsCase[] collectCases(Class<T> languageContributionClass, CredentialsCase... cases) {
+    List<CredentialsCase> exCases = new ArrayList<CredentialsCase>();
+    for (final CredentialsLanguageContribution contribution : CredentialsLanguageContribution.EP_NAME.getExtensions()) {
+      if (contribution.getLanguageContributionClass() == languageContributionClass) {
+        exCases.add(new CredentialsCase() {
+          @Override
+          public CredentialsType getType() {
+            return contribution.getType();
+          }
+
+          @Override
+          public void process(Object credentials) {
+            processLanguageContribution((T)contribution, credentials);
+          }
+        });
+      }
+    }
+
+    return ArrayUtil.mergeArrays(cases, exCases.toArray(new CredentialsCase[exCases.size()]));
+  }
+
+  protected abstract void processLanguageContribution(T languageContribution, Object credentials);
+}
index 3eebc7ee9a665949620af078270d5b9aa5af4123..0adfa2c09b3c045ea4f1106c0e730688ae7330f3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2015 JetBrains s.r.o.
+ * Copyright 2000-2016 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.
 package com.intellij.remote.ext;
 
 import org.jdom.Element;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-// TODO: wrapper?
+// TODO: (next) rename to wrapper?
 public interface RemoteCredentialsHandler {
 
   String getId();
 
-  void save(Element rootElement);
+  void save(@NotNull Element rootElement);
 
   String getPresentableDetails(String interpreterPath);
 
index 74097aae792eff3abf8841ced4c019c7db2605fe..d86d0dc7f53bf9932dc012031f08da7532b0405b 100644 (file)
@@ -33,7 +33,7 @@ public class SshCredentialsHandler extends RemoteCredentialsHandlerBase<RemoteCr
   }
 
   @Override
-  public void save(Element rootElement) {
+  public void save(@NotNull Element rootElement) {
     getCredentials().save(rootElement);
   }
 
index 2a0d16c5d5d7fafb1200ca82ac4974936ef31d64..3da8c0ba292ef229d119260b9a59358b2c5485d0 100644 (file)
@@ -19,6 +19,7 @@ import com.intellij.openapi.util.io.FileUtil;
 import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.remote.VagrantBasedCredentialsHolder;
 import org.jdom.Element;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 public class VagrantCredentialsHandler extends RemoteCredentialsHandlerBase<VagrantBasedCredentialsHolder> {
@@ -38,7 +39,7 @@ public class VagrantCredentialsHandler extends RemoteCredentialsHandlerBase<Vagr
   }
 
   @Override
-  public void save(Element rootElement) {
+  public void save(@NotNull Element rootElement) {
     getCredentials().save(rootElement);
   }
 
index 2fe4fee96b741afbad21863cf12ed1dca975ac61..446e23a08f8e22a006f84954c7e7a82bc794955a 100644 (file)
@@ -35,7 +35,7 @@ public class WebDeploymentCredentialsHandler extends RemoteCredentialsHandlerBas
   }
 
   @Override
-  public void save(Element rootElement) {
+  public void save(@NotNull Element rootElement) {
     getCredentials().save(rootElement);
   }
 
index fddd9d6d51cc001ac779fe35c8f1c5b2a13e8daa..0c3bd1951b77655b645b467253918e13beb58bdf 100644 (file)
     <extensionPoint name="jbProtocolCommand" interface="com.intellij.openapi.application.JBProtocolCommand"/>
 
     <extensionPoint name="vfs.local.pluggableFileWatcher" interface="com.intellij.openapi.vfs.local.PluggableFileWatcher" />
+
+    <extensionPoint name="remote.credentialsType" interface="com.intellij.remote.ext.CredentialsTypeEx"/>
+    <extensionPoint name="remote.credentialsLanguageContribution"
+                    interface="com.intellij.remote.ext.CredentialsLanguageContribution"/>
   </extensionPoints>
 </idea-plugin>
index 6dcd3c4d7f21c79a25204641afb2c3acb2327d93..898daf57d275034c0eec57ffbdfec1ef75dea45a 100644 (file)
                          displayName="Startup Tasks"
                          id="preferences.startup.tasks" nonDefaultProject="true"/>
     <postStartupActivity implementation="com.intellij.execution.startup.ProjectStartupRunner"/>
+
+    <applicationService serviceInterface="com.intellij.remote.ext.CredentialsManager"
+                        serviceImplementation="com.intellij.remote.ext.CredentialsManagerImpl"/>
   </extensions>
 </idea-plugin>
index 9d003ff8b4c13d2810bf4407bcf57ba9fc7ec2fc..56172f3b19e15774d98c838c4792efb58eca463d 100644 (file)
@@ -37,7 +37,8 @@ import com.jetbrains.python.psi.*;
 import com.jetbrains.python.psi.resolve.PyResolveContext;
 import com.jetbrains.python.psi.resolve.QualifiedResolveResult;
 import com.jetbrains.python.psi.types.TypeEvalContext;
-import com.jetbrains.python.sdk.PythonSdkType;
+import com.jetbrains.python.remote.PyCredentialsContribution;
+import com.jetbrains.python.sdk.CredentialsTypeExChecker;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -194,6 +195,11 @@ public class PyPackageUtil {
   }
 
   public static boolean packageManagementEnabled(@Nullable Sdk sdk) {
-    return !PythonSdkType.isDocker(sdk);
+    return new CredentialsTypeExChecker() {
+      @Override
+      protected boolean checkLanguageContribution(PyCredentialsContribution languageContribution) {
+        return languageContribution.isPackageManagementEnabled();
+      }
+    }.check(sdk);
   }
 }
index ef3b78c6db014a628960829380595a6f1922285f..2fe8f70bfeadcc5d26842af11b5743804943f6df 100644 (file)
@@ -24,7 +24,11 @@ import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.projectRoots.Sdk;
 import com.intellij.openapi.projectRoots.SdkAdditionalData;
 import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.remote.*;
+import com.intellij.remote.RemoteFile;
+import com.intellij.remote.RemoteSdkAdditionalData;
+import com.intellij.remote.RemoteSdkCredentials;
+import com.intellij.remote.VagrantNotStartedException;
+import com.intellij.remote.ext.CaseCollector;
 import com.intellij.util.ArrayUtil;
 import com.jetbrains.python.remote.PyRemotePathMapper;
 import com.jetbrains.python.remote.PyRemoteSdkAdditionalDataBase;
@@ -58,7 +62,7 @@ public class PyRemotePackageManagerImpl extends PyPackageManagerImpl {
       final PyRemoteSdkAdditionalDataBase remoteSdkData = (PyRemoteSdkAdditionalDataBase) sdkData;
       try {
         String helpersPath;
-        if (remoteSdkData.connectionCredentials().getRemoteConnectionType() != CredentialsType.DOCKER) {
+        if (CaseCollector.useRemoteCredentials(remoteSdkData)) {
           final RemoteSdkCredentials remoteSdkCredentials = remoteSdkData.getRemoteSdkCredentials(false);
           helpersPath = remoteSdkCredentials.getHelpersPath();
         }
@@ -98,7 +102,7 @@ public class PyRemotePackageManagerImpl extends PyPackageManagerImpl {
       final PythonRemoteInterpreterManager manager = PythonRemoteInterpreterManager.getInstance();
 
       RemoteSdkCredentials remoteSdkCredentials;
-      if (((PyRemoteSdkAdditionalDataBase)sdkData).connectionCredentials().getRemoteConnectionType() != CredentialsType.DOCKER) {
+      if (CaseCollector.useRemoteCredentials((PyRemoteSdkAdditionalDataBase)sdkData)) {
         try {
           remoteSdkCredentials = ((RemoteSdkAdditionalData)sdkData).getRemoteSdkCredentials(false);
         }
diff --git a/python/src/com/jetbrains/python/remote/PyCredentialsContribution.java b/python/src/com/jetbrains/python/remote/PyCredentialsContribution.java
new file mode 100644 (file)
index 0000000..e2d9897
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2000-2016 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.jetbrains.python.remote;
+
+public interface PyCredentialsContribution<T> {
+
+  boolean isValid(T credentials);
+
+  boolean shouldNotifySdkSkeletonFail();
+
+  boolean isPackageManagementEnabled();
+
+  boolean isSpecificCoverageAttach();
+
+  boolean isSpecificCoveragePatch();
+
+  boolean isRemoteProcessStartSupported();
+}
diff --git a/python/src/com/jetbrains/python/sdk/CredentialsTypeExChecker.java b/python/src/com/jetbrains/python/sdk/CredentialsTypeExChecker.java
new file mode 100644 (file)
index 0000000..92b52a9
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2000-2016 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.jetbrains.python.sdk;
+
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.util.Ref;
+import com.intellij.remote.RemoteSdkAdditionalData;
+import com.intellij.remote.ext.LanguageCaseCollector;
+import com.intellij.util.ObjectUtils;
+import com.jetbrains.python.remote.PyCredentialsContribution;
+import org.jetbrains.annotations.Nullable;
+
+public abstract class CredentialsTypeExChecker {
+
+  public boolean check(@Nullable final Sdk sdk) {
+    if (sdk == null) {
+      return false;
+    }
+    RemoteSdkAdditionalData data = ObjectUtils.tryCast(sdk.getSdkAdditionalData(), RemoteSdkAdditionalData.class);
+    if (data == null) {
+      return false;
+    }
+    return check(data);
+  }
+
+  public boolean check(RemoteSdkAdditionalData data) {
+    final Ref<Boolean> result = Ref.create(false);
+    data.switchOnConnectionType(new LanguageCaseCollector<PyCredentialsContribution>() {
+
+      @Override
+      protected void processLanguageContribution(PyCredentialsContribution languageContribution, Object credentials) {
+        result.set(checkLanguageContribution(languageContribution));
+      }
+    }.collectCases(PyCredentialsContribution.class));
+    return result.get();
+  }
+
+  protected abstract boolean checkLanguageContribution(PyCredentialsContribution languageContribution);
+}
index 5a0602bda89cd23be8c3abb8abac4b754017d6e8..c7904324a28bfd5c1201254bd5060bee8adcecd8 100644 (file)
@@ -55,6 +55,7 @@ import com.intellij.psi.PsiElement;
 import com.intellij.reference.SoftReference;
 import com.intellij.remote.*;
 import com.intellij.remote.ext.CredentialsCase;
+import com.intellij.remote.ext.LanguageCaseCollector;
 import com.intellij.util.ArrayUtil;
 import com.intellij.util.Consumer;
 import com.intellij.util.ExceptionUtil;
@@ -69,6 +70,7 @@ import com.jetbrains.python.packaging.PyCondaPackageManagerImpl;
 import com.jetbrains.python.psi.LanguageLevel;
 import com.jetbrains.python.psi.impl.PyBuiltinCache;
 import com.jetbrains.python.psi.search.PyProjectScopeBuilder;
+import com.jetbrains.python.remote.PyCredentialsContribution;
 import com.jetbrains.python.remote.PyRemoteSdkAdditionalDataBase;
 import com.jetbrains.python.remote.PythonRemoteInterpreterManager;
 import com.jetbrains.python.sdk.flavors.CPythonSdkFlavor;
@@ -246,11 +248,6 @@ public class PythonSdkType extends SdkType {
     return false;
   }
 
-  public static boolean isDocker(@Nullable final Sdk sdk) {
-    return sdk != null && sdk.getSdkAdditionalData() instanceof RemoteSdkAdditionalData &&
-           ((RemoteSdkAdditionalData)sdk.getSdkAdditionalData()).connectionCredentials().getRemoteConnectionType() == CredentialsType.DOCKER;
-  }
-
   public static boolean isRemote(@Nullable String sdkPath) {
     return isRemote(findSdkByPath(sdkPath));
   }
@@ -539,24 +536,20 @@ public class PythonSdkType extends SdkType {
         };
       notificationMessage = e.getMessage() + "\n<a href=\"#\">Launch vagrant and refresh skeletons</a>";
     }
-    else if (ExceptionUtil.causedBy(e, DockerMachineNotStartedException.class)) {
+    else if (ExceptionUtil.causedBy(e, ExceptionFix.class)) {
       //noinspection ThrowableResultOfMethodCallIgnored
-      DockerMachineNotStartedException cause = ExceptionUtil.findCause(e, DockerMachineNotStartedException.class);
-      final String machineName = cause.getMachineName();
+      final ExceptionFix fix = ExceptionUtil.findCause(e, ExceptionFix.class);
       notificationListener =
         new NotificationListener() {
           @Override
           public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) {
-            final DockerSupport dockerSupport = DockerSupport.getInstance();
-            if (dockerSupport != null) {
-              dockerSupport.startMachineWithProgressIndicator(null, machineName);
-            }
+            fix.apply();
             if (restartAction != null) {
               restartAction.run();
             }
           }
         };
-      notificationMessage = e.getMessage() + "\n<a href=\"#\">Start Docker Machine '" + machineName + "' and refresh skeletons</a>";
+      notificationMessage = fix.getNotificationMessage(e.getMessage());
     }
     else {
       notificationListener = null;
@@ -885,20 +878,21 @@ public class PythonSdkType extends SdkType {
       final Ref<Boolean> result = Ref.create(false);
       //noinspection ConstantConditions
       ((PyRemoteSdkAdditionalDataBase)sdk.getSdkAdditionalData()).switchOnConnectionType(
-        new CredentialsCase.Vagrant() {
+        new LanguageCaseCollector<PyCredentialsContribution>() {
+
           @Override
-          public void process(VagrantBasedCredentialsHolder cred) {
-            result.set(StringUtil.isEmpty(cred.getVagrantFolder()));
+          protected void processLanguageContribution(PyCredentialsContribution languageContribution, Object credentials) {
+            result.set(languageContribution.isValid(credentials));
           }
-        },
-        new CredentialsCase.Docker() {
-          @Override
-          public void process(DockerCredentialsHolder credentials) {
-            // TODO: validate if account exists
-            //credentials.getAccountName()
+        }.collectCases(
+          PyCredentialsContribution.class,
+          new CredentialsCase.Vagrant() {
+            @Override
+            public void process(VagrantBasedCredentialsHolder cred) {
+              result.set(StringUtil.isEmpty(cred.getVagrantFolder()));
+            }
           }
-        }
-      );
+        ));
       return result.get();
     }
     return false;
index dfb6a6da23c6d45843d7b087af88e7ef91e9c108..fe4367f3fce161c7b3072255940b84ebfa8cb7f1 100644 (file)
@@ -44,6 +44,7 @@ import com.intellij.util.concurrency.BlockingSet;
 import com.jetbrains.python.PyBundle;
 import com.jetbrains.python.codeInsight.userSkeletons.PyUserSkeletonsUtil;
 import com.jetbrains.python.psi.PyUtil;
+import com.jetbrains.python.remote.PyCredentialsContribution;
 import com.jetbrains.python.remote.PyRemoteSdkAdditionalDataBase;
 import com.jetbrains.python.sdk.skeletons.PySkeletonRefresher;
 import org.jetbrains.annotations.NotNull;
@@ -156,7 +157,13 @@ public class PythonSdkUpdater implements StartupActivity {
                   updateRemoteSdkPaths(sdk);
                 }
                 catch (InvalidSdkException e) {
-                  if (PythonSdkType.isVagrant(sdk) || PythonSdkType.isDocker(sdk)) {
+                  if (PythonSdkType.isVagrant(sdk)
+                      || new CredentialsTypeExChecker() {
+                    @Override
+                    protected boolean checkLanguageContribution(PyCredentialsContribution languageContribution) {
+                      return languageContribution.shouldNotifySdkSkeletonFail();
+                    }
+                  }.check(sdk)) {
                     PythonSdkType.notifyRemoteSdkSkeletonsFail(e, new Runnable() {
                       @Override
                       public void run() {