diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/AbstractCreateVirtualEnvDialog.java b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/AbstractCreateVirtualEnvDialog.java index f4a7ee4b..4d52c37a 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/AbstractCreateVirtualEnvDialog.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/AbstractCreateVirtualEnvDialog.java @@ -23,7 +23,6 @@ import consulo.application.progress.ProgressIndicator; import consulo.application.progress.ProgressManager; import consulo.application.progress.Task; -import consulo.application.util.function.Computable; import consulo.content.bundle.Sdk; import consulo.content.bundle.SdkUtil; import consulo.ide.impl.idea.webcore.packaging.PackagesNotificationPanel; @@ -42,14 +41,15 @@ import consulo.util.lang.StringUtil; import consulo.virtualFileSystem.LocalFileSystem; import consulo.virtualFileSystem.VirtualFile; - import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; + import javax.swing.*; import java.awt.*; import java.io.File; import java.util.Collections; import java.util.List; +import java.util.function.Supplier; public abstract class AbstractCreateVirtualEnvDialog extends IdeaDialog { @Nullable @@ -65,35 +65,30 @@ public interface VirtualEnvCallback { } @RequiredUIAccess - public static void setupVirtualEnvSdk(final String path, boolean associateWithProject, VirtualEnvCallback callback) { - final VirtualFile sdkHome = Application.get().runWriteAction(new Computable() { - @Nullable - @Override - public VirtualFile compute() { - return LocalFileSystem.getInstance().refreshAndFindFileByPath(path); - } - }); + public static void setupVirtualEnvSdk(String path, boolean associateWithProject, VirtualEnvCallback callback) { + VirtualFile sdkHome = + Application.get().runWriteAction((Supplier)() -> LocalFileSystem.getInstance().refreshAndFindFileByPath(path)); if (sdkHome != null) { - final Sdk sdk = + Sdk sdk = SdkUtil.createAndAddSDK(FileUtil.toSystemDependentName(sdkHome.getPath()), PythonSdkType.getInstance(), UIAccess.current()); callback.virtualEnvCreated(sdk, associateWithProject); } } - public AbstractCreateVirtualEnvDialog(Project project, final List allSdks) { + public AbstractCreateVirtualEnvDialog(Project project, List allSdks) { super(project); setupDialog(project, allSdks); } - public AbstractCreateVirtualEnvDialog(Component owner, final List allSdks) { + public AbstractCreateVirtualEnvDialog(Component owner, List allSdks) { super(owner); setupDialog(null, allSdks); } - void setupDialog(Project project, final List allSdks) { + void setupDialog(Project project, List allSdks) { myProject = project; - final GridBagLayout layout = new GridBagLayout(); + GridBagLayout layout = new GridBagLayout(); myMainPanel = new JPanel(layout); myName = new JTextField(); myDestination = new TextFieldWithBrowseButton(); @@ -129,18 +124,18 @@ public void validate() { protected void setInitialDestination() { myInitialPath = ""; - final VirtualFile file = VirtualEnvSdkFlavor.getDefaultLocation(); + VirtualFile file = VirtualEnvSdkFlavor.getDefaultLocation(); if (file != null) { myInitialPath = file.getPath(); } else { - final String savedPath = PyPackageService.getInstance().getVirtualEnvBasePath(); + String savedPath = PyPackageService.getInstance().getVirtualEnvBasePath(); if (!StringUtil.isEmptyOrSpaces(savedPath)) { myInitialPath = savedPath; } else if (myProject != null) { - final VirtualFile baseDir = myProject.getBaseDir(); + VirtualFile baseDir = myProject.getBaseDir(); if (baseDir != null) { myInitialPath = baseDir.getPath(); } @@ -148,7 +143,7 @@ else if (myProject != null) { } } - /*protected void registerValidators(final FacetValidatorsManager validatorsManager) { + /*protected void registerValidators(FacetValidatorsManager validatorsManager) { myDestination.getTextField().getDocument().addDocumentListener(new DocumentAdapter() { @Override protected void textChanged(DocumentEvent e) { @@ -178,10 +173,10 @@ public void caretUpdate(CaretEvent event) { }*/ protected void checkValid() { - final String projectName = myName.getText(); - final File destFile = new File(getDestination()); + String projectName = myName.getText(); + File destFile = new File(getDestination()); if (destFile.exists()) { - final String[] content = destFile.list(); + String[] content = destFile.list(); if (content != null && content.length != 0) { setOKActionEnabled(false); setErrorText(PyLocalize.sdkCreateVenvDialogErrorNotEmptyDirectory()); @@ -208,7 +203,7 @@ protected void checkValid() { clearErrorText(); } - abstract protected void layoutPanel(final List allSdks); + abstract protected void layoutPanel(List allSdks); @Override protected JComponent createCenterPanel() { @@ -232,22 +227,22 @@ public boolean associateWithProject() { return !myMakeAvailableToAllProjectsCheckbox.isSelected(); } - public void createVirtualEnv(final VirtualEnvCallback callback) { - final ProgressManager progman = ProgressManager.getInstance(); - final Sdk basicSdk = getSdk(); - final Task.Modal createTask = new Task.Modal(myProject, PyLocalize.sdkCreateVenvDialogCreatingVenv(), false) { + public void createVirtualEnv(VirtualEnvCallback callback) { + ProgressManager progman = ProgressManager.getInstance(); + Sdk basicSdk = getSdk(); + Task.Modal createTask = new Task.Modal(myProject, PyLocalize.sdkCreateVenvDialogCreatingVenv(), false) { String myPath; @Override - public void run(@Nonnull final ProgressIndicator indicator) { + public void run(@Nonnull ProgressIndicator indicator) { try { indicator.setTextValue(PyLocalize.sdkCreateVenvDialogCreatingVenv()); myPath = createEnvironment(basicSdk); } - catch (final ExecutionException e) { + catch (ExecutionException e) { Application.get().invokeLater( () -> { - final PackageManagementService.ErrorDescription description = + PackageManagementService.ErrorDescription description = PyPackageManagementService.toErrorDescription(Collections.singletonList(e), basicSdk); if (description != null) { PackagesNotificationPanel.showError( diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/InvalidSdkException.java b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/InvalidSdkException.java index 9469021f..4f0ecb05 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/InvalidSdkException.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/InvalidSdkException.java @@ -13,15 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.jetbrains.python.impl.sdk; public class InvalidSdkException extends Exception { - public InvalidSdkException(String s) { - super(s); - } + public InvalidSdkException(String s) { + super(s); + } - public InvalidSdkException(String message, Throwable cause) { - super(message, cause); - } + public InvalidSdkException(String message, Throwable cause) { + super(message, cause); + } } diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/LocationNameFieldsBinding.java b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/LocationNameFieldsBinding.java index 06ada24c..f4580ccd 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/LocationNameFieldsBinding.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/LocationNameFieldsBinding.java @@ -1,9 +1,9 @@ // 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. package com.jetbrains.python.impl.sdk; -import consulo.application.util.SystemInfo; import consulo.fileChooser.FileChooserDescriptor; import consulo.fileChooser.FileChooserDescriptorFactory; +import consulo.platform.Platform; import consulo.project.Project; import consulo.ui.ex.awt.ComponentWithBrowseButton.BrowseFolderActionListener; import consulo.ui.ex.awt.TextComponentAccessor; @@ -12,9 +12,9 @@ import consulo.util.io.FileUtil; import consulo.util.lang.StringUtil; import consulo.virtualFileSystem.VirtualFile; - import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; + import javax.swing.*; import javax.swing.event.DocumentEvent; import javax.swing.text.AttributeSet; @@ -28,115 +28,119 @@ * @author catherine */ public class LocationNameFieldsBinding { - private boolean myModifyingLocation = false; - private boolean myModifyingProjectName = false; - private boolean myExternalModify = false; - private String myBaseDir; - private final String mySuggestedProjectName; + private boolean myModifyingLocation = false; + private boolean myModifyingProjectName = false; + private boolean myExternalModify = false; + private String myBaseDir; + private final String mySuggestedProjectName; - public LocationNameFieldsBinding(@Nullable Project project, - final TextFieldWithBrowseButton locationField, - final JTextField nameField, - String baseDir, - String title) { - myBaseDir = baseDir; - File suggestedProjectDirectory = FileUtil.findSequentNonexistentFile(new File(baseDir), "untitled", ""); - locationField.setText(suggestedProjectDirectory.toString()); - nameField.setDocument(new NameFieldDocument(nameField, locationField)); - mySuggestedProjectName = suggestedProjectDirectory.getName(); - nameField.setText(mySuggestedProjectName); - nameField.selectAll(); + public LocationNameFieldsBinding( + @Nullable Project project, + TextFieldWithBrowseButton locationField, + JTextField nameField, + String baseDir, + String title + ) { + myBaseDir = baseDir; + File suggestedProjectDirectory = FileUtil.findSequentNonexistentFile(new File(baseDir), "untitled", ""); + locationField.setText(suggestedProjectDirectory.toString()); + nameField.setDocument(new NameFieldDocument(nameField, locationField)); + mySuggestedProjectName = suggestedProjectDirectory.getName(); + nameField.setText(mySuggestedProjectName); + nameField.selectAll(); - FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor(); - BrowseFolderActionListener listener = - new BrowseFolderActionListener(title, - "", - locationField, - project, - descriptor, - TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT) { - @Override - protected void onFileChosen(@Nonnull VirtualFile chosenFile) { - myBaseDir = chosenFile.getPath(); - if (isProjectNameChanged(nameField.getText()) && !nameField.getText().equals(chosenFile.getName())) { - myExternalModify = true; - locationField.setText(new File(chosenFile.getPath(), nameField.getText()).toString()); - myExternalModify = false; - } - else { - myExternalModify = true; - locationField.setText(chosenFile.getPath()); - nameField.setText(chosenFile.getName()); - myExternalModify = false; - } - } - }; - locationField.addActionListener(listener); - locationField.getTextField().getDocument().addDocumentListener(new DocumentAdapter() { - @Override - protected void textChanged(@Nonnull DocumentEvent e) { - if (myExternalModify) { - return; - } - myModifyingLocation = true; - String path = locationField.getText().trim(); - path = StringUtil.trimEnd(path, File.separator); - int ind = path.lastIndexOf(File.separator); - if (ind != -1) { - String projectName = path.substring(ind + 1); - if (!nameField.getText().trim().isEmpty()) { - myBaseDir = path.substring(0, ind); - } - if (!projectName.equals(nameField.getText())) { - if (!myModifyingProjectName) { - nameField.setText(projectName); + FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor(); + BrowseFolderActionListener listener = + new BrowseFolderActionListener( + title, + "", + locationField, + project, + descriptor, + TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT + ) { + @Override + protected void onFileChosen(@Nonnull VirtualFile chosenFile) { + myBaseDir = chosenFile.getPath(); + if (isProjectNameChanged(nameField.getText()) && !nameField.getText().equals(chosenFile.getName())) { + myExternalModify = true; + locationField.setText(new File(chosenFile.getPath(), nameField.getText()).toString()); + myExternalModify = false; + } + else { + myExternalModify = true; + locationField.setText(chosenFile.getPath()); + nameField.setText(chosenFile.getName()); + myExternalModify = false; + } + } + }; + locationField.addActionListener(listener); + locationField.getTextField().getDocument().addDocumentListener(new DocumentAdapter() { + @Override + protected void textChanged(@Nonnull DocumentEvent e) { + if (myExternalModify) { + return; + } + myModifyingLocation = true; + String path = locationField.getText().trim(); + path = StringUtil.trimEnd(path, File.separator); + int ind = path.lastIndexOf(File.separator); + if (ind != -1) { + String projectName = path.substring(ind + 1); + if (!nameField.getText().trim().isEmpty()) { + myBaseDir = path.substring(0, ind); + } + if (!projectName.equals(nameField.getText())) { + if (!myModifyingProjectName) { + nameField.setText(projectName); + } + } + } + myModifyingLocation = false; } - } - } - myModifyingLocation = false; - } - }); - } - - private boolean isProjectNameChanged(@Nonnull String currentName) { - return !currentName.equals(mySuggestedProjectName); - } + }); + } - private class NameFieldDocument extends PlainDocument { - NameFieldDocument(final JTextField projectNameTextField, final TextFieldWithBrowseButton locationField) { - addDocumentListener(new DocumentAdapter() { - @Override - protected void textChanged(@Nonnull final DocumentEvent e) { - if (!myModifyingLocation && !myExternalModify) { - myModifyingProjectName = true; - File f = new File(myBaseDir); - locationField.setText(new File(f, projectNameTextField.getText()).getPath()); - } - } - }); + private boolean isProjectNameChanged(@Nonnull String currentName) { + return !currentName.equals(mySuggestedProjectName); } - @Override - public void insertString(int offs, String str, AttributeSet a) throws BadLocationException { - StringBuilder sb = null; - for (int i = 0; i < str.length(); i++) { - char c = str.charAt(i); - boolean replace = c == '\\' || c == '/' || SystemInfo.isWindows && (c == '|' || c == ':'); - if (replace) { - if (sb == null) { - sb = new StringBuilder(str.length()); - sb.append(str, 0, i); - } - sb.append('_'); + private class NameFieldDocument extends PlainDocument { + NameFieldDocument(JTextField projectNameTextField, TextFieldWithBrowseButton locationField) { + addDocumentListener(new DocumentAdapter() { + @Override + protected void textChanged(@Nonnull DocumentEvent e) { + if (!myModifyingLocation && !myExternalModify) { + myModifyingProjectName = true; + File f = new File(myBaseDir); + locationField.setText(new File(f, projectNameTextField.getText()).getPath()); + } + } + }); } - else if (sb != null) { - sb.append(c); + + @Override + public void insertString(int offs, String str, AttributeSet a) throws BadLocationException { + StringBuilder sb = null; + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + boolean replace = c == '\\' || c == '/' || Platform.current().os().isWindows() && (c == '|' || c == ':'); + if (replace) { + if (sb == null) { + sb = new StringBuilder(str.length()); + sb.append(str, 0, i); + } + sb.append('_'); + } + else if (sb != null) { + sb.append(c); + } + } + if (sb != null) { + str = sb.toString(); + } + super.insertString(offs, str, a); } - } - if (sb != null) { - str = sb.toString(); - } - super.insertString(offs, str, a); } - } } diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PreferredSdkComparator.java b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PreferredSdkComparator.java index 94ee40a1..e5f40f8a 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PreferredSdkComparator.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PreferredSdkComparator.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.jetbrains.python.impl.sdk; import consulo.content.bundle.Sdk; @@ -24,30 +23,30 @@ import java.util.Comparator; /** -* @author yole -*/ + * @author yole + */ public class PreferredSdkComparator implements Comparator { - public static PreferredSdkComparator INSTANCE = new PreferredSdkComparator(); + public static PreferredSdkComparator INSTANCE = new PreferredSdkComparator(); - @Override - public int compare(Sdk o1, Sdk o2) { - final PythonSdkFlavor flavor1 = PythonSdkFlavor.getFlavor(o1); - final PythonSdkFlavor flavor2 = PythonSdkFlavor.getFlavor(o2); - int remote1Weight = PySdkUtil.isRemote(o1) ? 0 : 1; - int remote2Weight = PySdkUtil.isRemote(o2) ? 0 : 1; - if (remote1Weight != remote2Weight) { - return remote2Weight - remote1Weight; - } - int venv1weight = PythonSdkType.isVirtualEnv(o1) ? 0 : 1; - int venv2weight = PythonSdkType.isVirtualEnv(o2) ? 0 : 1; - if (venv1weight != venv2weight) { - return venv2weight - venv1weight; - } - int flavor1weight = flavor1 instanceof CPythonSdkFlavor ? 1 : 0; - int flavor2weight = flavor2 instanceof CPythonSdkFlavor ? 1 : 0; - if (flavor1weight != flavor2weight) { - return flavor2weight - flavor1weight; + @Override + public int compare(Sdk o1, Sdk o2) { + PythonSdkFlavor flavor1 = PythonSdkFlavor.getFlavor(o1); + PythonSdkFlavor flavor2 = PythonSdkFlavor.getFlavor(o2); + int remote1Weight = PySdkUtil.isRemote(o1) ? 0 : 1; + int remote2Weight = PySdkUtil.isRemote(o2) ? 0 : 1; + if (remote1Weight != remote2Weight) { + return remote2Weight - remote1Weight; + } + int venv1weight = PythonSdkType.isVirtualEnv(o1) ? 0 : 1; + int venv2weight = PythonSdkType.isVirtualEnv(o2) ? 0 : 1; + if (venv1weight != venv2weight) { + return venv2weight - venv1weight; + } + int flavor1weight = flavor1 instanceof CPythonSdkFlavor ? 1 : 0; + int flavor2weight = flavor2 instanceof CPythonSdkFlavor ? 1 : 0; + if (flavor1weight != flavor2weight) { + return flavor2weight - flavor1weight; + } + return -Comparing.compare(o1.getVersionString(), o2.getVersionString()); } - return -Comparing.compare(o1.getVersionString(), o2.getVersionString()); - } } diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PySdkListCellRenderer.java b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PySdkListCellRenderer.java index fc149e3d..15cc5142 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PySdkListCellRenderer.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PySdkListCellRenderer.java @@ -16,11 +16,11 @@ package com.jetbrains.python.impl.sdk; import com.jetbrains.python.impl.sdk.flavors.PythonSdkFlavor; -import consulo.application.AllIcons; import consulo.application.util.UserHomeFileUtil; import consulo.content.bundle.Sdk; import consulo.content.bundle.SdkModificator; import consulo.content.bundle.SdkType; +import consulo.platform.base.icon.PlatformIconGroup; import consulo.ui.ex.awt.ListCellRendererWrapper; import consulo.ui.ex.awtUnsafe.TargetAWT; import consulo.ui.image.Image; @@ -29,6 +29,7 @@ import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; + import javax.swing.*; import java.io.File; import java.util.Map; @@ -36,96 +37,96 @@ import java.util.regex.Pattern; public class PySdkListCellRenderer extends ListCellRendererWrapper { - private final String myNullText; - private final Map mySdkModifiers; - public static final String SEPARATOR = "separator"; + private final String myNullText; + private final Map mySdkModifiers; + public static final String SEPARATOR = "separator"; - final Pattern PYTHON_PATTERN = Pattern.compile("(\\d\\.?\\d\\.?\\d?)[ ]*\\(([^\\(\\)]*)\\)|(\\d\\.?\\d\\.?\\d?)[ ]*([^\\(\\)]*)"); - private boolean isShortVersion; + private static final Pattern PYTHON_PATTERN = + Pattern.compile("(\\d\\.?\\d\\.?\\d?)[ ]*\\(([^\\(\\)]*)\\)|(\\d\\.?\\d\\.?\\d?)[ ]*([^\\(\\)]*)"); + private boolean isShortVersion; - public PySdkListCellRenderer(boolean shortVersion) { - isShortVersion = shortVersion; - myNullText = ""; - mySdkModifiers = null; - } + public PySdkListCellRenderer(boolean shortVersion) { + isShortVersion = shortVersion; + myNullText = ""; + mySdkModifiers = null; + } - public PySdkListCellRenderer(String nullText, @Nullable Map sdkModifiers) { - myNullText = nullText; - mySdkModifiers = sdkModifiers; - } + public PySdkListCellRenderer(String nullText, @Nullable Map sdkModifiers) { + myNullText = nullText; + mySdkModifiers = sdkModifiers; + } - @Override - public void customize(JList list, Object item, int index, boolean selected, boolean hasFocus) { - if (item instanceof Sdk) { - Sdk sdk = (Sdk)item; - final PythonSdkFlavor flavor = PythonSdkFlavor.getPlatformIndependentFlavor(sdk.getHomePath()); - final Image baseIcon = flavor != null ? flavor.getIcon() : ((SdkType)sdk.getSdkType()).getIcon(); + @Override + public void customize(JList list, Object item, int index, boolean selected, boolean hasFocus) { + if (item instanceof Sdk sdk) { + PythonSdkFlavor flavor = PythonSdkFlavor.getPlatformIndependentFlavor(sdk.getHomePath()); + Image baseIcon = flavor != null ? flavor.getIcon() : ((SdkType)sdk.getSdkType()).getIcon(); - String name; - if (mySdkModifiers != null && mySdkModifiers.containsKey(sdk)) { - name = mySdkModifiers.get(sdk).getName(); - } - else { - name = sdk.getName(); - } - if (name.startsWith("Remote")) { - final String trimmedRemote = StringUtil.trim(name.substring("Remote".length())); - if (!trimmedRemote.isEmpty()) { - name = trimmedRemote; - } - } - final String flavorName = flavor == null ? "Python" : flavor.getName(); - if (name.startsWith(flavorName)) { - name = StringUtil.trim(name.substring(flavorName.length())); - } + String name; + if (mySdkModifiers != null && mySdkModifiers.containsKey(sdk)) { + name = mySdkModifiers.get(sdk).getName(); + } + else { + name = sdk.getName(); + } + if (name.startsWith("Remote")) { + String trimmedRemote = StringUtil.trim(name.substring("Remote".length())); + if (!trimmedRemote.isEmpty()) { + name = trimmedRemote; + } + } + String flavorName = flavor == null ? "Python" : flavor.getName(); + if (name.startsWith(flavorName)) { + name = StringUtil.trim(name.substring(flavorName.length())); + } - if (isShortVersion) { - name = shortenName(name); - } + if (isShortVersion) { + name = shortenName(name); + } - Image icon = null; - if (PythonSdkType.isInvalid(sdk)) { - setText("[invalid] " + name); - icon = wrapIconWithWarningDecorator(baseIcon); - } - else { - setText(name); - icon = baseIcon; - } + Image icon; + if (PythonSdkType.isInvalid(sdk)) { + setText("[invalid] " + name); + icon = wrapIconWithWarningDecorator(baseIcon); + } + else { + setText(name); + icon = baseIcon; + } - setIcon(TargetAWT.to(icon)); - } - else if (SEPARATOR.equals(item)) { - setSeparator(); - } - else if (item == null) { - setText(myNullText); + setIcon(TargetAWT.to(icon)); + } + else if (SEPARATOR.equals(item)) { + setSeparator(); + } + else if (item == null) { + setText(myNullText); + } } - } - private String shortenName(@Nonnull String name) { - final Matcher matcher = PYTHON_PATTERN.matcher(name); - if (matcher.matches()) { - String path = matcher.group(2); - if (path != null) { - name = matcher.group(1) + " at " + path; - } - else { - path = matcher.group(4); - final int index = path.lastIndexOf(File.separator); - if (index > 0) { - path = path.substring(index); + private String shortenName(@Nonnull String name) { + Matcher matcher = PYTHON_PATTERN.matcher(name); + if (matcher.matches()) { + String path = matcher.group(2); + if (path != null) { + name = matcher.group(1) + " at " + path; + } + else { + path = matcher.group(4); + int index = path.lastIndexOf(File.separator); + if (index > 0) { + path = path.substring(index); + } + name = matcher.group(3) + " at ..." + path; + } } - name = matcher.group(3) + " at ..." + path; - } - } - else if (new File(name).exists()) { - name = UserHomeFileUtil.getLocationRelativeToUserHome(name); + else if (new File(name).exists()) { + name = UserHomeFileUtil.getLocationRelativeToUserHome(name); + } + return name; } - return name; - } - private static Image wrapIconWithWarningDecorator(Image icon) { - return ImageEffects.layered(icon, AllIcons.Actions.Cancel); - } + private static Image wrapIconWithWarningDecorator(Image icon) { + return ImageEffects.layered(icon, PlatformIconGroup.actionsCancel()); + } } diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PySdkUtil.java b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PySdkUtil.java index 12f69cd1..3eccc3df 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PySdkUtil.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PySdkUtil.java @@ -15,30 +15,27 @@ */ package com.jetbrains.python.impl.sdk; -import consulo.application.util.SystemInfo; -import consulo.container.boot.ContainerPathManager; +import consulo.annotation.access.RequiredReadAction; import consulo.content.OrderRootType; import consulo.content.base.BinariesOrderRootType; import consulo.content.bundle.Sdk; -import consulo.ide.impl.idea.openapi.vfs.VfsUtilCore; import consulo.language.psi.PsiElement; import consulo.language.psi.PsiFile; import consulo.logging.Logger; +import consulo.platform.Platform; import consulo.process.ExecutionException; import consulo.process.ProcessHandler; import consulo.process.ProcessHandlerBuilder; import consulo.process.cmd.GeneralCommandLine; import consulo.process.util.CapturingProcessAdapter; import consulo.process.util.ProcessOutput; -import consulo.util.io.FileUtil; import consulo.util.lang.StringUtil; import consulo.util.lang.SystemProperties; import consulo.virtualFileSystem.VirtualFile; import consulo.virtualFileSystem.util.VirtualFileUtil; -import org.jetbrains.annotations.NonNls; - import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; + import java.io.File; import java.io.IOException; import java.io.OutputStream; @@ -54,194 +51,204 @@ * Time: 1:19:47 PM */ public class PySdkUtil { - protected static final Logger LOG = Logger.getInstance(PySdkUtil.class); - - // Windows EOF marker, Ctrl+Z - public static final int SUBSTITUTE = 26; - public static final String PATH_ENV_VARIABLE = "PATH"; - - private PySdkUtil() { - // explicitly none - } - - /** - * Executes a process and returns its stdout and stderr outputs as lists of lines. - * - * @param homePath process run directory - * @param command command to execute and its arguments - * @return a tuple of (stdout lines, stderr lines, exit_code), lines in them have line terminators stripped, or may be null. - */ - @Nonnull - public static ProcessOutput getProcessOutput(String homePath, @NonNls String[] command) { - return getProcessOutput(homePath, command, -1); - } - - /** - * Executes a process and returns its stdout and stderr outputs as lists of lines. - * Waits for process for possibly limited duration. - * - * @param homePath process run directory - * @param command command to execute and its arguments - * @param timeout how many milliseconds to wait until the process terminates; non-positive means inifinity. - * @return a tuple of (stdout lines, stderr lines, exit_code), lines in them have line terminators stripped, or may be null. - */ - @Nonnull - public static ProcessOutput getProcessOutput(String homePath, @NonNls String[] command, final int timeout) { - return getProcessOutput(homePath, command, null, timeout); - } - - @Nonnull - public static ProcessOutput getProcessOutput(String homePath, - @NonNls String[] command, - @Nullable @NonNls Map extraEnv, - final int timeout) { - return getProcessOutput(homePath, command, extraEnv, timeout, null, true); - } - - @Nonnull - public static ProcessOutput getProcessOutput(String homePath, - @NonNls String[] command, - @Nullable @NonNls Map extraEnv, - final int timeout, - @Nullable byte[] stdin, - boolean needEOFMarker) { - return getProcessOutput(new GeneralCommandLine(command), homePath, extraEnv, timeout, stdin, needEOFMarker); - } - - public static ProcessOutput getProcessOutput(@Nonnull GeneralCommandLine cmd, - @Nullable String homePath, - @Nullable @NonNls Map extraEnv, - int timeout) { - return getProcessOutput(cmd, homePath, extraEnv, timeout, null, true); - } - - public static ProcessOutput getProcessOutput(@Nonnull GeneralCommandLine cmd, - @Nullable String homePath, - @Nullable @NonNls Map extraEnv, - int timeout, - @Nullable byte[] stdin, - boolean needEOFMarker) { - if (homePath == null || !new File(homePath).exists()) { - return new ProcessOutput(); + protected static final Logger LOG = Logger.getInstance(PySdkUtil.class); + + // Windows EOF marker, Ctrl+Z + public static final int SUBSTITUTE = 26; + public static final String PATH_ENV_VARIABLE = "PATH"; + + private PySdkUtil() { + // explicitly none + } + + /** + * Executes a process and returns its stdout and stderr outputs as lists of lines. + * + * @param homePath process run directory + * @param command command to execute and its arguments + * @return a tuple of (stdout lines, stderr lines, exit_code), lines in them have line terminators stripped, or may be null. + */ + @Nonnull + public static ProcessOutput getProcessOutput(String homePath, String[] command) { + return getProcessOutput(homePath, command, -1); + } + + /** + * Executes a process and returns its stdout and stderr outputs as lists of lines. + * Waits for process for possibly limited duration. + * + * @param homePath process run directory + * @param command command to execute and its arguments + * @param timeout how many milliseconds to wait until the process terminates; non-positive means inifinity. + * @return a tuple of (stdout lines, stderr lines, exit_code), lines in them have line terminators stripped, or may be null. + */ + @Nonnull + public static ProcessOutput getProcessOutput(String homePath, String[] command, int timeout) { + return getProcessOutput(homePath, command, null, timeout); } - final Map systemEnv = System.getenv(); - final Map expandedCmdEnv = mergeEnvVariables(systemEnv, cmd.getEnvironment()); - final Map env = extraEnv != null ? mergeEnvVariables(expandedCmdEnv, extraEnv) : expandedCmdEnv; - PythonEnvUtil.resetHomePathChanges(homePath, env); - try { - - final GeneralCommandLine commandLine = cmd.withWorkDirectory(homePath).withEnvironment(env); - final ProcessHandler processHandler = ProcessHandlerBuilder.create(commandLine).build(); - if (stdin != null) { - final OutputStream processInput = processHandler.getProcessInput(); - assert processInput != null; - processInput.write(stdin); - if (SystemInfo.isWindows && needEOFMarker) { - processInput.write(SUBSTITUTE); - processInput.flush(); + + @Nonnull + public static ProcessOutput getProcessOutput( + String homePath, + String[] command, + @Nullable Map extraEnv, + int timeout + ) { + return getProcessOutput(homePath, command, extraEnv, timeout, null, true); + } + + @Nonnull + public static ProcessOutput getProcessOutput( + String homePath, + String[] command, + @Nullable Map extraEnv, + int timeout, + @Nullable byte[] stdin, + boolean needEOFMarker + ) { + return getProcessOutput(new GeneralCommandLine(command), homePath, extraEnv, timeout, stdin, needEOFMarker); + } + + public static ProcessOutput getProcessOutput( + @Nonnull GeneralCommandLine cmd, + @Nullable String homePath, + @Nullable Map extraEnv, + int timeout + ) { + return getProcessOutput(cmd, homePath, extraEnv, timeout, null, true); + } + + public static ProcessOutput getProcessOutput( + @Nonnull GeneralCommandLine cmd, + @Nullable String homePath, + @Nullable Map extraEnv, + int timeout, + @Nullable byte[] stdin, + boolean needEOFMarker + ) { + if (homePath == null || !new File(homePath).exists()) { + return new ProcessOutput(); } - else { - processInput.close(); + Map systemEnv = System.getenv(); + Map expandedCmdEnv = mergeEnvVariables(systemEnv, cmd.getEnvironment()); + Map env = extraEnv != null ? mergeEnvVariables(expandedCmdEnv, extraEnv) : expandedCmdEnv; + PythonEnvUtil.resetHomePathChanges(homePath, env); + try { + GeneralCommandLine commandLine = cmd.withWorkDirectory(homePath).withEnvironment(env); + ProcessHandler processHandler = ProcessHandlerBuilder.create(commandLine).build(); + if (stdin != null) { + OutputStream processInput = processHandler.getProcessInput(); + assert processInput != null; + processInput.write(stdin); + if (Platform.current().os().isWindows() && needEOFMarker) { + processInput.write(SUBSTITUTE); + processInput.flush(); + } + else { + processInput.close(); + } + } + CapturingProcessAdapter adapter = new CapturingProcessAdapter(); + processHandler.addProcessListener(adapter); + processHandler.startNotify(); + processHandler.waitFor(); + return adapter.getOutput(); } - } - CapturingProcessAdapter adapter = new CapturingProcessAdapter(); - processHandler.addProcessListener(adapter); - processHandler.startNotify(); - processHandler.waitFor(); - return adapter.getOutput(); + catch (ExecutionException e) { + return getOutputForException(e); + } + catch (IOException e) { + return getOutputForException(e); + } + } + + private static ProcessOutput getOutputForException(Exception e) { + LOG.warn(e); + return new ProcessOutput() { + @Nonnull + @Override + public String getStderr() { + String err = super.getStderr(); + if (!StringUtil.isEmpty(err)) { + err += "\n" + e.getMessage(); + } + else { + err = e.getMessage(); + } + return err; + } + }; } - catch (ExecutionException e) { - return getOutputForException(e); + + @Nonnull + public static Map mergeEnvVariables( + @Nonnull Map environment, + @Nonnull Map extraEnvironment + ) { + Map result = new HashMap<>(environment); + for (Map.Entry entry : extraEnvironment.entrySet()) { + String name = entry.getKey(); + if (PATH_ENV_VARIABLE.equals(name) || PythonEnvUtil.PYTHONPATH.equals(name)) { + PythonEnvUtil.addPathToEnv(result, name, entry.getValue()); + } + else { + result.put(name, entry.getValue()); + } + } + return result; } - catch (IOException e) { - return getOutputForException(e); + + @Deprecated + public static boolean isRemote(@Nullable Sdk sdk) { + return false; } - } - - private static ProcessOutput getOutputForException(final Exception e) { - LOG.warn(e); - return new ProcessOutput() { - @Nonnull - @Override - public String getStderr() { - String err = super.getStderr(); - if (!StringUtil.isEmpty(err)) { - err += "\n" + e.getMessage(); + + public static String getUserSite() { + if (Platform.current().os().isWindows()) { + String appdata = System.getenv("APPDATA"); + return appdata + File.separator + "Python"; } else { - err = e.getMessage(); + String userHome = SystemProperties.getUserHome(); + return userHome + File.separator + ".local"; } - return err; - } - }; - } - - @Nonnull - public static Map mergeEnvVariables(@Nonnull Map environment, - @Nonnull Map extraEnvironment) { - final Map result = new HashMap<>(environment); - for (Map.Entry entry : extraEnvironment.entrySet()) { - final String name = entry.getKey(); - if (PATH_ENV_VARIABLE.equals(name) || PythonEnvUtil.PYTHONPATH.equals(name)) { - PythonEnvUtil.addPathToEnv(result, name, entry.getValue()); - } - else { - result.put(name, entry.getValue()); - } } - return result; - } - - @Deprecated - public static boolean isRemote(@Nullable Sdk sdk) { - return false; - } - - public static String getUserSite() { - if (SystemInfo.isWindows) { - final String appdata = System.getenv("APPDATA"); - return appdata + File.separator + "Python"; + + @RequiredReadAction + public static boolean isElementInSkeletons(@Nonnull PsiElement element) { + PsiFile file = element.getContainingFile(); + if (file != null) { + VirtualFile virtualFile = file.getVirtualFile(); + if (virtualFile != null) { + Sdk sdk = PythonSdkType.getSdk(element); + if (sdk != null) { + VirtualFile skeletonsDir = findSkeletonsDir(sdk); + if (skeletonsDir != null && VirtualFileUtil.isAncestor(skeletonsDir, virtualFile, false)) { + return true; + } + } + } + } + return false; } - else { - final String userHome = SystemProperties.getUserHome(); - return userHome + File.separator + ".local"; + + @Nullable + public static VirtualFile findSkeletonsDir(@Nonnull Sdk sdk) { + return findLibraryDir(sdk, PythonSdkType.SKELETON_DIR_NAME, BinariesOrderRootType.getInstance()); } - } - - public static boolean isElementInSkeletons(@Nonnull final PsiElement element) { - final PsiFile file = element.getContainingFile(); - if (file != null) { - final VirtualFile virtualFile = file.getVirtualFile(); - if (virtualFile != null) { - final Sdk sdk = PythonSdkType.getSdk(element); - if (sdk != null) { - final VirtualFile skeletonsDir = findSkeletonsDir(sdk); - if (skeletonsDir != null && VirtualFileUtil.isAncestor(skeletonsDir, virtualFile, false)) { - return true; - } - } - } + + @Nullable + public static VirtualFile findAnyRemoteLibrary(@Nonnull Sdk sdk) { + return findLibraryDir(sdk, PythonSdkType.REMOTE_SOURCES_DIR_NAME, BinariesOrderRootType.getInstance()); } - return false; - } - - @Nullable - public static VirtualFile findSkeletonsDir(@Nonnull final Sdk sdk) { - return findLibraryDir(sdk, PythonSdkType.SKELETON_DIR_NAME, BinariesOrderRootType.getInstance()); - } - - @Nullable - public static VirtualFile findAnyRemoteLibrary(@Nonnull final Sdk sdk) { - return findLibraryDir(sdk, PythonSdkType.REMOTE_SOURCES_DIR_NAME, BinariesOrderRootType.getInstance()); - } - - private static VirtualFile findLibraryDir(Sdk sdk, String dirName, OrderRootType rootType) { - final VirtualFile[] virtualFiles = sdk.getRootProvider().getFiles(rootType); - for (VirtualFile virtualFile : virtualFiles) { - if (virtualFile.isValid() && virtualFile.getPath().contains(dirName)) { - return virtualFile; - } + + private static VirtualFile findLibraryDir(Sdk sdk, String dirName, OrderRootType rootType) { + VirtualFile[] virtualFiles = sdk.getRootProvider().getFiles(rootType); + for (VirtualFile virtualFile : virtualFiles) { + if (virtualFile.isValid() && virtualFile.getPath().contains(dirName)) { + return virtualFile; + } + } + return null; } - return null; - } } diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PythonEnvUtil.java b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PythonEnvUtil.java index 95987d89..def4f4ea 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PythonEnvUtil.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PythonEnvUtil.java @@ -30,114 +30,95 @@ /** * @author traff */ -public class PythonEnvUtil -{ - @SuppressWarnings("SpellCheckingInspection") - public static final String PYTHONPATH = "PYTHONPATH"; - @SuppressWarnings("SpellCheckingInspection") - public static final String PYTHONUNBUFFERED = "PYTHONUNBUFFERED"; - @SuppressWarnings("SpellCheckingInspection") - public static final String PYTHONIOENCODING = "PYTHONIOENCODING"; - @SuppressWarnings("SpellCheckingInspection") - public static final String IPYTHONENABLE = "IPYTHONENABLE"; - @SuppressWarnings("SpellCheckingInspection") - public static final String PYTHONDONTWRITEBYTECODE = "PYTHONDONTWRITEBYTECODE"; - @SuppressWarnings("SpellCheckingInspection") - public static final String PYVENV_LAUNCHER = "__PYVENV_LAUNCHER__"; +public class PythonEnvUtil { + @SuppressWarnings("SpellCheckingInspection") + public static final String PYTHONPATH = "PYTHONPATH"; + @SuppressWarnings("SpellCheckingInspection") + public static final String PYTHONUNBUFFERED = "PYTHONUNBUFFERED"; + @SuppressWarnings("SpellCheckingInspection") + public static final String PYTHONIOENCODING = "PYTHONIOENCODING"; + @SuppressWarnings("SpellCheckingInspection") + public static final String IPYTHONENABLE = "IPYTHONENABLE"; + @SuppressWarnings("SpellCheckingInspection") + public static final String PYTHONDONTWRITEBYTECODE = "PYTHONDONTWRITEBYTECODE"; + @SuppressWarnings("SpellCheckingInspection") + public static final String PYVENV_LAUNCHER = "__PYVENV_LAUNCHER__"; - private PythonEnvUtil() - { - } + private PythonEnvUtil() { + } - public static Map setPythonUnbuffered(@Nonnull Map env) - { - env.put(PYTHONUNBUFFERED, "1"); - return env; - } + public static Map setPythonUnbuffered(@Nonnull Map env) { + env.put(PYTHONUNBUFFERED, "1"); + return env; + } - public static Map setPythonIOEncoding(@Nonnull Map env, @Nonnull String encoding) - { - env.put(PYTHONIOENCODING, encoding); - return env; - } + public static Map setPythonIOEncoding(@Nonnull Map env, @Nonnull String encoding) { + env.put(PYTHONIOENCODING, encoding); + return env; + } - /** - * Resets the environment variables that affect the way the Python interpreter searches for its settings and libraries. - */ - public static Map resetHomePathChanges(@Nonnull String homePath, @Nonnull Map env) - { - if(System.getenv(PYVENV_LAUNCHER) != null || EnvironmentUtil.getEnvironmentMap().containsKey(PYVENV_LAUNCHER)) - { - env.put(PYVENV_LAUNCHER, homePath); - } - return env; - } + /** + * Resets the environment variables that affect the way the Python interpreter searches for its settings and libraries. + */ + public static Map resetHomePathChanges(@Nonnull String homePath, @Nonnull Map env) { + if (System.getenv(PYVENV_LAUNCHER) != null || EnvironmentUtil.getEnvironmentMap().containsKey(PYVENV_LAUNCHER)) { + env.put(PYVENV_LAUNCHER, homePath); + } + return env; + } - /** - * Appends a value to the end os a path-like environment variable, using system-dependent path separator. - * - * @param source path-like string to append to - * @param value what to append - * @return modified path-like string - */ - @Nonnull - public static String appendToPathEnvVar(@Nullable String source, @Nonnull String value) - { - if(StringUtil.isEmpty(source)) - { - return value; - } - Set paths = Sets.newHashSet(source.split(File.pathSeparator)); - return !paths.contains(value) ? source + File.pathSeparator + value : source; - } + /** + * Appends a value to the end os a path-like environment variable, using system-dependent path separator. + * + * @param source path-like string to append to + * @param value what to append + * @return modified path-like string + */ + @Nonnull + public static String appendToPathEnvVar(@Nullable String source, @Nonnull String value) { + if (StringUtil.isEmpty(source)) { + return value; + } + Set paths = Sets.newHashSet(source.split(File.pathSeparator)); + return !paths.contains(value) ? source + File.pathSeparator + value : source; + } - public static void addPathsToEnv(@Nonnull Map env, String key, @Nonnull Collection values) - { - for(String val : values) - { - addPathToEnv(env, key, val); - } - } + public static void addPathsToEnv(@Nonnull Map env, String key, @Nonnull Collection values) { + for (String val : values) { + addPathToEnv(env, key, val); + } + } - public static void addPathToEnv(@Nonnull Map env, String key, String value) - { - if(!StringUtil.isEmpty(value)) - { - if(env.containsKey(key)) - { - env.put(key, appendToPathEnvVar(env.get(key), value)); - } - else - { - env.put(key, value); - } - } - } + public static void addPathToEnv(@Nonnull Map env, String key, String value) { + if (!StringUtil.isEmpty(value)) { + if (env.containsKey(key)) { + env.put(key, appendToPathEnvVar(env.get(key), value)); + } + else { + env.put(key, value); + } + } + } - public static void addToPythonPath(@Nonnull Map env, @Nonnull Collection values) - { - addPathsToEnv(env, PYTHONPATH, values); - } + public static void addToPythonPath(@Nonnull Map env, @Nonnull Collection values) { + addPathsToEnv(env, PYTHONPATH, values); + } - public static void addToPythonPath(@Nonnull Map env, String value) - { - addPathToEnv(env, PYTHONPATH, value); - } + public static void addToPythonPath(@Nonnull Map env, String value) { + addPathToEnv(env, PYTHONPATH, value); + } - public static void mergePythonPath(@Nonnull Map from, @Nonnull Map to) - { - String value = from.get(PYTHONPATH); - if(value != null) - { - Set paths = Sets.newHashSet(value.split(File.pathSeparator)); - addToPythonPath(to, paths); - } - } + public static void mergePythonPath(@Nonnull Map from, @Nonnull Map to) { + String value = from.get(PYTHONPATH); + if (value != null) { + Set paths = Sets.newHashSet(value.split(File.pathSeparator)); + addToPythonPath(to, paths); + } + } - @Nonnull - public static Map setPythonDontWriteBytecode(@Nonnull Map env) - { - env.put(PYTHONDONTWRITEBYTECODE, "1"); - return env; - } + @Nonnull + public static Map setPythonDontWriteBytecode(@Nonnull Map env) { + env.put(PYTHONDONTWRITEBYTECODE, "1"); + return env; + } } diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PythonSdkAdditionalData.java b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PythonSdkAdditionalData.java index 2f05bdc6..d825e4f0 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PythonSdkAdditionalData.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PythonSdkAdditionalData.java @@ -29,11 +29,10 @@ import consulo.virtualFileSystem.VirtualFileManager; import consulo.virtualFileSystem.pointer.VirtualFilePointerContainer; import consulo.virtualFileSystem.pointer.VirtualFilePointerManager; -import org.jdom.Element; -import org.jetbrains.annotations.NonNls; - import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; +import org.jdom.Element; + import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -43,140 +42,135 @@ * @author traff */ public class PythonSdkAdditionalData implements SdkAdditionalData { - @NonNls - private static final String PATHS_ADDED_BY_USER_ROOT = "PATHS_ADDED_BY_USER_ROOT"; - @NonNls - private static final String PATH_ADDED_BY_USER = "PATH_ADDED_BY_USER"; - @NonNls - private static final String PATHS_REMOVED_BY_USER_ROOT = "PATHS_REMOVED_BY_USER_ROOT"; - @NonNls - private static final String PATH_REMOVED_BY_USER = "PATH_REMOVED_BY_USER"; - @NonNls - private static final String ASSOCIATED_PROJECT_PATH = "ASSOCIATED_PROJECT_PATH"; - - private final VirtualFilePointerContainer myAddedPaths; - private final VirtualFilePointerContainer myExcludedPaths; - - private final PythonSdkFlavor myFlavor; - private String myAssociatedProjectPath; - private boolean myAssociateWithNewProject; - - public PythonSdkAdditionalData(@Nullable PythonSdkFlavor flavor) { - myFlavor = flavor; - myAddedPaths = VirtualFilePointerManager.getInstance().createContainer(ApplicationManager.getApplication()); - myExcludedPaths = VirtualFilePointerManager.getInstance().createContainer(ApplicationManager.getApplication()); - } - - protected PythonSdkAdditionalData(@Nonnull PythonSdkAdditionalData from) { - myFlavor = from.getFlavor(); - myAddedPaths = from.myAddedPaths.clone(ApplicationManager.getApplication()); - myExcludedPaths = from.myExcludedPaths.clone(ApplicationManager.getApplication()); - myAssociatedProjectPath = from.myAssociatedProjectPath; - } - - @Override - public Object clone() throws CloneNotSupportedException { - return new PythonSdkAdditionalData(this); - } - - public void setAddedPathsFromVirtualFiles(@Nonnull Set addedPaths) { - myAddedPaths.killAll(); - for (VirtualFile file : addedPaths) { - myAddedPaths.add(file); - } - } - - public void setExcludedPathsFromVirtualFiles(@Nonnull Set addedPaths) { - myExcludedPaths.killAll(); - for (VirtualFile file : addedPaths) { - myExcludedPaths.add(file); - } - } - - public String getAssociatedProjectPath() { - return myAssociatedProjectPath; - } - - public void setAssociatedProjectPath(@Nullable String associatedProjectPath) { - myAssociatedProjectPath = associatedProjectPath; - } - - public void associateWithProject(Project project) { - final String path = project.getBasePath(); - if (path != null) { - myAssociatedProjectPath = FileUtil.toSystemIndependentName(path); - } - } - - public void associateWithNewProject() { - myAssociateWithNewProject = true; - } - - public void reassociateWithCreatedProject(Project project) { - if (myAssociateWithNewProject) { - associateWithProject(project); - } - } - - public void save(@Nonnull final Element rootElement) { - savePaths(rootElement, myAddedPaths, PATHS_ADDED_BY_USER_ROOT, PATH_ADDED_BY_USER); - savePaths(rootElement, myExcludedPaths, PATHS_REMOVED_BY_USER_ROOT, PATH_REMOVED_BY_USER); - - if (myAssociatedProjectPath != null) { - rootElement.setAttribute(ASSOCIATED_PROJECT_PATH, myAssociatedProjectPath); - } - } - - private static void savePaths(Element rootElement, VirtualFilePointerContainer paths, String root, String element) { - for (String addedPath : paths.getUrls()) { - final Element child = new Element(root); - child.setAttribute(element, addedPath); - rootElement.addContent(child); - } - } - - @Nullable - public PythonSdkFlavor getFlavor() { - return myFlavor; - } - - @Nonnull - public static PythonSdkAdditionalData load(Sdk sdk, @Nullable Element element) { - final PythonSdkAdditionalData data = new PythonSdkAdditionalData(PythonSdkFlavor.getFlavor(sdk.getHomePath())); - data.load(element); - return data; - } - - protected void load(@Nullable Element element) { - collectPaths(JDOMExternalizer.loadStringsList(element, PATHS_ADDED_BY_USER_ROOT, PATH_ADDED_BY_USER), myAddedPaths); - collectPaths(JDOMExternalizer.loadStringsList(element, PATHS_REMOVED_BY_USER_ROOT, PATH_REMOVED_BY_USER), myExcludedPaths); - if (element != null) { - setAssociatedProjectPath(element.getAttributeValue(ASSOCIATED_PROJECT_PATH)); - } - } - - private static void collectPaths(@Nonnull List paths, VirtualFilePointerContainer container) { - for (String path : paths) { - if (StringUtil.isEmpty(path)) { - continue; - } - final String protocol = VirtualFileManager.extractProtocol(path); - final String url = protocol != null ? path : VirtualFileManager.constructUrl(LocalFileSystem.PROTOCOL, path); - container.add(url); - } - } - - public Set getAddedPathFiles() { - return getPathsAsVirtualFiles(myAddedPaths); - } - - public Set getExcludedPathFiles() { - return getPathsAsVirtualFiles(myExcludedPaths); - } + private static final String PATHS_ADDED_BY_USER_ROOT = "PATHS_ADDED_BY_USER_ROOT"; + private static final String PATH_ADDED_BY_USER = "PATH_ADDED_BY_USER"; + private static final String PATHS_REMOVED_BY_USER_ROOT = "PATHS_REMOVED_BY_USER_ROOT"; + private static final String PATH_REMOVED_BY_USER = "PATH_REMOVED_BY_USER"; + private static final String ASSOCIATED_PROJECT_PATH = "ASSOCIATED_PROJECT_PATH"; + + private final VirtualFilePointerContainer myAddedPaths; + private final VirtualFilePointerContainer myExcludedPaths; + + private final PythonSdkFlavor myFlavor; + private String myAssociatedProjectPath; + private boolean myAssociateWithNewProject; + + public PythonSdkAdditionalData(@Nullable PythonSdkFlavor flavor) { + myFlavor = flavor; + myAddedPaths = VirtualFilePointerManager.getInstance().createContainer(ApplicationManager.getApplication()); + myExcludedPaths = VirtualFilePointerManager.getInstance().createContainer(ApplicationManager.getApplication()); + } + + protected PythonSdkAdditionalData(@Nonnull PythonSdkAdditionalData from) { + myFlavor = from.getFlavor(); + myAddedPaths = from.myAddedPaths.clone(ApplicationManager.getApplication()); + myExcludedPaths = from.myExcludedPaths.clone(ApplicationManager.getApplication()); + myAssociatedProjectPath = from.myAssociatedProjectPath; + } + + @Override + public Object clone() throws CloneNotSupportedException { + return new PythonSdkAdditionalData(this); + } + + public void setAddedPathsFromVirtualFiles(@Nonnull Set addedPaths) { + myAddedPaths.killAll(); + for (VirtualFile file : addedPaths) { + myAddedPaths.add(file); + } + } + + public void setExcludedPathsFromVirtualFiles(@Nonnull Set addedPaths) { + myExcludedPaths.killAll(); + for (VirtualFile file : addedPaths) { + myExcludedPaths.add(file); + } + } + + public String getAssociatedProjectPath() { + return myAssociatedProjectPath; + } + + public void setAssociatedProjectPath(@Nullable String associatedProjectPath) { + myAssociatedProjectPath = associatedProjectPath; + } + + public void associateWithProject(Project project) { + String path = project.getBasePath(); + if (path != null) { + myAssociatedProjectPath = FileUtil.toSystemIndependentName(path); + } + } + + public void associateWithNewProject() { + myAssociateWithNewProject = true; + } - private static Set getPathsAsVirtualFiles(VirtualFilePointerContainer paths) { - Set ret = new HashSet<>(); - Collections.addAll(ret, paths.getFiles()); - return ret; - } + public void reassociateWithCreatedProject(Project project) { + if (myAssociateWithNewProject) { + associateWithProject(project); + } + } + + public void save(@Nonnull Element rootElement) { + savePaths(rootElement, myAddedPaths, PATHS_ADDED_BY_USER_ROOT, PATH_ADDED_BY_USER); + savePaths(rootElement, myExcludedPaths, PATHS_REMOVED_BY_USER_ROOT, PATH_REMOVED_BY_USER); + + if (myAssociatedProjectPath != null) { + rootElement.setAttribute(ASSOCIATED_PROJECT_PATH, myAssociatedProjectPath); + } + } + + private static void savePaths(Element rootElement, VirtualFilePointerContainer paths, String root, String element) { + for (String addedPath : paths.getUrls()) { + Element child = new Element(root); + child.setAttribute(element, addedPath); + rootElement.addContent(child); + } + } + + @Nullable + public PythonSdkFlavor getFlavor() { + return myFlavor; + } + + @Nonnull + public static PythonSdkAdditionalData load(Sdk sdk, @Nullable Element element) { + PythonSdkAdditionalData data = new PythonSdkAdditionalData(PythonSdkFlavor.getFlavor(sdk.getHomePath())); + data.load(element); + return data; + } + + protected void load(@Nullable Element element) { + collectPaths(JDOMExternalizer.loadStringsList(element, PATHS_ADDED_BY_USER_ROOT, PATH_ADDED_BY_USER), myAddedPaths); + collectPaths(JDOMExternalizer.loadStringsList(element, PATHS_REMOVED_BY_USER_ROOT, PATH_REMOVED_BY_USER), myExcludedPaths); + if (element != null) { + setAssociatedProjectPath(element.getAttributeValue(ASSOCIATED_PROJECT_PATH)); + } + } + + private static void collectPaths(@Nonnull List paths, VirtualFilePointerContainer container) { + for (String path : paths) { + if (StringUtil.isEmpty(path)) { + continue; + } + String protocol = VirtualFileManager.extractProtocol(path); + String url = protocol != null ? path : VirtualFileManager.constructUrl(LocalFileSystem.PROTOCOL, path); + container.add(url); + } + } + + public Set getAddedPathFiles() { + return getPathsAsVirtualFiles(myAddedPaths); + } + + public Set getExcludedPathFiles() { + return getPathsAsVirtualFiles(myExcludedPaths); + } + + private static Set getPathsAsVirtualFiles(VirtualFilePointerContainer paths) { + Set ret = new HashSet<>(); + Collections.addAll(ret, paths.getFiles()); + return ret; + } } diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PythonSdkDetailsStep.java b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PythonSdkDetailsStep.java index 3046347e..1ba449e3 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PythonSdkDetailsStep.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PythonSdkDetailsStep.java @@ -20,8 +20,10 @@ import consulo.disposer.Disposer; import consulo.fileChooser.FileChooserDescriptor; import consulo.fileChooser.IdeaFileChooser; +import consulo.localize.LocalizeValue; import consulo.project.Project; -import consulo.project.ProjectBundle; +import consulo.project.localize.ProjectLocalize; +import consulo.ui.annotation.RequiredUIAccess; import consulo.ui.ex.awt.DialogWrapper; import consulo.ui.ex.awt.Messages; import consulo.ui.ex.popup.*; @@ -29,9 +31,9 @@ import consulo.util.io.FileUtil; import consulo.virtualFileSystem.LocalFileSystem; import consulo.virtualFileSystem.VirtualFile; - import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; + import javax.swing.*; import java.awt.*; import java.util.ArrayList; @@ -41,257 +43,279 @@ import java.util.function.Consumer; public class PythonSdkDetailsStep extends BaseListPopupStep { - @Nullable - private DialogWrapper myMore; - private final Project myProject; - private final Component myOwnerComponent; - private final Sdk[] myExistingSdks; - private final Consumer mySdkAddedCallback; - - private static final String LOCAL = PyBundle.message("sdk.details.step.add.local"); - private static final String MORE = PyBundle.message("sdk.details.step.show.more"); - private boolean myNewProject; - - public static void show(final Project project, - final Sdk[] existingSdks, - @Nullable final DialogWrapper moreDialog, - JComponent ownerComponent, - final Point popupPoint, - final Consumer sdkAddedCallback) { - show(project, existingSdks, moreDialog, ownerComponent, popupPoint, sdkAddedCallback, false); - - } - - public static void show(final Project project, - final Sdk[] existingSdks, - @Nullable final DialogWrapper moreDialog, - JComponent ownerComponent, - final Point popupPoint, - final Consumer sdkAddedCallback, - boolean isNewProject) { - final PythonSdkDetailsStep sdkHomesStep = new PythonSdkDetailsStep(project, moreDialog, ownerComponent, existingSdks, sdkAddedCallback); - sdkHomesStep.setNewProject(isNewProject); - final ListPopup popup = JBPopupFactory.getInstance().createListPopup(sdkHomesStep); - popup.showInScreenCoordinates(ownerComponent, popupPoint); - } - - private void setNewProject(boolean isNewProject) { - myNewProject = isNewProject; - } - - public PythonSdkDetailsStep(@Nullable final Project project, - @Nullable final DialogWrapper moreDialog, - @Nonnull final Component ownerComponent, - @Nonnull final Sdk[] existingSdks, - @Nonnull final Consumer sdkAddedCallback) { - super(null, getAvailableOptions(moreDialog != null)); - myProject = project; - myMore = moreDialog; - myOwnerComponent = ownerComponent; - myExistingSdks = existingSdks; - mySdkAddedCallback = sdkAddedCallback; - } - - private static List getAvailableOptions(boolean showMore) { - final List options = new ArrayList<>(); - options.add(LOCAL); -// options.add(VIRTUALENV); -// if (PyCondaPackageService.getSystemCondaExecutable() != null) { -// options.add(CONDA); -// } - - if (showMore) { - options.add(MORE); + @Nullable + private DialogWrapper myMore; + private final Project myProject; + private final Component myOwnerComponent; + private final Sdk[] myExistingSdks; + private final Consumer mySdkAddedCallback; + + private static final String LOCAL = PyBundle.message("sdk.details.step.add.local"); + private static final String MORE = PyBundle.message("sdk.details.step.show.more"); + private boolean myNewProject; + + public static void show( + Project project, + Sdk[] existingSdks, + @Nullable DialogWrapper moreDialog, + JComponent ownerComponent, + Point popupPoint, + Consumer sdkAddedCallback + ) { + show(project, existingSdks, moreDialog, ownerComponent, popupPoint, sdkAddedCallback, false); + } - return options; - } - - @Nullable - @Override - public ListSeparator getSeparatorAbove(String value) { - return MORE.equals(value) ? new ListSeparator() : null; - } - - private void optionSelected(final String selectedValue) { - if (!MORE.equals(selectedValue) && myMore != null) { - Disposer.dispose(myMore.getDisposable()); + + public static void show( + Project project, + Sdk[] existingSdks, + @Nullable DialogWrapper moreDialog, + JComponent ownerComponent, + Point popupPoint, + Consumer sdkAddedCallback, + boolean isNewProject + ) { + PythonSdkDetailsStep sdkHomesStep = + new PythonSdkDetailsStep(project, moreDialog, ownerComponent, existingSdks, sdkAddedCallback); + sdkHomesStep.setNewProject(isNewProject); + ListPopup popup = JBPopupFactory.getInstance().createListPopup(sdkHomesStep); + popup.showInScreenCoordinates(ownerComponent, popupPoint); } - if (LOCAL.equals(selectedValue)) { - createLocalSdk(); + + private void setNewProject(boolean isNewProject) { + myNewProject = isNewProject; } - else if (myMore != null) { - myMore.show(); + + public PythonSdkDetailsStep( + @Nullable Project project, + @Nullable DialogWrapper moreDialog, + @Nonnull Component ownerComponent, + @Nonnull Sdk[] existingSdks, + @Nonnull Consumer sdkAddedCallback + ) { + super(null, getAvailableOptions(moreDialog != null)); + myProject = project; + myMore = moreDialog; + myOwnerComponent = ownerComponent; + myExistingSdks = existingSdks; + mySdkAddedCallback = sdkAddedCallback; } - } - - private void createLocalSdk() { - createSdk(myProject, myExistingSdks, mySdkAddedCallback, false, PythonSdkType.getInstance()); - } - - public static void createSdk(@Nullable final Project project, - final Sdk[] existingSdks, - final Consumer onSdkCreatedCallBack, - final boolean createIfExists, - final SdkType... sdkTypes) { - if (sdkTypes.length == 0) { - onSdkCreatedCallBack.accept(null); - return; + + private static List getAvailableOptions(boolean showMore) { + List options = new ArrayList<>(); + options.add(LOCAL); +// options.add(VIRTUALENV); +// if (PyCondaPackageService.getSystemCondaExecutable() != null) { +// options.add(CONDA); +// } + + if (showMore) { + options.add(MORE); + } + return options; + } + + @Nullable + @Override + public ListSeparator getSeparatorAbove(String value) { + return MORE.equals(value) ? new ListSeparator() : null; } - FileChooserDescriptor descriptor = createCompositeDescriptor(sdkTypes); - VirtualFile suggestedDir = getSuggestedSdkRoot(sdkTypes[0]); - IdeaFileChooser.chooseFiles(descriptor, project, suggestedDir, new IdeaFileChooser.FileChooserConsumer() { - @Override - public void accept(List selectedFiles) { - for (SdkType sdkType : sdkTypes) { - final String path = selectedFiles.get(0).getPath(); - if (sdkType.isValidSdkHome(path)) { - Sdk newSdk = null; - if (!createIfExists) { - for (Sdk sdk : existingSdks) { - if (path.equals(sdk.getHomePath())) { - newSdk = sdk; - break; + @RequiredUIAccess + private void optionSelected(String selectedValue) { + if (!MORE.equals(selectedValue) && myMore != null) { + Disposer.dispose(myMore.getDisposable()); + } + if (LOCAL.equals(selectedValue)) { + createLocalSdk(); + } + else if (myMore != null) { + myMore.show(); + } + } + + private void createLocalSdk() { + createSdk(myProject, myExistingSdks, mySdkAddedCallback, false, PythonSdkType.getInstance()); + } + + public static void createSdk( + @Nullable Project project, + Sdk[] existingSdks, + Consumer onSdkCreatedCallBack, + boolean createIfExists, + SdkType... sdkTypes + ) { + if (sdkTypes.length == 0) { + onSdkCreatedCallBack.accept(null); + return; + } + + FileChooserDescriptor descriptor = createCompositeDescriptor(sdkTypes); + VirtualFile suggestedDir = getSuggestedSdkRoot(sdkTypes[0]); + IdeaFileChooser.chooseFiles( + descriptor, + project, + suggestedDir, + new IdeaFileChooser.FileChooserConsumer() { + @Override + @RequiredUIAccess + public void accept(List selectedFiles) { + for (SdkType sdkType : sdkTypes) { + String path = selectedFiles.get(0).getPath(); + if (sdkType.isValidSdkHome(path)) { + Sdk newSdk = null; + if (!createIfExists) { + for (Sdk sdk : existingSdks) { + if (path.equals(sdk.getHomePath())) { + newSdk = sdk; + break; + } + } + } + if (newSdk == null) { + newSdk = setupSdk(existingSdks, selectedFiles.get(0), sdkType, false, null, null); + } + onSdkCreatedCallBack.accept(newSdk); + return; + } + } + onSdkCreatedCallBack.accept(null); + } + + @Override + public void cancelled() { + onSdkCreatedCallBack.accept(null); } - } } - if (newSdk == null) { - newSdk = setupSdk(existingSdks, selectedFiles.get(0), sdkType, false, null, null); + ); + } + + @Nullable + @RequiredUIAccess + public static Sdk setupSdk( + @Nonnull Sdk[] allSdks, + @Nonnull VirtualFile homeDir, + SdkType sdkType, + boolean silent, + @Nullable SdkAdditionalData additionalData, + @Nullable String customSdkSuggestedName + ) { + Sdk sdk; + try { + sdk = createSdk(allSdks, homeDir, sdkType, additionalData, customSdkSuggestedName); + + sdkType.setupSdkPaths(sdk); + } + catch (Exception e) { + if (!silent) { + Messages.showErrorDialog( + "Error configuring SDK: " + e.getMessage() + ".\n" + + "Please make sure that " + FileUtil.toSystemDependentName(homeDir.getPath()) + + " is a valid home path for this SDK type.", + "Error Configuring SDK" + ); } - onSdkCreatedCallBack.accept(newSdk); - return; - } + return null; } - onSdkCreatedCallBack.accept(null); - } - - @Override - public void cancelled() { - onSdkCreatedCallBack.accept(null); - } - }); - } - - @Nullable - public static Sdk setupSdk(@Nonnull Sdk[] allSdks, - @Nonnull VirtualFile homeDir, - final SdkType sdkType, - final boolean silent, - @Nullable final SdkAdditionalData additionalData, - @Nullable final String customSdkSuggestedName) { - final Sdk sdk; - try { - sdk = createSdk(allSdks, homeDir, sdkType, additionalData, customSdkSuggestedName); - - sdkType.setupSdkPaths((Sdk)sdk); + return sdk; } - catch (Exception e) { - if (!silent) { - Messages.showErrorDialog("Error configuring SDK: " + - e.getMessage() + - ".\nPlease make sure that " + - FileUtil.toSystemDependentName(homeDir.getPath()) + - " is a valid home path for this SDK type.", "Error Configuring SDK"); - } - return null; + + public static Sdk createSdk( + @Nonnull Sdk[] allSdks, + @Nonnull VirtualFile homeDir, + SdkType sdkType, + @Nullable SdkAdditionalData additionalData, + @Nullable String customSdkSuggestedName + ) { + List sdksList = Arrays.asList(allSdks); + + String sdkPath = sdkType.sdkPath(homeDir); + + Sdk[] sdks = sdksList.toArray(new Sdk[sdksList.size()]); + String sdkName = customSdkSuggestedName == null + ? SdkUtil.createUniqueSdkName(sdkType, sdkPath, sdks) + : SdkUtil.createUniqueSdkName(customSdkSuggestedName, sdks); + + Sdk sdk = SdkTable.getInstance().createSdk(sdkName, sdkType); + + SdkModificator sdkModificator = sdk.getSdkModificator(); + + if (additionalData != null) { + // additional initialization. + // E.g. some ruby sdks must be initialized before + // setupSdkPaths() method invocation + sdkModificator.setSdkAdditionalData(additionalData); + } + + sdkModificator.setHomePath(sdkPath); + sdkModificator.commitChanges(); + + return sdk; } - return sdk; - } - - public static Sdk createSdk(@Nonnull Sdk[] allSdks, - @Nonnull VirtualFile homeDir, - SdkType sdkType, - @Nullable SdkAdditionalData additionalData, - @Nullable String customSdkSuggestedName) { - final List sdksList = Arrays.asList(allSdks); - - String sdkPath = sdkType.sdkPath(homeDir); - - Sdk[] sdks = sdksList.toArray(new Sdk[sdksList.size()]); - final String sdkName = customSdkSuggestedName == null ? SdkUtil.createUniqueSdkName(sdkType, - sdkPath, - sdks) : SdkUtil.createUniqueSdkName( - customSdkSuggestedName, - sdks); - - Sdk sdk = SdkTable.getInstance().createSdk(sdkName, sdkType); - - SdkModificator sdkModificator = sdk.getSdkModificator(); - - if (additionalData != null) { - // additional initialization. - // E.g. some ruby sdks must be initialized before - // setupSdkPaths() method invocation - sdkModificator.setSdkAdditionalData(additionalData); + + private static FileChooserDescriptor createCompositeDescriptor(SdkType... sdkTypes) { + return new FileChooserDescriptor(sdkTypes[0].getHomeChooserDescriptor()) { + @Override + public void validateSelectedFiles(VirtualFile[] files) throws Exception { + if (files.length > 0) { + for (SdkType type : sdkTypes) { + if (type.isValidSdkHome(files[0].getPath())) { + return; + } + } + } + String presentableName = sdkTypes[0].getPresentableName(); + LocalizeValue message = files.length > 0 && files[0].isDirectory() + ? ProjectLocalize.sdkConfigureHomeInvalidError(presentableName) + : ProjectLocalize.sdkConfigureHomeFileInvalidError(presentableName); + throw new Exception(message.get()); + } + }; } - sdkModificator.setHomePath(sdkPath); - sdkModificator.commitChanges(); + @Nullable + public static VirtualFile getSuggestedSdkRoot(@Nonnull SdkType sdkType) { + String homePath = ContainerUtil.getFirstItem(sdkType.suggestHomePaths()); + return homePath == null ? null : LocalFileSystem.getInstance().findFileByPath(homePath); + } - return sdk; - } + @Nonnull + public static List filterExistingPaths(@Nonnull SdkType sdkType, Collection sdkHomes, Sdk[] sdks) { + List result = new ArrayList<>(); + for (String sdkHome : sdkHomes) { + if (findByPath(sdkType, sdks, sdkHome) == null) { + result.add(sdkHome); + } + } + return result; + } - private static FileChooserDescriptor createCompositeDescriptor(final SdkType... sdkTypes) { - return new FileChooserDescriptor(sdkTypes[0].getHomeChooserDescriptor()) { - @Override - public void validateSelectedFiles(final VirtualFile[] files) throws Exception { - if (files.length > 0) { - for (SdkType type : sdkTypes) { - if (type.isValidSdkHome(files[0].getPath())) { - return; + @Nullable + private static Sdk findByPath(@Nonnull SdkType sdkType, @Nonnull Sdk[] sdks, @Nonnull String sdkHome) { + for (Sdk sdk : sdks) { + String path = sdk.getHomePath(); + if (sdk.getSdkType() == sdkType && path != null + && FileUtil.pathsEqual(FileUtil.toSystemIndependentName(path), FileUtil.toSystemIndependentName(sdkHome))) { + return sdk; } - } } - String key = - files.length > 0 && files[0].isDirectory() ? "sdk.configure.home.invalid.error" : "sdk.configure.home.file.invalid.error"; - throw new Exception(ProjectBundle.message(key, sdkTypes[0].getPresentableName())); - } - }; - } - - @Nullable - public static VirtualFile getSuggestedSdkRoot(@Nonnull SdkType sdkType) { - final String homePath = ContainerUtil.getFirstItem(sdkType.suggestHomePaths()); - return homePath == null ? null : LocalFileSystem.getInstance().findFileByPath(homePath); - } - - @Nonnull - public static List filterExistingPaths(@Nonnull SdkType sdkType, Collection sdkHomes, final Sdk[] sdks) { - List result = new ArrayList<>(); - for (String sdkHome : sdkHomes) { - if (findByPath(sdkType, sdks, sdkHome) == null) { - result.add(sdkHome); - } + return null; } - return result; - } - - @Nullable - private static Sdk findByPath(@Nonnull SdkType sdkType, @Nonnull Sdk[] sdks, @Nonnull String sdkHome) { - for (Sdk sdk : sdks) { - final String path = sdk.getHomePath(); - if (sdk.getSdkType() == sdkType && path != null && - FileUtil.pathsEqual(FileUtil.toSystemIndependentName(path), FileUtil.toSystemIndependentName(sdkHome))) { - return sdk; - } + + @Override + public boolean canBeHidden(String value) { + return true; } - return null; - } - - @Override - public boolean canBeHidden(String value) { - return true; - } - - @Override - public void canceled() { - if (getFinalRunnable() == null && myMore != null) { - Disposer.dispose(myMore.getDisposable()); + + @Override + public void canceled() { + if (getFinalRunnable() == null && myMore != null) { + Disposer.dispose(myMore.getDisposable()); + } } - } - @Override - public PopupStep onChosen(final String selectedValue, boolean finalChoice) { - return doFinalStep(() -> optionSelected(selectedValue)); - } + @Override + public PopupStep onChosen(String selectedValue, boolean finalChoice) { + return doFinalStep(() -> optionSelected(selectedValue)); + } } diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PythonSdkType.java b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PythonSdkType.java index 59ac0157..56d72cd5 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PythonSdkType.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PythonSdkType.java @@ -15,54 +15,53 @@ */ package com.jetbrains.python.impl.sdk; -import com.jetbrains.python.impl.PyBundle; import com.jetbrains.python.PyNames; import com.jetbrains.python.impl.PythonHelper; -import com.jetbrains.python.impl.PythonIcons; import com.jetbrains.python.impl.packaging.PyCondaPackageManagerImpl; -import com.jetbrains.python.psi.LanguageLevel; import com.jetbrains.python.impl.psi.impl.PyBuiltinCache; import com.jetbrains.python.impl.psi.search.PyProjectScopeBuilder; import com.jetbrains.python.impl.sdk.flavors.CPythonSdkFlavor; import com.jetbrains.python.impl.sdk.flavors.PythonSdkFlavor; +import com.jetbrains.python.psi.LanguageLevel; +import consulo.annotation.access.RequiredReadAction; import consulo.annotation.component.ExtensionImpl; import consulo.application.Application; import consulo.application.ApplicationManager; -import consulo.application.util.SystemInfo; import consulo.application.util.UserHomeFileUtil; import consulo.content.OrderRootType; import consulo.content.base.BinariesOrderRootType; import consulo.content.bundle.*; import consulo.dataContext.DataManager; import consulo.fileChooser.FileChooserDescriptor; -import consulo.language.editor.CommonDataKeys; import consulo.language.psi.PsiElement; import consulo.language.util.ModuleUtilCore; import consulo.logging.Logger; import consulo.module.Module; +import consulo.platform.Platform; +import consulo.platform.PlatformOperatingSystem; import consulo.process.cmd.GeneralCommandLine; import consulo.process.util.ProcessOutput; import consulo.project.Project; import consulo.project.ui.notification.NotificationGroup; +import consulo.python.impl.icon.PythonImplIconGroup; +import consulo.python.impl.localize.PyLocalize; import consulo.python.module.extension.PyModuleExtension; import consulo.ui.image.Image; import consulo.util.collection.ArrayUtil; import consulo.util.collection.ContainerUtil; import consulo.util.dataholder.Key; import consulo.util.io.FileUtil; -import consulo.util.lang.CharFilter; import consulo.util.lang.Comparing; import consulo.util.lang.StringUtil; import consulo.virtualFileSystem.LocalFileSystem; import consulo.virtualFileSystem.VirtualFile; import consulo.virtualFileSystem.archive.ArchiveVfsUtil; import consulo.virtualFileSystem.util.VirtualFileUtil; +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; import jakarta.inject.Inject; import org.jdom.Element; -import org.jetbrains.annotations.NonNls; -import jakarta.annotation.Nonnull; -import jakarta.annotation.Nullable; import javax.swing.*; import java.awt.*; import java.io.File; @@ -83,720 +82,724 @@ */ @ExtensionImpl public final class PythonSdkType extends SdkType { - public static final String REMOTE_SOURCES_DIR_NAME = "remote_sources"; - private static final Logger LOG = Logger.getInstance(PythonSdkType.class); - private static final String[] WINDOWS_EXECUTABLE_SUFFIXES = new String[]{ - "cmd", - "exe", - "bat", - "com" - }; - - static final int MINUTE = 60 * 1000; // 60 seconds, used with script timeouts - public static final NotificationGroup SKELETONS_TOPIC = NotificationGroup.balloonGroup("Python Skeletons"); - private static final String[] DIRS_WITH_BINARY = new String[]{ - "", - "bin", - "Scripts" - }; - private static final String[] UNIX_BINARY_NAMES = new String[]{ - "jython", - "pypy", - "python" - }; - private static final String[] WIN_BINARY_NAMES = new String[]{ - "jython.bat", - "ipy.exe", - "pypy.exe", - "python.exe" - }; - - private static final Key> SDK_CREATOR_COMPONENT_KEY = Key.create("#com.jetbrains.python.sdk.creatorComponent"); - public static final Predicate REMOTE_SDK_PREDICATE = sdk -> isRemote(sdk); - - public static PythonSdkType getInstance() { - return SdkType.EP_NAME.findExtension(PythonSdkType.class); - } - - @Inject - PythonSdkType() { - super("Python SDK"); - } - - @Override - public Image getIcon() { - return PythonIcons.Python.Python; - } - - @Nonnull - @Override - public String getHelpTopic() { - return "reference.project.structure.sdk.python"; - } - - /** - * Name of directory where skeleton files (despite the value) are stored. - */ - public static final String SKELETON_DIR_NAME = "python_stubs"; - - /** - * @return name of builtins skeleton file; for Python 2.x it is '{@code __builtins__.py}'. - */ - @Nonnull - @NonNls - public static String getBuiltinsFileName(@Nonnull Sdk sdk) { - final LanguageLevel level = getLanguageLevelForSdk(sdk); - return level.isOlderThan(LanguageLevel.PYTHON30) ? PyBuiltinCache.BUILTIN_FILE : PyBuiltinCache.BUILTIN_FILE_3K; - } - - @NonNls - @Nullable - public String suggestHomePath() { - final String pythonFromPath = findPythonInPath(); - if (pythonFromPath != null) { - return pythonFromPath; - } - for (PythonSdkFlavor flavor : PythonSdkFlavor.getApplicableFlavors()) { - TreeSet candidates = createVersionSet(); - candidates.addAll(flavor.suggestHomePaths()); - if (!candidates.isEmpty()) { - // return latest version - String[] candidateArray = ArrayUtil.toStringArray(candidates); - return candidateArray[candidateArray.length - 1]; - } - } - return null; - } - - @Nullable - private static String findPythonInPath() { - final String defaultCommand = SystemInfo.isWindows ? "python.exe" : "python"; - final String path = System.getenv("PATH"); - for (String root : path.split(File.pathSeparator)) { - final File file = new File(root, defaultCommand); - if (file.exists()) { - try { - return file.getCanonicalPath(); - } - catch (IOException ignored) { - } - } - } - return null; - } - - @Nonnull - @Override - public Collection suggestHomePaths() { - List candidates = new ArrayList<>(); - for (PythonSdkFlavor flavor : PythonSdkFlavor.getApplicableFlavors()) { - candidates.addAll(flavor.suggestHomePaths()); - } - return candidates; - } - - private static TreeSet createVersionSet() { - return new TreeSet<>((o1, o2) -> findDigits(o1).compareTo(findDigits(o2))); - } - - private static String findDigits(String s) { - int pos = StringUtil.findFirst(s, new CharFilter() { - @Override - public boolean accept(char ch) { - return Character.isDigit(ch); - } - }); - if (pos >= 0) { - return s.substring(pos); - } - return s; - } - - public static boolean hasValidSdk() { - for (Sdk sdk : SdkTable.getInstance().getAllSdks()) { - if (sdk.getSdkType() instanceof PythonSdkType) { - return true; - } - } - return false; - } - - @Override - public boolean isValidSdkHome(@Nullable final String path) { - return PythonSdkFlavor.getFlavor(path) != null; - } - - public static boolean isInvalid(@Nonnull Sdk sdk) { - final VirtualFile interpreter = sdk.getHomeDirectory(); - return interpreter == null || !interpreter.exists(); - } - - @Deprecated - public static boolean isRemote(@Nullable Sdk sdk) { - return false; - } - - @Deprecated - public static boolean isVagrant(@Nullable Sdk sdk) { - return false; - } - - public static boolean isRemote(@Nullable String sdkPath) { - return isRemote(findSdkByPath(sdkPath)); - } - - @Nonnull - @Override - public FileChooserDescriptor getHomeChooserDescriptor() { - final boolean isWindows = SystemInfo.isWindows; - return new FileChooserDescriptor(true, false, false, false, false, false) { - @Override - public void validateSelectedFiles(VirtualFile[] files) throws Exception { - if (files.length != 0) { - if (!isValidSdkHome(files[0].getPath())) { - throw new Exception(PyBundle.message("sdk.error.invalid.interpreter.name.$0", files[0].getName())); - } - } - } - - @Override - public boolean isFileVisible(VirtualFile file, boolean showHiddenFiles) { - // TODO: add a better, customizable filtering - if (!file.isDirectory()) { - if (isWindows) { - String path = file.getPath(); - boolean looksExecutable = false; - for (String ext : WINDOWS_EXECUTABLE_SUFFIXES) { - if (path.endsWith(ext)) { - looksExecutable = true; - break; - } - } - return looksExecutable && super.isFileVisible(file, showHiddenFiles); - } - } - return super.isFileVisible(file, showHiddenFiles); - } - }.withTitle(PyBundle.message("sdk.select.path")).withShowHiddenFiles(SystemInfo.isUnix); - } - - public boolean supportsCustomCreateUI() { - return true; - } - - public void showCustomCreateUI(@Nonnull SdkModel sdkModel, - @Nonnull final JComponent parentComponent, - @Nonnull final Consumer sdkCreatedCallback) { - Project project = DataManager.getInstance().getDataContext(parentComponent).getData(CommonDataKeys.PROJECT); - final PointerInfo pointerInfo = MouseInfo.getPointerInfo(); - if (pointerInfo == null) { - return; - } - final Point point = pointerInfo.getLocation(); - PythonSdkDetailsStep.show(project, sdkModel.getSdks(), null, parentComponent, point, sdk -> { - if (sdk != null) { - sdk.putUserData(SDK_CREATOR_COMPONENT_KEY, new WeakReference<>(parentComponent)); - sdkCreatedCallback.accept(sdk); - } - }); - } - - public static boolean isVirtualEnv(@Nonnull Sdk sdk) { - final String path = sdk.getHomePath(); - return isVirtualEnv(path); - } - - public static boolean isVirtualEnv(String path) { - return path != null && getVirtualEnvRoot(path) != null; - } - - public static boolean isCondaVirtualEnv(Sdk sdk) { - final String path = sdk.getHomePath(); - return path != null && PyCondaPackageManagerImpl.isCondaVEnv(sdk); - } - - @Nullable - public Sdk getVirtualEnvBaseSdk(Sdk sdk) { - if (isVirtualEnv(sdk)) { - final PythonSdkFlavor flavor = PythonSdkFlavor.getFlavor(sdk); - final String version = getVersionString(sdk); - if (flavor != null && version != null) { - for (Sdk baseSdk : getAllSdks()) { - if (!isRemote(baseSdk)) { - final PythonSdkFlavor baseFlavor = PythonSdkFlavor.getFlavor(baseSdk); - if (!isVirtualEnv(baseSdk) && flavor.equals(baseFlavor) && version.equals(getVersionString(baseSdk))) { - return baseSdk; - } - } - } - } - } - return null; - } - - /** - * @param binaryPath must point to a Python interpreter - * @return if the surroundings look like a virtualenv installation, its root is returned (normally the grandparent of binaryPath). - */ - @Nullable - public static File getVirtualEnvRoot(@Nonnull final String binaryPath) { - final File bin = new File(binaryPath).getParentFile(); - if (bin != null) { - final String rootPath = bin.getParent(); - if (rootPath != null) { - final File root = new File(rootPath); - final File activateThis = new File(bin, "activate_this.py"); - // binaryPath should contain an 'activate' script, and root should have bin (with us) and include and libp - if (activateThis.exists()) { - final File activate = findExecutableFile(bin, "activate"); - if (activate != null) { - return root; - } - } - // Python 3.3 virtualenvs can be found as described in PEP 405 - final String pyVenvCfg = "pyvenv.cfg"; - if (new File(root, pyVenvCfg).exists() || new File(bin, pyVenvCfg).exists()) { - return root; - } - } - } - return null; - } - - /** - * Finds a file that looks executable: an .exe or .cmd under windows, plain file under *nix. - * - * @param parent directory to look at - * @param name name of the executable without suffix - * @return File representing the executable, or null. - */ - @Nullable - public static File findExecutableFile(File parent, String name) { - if (SystemInfo.isWindows) { - for (String suffix : WINDOWS_EXECUTABLE_SUFFIXES) { - File file = new File(parent, name + "." + suffix); - if (file.exists()) { - return file; - } - } - } - else if (SystemInfo.isUnix) { - File file = new File(parent, name); - if (file.exists()) { - return file; - } - } - return null; - } - - /** - * Alters PATH so that a virtualenv is activated, if present. - * - * @param commandLine what to patch - * @param sdkHome home of SDK we're using - * @param passParentEnvironment iff true, include system paths in PATH - */ - public static void patchCommandLineForVirtualenv(GeneralCommandLine commandLine, String sdkHome, boolean passParentEnvironment) { - File virtualEnvRoot = getVirtualEnvRoot(sdkHome); - if (virtualEnvRoot != null) { - @NonNls final String PATH = "PATH"; - - // prepend virtualenv bin if it's not already on PATH - File bin = new File(virtualEnvRoot, "bin"); - if (!bin.exists()) { - bin = new File(virtualEnvRoot, "Scripts"); // on Windows - } - String virtualenvBin = bin.getPath(); - - Map env = commandLine.getEnvironment(); - String pathValue; - if (env.containsKey(PATH)) { - pathValue = PythonEnvUtil.appendToPathEnvVar(env.get(PATH), virtualenvBin); - } - else if (passParentEnvironment) { - // append to PATH - pathValue = PythonEnvUtil.appendToPathEnvVar(System.getenv(PATH), virtualenvBin); - } - else { - pathValue = virtualenvBin; - } - env.put(PATH, pathValue); - } - } - - @Override - public String suggestSdkName(final String currentSdkName, final String sdkHome) { - String name = getVersionString(sdkHome); - return suggestSdkNameFromVersion(sdkHome, name); - } - - private static String suggestSdkNameFromVersion(String sdkHome, String version) { - sdkHome = FileUtil.toSystemDependentName(sdkHome); - final String shortHomeName = UserHomeFileUtil.getLocationRelativeToUserHome(sdkHome); - if (version != null) { - File virtualEnvRoot = getVirtualEnvRoot(sdkHome); - if (virtualEnvRoot != null) { - version += " virtualenv at " + UserHomeFileUtil.getLocationRelativeToUserHome(virtualEnvRoot.getAbsolutePath()); - } - else { - version += " (" + shortHomeName + ")"; - } - } - else { - version = "Unknown at " + shortHomeName; - } // last resort - return version; - } - - @Override - @Nullable - public AdditionalDataConfigurable createAdditionalDataConfigurable(@Nonnull final SdkModel sdkModel, - @Nonnull final SdkModificator sdkModificator) { - return null; - } - - @Override - public void saveAdditionalData(@Nonnull final SdkAdditionalData additionalData, @Nonnull final Element additional) { - if (additionalData instanceof PythonSdkAdditionalData) { - ((PythonSdkAdditionalData)additionalData).save(additional); - } - } - - @Override - public SdkAdditionalData loadAdditionalData(@Nonnull final Sdk currentSdk, final Element additional) { - return PythonSdkAdditionalData.load(currentSdk, additional); - } - - public static boolean isSkeletonsPath(String path) { - return path.contains(SKELETON_DIR_NAME); - } - - @Override - @Nonnull - @NonNls - public String getPresentableName() { - return "Python"; - } - - @Override - public String sdkPath(@Nonnull VirtualFile homePath) { - String path = super.sdkPath(homePath); - PythonSdkFlavor flavor = PythonSdkFlavor.getFlavor(path); - if (flavor != null) { - VirtualFile sdkPath = flavor.getSdkPath(homePath); - if (sdkPath != null) { - return FileUtil.toSystemDependentName(sdkPath.getPath()); - } - } - return FileUtil.toSystemDependentName(path); - } - - - @Override - public void setupSdkPaths(@Nonnull Sdk sdk) { - PythonSdkUpdater.updateLocalSdkPaths(sdk, null, null); - } - - @Nonnull - public static VirtualFile getSdkRootVirtualFile(@Nonnull VirtualFile path) { - String suffix = path.getExtension(); - if (suffix != null) { - suffix = suffix.toLowerCase(); // Why on earth empty suffix is null and not ""? - } - if ((!path.isDirectory()) && ("zip".equals(suffix) || "egg".equals(suffix))) { - // a .zip / .egg file must have its root extracted first - final VirtualFile jar = ArchiveVfsUtil.getJarRootForLocalFile(path); - if (jar != null) { - return jar; - } - } - return path; - } - - /** - * Returns skeletons location on the local machine. Independent of SDK credentials type (e.g. ssh, Vagrant, Docker or else). - */ - public static String getSkeletonsPath(String basePath, String sdkHome) { - String sep = File.separator; - return getSkeletonsRootPath(basePath) + sep + FileUtil.toSystemIndependentName(sdkHome).hashCode() + sep; - } - - public static String getSkeletonsRootPath(String basePath) { - return basePath + File.separator + SKELETON_DIR_NAME; - } - - @Nonnull - public static List getSysPath(String bin_path) throws InvalidSdkException { - String working_dir = new File(bin_path).getParent(); - Application application = ApplicationManager.getApplication(); - if (application != null && !application.isUnitTestMode()) { - return getSysPathsFromScript(bin_path); - } - else { // mock sdk - List ret = new ArrayList<>(1); - ret.add(working_dir); - return ret; - } - } - - @Nonnull - public static List getSysPathsFromScript(@Nonnull String binaryPath) throws InvalidSdkException { - // to handle the situation when PYTHONPATH contains ., we need to run the syspath script in the - // directory of the script itself - otherwise the dir in which we run the script (e.g. /usr/bin) will be added to SDK path - GeneralCommandLine cmd = PythonHelper.SYSPATH.newCommandLine(binaryPath, new ArrayList<>()); - final ProcessOutput runResult = - PySdkUtil.getProcessOutput(cmd, new File(binaryPath).getParent(), getVirtualEnvExtraEnv(binaryPath), MINUTE); - if (!runResult.checkSuccess(LOG)) { - throw new InvalidSdkException(String.format("Failed to determine Python's sys.path value:\nSTDOUT: %s\nSTDERR: %s", - runResult.getStdout(), - runResult.getStderr())); - } - return runResult.getStdoutLines(); - } - - /** - * Returns a piece of env good as additional env for getProcessOutput. - */ - @Nullable - public static Map getVirtualEnvExtraEnv(@Nonnull String binaryPath) { - final File root = getVirtualEnvRoot(binaryPath); - if (root != null) { - return Map.of("PATH", root.toString()); - } - return null; - } - - @Override - @Nullable - public String getVersionString(final String sdkHome) { - final PythonSdkFlavor flavor = PythonSdkFlavor.getFlavor(sdkHome); - return flavor != null ? flavor.getVersionString(sdkHome) : null; - } - - public static List getAllSdks() { - return SdkTable.getInstance().getSdksOfType(getInstance()); - } - - @Nullable - public static Sdk findPythonSdk(@Nullable Module module) { - if (module == null) { - return null; - } - return ModuleUtilCore.getSdk(module, PyModuleExtension.class); - } - - @Nullable - public static Sdk findSdkByPath(@Nullable String path) { - if (path != null) { - return findSdkByPath(getAllSdks(), path); - } - return null; - } - - @Nullable - public static Sdk findSdkByPath(List sdkList, @Nullable String path) { - if (path != null) { - for (Sdk sdk : sdkList) { - if (sdk != null && FileUtil.pathsEqual(path, sdk.getHomePath())) { - return sdk; - } - } - } - return null; - } - - @Nonnull - public static LanguageLevel getLanguageLevelForSdk(@Nullable Sdk sdk) { - if (sdk != null && sdk.getSdkType() instanceof PythonSdkType) { - final PythonSdkFlavor flavor = PythonSdkFlavor.getFlavor(sdk); - if (flavor != null) { - return flavor.getLanguageLevel(sdk); - } - } - return LanguageLevel.getDefault(); - } - - @Override - public boolean isRootTypeApplicable(@Nonnull final OrderRootType type) { - return type == BinariesOrderRootType.getInstance(); - } - - @Override - public boolean sdkHasValidPath(@Nonnull Sdk sdk) { - if (PySdkUtil.isRemote(sdk)) { - return true; - } - VirtualFile homeDir = sdk.getHomeDirectory(); - return homeDir != null && homeDir.isValid(); - } - - public static boolean isStdLib(VirtualFile vFile, Sdk pythonSdk) { - if (pythonSdk != null) { - final VirtualFile libDir = PyProjectScopeBuilder.findLibDir(pythonSdk); - if (libDir != null && VirtualFileUtil.isAncestor(libDir, vFile, false)) { - return isNotSitePackages(vFile, libDir); - } - final VirtualFile venvLibDir = PyProjectScopeBuilder.findVirtualEnvLibDir(pythonSdk); - if (venvLibDir != null && VirtualFileUtil.isAncestor(venvLibDir, vFile, false)) { - return isNotSitePackages(vFile, venvLibDir); - } - final VirtualFile skeletonsDir = PySdkUtil.findSkeletonsDir(pythonSdk); - if (skeletonsDir != null && Comparing.equal(vFile.getParent(), - skeletonsDir)) { // note: this will pick up some of the binary libraries not in packages + public static final String REMOTE_SOURCES_DIR_NAME = "remote_sources"; + private static final Logger LOG = Logger.getInstance(PythonSdkType.class); + private static final String[] WINDOWS_EXECUTABLE_SUFFIXES = new String[]{ + "cmd", + "exe", + "bat", + "com" + }; + + static final int MINUTE = 60 * 1000; // 60 seconds, used with script timeouts + public static final NotificationGroup SKELETONS_TOPIC = NotificationGroup.balloonGroup("Python Skeletons"); + private static final String[] DIRS_WITH_BINARY = new String[]{ + "", + "bin", + "Scripts" + }; + private static final String[] UNIX_BINARY_NAMES = new String[]{ + "jython", + "pypy", + "python" + }; + private static final String[] WIN_BINARY_NAMES = new String[]{ + "jython.bat", + "ipy.exe", + "pypy.exe", + "python.exe" + }; + + private static final Key> SDK_CREATOR_COMPONENT_KEY = Key.create("#com.jetbrains.python.sdk.creatorComponent"); + public static final Predicate REMOTE_SDK_PREDICATE = sdk -> isRemote(sdk); + + public static PythonSdkType getInstance() { + return Application.get().getExtensionPoint(SdkType.class).findExtensionOrFail(PythonSdkType.class); + } + + @Inject + PythonSdkType() { + super("Python SDK"); + } + + @Nonnull + @Override + public Image getIcon() { + return PythonImplIconGroup.pythonPython(); + } + + @Nonnull + @Override + public String getHelpTopic() { + return "reference.project.structure.sdk.python"; + } + + /** + * Name of directory where skeleton files (despite the value) are stored. + */ + public static final String SKELETON_DIR_NAME = "python_stubs"; + + /** + * @return name of builtins skeleton file; for Python 2.x it is '{@code __builtins__.py}'. + */ + @Nonnull + public static String getBuiltinsFileName(@Nonnull Sdk sdk) { + LanguageLevel level = getLanguageLevelForSdk(sdk); + return level.isOlderThan(LanguageLevel.PYTHON30) ? PyBuiltinCache.BUILTIN_FILE : PyBuiltinCache.BUILTIN_FILE_3K; + } + + @Nullable + public String suggestHomePath() { + String pythonFromPath = findPythonInPath(); + if (pythonFromPath != null) { + return pythonFromPath; + } + for (PythonSdkFlavor flavor : PythonSdkFlavor.getApplicableFlavors()) { + TreeSet candidates = createVersionSet(); + candidates.addAll(flavor.suggestHomePaths()); + if (!candidates.isEmpty()) { + // return latest version + String[] candidateArray = ArrayUtil.toStringArray(candidates); + return candidateArray[candidateArray.length - 1]; + } + } + return null; + } + + @Nullable + private static String findPythonInPath() { + String defaultCommand = Platform.current().os().isWindows() ? "python.exe" : "python"; + String path = System.getenv("PATH"); + for (String root : path.split(File.pathSeparator)) { + File file = new File(root, defaultCommand); + if (file.exists()) { + try { + return file.getCanonicalPath(); + } + catch (IOException ignored) { + } + } + } + return null; + } + + @Nonnull + @Override + public Collection suggestHomePaths() { + List candidates = new ArrayList<>(); + for (PythonSdkFlavor flavor : PythonSdkFlavor.getApplicableFlavors()) { + candidates.addAll(flavor.suggestHomePaths()); + } + return candidates; + } + + private static TreeSet createVersionSet() { + return new TreeSet<>((o1, o2) -> findDigits(o1).compareTo(findDigits(o2))); + } + + private static String findDigits(String s) { + int pos = StringUtil.findFirst(s, Character::isDigit); + if (pos >= 0) { + return s.substring(pos); + } + return s; + } + + public static boolean hasValidSdk() { + for (Sdk sdk : SdkTable.getInstance().getAllSdks()) { + if (sdk.getSdkType() instanceof PythonSdkType) { + return true; + } + } + return false; + } + + @Override + public boolean isValidSdkHome(@Nullable String path) { + return PythonSdkFlavor.getFlavor(path) != null; + } + + public static boolean isInvalid(@Nonnull Sdk sdk) { + VirtualFile interpreter = sdk.getHomeDirectory(); + return interpreter == null || !interpreter.exists(); + } + + @Deprecated + public static boolean isRemote(@Nullable Sdk sdk) { + return false; + } + + @Deprecated + public static boolean isVagrant(@Nullable Sdk sdk) { + return false; + } + + public static boolean isRemote(@Nullable String sdkPath) { + return isRemote(findSdkByPath(sdkPath)); + } + + @Nonnull + @Override + public FileChooserDescriptor getHomeChooserDescriptor() { + boolean isWindows = Platform.current().os().isWindows(); + return new FileChooserDescriptor(true, false, false, false, false, false) { + @Override + public void validateSelectedFiles(VirtualFile[] files) throws Exception { + if (files.length != 0) { + if (!isValidSdkHome(files[0].getPath())) { + throw new Exception(PyLocalize.sdkErrorInvalidInterpreterName$0(files[0].getName()).get()); + } + } + } + + @Override + public boolean isFileVisible(VirtualFile file, boolean showHiddenFiles) { + // TODO: add a better, customizable filtering + if (!file.isDirectory()) { + if (isWindows) { + String path = file.getPath(); + boolean looksExecutable = false; + for (String ext : WINDOWS_EXECUTABLE_SUFFIXES) { + if (path.endsWith(ext)) { + looksExecutable = true; + break; + } + } + return looksExecutable && super.isFileVisible(file, showHiddenFiles); + } + } + return super.isFileVisible(file, showHiddenFiles); + } + }.withTitleValue(PyLocalize.sdkSelectPath()).withShowHiddenFiles(Platform.current().os().isUnix()); + } + + public boolean supportsCustomCreateUI() { return true; - } - } - return false; - } - - private static boolean isNotSitePackages(VirtualFile vFile, VirtualFile libDir) { - final VirtualFile sitePackages = libDir.findChild(PyNames.SITE_PACKAGES); - if (sitePackages != null && VirtualFileUtil.isAncestor(sitePackages, vFile, false)) { - return false; - } - return true; - } - - @Nullable - public static Sdk findPython2Sdk(@Nullable Module module) { - final Sdk moduleSDK = findPythonSdk(module); - if (moduleSDK != null && !getLanguageLevelForSdk(moduleSDK).isPy3K()) { - return moduleSDK; - } - return findPython2Sdk(getAllSdks()); - } - - @Nullable - public static Sdk findPython2Sdk(@Nonnull List sdks) { - for (Sdk sdk : ContainerUtil.sorted(sdks, PreferredSdkComparator.INSTANCE)) { - if (!getLanguageLevelForSdk(sdk).isPy3K()) { - return sdk; - } - } - return null; - } - - @Nullable - public static Sdk findLocalCPython(@Nullable Module module) { - final Sdk moduleSDK = findPythonSdk(module); - if (moduleSDK != null && !isRemote(moduleSDK) && PythonSdkFlavor.getFlavor(moduleSDK) instanceof CPythonSdkFlavor) { - return moduleSDK; - } - for (Sdk sdk : ContainerUtil.sorted(getAllSdks(), PreferredSdkComparator.INSTANCE)) { - if (!isRemote(sdk)) { - return sdk; - } - } - return null; - } - - public static List getAllLocalCPythons() { - return getAllSdks().stream().filter(REMOTE_SDK_PREDICATE.negate()).collect(Collectors.toList()); - } - - @Nullable - public static String getPythonExecutable(@Nonnull String rootPath) { - final File rootFile = new File(rootPath); - if (rootFile.isFile()) { - return rootFile.getAbsolutePath(); - } - for (String dir : DIRS_WITH_BINARY) { - final File subDir; - if (StringUtil.isEmpty(dir)) { - subDir = rootFile; - } - else { - subDir = new File(rootFile, dir); - } - if (!subDir.isDirectory()) { - continue; - } - for (String binaryName : getBinaryNames()) { - final File executable = new File(subDir, binaryName); - if (executable.isFile()) { - return executable.getAbsolutePath(); - } - } - } - return null; - } - - @Nullable - public static String getExecutablePath(@Nonnull final String homeDirectory, @Nonnull String name) { - File binPath = new File(homeDirectory); - File binDir = binPath.getParentFile(); - if (binDir == null) { - return null; - } - File runner = new File(binDir, name); - if (runner.exists()) { - return LocalFileSystem.getInstance().extractPresentableUrl(runner.getPath()); - } - runner = new File(new File(binDir, "Scripts"), name); - if (runner.exists()) { - return LocalFileSystem.getInstance().extractPresentableUrl(runner.getPath()); - } - runner = new File(new File(binDir.getParentFile(), "Scripts"), name); - if (runner.exists()) { - return LocalFileSystem.getInstance().extractPresentableUrl(runner.getPath()); - } - runner = new File(new File(binDir.getParentFile(), "local"), name); - if (runner.exists()) { - return LocalFileSystem.getInstance().extractPresentableUrl(runner.getPath()); - } - runner = new File(new File(new File(binDir.getParentFile(), "local"), "bin"), name); - if (runner.exists()) { - return LocalFileSystem.getInstance().extractPresentableUrl(runner.getPath()); - } - - // if interpreter is a symlink - Path homePath = Path.of(homeDirectory); - if (Files.isSymbolicLink(homePath)) { - String resolvedPath = null; - try { - resolvedPath = Files.readSymbolicLink(homePath).toString(); - } - catch (IOException ignored) { - } - - if (resolvedPath != null) { - return getExecutablePath(resolvedPath, name); - } - } - // Search in standard unix path - runner = new File(new File("/usr", "bin"), name); - if (runner.exists()) { - return LocalFileSystem.getInstance().extractPresentableUrl(runner.getPath()); - } - runner = new File(new File(new File("/usr", "local"), "bin"), name); - if (runner.exists()) { - return LocalFileSystem.getInstance().extractPresentableUrl(runner.getPath()); - } - return null; - } - - private static String[] getBinaryNames() { - if (SystemInfo.isUnix) { - return UNIX_BINARY_NAMES; - } - else { - return WIN_BINARY_NAMES; - } - } - - @Nullable - public static Sdk getSdk(@Nonnull final PsiElement element) { - return ModuleUtilCore.getSdk(element, PyModuleExtension.class); - } - - @Nonnull - public static String getSdkKey(@Nonnull Sdk sdk) { - return sdk.getName(); - } - - @Nullable - public static Sdk findSdkByKey(@Nonnull String key) { - return SdkTable.getInstance().findSdk(key); - } -} + } + + public void showCustomCreateUI( + @Nonnull SdkModel sdkModel, + @Nonnull JComponent parentComponent, + @Nonnull Consumer sdkCreatedCallback + ) { + Project project = DataManager.getInstance().getDataContext(parentComponent).getData(Project.KEY); + PointerInfo pointerInfo = MouseInfo.getPointerInfo(); + if (pointerInfo == null) { + return; + } + Point point = pointerInfo.getLocation(); + PythonSdkDetailsStep.show( + project, + sdkModel.getSdks(), + null, + parentComponent, + point, + sdk -> { + if (sdk != null) { + sdk.putUserData(SDK_CREATOR_COMPONENT_KEY, new WeakReference<>(parentComponent)); + sdkCreatedCallback.accept(sdk); + } + } + ); + } + + public static boolean isVirtualEnv(@Nonnull Sdk sdk) { + String path = sdk.getHomePath(); + return isVirtualEnv(path); + } + + public static boolean isVirtualEnv(String path) { + return path != null && getVirtualEnvRoot(path) != null; + } + + public static boolean isCondaVirtualEnv(Sdk sdk) { + String path = sdk.getHomePath(); + return path != null && PyCondaPackageManagerImpl.isCondaVEnv(sdk); + } + + @Nullable + public Sdk getVirtualEnvBaseSdk(Sdk sdk) { + if (isVirtualEnv(sdk)) { + PythonSdkFlavor flavor = PythonSdkFlavor.getFlavor(sdk); + String version = getVersionString(sdk); + if (flavor != null && version != null) { + for (Sdk baseSdk : getAllSdks()) { + if (!isRemote(baseSdk)) { + PythonSdkFlavor baseFlavor = PythonSdkFlavor.getFlavor(baseSdk); + if (!isVirtualEnv(baseSdk) && flavor.equals(baseFlavor) && version.equals(getVersionString(baseSdk))) { + return baseSdk; + } + } + } + } + } + return null; + } + + /** + * @param binaryPath must point to a Python interpreter + * @return if the surroundings look like a virtualenv installation, its root is returned (normally the grandparent of binaryPath). + */ + @Nullable + public static File getVirtualEnvRoot(@Nonnull String binaryPath) { + File bin = new File(binaryPath).getParentFile(); + if (bin != null) { + String rootPath = bin.getParent(); + if (rootPath != null) { + File root = new File(rootPath); + File activateThis = new File(bin, "activate_this.py"); + // binaryPath should contain an 'activate' script, and root should have bin (with us) and include and libp + if (activateThis.exists()) { + File activate = findExecutableFile(bin, "activate"); + if (activate != null) { + return root; + } + } + // Python 3.3 virtualenvs can be found as described in PEP 405 + String pyVenvCfg = "pyvenv.cfg"; + if (new File(root, pyVenvCfg).exists() || new File(bin, pyVenvCfg).exists()) { + return root; + } + } + } + return null; + } + + /** + * Finds a file that looks executable: an .exe or .cmd under windows, plain file under *nix. + * + * @param parent directory to look at + * @param name name of the executable without suffix + * @return File representing the executable, or null. + */ + @Nullable + public static File findExecutableFile(File parent, String name) { + PlatformOperatingSystem os = Platform.current().os(); + if (os.isWindows()) { + for (String suffix : WINDOWS_EXECUTABLE_SUFFIXES) { + File file = new File(parent, name + "." + suffix); + if (file.exists()) { + return file; + } + } + } + else if (os.isUnix()) { + File file = new File(parent, name); + if (file.exists()) { + return file; + } + } + return null; + } + + /** + * Alters PATH so that a virtualenv is activated, if present. + * + * @param commandLine what to patch + * @param sdkHome home of SDK we're using + * @param passParentEnvironment iff true, include system paths in PATH + */ + public static void patchCommandLineForVirtualenv(GeneralCommandLine commandLine, String sdkHome, boolean passParentEnvironment) { + File virtualEnvRoot = getVirtualEnvRoot(sdkHome); + if (virtualEnvRoot != null) { + String PATH = "PATH"; + + // prepend virtualenv bin if it's not already on PATH + File bin = new File(virtualEnvRoot, "bin"); + if (!bin.exists()) { + bin = new File(virtualEnvRoot, "Scripts"); // on Windows + } + String virtualenvBin = bin.getPath(); + + Map env = commandLine.getEnvironment(); + String pathValue; + if (env.containsKey(PATH)) { + pathValue = PythonEnvUtil.appendToPathEnvVar(env.get(PATH), virtualenvBin); + } + else if (passParentEnvironment) { + // append to PATH + pathValue = PythonEnvUtil.appendToPathEnvVar(System.getenv(PATH), virtualenvBin); + } + else { + pathValue = virtualenvBin; + } + env.put(PATH, pathValue); + } + } + + @Override + public String suggestSdkName(String currentSdkName, String sdkHome) { + String name = getVersionString(sdkHome); + return suggestSdkNameFromVersion(sdkHome, name); + } + + private static String suggestSdkNameFromVersion(String sdkHome, String version) { + sdkHome = FileUtil.toSystemDependentName(sdkHome); + String shortHomeName = UserHomeFileUtil.getLocationRelativeToUserHome(sdkHome); + if (version != null) { + File virtualEnvRoot = getVirtualEnvRoot(sdkHome); + if (virtualEnvRoot != null) { + version += " virtualenv at " + UserHomeFileUtil.getLocationRelativeToUserHome(virtualEnvRoot.getAbsolutePath()); + } + else { + version += " (" + shortHomeName + ")"; + } + } + else { + version = "Unknown at " + shortHomeName; + } // last resort + return version; + } + + @Override + @Nullable + public AdditionalDataConfigurable createAdditionalDataConfigurable( + @Nonnull SdkModel sdkModel, + @Nonnull SdkModificator sdkModificator + ) { + return null; + } + + @Override + public void saveAdditionalData(@Nonnull SdkAdditionalData additionalData, @Nonnull Element additional) { + if (additionalData instanceof PythonSdkAdditionalData pythonSdkAdditionalData) { + pythonSdkAdditionalData.save(additional); + } + } + + @Override + public SdkAdditionalData loadAdditionalData(@Nonnull Sdk currentSdk, Element additional) { + return PythonSdkAdditionalData.load(currentSdk, additional); + } + + public static boolean isSkeletonsPath(String path) { + return path.contains(SKELETON_DIR_NAME); + } + + @Override + @Nonnull + public String getPresentableName() { + return "Python"; + } + + @Override + public String sdkPath(@Nonnull VirtualFile homePath) { + String path = super.sdkPath(homePath); + PythonSdkFlavor flavor = PythonSdkFlavor.getFlavor(path); + if (flavor != null) { + VirtualFile sdkPath = flavor.getSdkPath(homePath); + if (sdkPath != null) { + return FileUtil.toSystemDependentName(sdkPath.getPath()); + } + } + return FileUtil.toSystemDependentName(path); + } + + + @Override + public void setupSdkPaths(@Nonnull Sdk sdk) { + PythonSdkUpdater.updateLocalSdkPaths(sdk, null, null); + } + + @Nonnull + public static VirtualFile getSdkRootVirtualFile(@Nonnull VirtualFile path) { + String suffix = path.getExtension(); + if (suffix != null) { + suffix = suffix.toLowerCase(); // Why on earth empty suffix is null and not ""? + } + if ((!path.isDirectory()) && ("zip".equals(suffix) || "egg".equals(suffix))) { + // a .zip / .egg file must have its root extracted first + VirtualFile jar = ArchiveVfsUtil.getJarRootForLocalFile(path); + if (jar != null) { + return jar; + } + } + return path; + } + + /** + * Returns skeletons location on the local machine. Independent of SDK credentials type (e.g. ssh, Vagrant, Docker or else). + */ + public static String getSkeletonsPath(String basePath, String sdkHome) { + String sep = File.separator; + return getSkeletonsRootPath(basePath) + sep + FileUtil.toSystemIndependentName(sdkHome).hashCode() + sep; + } + + public static String getSkeletonsRootPath(String basePath) { + return basePath + File.separator + SKELETON_DIR_NAME; + } + + @Nonnull + public static List getSysPath(String bin_path) throws InvalidSdkException { + String working_dir = new File(bin_path).getParent(); + Application application = ApplicationManager.getApplication(); + if (application != null && !application.isUnitTestMode()) { + return getSysPathsFromScript(bin_path); + } + else { // mock sdk + List ret = new ArrayList<>(1); + ret.add(working_dir); + return ret; + } + } + + @Nonnull + public static List getSysPathsFromScript(@Nonnull String binaryPath) throws InvalidSdkException { + // to handle the situation when PYTHONPATH contains ., we need to run the syspath script in the + // directory of the script itself - otherwise the dir in which we run the script (e.g. /usr/bin) will be added to SDK path + GeneralCommandLine cmd = PythonHelper.SYSPATH.newCommandLine(binaryPath, new ArrayList<>()); + ProcessOutput runResult = + PySdkUtil.getProcessOutput(cmd, new File(binaryPath).getParent(), getVirtualEnvExtraEnv(binaryPath), MINUTE); + if (!runResult.checkSuccess(LOG)) { + throw new InvalidSdkException(String.format( + "Failed to determine Python's sys.path value:\nSTDOUT: %s\nSTDERR: %s", + runResult.getStdout(), + runResult.getStderr() + )); + } + return runResult.getStdoutLines(); + } + + /** + * Returns a piece of env good as additional env for getProcessOutput. + */ + @Nullable + public static Map getVirtualEnvExtraEnv(@Nonnull String binaryPath) { + File root = getVirtualEnvRoot(binaryPath); + if (root != null) { + return Map.of("PATH", root.toString()); + } + return null; + } + + @Override + @Nullable + public String getVersionString(String sdkHome) { + PythonSdkFlavor flavor = PythonSdkFlavor.getFlavor(sdkHome); + return flavor != null ? flavor.getVersionString(sdkHome) : null; + } + + public static List getAllSdks() { + return SdkTable.getInstance().getSdksOfType(getInstance()); + } + + @Nullable + public static Sdk findPythonSdk(@Nullable Module module) { + if (module == null) { + return null; + } + return ModuleUtilCore.getSdk(module, PyModuleExtension.class); + } + + @Nullable + public static Sdk findSdkByPath(@Nullable String path) { + if (path != null) { + return findSdkByPath(getAllSdks(), path); + } + return null; + } + + @Nullable + public static Sdk findSdkByPath(List sdkList, @Nullable String path) { + if (path != null) { + for (Sdk sdk : sdkList) { + if (sdk != null && FileUtil.pathsEqual(path, sdk.getHomePath())) { + return sdk; + } + } + } + return null; + } + + @Nonnull + public static LanguageLevel getLanguageLevelForSdk(@Nullable Sdk sdk) { + if (sdk != null && sdk.getSdkType() instanceof PythonSdkType) { + PythonSdkFlavor flavor = PythonSdkFlavor.getFlavor(sdk); + if (flavor != null) { + return flavor.getLanguageLevel(sdk); + } + } + return LanguageLevel.getDefault(); + } + + @Override + public boolean isRootTypeApplicable(@Nonnull OrderRootType type) { + return type == BinariesOrderRootType.getInstance(); + } + + @Override + public boolean sdkHasValidPath(@Nonnull Sdk sdk) { + if (PySdkUtil.isRemote(sdk)) { + return true; + } + VirtualFile homeDir = sdk.getHomeDirectory(); + return homeDir != null && homeDir.isValid(); + } + + public static boolean isStdLib(VirtualFile vFile, Sdk pythonSdk) { + if (pythonSdk != null) { + VirtualFile libDir = PyProjectScopeBuilder.findLibDir(pythonSdk); + if (libDir != null && VirtualFileUtil.isAncestor(libDir, vFile, false)) { + return isNotSitePackages(vFile, libDir); + } + VirtualFile venvLibDir = PyProjectScopeBuilder.findVirtualEnvLibDir(pythonSdk); + if (venvLibDir != null && VirtualFileUtil.isAncestor(venvLibDir, vFile, false)) { + return isNotSitePackages(vFile, venvLibDir); + } + VirtualFile skeletonsDir = PySdkUtil.findSkeletonsDir(pythonSdk); + if (skeletonsDir != null && Comparing.equal(vFile.getParent(), skeletonsDir)) { + // note: this will pick up some of the binary libraries not in packages + return true; + } + } + return false; + } + + private static boolean isNotSitePackages(VirtualFile vFile, VirtualFile libDir) { + VirtualFile sitePackages = libDir.findChild(PyNames.SITE_PACKAGES); + return sitePackages == null || !VirtualFileUtil.isAncestor(sitePackages, vFile, false); + } + @Nullable + public static Sdk findPython2Sdk(@Nullable Module module) { + Sdk moduleSDK = findPythonSdk(module); + if (moduleSDK != null && !getLanguageLevelForSdk(moduleSDK).isPy3K()) { + return moduleSDK; + } + return findPython2Sdk(getAllSdks()); + } + + @Nullable + public static Sdk findPython2Sdk(@Nonnull List sdks) { + for (Sdk sdk : ContainerUtil.sorted(sdks, PreferredSdkComparator.INSTANCE)) { + if (!getLanguageLevelForSdk(sdk).isPy3K()) { + return sdk; + } + } + return null; + } + + @Nullable + public static Sdk findLocalCPython(@Nullable Module module) { + Sdk moduleSDK = findPythonSdk(module); + if (moduleSDK != null && !isRemote(moduleSDK) && PythonSdkFlavor.getFlavor(moduleSDK) instanceof CPythonSdkFlavor) { + return moduleSDK; + } + for (Sdk sdk : ContainerUtil.sorted(getAllSdks(), PreferredSdkComparator.INSTANCE)) { + if (!isRemote(sdk)) { + return sdk; + } + } + return null; + } + + public static List getAllLocalCPythons() { + return getAllSdks().stream().filter(REMOTE_SDK_PREDICATE.negate()).collect(Collectors.toList()); + } + + @Nullable + public static String getPythonExecutable(@Nonnull String rootPath) { + File rootFile = new File(rootPath); + if (rootFile.isFile()) { + return rootFile.getAbsolutePath(); + } + for (String dir : DIRS_WITH_BINARY) { + File subDir; + if (StringUtil.isEmpty(dir)) { + subDir = rootFile; + } + else { + subDir = new File(rootFile, dir); + } + if (!subDir.isDirectory()) { + continue; + } + for (String binaryName : getBinaryNames()) { + File executable = new File(subDir, binaryName); + if (executable.isFile()) { + return executable.getAbsolutePath(); + } + } + } + return null; + } + + @Nullable + public static String getExecutablePath(@Nonnull String homeDirectory, @Nonnull String name) { + File binPath = new File(homeDirectory); + File binDir = binPath.getParentFile(); + if (binDir == null) { + return null; + } + File runner = new File(binDir, name); + if (runner.exists()) { + return LocalFileSystem.getInstance().extractPresentableUrl(runner.getPath()); + } + runner = new File(new File(binDir, "Scripts"), name); + if (runner.exists()) { + return LocalFileSystem.getInstance().extractPresentableUrl(runner.getPath()); + } + runner = new File(new File(binDir.getParentFile(), "Scripts"), name); + if (runner.exists()) { + return LocalFileSystem.getInstance().extractPresentableUrl(runner.getPath()); + } + runner = new File(new File(binDir.getParentFile(), "local"), name); + if (runner.exists()) { + return LocalFileSystem.getInstance().extractPresentableUrl(runner.getPath()); + } + runner = new File(new File(new File(binDir.getParentFile(), "local"), "bin"), name); + if (runner.exists()) { + return LocalFileSystem.getInstance().extractPresentableUrl(runner.getPath()); + } + + // if interpreter is a symlink + Path homePath = Path.of(homeDirectory); + if (Files.isSymbolicLink(homePath)) { + String resolvedPath = null; + try { + resolvedPath = Files.readSymbolicLink(homePath).toString(); + } + catch (IOException ignored) { + } + + if (resolvedPath != null) { + return getExecutablePath(resolvedPath, name); + } + } + // Search in standard unix path + runner = new File(new File("/usr", "bin"), name); + if (runner.exists()) { + return LocalFileSystem.getInstance().extractPresentableUrl(runner.getPath()); + } + runner = new File(new File(new File("/usr", "local"), "bin"), name); + if (runner.exists()) { + return LocalFileSystem.getInstance().extractPresentableUrl(runner.getPath()); + } + return null; + } + + private static String[] getBinaryNames() { + if (Platform.current().os().isUnix()) { + return UNIX_BINARY_NAMES; + } + else { + return WIN_BINARY_NAMES; + } + } + + @Nullable + @RequiredReadAction + public static Sdk getSdk(@Nonnull PsiElement element) { + return ModuleUtilCore.getSdk(element, PyModuleExtension.class); + } + + @Nonnull + public static String getSdkKey(@Nonnull Sdk sdk) { + return sdk.getName(); + } + + @Nullable + public static Sdk findSdkByKey(@Nonnull String key) { + return SdkTable.getInstance().findSdk(key); + } +} diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PythonSdkUpdater.java b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PythonSdkUpdater.java index d4c9937a..6b645338 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PythonSdkUpdater.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/PythonSdkUpdater.java @@ -18,14 +18,13 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.collect.Sets; -import com.jetbrains.python.impl.PyBundle; import com.jetbrains.python.impl.codeInsight.userSkeletons.PyUserSkeletonsUtil; import com.jetbrains.python.impl.psi.PyUtil; import com.jetbrains.python.impl.sdk.skeletons.PySkeletonRefresher; import com.jetbrains.python.packaging.PyPackageManager; +import consulo.annotation.access.RequiredReadAction; import consulo.annotation.component.ExtensionImpl; import consulo.application.Application; -import consulo.application.ApplicationManager; import consulo.application.progress.ProgressIndicator; import consulo.application.progress.ProgressManager; import consulo.application.progress.Task; @@ -35,20 +34,23 @@ import consulo.content.bundle.SdkAdditionalData; import consulo.content.bundle.SdkModificator; import consulo.ide.impl.idea.util.concurrency.BlockingSet; +import consulo.localize.LocalizeValue; import consulo.logging.Logger; import consulo.module.Module; import consulo.module.ModuleManager; import consulo.process.ExecutionException; import consulo.project.Project; import consulo.project.startup.PostStartupActivity; +import consulo.python.impl.localize.PyLocalize; import consulo.ui.UIAccess; +import consulo.ui.annotation.RequiredUIAccess; import consulo.ui.ex.awt.Messages; import consulo.util.io.FileUtil; import consulo.virtualFileSystem.StandardFileSystems; import consulo.virtualFileSystem.VirtualFile; - import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; + import java.awt.*; import java.io.File; import java.util.List; @@ -74,20 +76,25 @@ public class PythonSdkUpdater implements PostStartupActivity { * Refreshes the SDKs of the modules for the open project after some delay. */ @Override - public void runActivity(@Nonnull final Project project, UIAccess uiAccess) { - uiAccess.getScheduler() - .schedule(() -> ProgressManager.getInstance().run(new Task.Backgroundable(project, "Updating Python Paths", false) { - @Override - public void run(@Nonnull ProgressIndicator indicator) { - final Project project = (Project) getProject(); - if (project.isDisposed()) { - return; - } - for (final Sdk sdk : getPythonSdks(project)) { - update(sdk, null, project, null); + public void runActivity(@Nonnull Project project, UIAccess uiAccess) { + uiAccess.getScheduler().schedule( + () -> ProgressManager.getInstance().run( + new Task.Backgroundable(project, LocalizeValue.localizeTODO("Updating Python Paths"), false) { + @Override + public void run(@Nonnull ProgressIndicator indicator) { + Project project = (Project)getProject(); + if (project.isDisposed()) { + return; + } + for (Sdk sdk : getPythonSdks(project)) { + update(sdk, null, project, null); + } } } - }), INITIAL_ACTIVITY_DELAY, TimeUnit.MILLISECONDS); + ), + INITIAL_ACTIVITY_DELAY, + TimeUnit.MILLISECONDS + ); } /** @@ -104,11 +111,14 @@ public void run(@Nonnull ProgressIndicator indicator) { * passed as an argument accessed from the AWT thread * @return false if there was an immediate problem updating the SDK. Other problems are reported as log entries and balloons. */ - public static boolean update(@Nonnull Sdk sdk, - @Nullable SdkModificator sdkModificator, - @Nullable final Project project, - @Nullable final Component ownerComponent) { - final String key = PythonSdkType.getSdkKey(sdk); + @RequiredReadAction + public static boolean update( + @Nonnull Sdk sdk, + @Nullable SdkModificator sdkModificator, + @Nullable Project project, + @Nullable Component ownerComponent + ) { + String key = PythonSdkType.getSdkKey(sdk); synchronized (ourLock) { ourScheduledToRefresh.add(key); } @@ -116,8 +126,7 @@ public static boolean update(@Nonnull Sdk sdk, return false; } - - final Application application = ApplicationManager.getApplication(); + Application application = Application.get(); if (application.isUnitTestMode()) { // All actions we take after this line are dedicated to skeleton update process. Not all tests do need them. To find test API that @@ -125,7 +134,7 @@ public static boolean update(@Nonnull Sdk sdk, return true; } - @SuppressWarnings("ThrowableInstanceNeverThrown") final Throwable methodCallStacktrace = new Throwable(); + @SuppressWarnings("ThrowableInstanceNeverThrown") Throwable methodCallStacktrace = new Throwable(); application.invokeLater(() -> { synchronized (ourLock) { if (!ourScheduledToRefresh.contains(key)) { @@ -133,26 +142,29 @@ public static boolean update(@Nonnull Sdk sdk, } ourScheduledToRefresh.remove(key); } - ProgressManager.getInstance().run(new Task.Backgroundable(project, PyBundle.message("sdk.gen.updating.interpreter"), false) { + ProgressManager.getInstance().run(new Task.Backgroundable(project, PyLocalize.sdkGenUpdatingInterpreter(), false) { @Override public void run(@Nonnull ProgressIndicator indicator) { - final Project project1 = (Project) getProject(); - final Sdk sdkInsideTask = PythonSdkType.findSdkByKey(key); + Project project1 = (Project)getProject(); + Sdk sdkInsideTask = PythonSdkType.findSdkByKey(key); if (sdkInsideTask != null) { ourUnderRefresh.put(key); try { - final String skeletonsPath = getBinarySkeletonsPath(sdk.getHomePath()); + String skeletonsPath = getBinarySkeletonsPath(sdk.getHomePath()); try { if (PythonSdkType.isRemote(sdkInsideTask) && project1 == null && ownerComponent == null) { - LOG.error("For refreshing skeletons of remote SDK, either project or owner component must be specified"); + LOG.error( + "For refreshing skeletons of remote SDK, " + + "either project or owner component must be specified" + ); } - final String sdkPresentableName = getSdkPresentableName(sdk); + String sdkPresentableName = getSdkPresentableName(sdk); LOG.info("Performing background update of skeletons for SDK " + sdkPresentableName); - indicator.setText("Updating skeletons..."); + indicator.setTextValue(LocalizeValue.localizeTODO("Updating skeletons...")); PySkeletonRefresher.refreshSkeletonsOfSdk(project1, ownerComponent, skeletonsPath, sdkInsideTask); indicator.setIndeterminate(true); - indicator.setText("Scanning installed packages..."); - indicator.setText2(""); + indicator.setTextValue(LocalizeValue.localizeTODO("Scanning installed packages...")); + indicator.setText2Value(LocalizeValue.empty()); LOG.info("Performing background scan of packages for SDK " + sdkPresentableName); try { PyPackageManager.getInstance(sdkInsideTask).refreshAndGetPackages(true); @@ -193,15 +205,20 @@ public void run(@Nonnull ProgressIndicator indicator) { * * @see {@link #update(Sdk, SdkModificator, Project, Component)} */ - public static void updateOrShowError(@Nonnull Sdk sdk, - @Nullable SdkModificator sdkModificator, - @Nullable Project project, - @Nullable Component ownerComponent) { - final boolean success = update(sdk, sdkModificator, project, ownerComponent); + @RequiredUIAccess + public static void updateOrShowError( + @Nonnull Sdk sdk, + @Nullable SdkModificator sdkModificator, + @Nullable Project project, + @Nullable Component ownerComponent + ) { + boolean success = update(sdk, sdkModificator, project, ownerComponent); if (!success) { - Messages.showErrorDialog(project, - PyBundle.message("MSG.cant.setup.sdk.$0", getSdkPresentableName(sdk)), - PyBundle.message("MSG.title.bad.sdk")); + Messages.showErrorDialog( + project, + PyLocalize.msgCantSetupSdk$0(getSdkPresentableName(sdk)).get(), + PyLocalize.msgTitleBadSdk().get() + ); } } @@ -210,10 +227,11 @@ public static void updateOrShowError(@Nonnull Sdk sdk, *

* May be invoked from any thread. May freeze the current thread while evaluating sys.path. */ + @RequiredReadAction public static boolean updateLocalSdkPaths(@Nonnull Sdk sdk, @Nullable SdkModificator sdkModificator, @Nullable Project project) { if (!PythonSdkType.isRemote(sdk)) { - final List localSdkPaths; - final boolean forceCommit = ensureBinarySkeletonsDirectoryExists(sdk); + List localSdkPaths; + boolean forceCommit = ensureBinarySkeletonsDirectoryExists(sdk); try { localSdkPaths = getLocalSdkPaths(sdk, project); } @@ -229,7 +247,7 @@ public static boolean updateLocalSdkPaths(@Nonnull Sdk sdk, @Nullable SdkModific } private static boolean ensureBinarySkeletonsDirectoryExists(Sdk sdk) { - final String skeletonsPath = getBinarySkeletonsPath(sdk.getHomePath()); + String skeletonsPath = getBinarySkeletonsPath(sdk.getHomePath()); if (skeletonsPath != null) { if (new File(skeletonsPath).mkdirs()) { return true; @@ -242,6 +260,7 @@ private static boolean ensureBinarySkeletonsDirectoryExists(Sdk sdk) { * Returns all the paths for a local SDK. */ @Nonnull + @RequiredReadAction private static List getLocalSdkPaths(@Nonnull Sdk sdk, @Nullable Project project) throws InvalidSdkException { return ImmutableList.builder().addAll(filterRootPaths(sdk, evaluateSysPath(sdk), project)) .addAll(getSkeletonsPaths(sdk)) @@ -254,8 +273,8 @@ private static List getLocalSdkPaths(@Nonnull Sdk sdk, @Nullable Pr */ @Nonnull private static List getUserAddedPaths(@Nonnull Sdk sdk) { - final SdkAdditionalData additionalData = sdk.getSdkAdditionalData(); - final PythonSdkAdditionalData pythonAdditionalData = PyUtil.as(additionalData, PythonSdkAdditionalData.class); + SdkAdditionalData additionalData = sdk.getSdkAdditionalData(); + PythonSdkAdditionalData pythonAdditionalData = PyUtil.as(additionalData, PythonSdkAdditionalData.class); return pythonAdditionalData != null ? Lists.newArrayList(pythonAdditionalData.getAddedPathFiles()) : Collections.emptyList(); } @@ -263,23 +282,24 @@ private static List getUserAddedPaths(@Nonnull Sdk sdk) { * Filters valid paths from an initial set of Python paths and returns them as virtual files. */ @Nonnull + @RequiredReadAction private static List filterRootPaths(@Nonnull Sdk sdk, @Nonnull List paths, @Nullable Project project) { - final PythonSdkAdditionalData pythonAdditionalData = PyUtil.as(sdk.getSdkAdditionalData(), PythonSdkAdditionalData.class); - final Collection excludedPaths = + PythonSdkAdditionalData pythonAdditionalData = PyUtil.as(sdk.getSdkAdditionalData(), PythonSdkAdditionalData.class); + Collection excludedPaths = pythonAdditionalData != null ? pythonAdditionalData.getExcludedPathFiles() : Collections.emptyList(); - final Set moduleRoots = new HashSet<>(); + Set moduleRoots = new HashSet<>(); if (project != null) { - final Module[] modules = ModuleManager.getInstance(project).getModules(); + Module[] modules = ModuleManager.getInstance(project).getModules(); for (Module module : modules) { moduleRoots.addAll(PyUtil.getSourceRoots(module)); } } - final List results = Lists.newArrayList(); + List results = Lists.newArrayList(); for (String path : paths) { if (path != null && !FileUtil.extensionEquals(path, "egg-info")) { - final VirtualFile virtualFile = StandardFileSystems.local().refreshAndFindFileByPath(path); + VirtualFile virtualFile = StandardFileSystems.local().refreshAndFindFileByPath(path); if (virtualFile != null) { - final VirtualFile rootFile = PythonSdkType.getSdkRootVirtualFile(virtualFile); + VirtualFile rootFile = PythonSdkType.getSdkRootVirtualFile(virtualFile); if (!excludedPaths.contains(rootFile) && !moduleRoots.contains(rootFile)) { results.add(rootFile); continue; @@ -296,16 +316,16 @@ private static List filterRootPaths(@Nonnull Sdk sdk, @Nonnull List */ @Nonnull private static List getSkeletonsPaths(@Nonnull Sdk sdk) { - final List results = Lists.newArrayList(); - final String skeletonsPath = getBinarySkeletonsPath(sdk.getHomePath()); + List results = Lists.newArrayList(); + String skeletonsPath = getBinarySkeletonsPath(sdk.getHomePath()); if (skeletonsPath != null) { - final VirtualFile skeletonsDir = StandardFileSystems.local().refreshAndFindFileByPath(skeletonsPath); + VirtualFile skeletonsDir = StandardFileSystems.local().refreshAndFindFileByPath(skeletonsPath); if (skeletonsDir != null) { results.add(skeletonsDir); LOG.info("Binary skeletons directory for SDK " + getSdkPresentableName(sdk) + "): " + skeletonsDir.getPath()); } } - final VirtualFile userSkeletonsDir = PyUserSkeletonsUtil.getUserSkeletonsDirectory(); + VirtualFile userSkeletonsDir = PyUserSkeletonsUtil.getUserSkeletonsDirectory(); if (userSkeletonsDir != null) { results.add(userSkeletonsDir); LOG.info("User skeletons directory for SDK " + getSdkPresentableName(sdk) + "): " + userSkeletonsDir.getPath()); @@ -315,8 +335,8 @@ private static List getSkeletonsPaths(@Nonnull Sdk sdk) { @Nonnull private static String getSdkPresentableName(@Nonnull Sdk sdk) { - final String homePath = sdk.getHomePath(); - final String name = sdk.getName(); + String homePath = sdk.getHomePath(); + String name = sdk.getName(); return homePath != null ? name + " (" + homePath + ")" : name; } @@ -335,8 +355,8 @@ private static List evaluateSysPath(@Nonnull Sdk sdk) throws InvalidSdkE if (PythonSdkType.isRemote(sdk)) { throw new IllegalArgumentException("Cannot evaluate sys.path for remote Python interpreter " + sdk); } - final long startTime = System.currentTimeMillis(); - final List sysPath = PythonSdkType.getSysPath(sdk.getHomePath()); + long startTime = System.currentTimeMillis(); + List sysPath = PythonSdkType.getSysPath(sdk.getHomePath()); LOG.info("Updating sys.path took " + (System.currentTimeMillis() - startTime) + " ms"); return sysPath; } @@ -346,17 +366,19 @@ private static List evaluateSysPath(@Nonnull Sdk sdk) throws InvalidSdkE *

* You may invoke it from any thread. Blocks until the commit is done in the AWT thread. */ - private static void commitSdkPathsIfChanged(@Nonnull Sdk sdk, - @Nullable final SdkModificator sdkModificator, - @Nonnull final List sdkPaths, - boolean forceCommit) { - final String key = PythonSdkType.getSdkKey(sdk); - final SdkModificator modificatorToGetRoots = sdkModificator != null ? sdkModificator : sdk.getSdkModificator(); - final List currentSdkPaths = Arrays.asList(modificatorToGetRoots.getRoots(BinariesOrderRootType.getInstance())); + private static void commitSdkPathsIfChanged( + @Nonnull Sdk sdk, + @Nullable SdkModificator sdkModificator, + @Nonnull List sdkPaths, + boolean forceCommit + ) { + String key = PythonSdkType.getSdkKey(sdk); + SdkModificator modificatorToGetRoots = sdkModificator != null ? sdkModificator : sdk.getSdkModificator(); + List currentSdkPaths = Arrays.asList(modificatorToGetRoots.getRoots(BinariesOrderRootType.getInstance())); if (forceCommit || !Sets.newHashSet(sdkPaths).equals(Sets.newHashSet(currentSdkPaths))) { - final Sdk sdkInsideInvoke = PythonSdkType.findSdkByKey(key); - final SdkModificator modificatorToCommit = - sdkModificator != null ? sdkModificator : sdkInsideInvoke != null ? sdkInsideInvoke.getSdkModificator() : modificatorToGetRoots; + Sdk sdkInsideInvoke = PythonSdkType.findSdkByKey(key); + SdkModificator modificatorToCommit = sdkModificator != null ? sdkModificator + : sdkInsideInvoke != null ? sdkInsideInvoke.getSdkModificator() : modificatorToGetRoots; modificatorToCommit.removeAllRoots(); for (VirtualFile sdkPath : sdkPaths) { modificatorToCommit.addRoot(PythonSdkType.getSdkRootVirtualFile(sdkPath), BinariesOrderRootType.getInstance()); @@ -369,10 +391,11 @@ private static void commitSdkPathsIfChanged(@Nonnull Sdk sdk, * Returns unique Python SDKs for the open modules of the project. */ @Nonnull + @RequiredReadAction private static Set getPythonSdks(@Nonnull Project project) { - final Set pythonSdks = Sets.newLinkedHashSet(); + Set pythonSdks = Sets.newLinkedHashSet(); for (Module module : ModuleManager.getInstance(project).getModules()) { - final Sdk sdk = PythonSdkType.findPythonSdk(module); + Sdk sdk = PythonSdkType.findPythonSdk(module); if (sdk != null && sdk.getSdkType() instanceof PythonSdkType) { pythonSdks.add(sdk); } diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/CPythonSdkFlavor.java b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/CPythonSdkFlavor.java index ae1f6867..26e3e883 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/CPythonSdkFlavor.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/CPythonSdkFlavor.java @@ -16,17 +16,18 @@ package com.jetbrains.python.impl.sdk.flavors; import jakarta.annotation.Nonnull; + import java.util.regex.Pattern; /** * @author yole */ public abstract class CPythonSdkFlavor extends PythonSdkFlavor { - public final static Pattern PYTHON_RE = Pattern.compile("python-?(\\d\\.\\d)?|python-?(\\d)?"); + public final static Pattern PYTHON_RE = Pattern.compile("python-?(\\d\\.\\d)?|python-?(\\d)?"); - @Nonnull - @Override - public String getName() { - return "Python"; - } + @Nonnull + @Override + public String getName() { + return "Python"; + } } diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/MacPythonSdkFlavor.java b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/MacPythonSdkFlavor.java index 9db1bcff..78df6994 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/MacPythonSdkFlavor.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/MacPythonSdkFlavor.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.jetbrains.python.impl.sdk.flavors; import consulo.virtualFileSystem.LocalFileSystem; @@ -28,45 +27,45 @@ * @author yole */ public class MacPythonSdkFlavor extends CPythonSdkFlavor { - private MacPythonSdkFlavor() { - } + private MacPythonSdkFlavor() { + } - public static MacPythonSdkFlavor INSTANCE = new MacPythonSdkFlavor(); - private static final String[] POSSIBLE_BINARY_NAMES = {"python", "python2", "python3"}; + public static MacPythonSdkFlavor INSTANCE = new MacPythonSdkFlavor(); + private static final String[] POSSIBLE_BINARY_NAMES = {"python", "python2", "python3"}; - @Override - public Collection suggestHomePaths() { - List candidates = new ArrayList(); - collectPythonInstallations("/Library/Frameworks/Python.framework/Versions", candidates); - collectPythonInstallations("/System/Library/Frameworks/Python.framework/Versions", candidates); - UnixPythonSdkFlavor.collectUnixPythons("/usr/local/bin", candidates); - return candidates; - } + @Override + public Collection suggestHomePaths() { + List candidates = new ArrayList<>(); + collectPythonInstallations("/Library/Frameworks/Python.framework/Versions", candidates); + collectPythonInstallations("/System/Library/Frameworks/Python.framework/Versions", candidates); + UnixPythonSdkFlavor.collectUnixPythons("/usr/local/bin", candidates); + return candidates; + } - private static void collectPythonInstallations(String pythonPath, List candidates) { - VirtualFile rootVDir = LocalFileSystem.getInstance().findFileByPath(pythonPath); - if (rootVDir != null) { - if (rootVDir instanceof NewVirtualFile) { - ((NewVirtualFile)rootVDir).markDirty(); - } - rootVDir.refresh(false, false); - for (VirtualFile dir : rootVDir.getChildren()) { - final String dir_name = dir.getName().toLowerCase(); - if (dir.isDirectory()) { - if ("Current".equals(dir_name) || dir_name.startsWith("2") || dir_name.startsWith("3")) { - final VirtualFile binDir = dir.findChild("bin"); - if (binDir != null && binDir.isDirectory()) { - for (String name : POSSIBLE_BINARY_NAMES) { - final VirtualFile child = binDir.findChild(name); - if (child != null) { - candidates.add(child.getPath()); - break; + private static void collectPythonInstallations(String pythonPath, List candidates) { + VirtualFile rootVDir = LocalFileSystem.getInstance().findFileByPath(pythonPath); + if (rootVDir != null) { + if (rootVDir instanceof NewVirtualFile newVirtualFile) { + newVirtualFile.markDirty(); + } + rootVDir.refresh(false, false); + for (VirtualFile dir : rootVDir.getChildren()) { + String dir_name = dir.getName().toLowerCase(); + if (dir.isDirectory()) { + if ("Current".equals(dir_name) || dir_name.startsWith("2") || dir_name.startsWith("3")) { + VirtualFile binDir = dir.findChild("bin"); + if (binDir != null && binDir.isDirectory()) { + for (String name : POSSIBLE_BINARY_NAMES) { + VirtualFile child = binDir.findChild(name); + if (child != null) { + candidates.add(child.getPath()); + break; + } + } + } + } } - } } - } } - } } - } } diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/MayaSdkFlavor.java b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/MayaSdkFlavor.java index 0a6b8773..417d1157 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/MayaSdkFlavor.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/MayaSdkFlavor.java @@ -16,13 +16,13 @@ package com.jetbrains.python.impl.sdk.flavors; -import com.jetbrains.python.impl.PythonIcons; import consulo.annotation.component.ExtensionImpl; +import consulo.python.impl.icon.PythonImplIconGroup; import consulo.ui.image.Image; import consulo.util.io.FileUtil; import consulo.virtualFileSystem.VirtualFile; - import jakarta.annotation.Nonnull; + import java.io.File; /** @@ -30,40 +30,44 @@ */ @ExtensionImpl public class MayaSdkFlavor extends PythonSdkFlavor { - public boolean isValidSdkHome(String path) { - File file = new File(path); - return (file.isFile() && isValidSdkPath(file)) || isMayaFolder(file); - } + @Override + public boolean isValidSdkHome(String path) { + File file = new File(path); + return (file.isFile() && isValidSdkPath(file)) || isMayaFolder(file); + } - private static boolean isMayaFolder(File file) { - return file.isDirectory() && file.getName().equals("Maya.app"); - } + private static boolean isMayaFolder(File file) { + return file.isDirectory() && file.getName().equals("Maya.app"); + } - public boolean isValidSdkPath(@Nonnull File file) { - String name = FileUtil.getNameWithoutExtension(file).toLowerCase(); - return name.startsWith("mayapy"); - } + @Override + public boolean isValidSdkPath(@Nonnull File file) { + String name = FileUtil.getNameWithoutExtension(file).toLowerCase(); + return name.startsWith("mayapy"); + } - public String getVersionOption() { - return "--version"; - } + @Override + public String getVersionOption() { + return "--version"; + } - @Nonnull - @Override - public String getName() { - return "MayaPy"; - } + @Nonnull + @Override + public String getName() { + return "MayaPy"; + } - @Override - public Image getIcon() { - return PythonIcons.Python.Python; //TODO: maya icon - } + @Nonnull + @Override + public Image getIcon() { + return PythonImplIconGroup.pythonPython(); //TODO: maya icon + } - @Override - public VirtualFile getSdkPath(VirtualFile path) { - if (isMayaFolder(new File(path.getPath()))) { - return path.findFileByRelativePath("Contents/bin/mayapy"); + @Override + public VirtualFile getSdkPath(VirtualFile path) { + if (isMayaFolder(new File(path.getPath()))) { + return path.findFileByRelativePath("Contents/bin/mayapy"); + } + return path; } - return path; - } } diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/PyPySdkFlavor.java b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/PyPySdkFlavor.java index 87517b83..d70a3250 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/PyPySdkFlavor.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/PyPySdkFlavor.java @@ -16,15 +16,16 @@ package com.jetbrains.python.impl.sdk.flavors; -import com.jetbrains.python.impl.PythonIcons; import com.jetbrains.python.psi.LanguageLevel; import consulo.annotation.component.ExtensionImpl; import consulo.content.bundle.Sdk; +import consulo.python.impl.icon.PythonImplIconGroup; import consulo.ui.image.Image; import consulo.util.io.FileUtil; import consulo.util.lang.StringUtil; import jakarta.annotation.Nonnull; + import java.io.File; import java.util.List; @@ -33,66 +34,67 @@ */ @ExtensionImpl public class PyPySdkFlavor extends PythonSdkFlavor { - @Override - public boolean isValidSdkPath(@Nonnull File file) { - return FileUtil.getNameWithoutExtension(file).toLowerCase().startsWith("pypy"); - } + @Override + public boolean isValidSdkPath(@Nonnull File file) { + return FileUtil.getNameWithoutExtension(file).toLowerCase().startsWith("pypy"); + } - @Override - public String getVersionRegexp() { - return "\\[(PyPy \\S+).*\\]"; - } + @Override + public String getVersionRegexp() { + return "\\[(PyPy \\S+).*\\]"; + } - @Override - public String getVersionOption() { - return "--version"; - } + @Override + public String getVersionOption() { + return "--version"; + } - @Nonnull - @Override - public String getName() { - return "PyPy"; - } + @Nonnull + @Override + public String getName() { + return "PyPy"; + } - @Override - public LanguageLevel getLanguageLevel(Sdk sdk) { - final String version = sdk.getVersionString(); - final String prefix = getName() + " "; - if (version != null && version.startsWith(prefix)) { - String pypyVersion = version.substring(prefix.length()); - return LanguageLevel.fromPythonVersion(getPythonVersion(pypyVersion)); + @Override + public LanguageLevel getLanguageLevel(Sdk sdk) { + String version = sdk.getVersionString(); + String prefix = getName() + " "; + if (version != null && version.startsWith(prefix)) { + String pypyVersion = version.substring(prefix.length()); + return LanguageLevel.fromPythonVersion(getPythonVersion(pypyVersion)); + } + return LanguageLevel.getDefault(); } - return LanguageLevel.getDefault(); - } - private static String getPythonVersion(@Nonnull String pypyVersion) { - final String DEFAULT = "2.4"; - final String LATEST = "2.7"; - final List vs = StringUtil.split(pypyVersion, "."); - try { - if (vs.size() >= 2) { - final int major = Integer.parseInt(vs.get(0)); - final int minor = Integer.parseInt(vs.get(1)); - if (major > 1) { - return LATEST; + private static String getPythonVersion(@Nonnull String pypyVersion) { + String DEFAULT = "2.4"; + String LATEST = "2.7"; + List vs = StringUtil.split(pypyVersion, "."); + try { + if (vs.size() >= 2) { + int major = Integer.parseInt(vs.get(0)); + int minor = Integer.parseInt(vs.get(1)); + if (major > 1) { + return LATEST; + } + else if (major == 1) { + if (minor >= 5) { + return "2.7"; + } + else if (minor >= 4) { + return "2.5"; + } + } + } } - else if (major == 1) { - if (minor >= 5) { - return "2.7"; - } - else if (minor >= 4) { - return "2.5"; - } + catch (NumberFormatException ignored) { } - } + return DEFAULT; } - catch (NumberFormatException ignored) { - } - return DEFAULT; - } - @Override - public Image getIcon() { - return PythonIcons.Python.Pypy; - } + @Nonnull + @Override + public Image getIcon() { + return PythonImplIconGroup.pythonPypy(); + } } diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/PythonSdkFlavor.java b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/PythonSdkFlavor.java index b0e1dfb6..0fdd716b 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/PythonSdkFlavor.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/PythonSdkFlavor.java @@ -16,7 +16,6 @@ package com.jetbrains.python.impl.sdk.flavors; -import com.jetbrains.python.impl.PythonIcons; import com.jetbrains.python.impl.run.PythonProcessHandler; import com.jetbrains.python.impl.sdk.PySdkUtil; import com.jetbrains.python.impl.sdk.PythonEnvUtil; @@ -24,15 +23,17 @@ import com.jetbrains.python.psi.LanguageLevel; import consulo.annotation.component.ComponentScope; import consulo.annotation.component.ExtensionAPI; -import consulo.application.util.SystemInfo; import consulo.component.extension.ExtensionPointName; import consulo.content.bundle.Sdk; import consulo.content.bundle.SdkAdditionalData; import consulo.logging.Logger; +import consulo.platform.Platform; +import consulo.platform.PlatformOperatingSystem; import consulo.process.ExecutionException; import consulo.process.ProcessHandler; import consulo.process.cmd.GeneralCommandLine; import consulo.process.util.ProcessOutput; +import consulo.python.impl.icon.PythonImplIconGroup; import consulo.ui.image.Image; import consulo.util.io.FileUtil; import consulo.util.lang.PatternUtil; @@ -42,6 +43,7 @@ import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; + import java.io.File; import java.nio.charset.Charset; import java.util.*; @@ -52,217 +54,222 @@ */ @ExtensionAPI(ComponentScope.APPLICATION) public abstract class PythonSdkFlavor { - public static final ExtensionPointName EP_NAME = ExtensionPointName.create(PythonSdkFlavor.class); - private static final Logger LOG = Logger.getInstance(PythonSdkFlavor.class); + public static final ExtensionPointName EP_NAME = ExtensionPointName.create(PythonSdkFlavor.class); + private static final Logger LOG = Logger.getInstance(PythonSdkFlavor.class); + + public static Collection appendSystemPythonPath(@Nonnull Collection pythonPath) { + return appendSystemEnvPaths(pythonPath, PythonEnvUtil.PYTHONPATH); + } + + protected static Collection appendSystemEnvPaths(@Nonnull Collection pythonPath, String envname) { + String syspath = System.getenv(envname); + if (syspath != null) { + pythonPath.addAll(List.of(syspath.split(File.pathSeparator))); + } + return pythonPath; + } + + public static void initPythonPath( + @Nonnull Map envs, + boolean passParentEnvs, + @Nonnull Collection pythonPathList + ) { + if (passParentEnvs && !envs.containsKey(PythonEnvUtil.PYTHONPATH)) { + pythonPathList = appendSystemPythonPath(pythonPathList); + } + PythonEnvUtil.addToPythonPath(envs, pythonPathList); + } + + public static List getApplicableFlavors() { + List result = new ArrayList(); + + PlatformOperatingSystem os = Platform.current().os(); + if (os.isWindows()) { + result.add(WinPythonSdkFlavor.INSTANCE); + } + else if (os.isMac()) { + result.add(MacPythonSdkFlavor.INSTANCE); + } + else if (os.isUnix()) { + result.add(UnixPythonSdkFlavor.INSTANCE); + } + + Collections.addAll(result, EP_NAME.getExtensions()); + + return result; + } + + @Nullable + public static PythonSdkFlavor getFlavor(Sdk sdk) { + SdkAdditionalData data = sdk.getSdkAdditionalData(); + if (data instanceof PythonSdkAdditionalData pythonSdkAdditionalData) { + PythonSdkFlavor flavor = pythonSdkAdditionalData.getFlavor(); + if (flavor != null) { + return flavor; + } + } + return getFlavor(sdk.getHomePath()); + } + + @Nullable + public static PythonSdkFlavor getFlavor(@Nullable String sdkPath) { + if (sdkPath == null) { + return null; + } + + for (PythonSdkFlavor flavor : getApplicableFlavors()) { + if (flavor.isValidSdkHome(sdkPath)) { + return flavor; + } + } + return null; + } + + @Nullable + public static PythonSdkFlavor getPlatformIndependentFlavor(@Nullable String sdkPath) { + if (sdkPath == null) { + return null; + } + + for (PythonSdkFlavor flavor : EP_NAME.getExtensionList()) { + if (flavor.isValidSdkHome(sdkPath)) { + return flavor; + } + } + return null; + } - public static Collection appendSystemPythonPath(@Nonnull Collection pythonPath) { - return appendSystemEnvPaths(pythonPath, PythonEnvUtil.PYTHONPATH); - } + @Nullable + protected static String getVersionFromOutput(String sdkHome, String version_opt, String version_regexp) { + String run_dir = new File(sdkHome).getParent(); + ProcessOutput process_output = PySdkUtil.getProcessOutput(run_dir, new String[]{ + sdkHome, + version_opt + }); - protected static Collection appendSystemEnvPaths(@Nonnull Collection pythonPath, String envname) { - String syspath = System.getenv(envname); - if (syspath != null) { - pythonPath.addAll(List.of(syspath.split(File.pathSeparator))); + return getVersionFromOutput(version_regexp, process_output); } - return pythonPath; - } - public static void initPythonPath(@Nonnull Map envs, boolean passParentEnvs, @Nonnull Collection pythonPathList) { - if (passParentEnvs && !envs.containsKey(PythonEnvUtil.PYTHONPATH)) { - pythonPathList = appendSystemPythonPath(pythonPathList); + @Nullable + private static String getVersionFromOutput(String version_regexp, ProcessOutput process_output) { + if (process_output.getExitCode() != 0) { + String err = process_output.getStderr(); + if (StringUtil.isEmpty(err)) { + err = process_output.getStdout(); + } + LOG.warn("Couldn't get interpreter version: process exited with code " + process_output.getExitCode() + "\n" + err); + return null; + } + Pattern pattern = Pattern.compile(version_regexp); + String result = PatternUtil.getFirstMatch(process_output.getStderrLines(), pattern); + if (result != null) { + return result; + } + return PatternUtil.getFirstMatch(process_output.getStdoutLines(), pattern); } - PythonEnvUtil.addToPythonPath(envs, pythonPathList); - } - public static List getApplicableFlavors() { - List result = new ArrayList(); + public static void addToEnv(String key, String value, Map envs) { + PythonEnvUtil.addPathToEnv(envs, key, value); + } + + public Collection suggestHomePaths() { + return Collections.emptyList(); + } + + /** + * Checks if the path is the name of a Python interpreter of this flavor. + * + * @param path path to check. + * @return true if paths points to a valid home. + */ + public boolean isValidSdkHome(String path) { + File file = new File(path); + return file.isFile() && isValidSdkPath(file); + } + + public boolean isValidSdkPath(@Nonnull File file) { + return FileUtil.getNameWithoutExtension(file).toLowerCase().startsWith("python"); + } + + public String getVersionString(String sdkHome) { + return getVersionStringFromOutput(getVersionFromOutput(sdkHome, getVersionOption(), getVersionRegexp())); + } - if (SystemInfo.isWindows) { - result.add(WinPythonSdkFlavor.INSTANCE); + public String getVersionStringFromOutput(String version) { + return version; } - else if (SystemInfo.isMac) { - result.add(MacPythonSdkFlavor.INSTANCE); + + public boolean allowCreateVirtualEnv() { + return true; } - else if (SystemInfo.isUnix) { - result.add(UnixPythonSdkFlavor.INSTANCE); + + public String getVersionRegexp() { + return "(Python \\S+).*"; } - Collections.addAll(result, EP_NAME.getExtensions()); + public String getVersionOption() { + return "-V"; + } - return result; - } + @Nullable + public String getVersionFromOutput(ProcessOutput processOutput) { + return getVersionFromOutput(getVersionRegexp(), processOutput); + } - @Nullable - public static PythonSdkFlavor getFlavor(Sdk sdk) { - final SdkAdditionalData data = sdk.getSdkAdditionalData(); - if (data instanceof PythonSdkAdditionalData) { - PythonSdkFlavor flavor = ((PythonSdkAdditionalData)data).getFlavor(); - if (flavor != null) { - return flavor; - } + public Collection getExtraDebugOptions() { + return Collections.emptyList(); } - return getFlavor(sdk.getHomePath()); - } - @Nullable - public static PythonSdkFlavor getFlavor(@Nullable String sdkPath) { - if (sdkPath == null) { - return null; + public void initPythonPath(GeneralCommandLine cmd, Collection path) { + initPythonPath(path, cmd.getEnvironment()); } - for (PythonSdkFlavor flavor : getApplicableFlavors()) { - if (flavor.isValidSdkHome(sdkPath)) { - return flavor; - } + public ProcessHandler createProcessHandler(GeneralCommandLine commandLine, boolean withMediator) throws ExecutionException { + return PythonProcessHandler.createDefaultProcessHandler(commandLine, withMediator); } - return null; - } - @Nullable - public static PythonSdkFlavor getPlatformIndependentFlavor(@Nullable final String sdkPath) { - if (sdkPath == null) { - return null; + public static void setupEncodingEnvs(Map envs, @Nonnull Charset charset) { + String encoding = charset.name(); + PythonEnvUtil.setPythonIOEncoding(envs, encoding); } - for (PythonSdkFlavor flavor : EP_NAME.getExtensionList()) { - if (flavor.isValidSdkHome(sdkPath)) { - return flavor; - } + @SuppressWarnings({"MethodMayBeStatic"}) + public void addPredefinedEnvironmentVariables(Map envs) { + Charset defaultCharset = EncodingManager.getInstance().getDefaultCharset(); + if (defaultCharset != null) { + String encoding = defaultCharset.name(); + PythonEnvUtil.setPythonIOEncoding(envs, encoding); + } } - return null; - } - - @Nullable - protected static String getVersionFromOutput(String sdkHome, String version_opt, String version_regexp) { - String run_dir = new File(sdkHome).getParent(); - final ProcessOutput process_output = PySdkUtil.getProcessOutput(run_dir, new String[]{ - sdkHome, - version_opt - }); - - return getVersionFromOutput(version_regexp, process_output); - } - - @Nullable - private static String getVersionFromOutput(String version_regexp, ProcessOutput process_output) { - if (process_output.getExitCode() != 0) { - String err = process_output.getStderr(); - if (StringUtil.isEmpty(err)) { - err = process_output.getStdout(); - } - LOG.warn("Couldn't get interpreter version: process exited with code " + process_output.getExitCode() + "\n" + err); - return null; + + @Nonnull + public abstract String getName(); + + public LanguageLevel getLanguageLevel(Sdk sdk) { + String version = sdk.getVersionString(); + String prefix = getName() + " "; + if (version != null && version.startsWith(prefix)) { + return LanguageLevel.fromPythonVersion(version.substring(prefix.length())); + } + return LanguageLevel.getDefault(); } - Pattern pattern = Pattern.compile(version_regexp); - final String result = PatternUtil.getFirstMatch(process_output.getStderrLines(), pattern); - if (result != null) { - return result; + + @Nonnull + public Image getIcon() { + return PythonImplIconGroup.pythonPython(); } - return PatternUtil.getFirstMatch(process_output.getStdoutLines(), pattern); - } - - public static void addToEnv(final String key, String value, Map envs) { - PythonEnvUtil.addPathToEnv(envs, key, value); - } - - public Collection suggestHomePaths() { - return Collections.emptyList(); - } - - /** - * Checks if the path is the name of a Python interpreter of this flavor. - * - * @param path path to check. - * @return true if paths points to a valid home. - */ - public boolean isValidSdkHome(String path) { - File file = new File(path); - return file.isFile() && isValidSdkPath(file); - } - - public boolean isValidSdkPath(@Nonnull File file) { - return FileUtil.getNameWithoutExtension(file).toLowerCase().startsWith("python"); - } - - public String getVersionString(String sdkHome) { - return getVersionStringFromOutput(getVersionFromOutput(sdkHome, getVersionOption(), getVersionRegexp())); - } - - public String getVersionStringFromOutput(String version) { - return version; - } - - public boolean allowCreateVirtualEnv() { - return true; - } - - public String getVersionRegexp() { - return "(Python \\S+).*"; - } - - public String getVersionOption() { - return "-V"; - } - - @Nullable - public String getVersionFromOutput(ProcessOutput processOutput) { - return getVersionFromOutput(getVersionRegexp(), processOutput); - } - - public Collection getExtraDebugOptions() { - return Collections.emptyList(); - } - - public void initPythonPath(GeneralCommandLine cmd, Collection path) { - initPythonPath(path, cmd.getEnvironment()); - } - - public ProcessHandler createProcessHandler(GeneralCommandLine commandLine, boolean withMediator) throws ExecutionException { - return PythonProcessHandler.createDefaultProcessHandler(commandLine, withMediator); - } - - public static void setupEncodingEnvs(Map envs, @Nonnull Charset charset) { - final String encoding = charset.name(); - PythonEnvUtil.setPythonIOEncoding(envs, encoding); - } - - @SuppressWarnings({"MethodMayBeStatic"}) - public void addPredefinedEnvironmentVariables(Map envs) { - Charset defaultCharset = EncodingManager.getInstance().getDefaultCharset(); - if (defaultCharset != null) { - final String encoding = defaultCharset.name(); - PythonEnvUtil.setPythonIOEncoding(envs, encoding); + + public void initPythonPath(Collection path, Map env) { + path = appendSystemPythonPath(path); + addToEnv(PythonEnvUtil.PYTHONPATH, StringUtil.join(path, File.pathSeparator), env); } - } - @Nonnull - public abstract String getName(); + public VirtualFile getSdkPath(VirtualFile path) { + return path; + } - public LanguageLevel getLanguageLevel(Sdk sdk) { - final String version = sdk.getVersionString(); - final String prefix = getName() + " "; - if (version != null && version.startsWith(prefix)) { - return LanguageLevel.fromPythonVersion(version.substring(prefix.length())); + @Nonnull + public Collection collectDebugPythonPath() { + return Collections.emptyList(); } - return LanguageLevel.getDefault(); - } - - @Nonnull - public Image getIcon() { - return PythonIcons.Python.Python; - } - - public void initPythonPath(Collection path, Map env) { - path = appendSystemPythonPath(path); - addToEnv(PythonEnvUtil.PYTHONPATH, StringUtil.join(path, File.pathSeparator), env); - } - - public VirtualFile getSdkPath(VirtualFile path) { - return path; - } - - @Nonnull - public Collection collectDebugPythonPath() { - return Collections.emptyList(); - } } diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/UnixPythonSdkFlavor.java b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/UnixPythonSdkFlavor.java index 48cc4bef..74eb2379 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/UnixPythonSdkFlavor.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/UnixPythonSdkFlavor.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.jetbrains.python.impl.sdk.flavors; import consulo.virtualFileSystem.LocalFileSystem; @@ -28,41 +27,41 @@ * @author yole */ public class UnixPythonSdkFlavor extends CPythonSdkFlavor { - private UnixPythonSdkFlavor() { - } + private UnixPythonSdkFlavor() { + } - private final static String[] NAMES = new String[]{"python", "jython", "pypy"}; + private final static String[] NAMES = new String[]{"python", "jython", "pypy"}; - public static UnixPythonSdkFlavor INSTANCE = new UnixPythonSdkFlavor(); + public static UnixPythonSdkFlavor INSTANCE = new UnixPythonSdkFlavor(); - @Override - public Collection suggestHomePaths() { - List candidates = new ArrayList(); - collectUnixPythons("/usr/bin", candidates); - return candidates; - } + @Override + public Collection suggestHomePaths() { + List candidates = new ArrayList<>(); + collectUnixPythons("/usr/bin", candidates); + return candidates; + } - public static void collectUnixPythons(String path, List candidates) { - VirtualFile rootDir = LocalFileSystem.getInstance().findFileByPath(path); - if (rootDir != null) { - if (rootDir instanceof NewVirtualFile) { - ((NewVirtualFile)rootDir).markDirty(); - } - rootDir.refresh(false, false); - VirtualFile[] suspects = rootDir.getChildren(); - for (VirtualFile child : suspects) { - if (!child.isDirectory()) { - final String childName = child.getName(); - for (String name : NAMES) { - if (childName.startsWith(name)) { - if (!childName.endsWith("-config") && !childName.startsWith("pythonw")) { - candidates.add(child.getPath()); - } - break; + public static void collectUnixPythons(String path, List candidates) { + VirtualFile rootDir = LocalFileSystem.getInstance().findFileByPath(path); + if (rootDir != null) { + if (rootDir instanceof NewVirtualFile newVirtualFile) { + newVirtualFile.markDirty(); + } + rootDir.refresh(false, false); + VirtualFile[] suspects = rootDir.getChildren(); + for (VirtualFile child : suspects) { + if (!child.isDirectory()) { + String childName = child.getName(); + for (String name : NAMES) { + if (childName.startsWith(name)) { + if (!childName.endsWith("-config") && !childName.startsWith("pythonw")) { + candidates.add(child.getPath()); + } + break; + } + } + } } - } } - } } - } } diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/VirtualEnvSdkFlavor.java b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/VirtualEnvSdkFlavor.java index 43f3989e..d1b0055e 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/VirtualEnvSdkFlavor.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/VirtualEnvSdkFlavor.java @@ -17,21 +17,21 @@ import com.jetbrains.python.impl.sdk.PythonSdkType; import consulo.annotation.component.ExtensionImpl; -import consulo.application.util.SystemInfo; import consulo.application.util.UserHomeFileUtil; import consulo.dataContext.DataManager; -import consulo.language.editor.CommonDataKeys; +import consulo.platform.Platform; import consulo.project.Project; +import consulo.python.impl.icon.PythonImplIconGroup; import consulo.ui.image.Image; import consulo.util.io.FileUtil; import consulo.util.lang.StringUtil; import consulo.util.lang.SystemProperties; import consulo.virtualFileSystem.LocalFileSystem; import consulo.virtualFileSystem.VirtualFile; -import com.jetbrains.python.impl.PythonIcons; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; + import java.io.File; import java.util.ArrayList; import java.util.Collection; @@ -42,180 +42,182 @@ */ @ExtensionImpl public class VirtualEnvSdkFlavor extends CPythonSdkFlavor { + private final static String[] NAMES = new String[]{ + "jython", + "pypy", + "python.exe", + "jython.bat", + "pypy.exe" + }; + public final static String[] CONDA_DEFAULT_ROOTS = new String[]{ + "anaconda", + "anaconda3", + "miniconda", + "miniconda3", + "Anaconda", + "Anaconda3", + "Miniconda", + "Miniconda3" + }; + + public static VirtualEnvSdkFlavor INSTANCE = new VirtualEnvSdkFlavor(); + + @Override + public Collection suggestHomePaths() { + Project project = DataManager.getInstance().getDataContext().getData(Project.KEY); + List candidates = new ArrayList<>(); + if (project != null) { + VirtualFile rootDir = project.getBaseDir(); + if (rootDir != null) { + candidates.addAll(findInDirectory(rootDir)); + } + } - private final static String[] NAMES = new String[]{ - "jython", - "pypy", - "python.exe", - "jython.bat", - "pypy.exe" - }; - public final static String[] CONDA_DEFAULT_ROOTS = new String[]{ - "anaconda", - "anaconda3", - "miniconda", - "miniconda3", - "Anaconda", - "Anaconda3", - "Miniconda", - "Miniconda3" - }; - - public static VirtualEnvSdkFlavor INSTANCE = new VirtualEnvSdkFlavor(); - - @Override - public Collection suggestHomePaths() { - final Project project = DataManager.getInstance().getDataContext().getData(CommonDataKeys.PROJECT); - List candidates = new ArrayList<>(); - if (project != null) { - VirtualFile rootDir = project.getBaseDir(); - if (rootDir != null) { - candidates.addAll(findInDirectory(rootDir)); - } - } + VirtualFile path = getDefaultLocation(); + if (path != null) { + candidates.addAll(findInDirectory(path)); + } - final VirtualFile path = getDefaultLocation(); - if (path != null) { - candidates.addAll(findInDirectory(path)); - } + for (VirtualFile file : getCondaDefaultLocations()) { + candidates.addAll(findInDirectory(file)); + } - for (VirtualFile file : getCondaDefaultLocations()) { - candidates.addAll(findInDirectory(file)); + VirtualFile pyEnvLocation = getPyEnvDefaultLocations(); + if (pyEnvLocation != null) { + candidates.addAll(findInDirectory(pyEnvLocation)); + } + return candidates; } - final VirtualFile pyEnvLocation = getPyEnvDefaultLocations(); - if (pyEnvLocation != null) { - candidates.addAll(findInDirectory(pyEnvLocation)); - } - return candidates; - } - - @Nullable - public static VirtualFile getPyEnvDefaultLocations() { - final String path = System.getenv().get("PYENV_ROOT"); - if (!StringUtil.isEmpty(path)) { - final VirtualFile pyEnvRoot = LocalFileSystem.getInstance().findFileByPath(UserHomeFileUtil.expandUserHome(path).replace('\\', '/')); - if (pyEnvRoot != null) { - return pyEnvRoot.findFileByRelativePath("versions"); - } - } - final VirtualFile userHome = LocalFileSystem.getInstance().findFileByPath(SystemProperties.getUserHome().replace('\\', '/')); - if (userHome != null) { - return userHome.findFileByRelativePath(".pyenv/versions"); - } - return null; - } - - public static List getCondaDefaultLocations() { - List roots = new ArrayList<>(); - final VirtualFile userHome = LocalFileSystem.getInstance().findFileByPath(SystemProperties.getUserHome().replace('\\', '/')); - if (userHome != null) { - for (String root : CONDA_DEFAULT_ROOTS) { - VirtualFile condaFolder = userHome.findChild(root); - addEnvsFolder(roots, condaFolder); - if (SystemInfo.isWindows) { - final VirtualFile appData = userHome.findFileByRelativePath("AppData\\Local\\Continuum\\" + root); - addEnvsFolder(roots, appData); - condaFolder = LocalFileSystem.getInstance().findFileByPath("C:\\" + root); - addEnvsFolder(roots, condaFolder); + @Nullable + public static VirtualFile getPyEnvDefaultLocations() { + String path = System.getenv().get("PYENV_ROOT"); + if (!StringUtil.isEmpty(path)) { + VirtualFile pyEnvRoot = + LocalFileSystem.getInstance().findFileByPath(UserHomeFileUtil.expandUserHome(path).replace('\\', '/')); + if (pyEnvRoot != null) { + return pyEnvRoot.findFileByRelativePath("versions"); + } } - else { - final String systemWidePath = "/opt/anaconda"; - condaFolder = LocalFileSystem.getInstance().findFileByPath(systemWidePath); - addEnvsFolder(roots, condaFolder); + VirtualFile userHome = LocalFileSystem.getInstance().findFileByPath(SystemProperties.getUserHome().replace('\\', '/')); + if (userHome != null) { + return userHome.findFileByRelativePath(".pyenv/versions"); } - } - } - return roots; - } - - private static void addEnvsFolder(@Nonnull final List roots, @Nullable final VirtualFile condaFolder) { - if (condaFolder != null) { - final VirtualFile envs = condaFolder.findChild("envs"); - if (envs != null) { - roots.add(envs); - } + return null; } - } - public static VirtualFile getDefaultLocation() { - final String path = System.getenv().get("WORKON_HOME"); - if (!StringUtil.isEmpty(path)) { - return LocalFileSystem.getInstance().findFileByPath(UserHomeFileUtil.expandUserHome(path).replace('\\', '/')); + public static List getCondaDefaultLocations() { + List roots = new ArrayList<>(); + VirtualFile userHome = LocalFileSystem.getInstance().findFileByPath(SystemProperties.getUserHome().replace('\\', '/')); + if (userHome != null) { + for (String root : CONDA_DEFAULT_ROOTS) { + VirtualFile condaFolder = userHome.findChild(root); + addEnvsFolder(roots, condaFolder); + if (Platform.current().os().isWindows()) { + VirtualFile appData = userHome.findFileByRelativePath("AppData\\Local\\Continuum\\" + root); + addEnvsFolder(roots, appData); + condaFolder = LocalFileSystem.getInstance().findFileByPath("C:\\" + root); + addEnvsFolder(roots, condaFolder); + } + else { + String systemWidePath = "/opt/anaconda"; + condaFolder = LocalFileSystem.getInstance().findFileByPath(systemWidePath); + addEnvsFolder(roots, condaFolder); + } + } + } + return roots; } - final VirtualFile userHome = LocalFileSystem.getInstance().findFileByPath(SystemProperties.getUserHome().replace('\\', '/')); - if (userHome != null) { - final VirtualFile predefinedFolder = userHome.findChild(".virtualenvs"); - if (predefinedFolder == null) { - return userHome; - } - return predefinedFolder; - } - return null; - } - - public static Collection findInDirectory(VirtualFile rootDir) { - List candidates = new ArrayList<>(); - if (rootDir != null) { - rootDir.refresh(true, false); - VirtualFile[] suspects = rootDir.getChildren(); - for (VirtualFile child : suspects) { - if (child.isDirectory()) { - final VirtualFile bin = child.findChild("bin"); - final VirtualFile scripts = child.findChild("Scripts"); - if (bin != null) { - final String interpreter = findInterpreter(bin); - if (interpreter != null) { - candidates.add(interpreter); + private static void addEnvsFolder(@Nonnull List roots, @Nullable VirtualFile condaFolder) { + if (condaFolder != null) { + VirtualFile envs = condaFolder.findChild("envs"); + if (envs != null) { + roots.add(envs); } - } - if (scripts != null) { - final String interpreter = findInterpreter(scripts); - if (interpreter != null) { - candidates.add(interpreter); + } + } + + public static VirtualFile getDefaultLocation() { + String path = System.getenv().get("WORKON_HOME"); + if (!StringUtil.isEmpty(path)) { + return LocalFileSystem.getInstance().findFileByPath(UserHomeFileUtil.expandUserHome(path).replace('\\', '/')); + } + + VirtualFile userHome = + LocalFileSystem.getInstance().findFileByPath(SystemProperties.getUserHome().replace('\\', '/')); + if (userHome != null) { + VirtualFile predefinedFolder = userHome.findChild(".virtualenvs"); + if (predefinedFolder == null) { + return userHome; } - } + return predefinedFolder; } - } + return null; } - return candidates; - } - - @Nullable - private static String findInterpreter(VirtualFile dir) { - for (VirtualFile child : dir.getChildren()) { - if (!child.isDirectory()) { - final String childName = child.getName().toLowerCase(); - for (String name : NAMES) { - if (SystemInfo.isWindows) { - if (childName.equals(name)) { - return FileUtil.toSystemDependentName(child.getPath()); + + public static Collection findInDirectory(VirtualFile rootDir) { + List candidates = new ArrayList<>(); + if (rootDir != null) { + rootDir.refresh(true, false); + VirtualFile[] suspects = rootDir.getChildren(); + for (VirtualFile child : suspects) { + if (child.isDirectory()) { + VirtualFile bin = child.findChild("bin"); + VirtualFile scripts = child.findChild("Scripts"); + if (bin != null) { + String interpreter = findInterpreter(bin); + if (interpreter != null) { + candidates.add(interpreter); + } + } + if (scripts != null) { + String interpreter = findInterpreter(scripts); + if (interpreter != null) { + candidates.add(interpreter); + } + } + } } - } - else { - if (childName.startsWith(name) || PYTHON_RE.matcher(childName).matches()) { - if (!childName.endsWith("-config")) { - return child.getPath(); - } + } + return candidates; + } + + @Nullable + private static String findInterpreter(VirtualFile dir) { + for (VirtualFile child : dir.getChildren()) { + if (!child.isDirectory()) { + String childName = child.getName().toLowerCase(); + for (String name : NAMES) { + if (Platform.current().os().isWindows()) { + if (childName.equals(name)) { + return FileUtil.toSystemDependentName(child.getPath()); + } + } + else { + if (childName.startsWith(name) || PYTHON_RE.matcher(childName).matches()) { + if (!childName.endsWith("-config")) { + return child.getPath(); + } + } + } + } } - } } - } + return null; } - return null; - } - @Override - public boolean isValidSdkPath(@Nonnull File file) { - if (!super.isValidSdkPath(file)) { - return false; + @Override + public boolean isValidSdkPath(@Nonnull File file) { + if (!super.isValidSdkPath(file)) { + return false; + } + return PythonSdkType.getVirtualEnvRoot(file.getPath()) != null; } - return PythonSdkType.getVirtualEnvRoot(file.getPath()) != null; - } - @Override - public Image getIcon() { - return PythonIcons.Python.Virtualenv; - } + @Nonnull + @Override + public Image getIcon() { + return PythonImplIconGroup.pythonVirtualenv(); + } } diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/WinPythonSdkFlavor.java b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/WinPythonSdkFlavor.java index 362f2b84..14e8a919 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/WinPythonSdkFlavor.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/flavors/WinPythonSdkFlavor.java @@ -31,58 +31,62 @@ * @author yole */ public class WinPythonSdkFlavor extends CPythonSdkFlavor { - public static WinPythonSdkFlavor INSTANCE = new WinPythonSdkFlavor(); + public static WinPythonSdkFlavor INSTANCE = new WinPythonSdkFlavor(); - private WinPythonSdkFlavor() { - } + private WinPythonSdkFlavor() { + } - @Override - public Collection suggestHomePaths() { - Set candidates = new TreeSet(); - findInCandidatePaths(candidates, "python.exe", "jython.bat", "pypy.exe"); - return candidates; - } + @Override + public Collection suggestHomePaths() { + Set candidates = new TreeSet<>(); + findInCandidatePaths(candidates, "python.exe", "jython.bat", "pypy.exe"); + return candidates; + } - private static void findInCandidatePaths(Set candidates, String... exe_names) { - for (String name : exe_names) { - findInstallations(candidates, name, "C:\\", "C:\\Program Files\\"); - findInPath(candidates, name); + private static void findInCandidatePaths(Set candidates, String... exe_names) { + for (String name : exe_names) { + findInstallations(candidates, name, "C:\\", "C:\\Program Files\\"); + findInPath(candidates, name); + } } - } - private static void findInstallations(Set candidates, String exe_name, String... roots) { - for (String root : roots) { - findSubdirInstallations(candidates, root, FileUtil.getNameWithoutExtension(exe_name), exe_name); + private static void findInstallations(Set candidates, String exe_name, String... roots) { + for (String root : roots) { + findSubdirInstallations(candidates, root, FileUtil.getNameWithoutExtension(exe_name), exe_name); + } } - } - public static void findInPath(Collection candidates, String exeName) { - final String path = System.getenv("PATH"); - for (String pathEntry : StringUtil.split(path, ";")) { - if (pathEntry.startsWith("\"") && pathEntry.endsWith("\"")) { - if (pathEntry.length() < 2) continue; - pathEntry = pathEntry.substring(1, pathEntry.length() - 1); - } - File f = new File(pathEntry, exeName); - if (f.exists()) { - candidates.add(FileUtil.toSystemIndependentName(f.getPath())); - } + public static void findInPath(Collection candidates, String exeName) { + String path = System.getenv("PATH"); + for (String pathEntry : StringUtil.split(path, ";")) { + if (pathEntry.startsWith("\"") && pathEntry.endsWith("\"")) { + if (pathEntry.length() < 2) { + continue; + } + pathEntry = pathEntry.substring(1, pathEntry.length() - 1); + } + File f = new File(pathEntry, exeName); + if (f.exists()) { + candidates.add(FileUtil.toSystemIndependentName(f.getPath())); + } + } } - } - private static void findSubdirInstallations(Collection candidates, String rootDir, String dir_prefix, String exe_name) { - VirtualFile rootVDir = LocalFileSystem.getInstance().findFileByPath(rootDir); - if (rootVDir != null) { - if (rootVDir instanceof NewVirtualFile) { - ((NewVirtualFile)rootVDir).markDirty(); - } - rootVDir.refresh(false, false); - for (VirtualFile dir : rootVDir.getChildren()) { - if (dir.isDirectory() && dir.getName().toLowerCase().startsWith(dir_prefix)) { - VirtualFile python_exe = dir.findChild(exe_name); - if (python_exe != null) candidates.add(FileUtil.toSystemIndependentName(python_exe.getPath())); + private static void findSubdirInstallations(Collection candidates, String rootDir, String dirPrefix, String exeName) { + VirtualFile rootVDir = LocalFileSystem.getInstance().findFileByPath(rootDir); + if (rootVDir != null) { + if (rootVDir instanceof NewVirtualFile newVirtualFile) { + newVirtualFile.markDirty(); + } + rootVDir.refresh(false, false); + for (VirtualFile dir : rootVDir.getChildren()) { + if (dir.isDirectory() && dir.getName().toLowerCase().startsWith(dirPrefix)) { + VirtualFile pythonExe = dir.findChild(exeName); + if (pythonExe != null) { + candidates.add(FileUtil.toSystemIndependentName(pythonExe.getPath())); + } + } + } } - } } - } } diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/skeletons/PySkeletonGenerator.java b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/skeletons/PySkeletonGenerator.java index 5db8553f..ec3feb55 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/skeletons/PySkeletonGenerator.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/skeletons/PySkeletonGenerator.java @@ -33,6 +33,7 @@ import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; + import java.io.File; import java.util.*; import java.util.function.Consumer; @@ -42,249 +43,233 @@ /** * @author traff */ -public class PySkeletonGenerator -{ - protected static final Logger LOG = Logger.getInstance(PySkeletonGenerator.class); - protected static final int MINUTE = 60 * 1000; - protected static final String GENERATOR3 = "generator3.py"; +public class PySkeletonGenerator { + protected static final Logger LOG = Logger.getInstance(PySkeletonGenerator.class); + protected static final int MINUTE = 60 * 1000; + protected static final String GENERATOR3 = "generator3.py"; - private final String mySkeletonsPath; - @Nonnull - private final Map myEnv; + private final String mySkeletonsPath; + @Nonnull + private final Map myEnv; - public void finishSkeletonsGeneration() - { - } + public void finishSkeletonsGeneration() { + } - public boolean exists(String name) - { - return new File(name).exists(); - } + public boolean exists(String name) { + return new File(name).exists(); + } - public static class ListBinariesResult - { - public final int generatorVersion; - public final Map modules; + public static class ListBinariesResult { + public final int generatorVersion; + public final Map modules; - public ListBinariesResult(int generatorVersion, Map modules) - { - this.generatorVersion = generatorVersion; - this.modules = modules; - } - } + public ListBinariesResult(int generatorVersion, Map modules) { + this.generatorVersion = generatorVersion; + this.modules = modules; + } + } - /** - * @param skeletonPath path where skeletons should be generated - * @param pySdk SDK - * @param currentFolder current folder (some flavors may search for binary files there) or null if unknown - */ - public PySkeletonGenerator(String skeletonPath, @Nonnull final Sdk pySdk, @Nullable final String currentFolder) - { - mySkeletonsPath = skeletonPath; - final PythonSdkFlavor flavor = PythonSdkFlavor.getFlavor(pySdk); - if(flavor != null) - { - myEnv = new HashMap<>(); - flavor.addPredefinedEnvironmentVariables(myEnv); - } - else - { - myEnv = Collections.emptyMap(); - } - } + /** + * @param skeletonPath path where skeletons should be generated + * @param pySdk SDK + * @param currentFolder current folder (some flavors may search for binary files there) or null if unknown + */ + public PySkeletonGenerator(String skeletonPath, @Nonnull Sdk pySdk, @Nullable String currentFolder) { + mySkeletonsPath = skeletonPath; + PythonSdkFlavor flavor = PythonSdkFlavor.getFlavor(pySdk); + if (flavor != null) { + myEnv = new HashMap<>(); + flavor.addPredefinedEnvironmentVariables(myEnv); + } + else { + myEnv = Collections.emptyMap(); + } + } - public String getSkeletonsPath() - { - return mySkeletonsPath; - } + public String getSkeletonsPath() { + return mySkeletonsPath; + } - public void prepare() - { - } + public void prepare() { + } - protected void generateSkeleton(String modname, String modfilename, List assemblyRefs, String syspath, String sdkHomePath, Consumer resultConsumer) throws InvalidSdkException - { - final ProcessOutput genResult = runSkeletonGeneration(modname, modfilename, assemblyRefs, sdkHomePath, syspath); + protected void generateSkeleton( + String modname, + String modfilename, + List assemblyRefs, + String syspath, + String sdkHomePath, + Consumer resultConsumer + ) throws InvalidSdkException { + ProcessOutput genResult = runSkeletonGeneration(modname, modfilename, assemblyRefs, sdkHomePath, syspath); - if(genResult.getStderrLines().size() > 0) - { - StringBuilder sb = new StringBuilder("Skeleton for "); - sb.append(modname); - if(genResult.getExitCode() != 0) - { - sb.append(" failed on "); - } - else - { - sb.append(" had some minor errors on "); - } - sb.append(sdkHomePath).append(". stderr: --\n"); - for(String err_line : genResult.getStderrLines()) - { - sb.append(err_line).append("\n"); - } - sb.append("--"); - if(ApplicationProperties.isInSandbox()) - { - LOG.warn(sb.toString()); - } - else - { - LOG.info(sb.toString()); - } - } + if (genResult.getStderrLines().size() > 0) { + StringBuilder sb = new StringBuilder("Skeleton for "); + sb.append(modname); + if (genResult.getExitCode() != 0) { + sb.append(" failed on "); + } + else { + sb.append(" had some minor errors on "); + } + sb.append(sdkHomePath).append(". stderr: --\n"); + for (String err_line : genResult.getStderrLines()) { + sb.append(err_line).append("\n"); + } + sb.append("--"); + if (ApplicationProperties.isInSandbox()) { + LOG.warn(sb.toString()); + } + else { + LOG.info(sb.toString()); + } + } - resultConsumer.accept(genResult.getExitCode() == 0); - } + resultConsumer.accept(genResult.getExitCode() == 0); + } - public ProcessOutput runSkeletonGeneration(String modname, String modfilename, List assemblyRefs, String binaryPath, String extraSyspath) throws InvalidSdkException - { - final String parent_dir = new File(binaryPath).getParent(); - List commandLine = new ArrayList<>(); - commandLine.add(binaryPath); - commandLine.add(PythonHelpersLocator.getHelperPath(GENERATOR3)); - commandLine.add("-d"); - commandLine.add(getSkeletonsPath()); - if(assemblyRefs != null && !assemblyRefs.isEmpty()) - { - commandLine.add("-c"); - commandLine.add(StringUtil.join(assemblyRefs, ";")); - } - if(ApplicationProperties.isInSandbox()) - { - commandLine.add("-x"); - } - if(!StringUtil.isEmpty(extraSyspath)) - { - commandLine.add("-s"); - commandLine.add(extraSyspath); - } - commandLine.add(modname); - if(modfilename != null) - { - commandLine.add(modfilename); - } + public ProcessOutput runSkeletonGeneration( + String modname, + String modfilename, + List assemblyRefs, + String binaryPath, + String extraSyspath + ) throws InvalidSdkException { + String parent_dir = new File(binaryPath).getParent(); + List commandLine = new ArrayList<>(); + commandLine.add(binaryPath); + commandLine.add(PythonHelpersLocator.getHelperPath(GENERATOR3)); + commandLine.add("-d"); + commandLine.add(getSkeletonsPath()); + if (assemblyRefs != null && !assemblyRefs.isEmpty()) { + commandLine.add("-c"); + commandLine.add(StringUtil.join(assemblyRefs, ";")); + } + if (ApplicationProperties.isInSandbox()) { + commandLine.add("-x"); + } + if (!StringUtil.isEmpty(extraSyspath)) { + commandLine.add("-s"); + commandLine.add(extraSyspath); + } + commandLine.add(modname); + if (modfilename != null) { + commandLine.add(modfilename); + } - final Map extraEnv = PythonSdkType.getVirtualEnvExtraEnv(binaryPath); - final Map env = extraEnv != null ? PySdkUtil.mergeEnvVariables(myEnv, extraEnv) : myEnv; + Map extraEnv = PythonSdkType.getVirtualEnvExtraEnv(binaryPath); + Map env = extraEnv != null ? PySdkUtil.mergeEnvVariables(myEnv, extraEnv) : myEnv; - return getProcessOutput(parent_dir, ArrayUtil.toStringArray(commandLine), env, MINUTE * 10); - } + return getProcessOutput(parent_dir, ArrayUtil.toStringArray(commandLine), env, MINUTE * 10); + } - protected ProcessOutput getProcessOutput(String homePath, String[] commandLine, Map extraEnv, int timeout) throws InvalidSdkException - { - final Map env = extraEnv != null ? new HashMap<>(extraEnv) : new HashMap<>(); - PythonEnvUtil.setPythonDontWriteBytecode(env); - return PySdkUtil.getProcessOutput(homePath, commandLine, env, timeout); - } + protected ProcessOutput getProcessOutput( + String homePath, + String[] commandLine, + Map extraEnv, + int timeout + ) throws InvalidSdkException { + Map env = extraEnv != null ? new HashMap<>(extraEnv) : new HashMap<>(); + PythonEnvUtil.setPythonDontWriteBytecode(env); + return PySdkUtil.getProcessOutput(homePath, commandLine, env, timeout); + } - public void generateBuiltinSkeletons(@Nonnull Sdk sdk) throws InvalidSdkException - { - //noinspection ResultOfMethodCallIgnored - new File(mySkeletonsPath).mkdirs(); - String binaryPath = sdk.getHomePath(); - if(binaryPath == null) - { - throw new InvalidSdkException("Broken home path for " + sdk.getName()); - } + public void generateBuiltinSkeletons(@Nonnull Sdk sdk) throws InvalidSdkException { + //noinspection ResultOfMethodCallIgnored + new File(mySkeletonsPath).mkdirs(); + String binaryPath = sdk.getHomePath(); + if (binaryPath == null) { + throw new InvalidSdkException("Broken home path for " + sdk.getName()); + } - long startTime = System.currentTimeMillis(); - final ProcessOutput runResult = getProcessOutput(new File(binaryPath).getParent(), new String[]{ - binaryPath, - PythonHelpersLocator.getHelperPath(GENERATOR3), - "-d", - mySkeletonsPath, - // output dir - "-b", - // for builtins - }, PythonSdkType.getVirtualEnvExtraEnv(binaryPath), MINUTE * 5); - runResult.checkSuccess(LOG); - LOG.info("Rebuilding builtin skeletons took " + (System.currentTimeMillis() - startTime) + " ms"); - } + long startTime = System.currentTimeMillis(); + ProcessOutput runResult = getProcessOutput(new File(binaryPath).getParent(), new String[]{ + binaryPath, + PythonHelpersLocator.getHelperPath(GENERATOR3), + "-d", + mySkeletonsPath, + // output dir + "-b", + // for builtins + }, PythonSdkType.getVirtualEnvExtraEnv(binaryPath), MINUTE * 5); + runResult.checkSuccess(LOG); + LOG.info("Rebuilding builtin skeletons took " + (System.currentTimeMillis() - startTime) + " ms"); + } - @Nonnull - public ListBinariesResult listBinaries(@Nonnull Sdk sdk, @Nonnull String extraSysPath) throws InvalidSdkException - { - final String homePath = sdk.getHomePath(); - final long startTime = System.currentTimeMillis(); - if(homePath == null) - { - throw new InvalidSdkException("Broken home path for " + sdk.getName()); - } - final String parentDir = new File(homePath).getParent(); + @Nonnull + public ListBinariesResult listBinaries(@Nonnull Sdk sdk, @Nonnull String extraSysPath) throws InvalidSdkException { + String homePath = sdk.getHomePath(); + long startTime = System.currentTimeMillis(); + if (homePath == null) { + throw new InvalidSdkException("Broken home path for " + sdk.getName()); + } + String parentDir = new File(homePath).getParent(); - List cmd = new ArrayList<>(Arrays.asList(homePath, PythonHelpersLocator.getHelperPath(GENERATOR3), "-v", "-L")); - if(!StringUtil.isEmpty(extraSysPath)) - { - cmd.add("-s"); - cmd.add(extraSysPath); - } + List cmd = new ArrayList<>(Arrays.asList(homePath, PythonHelpersLocator.getHelperPath(GENERATOR3), "-v", "-L")); + if (!StringUtil.isEmpty(extraSysPath)) { + cmd.add("-s"); + cmd.add(extraSysPath); + } - final ProcessOutput process = getProcessOutput(parentDir, ArrayUtil.toStringArray(cmd), PythonSdkType.getVirtualEnvExtraEnv(homePath), MINUTE * 4); // see PY-3898 + ProcessOutput process = getProcessOutput( + parentDir, + ArrayUtil.toStringArray(cmd), + PythonSdkType.getVirtualEnvExtraEnv(homePath), + MINUTE * 4 + ); // see PY-3898 - LOG.info("Retrieving binary module list took " + (System.currentTimeMillis() - startTime) + " ms"); - if(process.getExitCode() != 0) - { - final StringBuilder sb = new StringBuilder("failed to run ").append(GENERATOR3).append(" for ").append(homePath); - if(process.isTimeout()) - { - sb.append(": timed out."); - } - else - { - sb.append(", exit code ").append(process.getExitCode()).append(", stderr: \n-----\n"); - for(String line : process.getStderrLines()) - { - sb.append(line).append("\n"); - } - sb.append("-----"); - } - throw new InvalidSdkException(sb.toString()); - } - final List lines = process.getStdoutLines(); - if(lines.size() < 1) - { - throw new InvalidSdkException("Empty output from " + GENERATOR3 + " for " + homePath); - } - final Iterator iter = lines.iterator(); - final int generatorVersion = fromVersionString(iter.next().trim()); - final Map binaries = Maps.newHashMap(); - while(iter.hasNext()) - { - final String line = iter.next(); - int cutpos = line.indexOf('\t'); - if(cutpos >= 0) - { - String[] strs = line.split("\t"); - String moduleName = strs[0]; - String path = strs[1]; - int length = Integer.parseInt(strs[2]); - int lastModified = Integer.parseInt(strs[3]); + LOG.info("Retrieving binary module list took " + (System.currentTimeMillis() - startTime) + " ms"); + if (process.getExitCode() != 0) { + StringBuilder sb = new StringBuilder("failed to run ").append(GENERATOR3).append(" for ").append(homePath); + if (process.isTimeout()) { + sb.append(": timed out."); + } + else { + sb.append(", exit code ").append(process.getExitCode()).append(", stderr: \n-----\n"); + for (String line : process.getStderrLines()) { + sb.append(line).append("\n"); + } + sb.append("-----"); + } + throw new InvalidSdkException(sb.toString()); + } + List lines = process.getStdoutLines(); + if (lines.size() < 1) { + throw new InvalidSdkException("Empty output from " + GENERATOR3 + " for " + homePath); + } + Iterator iter = lines.iterator(); + int generatorVersion = fromVersionString(iter.next().trim()); + Map binaries = Maps.newHashMap(); + while (iter.hasNext()) { + String line = iter.next(); + int cutpos = line.indexOf('\t'); + if (cutpos >= 0) { + String[] strs = line.split("\t"); + String moduleName = strs[0]; + String path = strs[1]; + int length = Integer.parseInt(strs[2]); + int lastModified = Integer.parseInt(strs[3]); - binaries.put(moduleName, new PySkeletonRefresher.PyBinaryItem(moduleName, path, length, lastModified)); - } - else - { - LOG.error("Bad binaries line: '" + line + "', SDK " + homePath); // but don't die yet - } - } - return new ListBinariesResult(generatorVersion, binaries); - } + binaries.put(moduleName, new PySkeletonRefresher.PyBinaryItem(moduleName, path, length, lastModified)); + } + else { + LOG.error("Bad binaries line: '" + line + "', SDK " + homePath); // but don't die yet + } + } + return new ListBinariesResult(generatorVersion, binaries); + } - public boolean deleteOrLog(@Nonnull File item) - { - boolean deleted = item.delete(); - if(!deleted) - { - LOG.warn("Failed to delete skeleton file " + item.getAbsolutePath()); - } - return deleted; - } + public boolean deleteOrLog(@Nonnull File item) { + boolean deleted = item.delete(); + if (!deleted) { + LOG.warn("Failed to delete skeleton file " + item.getAbsolutePath()); + } + return deleted; + } - public void refreshGeneratedSkeletons() - { - VirtualFile skeletonsVFile = LocalFileSystem.getInstance().refreshAndFindFileByPath(getSkeletonsPath()); - assert skeletonsVFile != null; - skeletonsVFile.refresh(false, true); - } + public void refreshGeneratedSkeletons() { + VirtualFile skeletonsVFile = LocalFileSystem.getInstance().refreshAndFindFileByPath(getSkeletonsPath()); + assert skeletonsVFile != null; + skeletonsVFile.refresh(false, true); + } } diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/skeletons/PySkeletonRefresher.java b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/skeletons/PySkeletonRefresher.java index a64358a2..b6a78e4d 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/skeletons/PySkeletonRefresher.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/skeletons/PySkeletonRefresher.java @@ -18,13 +18,12 @@ import com.google.common.base.Joiner; import com.google.common.collect.Lists; import com.jetbrains.python.PyNames; -import com.jetbrains.python.impl.PyBundle; import com.jetbrains.python.impl.codeInsight.userSkeletons.PyUserSkeletonsUtil; import com.jetbrains.python.impl.psi.resolve.PythonSdkPathCache; import com.jetbrains.python.impl.sdk.InvalidSdkException; import com.jetbrains.python.impl.sdk.PySdkUtil; import com.jetbrains.python.impl.sdk.PythonSdkType; -import consulo.application.ApplicationManager; +import consulo.application.Application; import consulo.application.progress.ProgressIndicator; import consulo.application.progress.ProgressManager; import consulo.application.util.SystemInfo; @@ -33,9 +32,13 @@ import consulo.content.base.BinariesOrderRootType; import consulo.content.bundle.Sdk; import consulo.language.editor.DaemonCodeAnalyzer; +import consulo.localize.LocalizeValue; import consulo.logging.Logger; +import consulo.platform.Platform; +import consulo.platform.PlatformOperatingSystem; import consulo.project.Project; import consulo.python.buildout.module.extension.BuildoutModuleExtension; +import consulo.python.impl.localize.PyLocalize; import consulo.util.collection.ContainerUtil; import consulo.util.collection.SmartList; import consulo.util.io.FilePermissionCopier; @@ -46,10 +49,9 @@ import consulo.virtualFileSystem.LocalFileSystem; import consulo.virtualFileSystem.VirtualFile; import consulo.virtualFileSystem.archive.ArchiveVfsUtil; -import org.jetbrains.annotations.NonNls; - import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; + import java.awt.*; import java.io.*; import java.util.List; @@ -65,24 +67,21 @@ * Handles a refresh of SDK's skeletons. * Does all the heavy lifting calling skeleton generator, managing blacklists, etc. * One-time, non-reusable instances. - *
- * User: dcheryasov - * Date: 4/15/11 5:38 PM + * + * @author dcheryasov + * @since 2011-04-15 */ public class PySkeletonRefresher { private static final Logger LOG = Logger.getInstance("#" + PySkeletonRefresher.class.getName()); - @Nullable private Project myProject; - private @Nullable - final ProgressIndicator myIndicator; + private final ProgressIndicator myIndicator; @Nonnull private final Sdk mySdk; private String mySkeletonsPath; - @NonNls public static final String BLACKLIST_FILE_NAME = ".blacklist"; private final static Pattern BLACKLIST_LINE = Pattern.compile("^([^=]+) = (\\d+\\.\\d+) (\\d+)\\s*$"); // we use the equals sign after filename so that we can freely include space in the filename @@ -112,18 +111,23 @@ private static synchronized void changeGeneratingSkeletons(int increment) { ourGeneratingCount += increment; } - public static void refreshSkeletonsOfSdk(@Nullable Project project, Component ownerComponent, String skeletonsPath, @Nonnull Sdk sdk) throws InvalidSdkException { - final Map> errors = new TreeMap<>(); - final List failedSdks = new SmartList<>(); - final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); - final String homePath = sdk.getHomePath(); + public static void refreshSkeletonsOfSdk( + @Nullable Project project, + Component ownerComponent, + String skeletonsPath, + @Nonnull Sdk sdk + ) throws InvalidSdkException { + Map> errors = new TreeMap<>(); + List failedSdks = new SmartList<>(); + ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); + String homePath = sdk.getHomePath(); if (skeletonsPath == null) { LOG.info("Could not find skeletons path for SDK path " + homePath); } else { LOG.info("Refreshing skeletons for " + homePath); SkeletonVersionChecker checker = new SkeletonVersionChecker(0); // this default version won't be used - final PySkeletonRefresher refresher = new PySkeletonRefresher(project, ownerComponent, sdk, skeletonsPath, indicator, null); + PySkeletonRefresher refresher = new PySkeletonRefresher(project, ownerComponent, sdk, skeletonsPath, indicator, null); changeGeneratingSkeletons(1); try { @@ -150,26 +154,30 @@ public static void refreshSkeletonsOfSdk(@Nullable Project project, Component ow } String message; if (failedSdks.size() > 0) { - message = PyBundle.message("sdk.errorlog.$0.mods.fail.in.$1.sdks.$2.completely", module_errors, errors.size(), failedSdks.size()); + message = PyLocalize.sdkErrorlog$0ModsFailIn$1Sdks$2Completely(module_errors, errors.size(), failedSdks.size()).get(); } else { - message = PyBundle.message("sdk.errorlog.$0.mods.fail.in.$1.sdks", module_errors, errors.size()); + message = PyLocalize.sdkErrorlog$0ModsFailIn$1Sdks(module_errors, errors.size()).get(); } logErrors(errors, failedSdks, message); } } - private static void logErrors(@Nonnull final Map> errors, @Nonnull final List failedSdks, @Nonnull final String message) { - LOG.warn(PyBundle.message("sdk.some.skeletons.failed")); + private static void logErrors( + @Nonnull Map> errors, + @Nonnull List failedSdks, + @Nonnull String message + ) { + LOG.warn("Some skeletons failed to generate"); LOG.warn(message); if (failedSdks.size() > 0) { - LOG.warn(PyBundle.message("sdk.error.dialog.failed.sdks")); + LOG.warn("Failed interpreters"); LOG.warn(StringUtil.join(failedSdks, ", ")); } if (errors.size() > 0) { - LOG.warn(PyBundle.message("sdk.error.dialog.failed.modules")); + LOG.warn("Failed modules"); for (String sdkName : errors.keySet()) { for (String moduleName : errors.get(sdkName)) { LOG.warn(moduleName); @@ -185,12 +193,14 @@ private static void logErrors(@Nonnull final Map> errors, @ * @param skeletonsPath if known; null means 'determine and create as needed'. * @param indicator to report progress of long operations */ - public PySkeletonRefresher(@Nullable Project project, - @Nullable Component ownerComponent, - @Nonnull Sdk sdk, - @Nullable String skeletonsPath, - @Nullable ProgressIndicator indicator, - @Nullable String folder) throws InvalidSdkException { + public PySkeletonRefresher( + @Nullable Project project, + @Nullable Component ownerComponent, + @Nonnull Sdk sdk, + @Nullable String skeletonsPath, + @Nullable ProgressIndicator indicator, + @Nullable String folder + ) throws InvalidSdkException { myProject = project; myIndicator = indicator; mySdk = sdk; @@ -198,17 +208,17 @@ public PySkeletonRefresher(@Nullable Project project, mySkeletonsGenerator = new PySkeletonGenerator(getSkeletonsPath(), mySdk, folder); } - private void indicate(String msg) { + private void indicate(@Nonnull LocalizeValue msg) { if (myIndicator != null) { myIndicator.checkCanceled(); - myIndicator.setText(msg); - myIndicator.setText2(""); + myIndicator.setTextValue(msg); + myIndicator.setText2Value(LocalizeValue.empty()); } } private void indicateMinor(String msg) { if (myIndicator != null) { - myIndicator.setText2(msg); + myIndicator.setText2Value(LocalizeValue.ofNullable(msg)); } } @@ -218,28 +228,28 @@ private void checkCanceled() { } } - private static String calculateExtraSysPath(@Nonnull final Sdk sdk, @Nullable final String skeletonsPath) { - final File skeletons = skeletonsPath != null ? new File(skeletonsPath) : null; + private static String calculateExtraSysPath(@Nonnull Sdk sdk, @Nullable String skeletonsPath) { + File skeletons = skeletonsPath != null ? new File(skeletonsPath) : null; - final VirtualFile userSkeletonsDir = PyUserSkeletonsUtil.getUserSkeletonsDirectory(); - final File userSkeletons = userSkeletonsDir != null ? new File(userSkeletonsDir.getPath()) : null; + VirtualFile userSkeletonsDir = PyUserSkeletonsUtil.getUserSkeletonsDirectory(); + File userSkeletons = userSkeletonsDir != null ? new File(userSkeletonsDir.getPath()) : null; - final VirtualFile remoteSourcesDir = PySdkUtil.findAnyRemoteLibrary(sdk); - final File remoteSources = remoteSourcesDir != null ? new File(remoteSourcesDir.getPath()) : null; + VirtualFile remoteSourcesDir = PySdkUtil.findAnyRemoteLibrary(sdk); + File remoteSources = remoteSourcesDir != null ? new File(remoteSourcesDir.getPath()) : null; - final List paths = new ArrayList<>(); + List paths = new ArrayList<>(); paths.addAll(Arrays.asList(sdk.getRootProvider().getFiles(BinariesOrderRootType.getInstance()))); paths.addAll(BuildoutModuleExtension.getExtraPathForAllOpenModules()); - return Joiner.on(File.pathSeparator).join(ContainerUtil.mapNotNull(paths, (Function) file -> { + return Joiner.on(File.pathSeparator).join(ContainerUtil.mapNotNull(paths, (Function)file -> { if (file.isInLocalFileSystem()) { // We compare canonical files, not strings because "c:/some/folder" equals "c:\\some\\bin\\..\\folder\\" - final File canonicalFile = new File(file.getPath()); - if (canonicalFile.exists() && - !FileUtil.filesEqual(canonicalFile, skeletons) && - !FileUtil.filesEqual(canonicalFile, userSkeletons) && - !FileUtil.filesEqual(canonicalFile, remoteSources)) { + File canonicalFile = new File(file.getPath()); + if (canonicalFile.exists() + && !FileUtil.filesEqual(canonicalFile, skeletons) + && !FileUtil.filesEqual(canonicalFile, userSkeletons) + && !FileUtil.filesEqual(canonicalFile, remoteSources)) { return file.getPath(); } } @@ -256,7 +266,7 @@ private static String calculateExtraSysPath(@Nonnull final Sdk sdk, @Nullable fi public String getSkeletonsPath() throws InvalidSdkException { if (mySkeletonsPath == null) { mySkeletonsPath = PythonSdkType.getSkeletonsPath(ContainerPathManager.get().getSystemPath(), mySdk.getHomePath()); - final File skeletonsDir = new File(mySkeletonsPath); + File skeletonsDir = new File(mySkeletonsPath); if (!skeletonsDir.exists() && !skeletonsDir.mkdirs()) { throw new InvalidSdkException("Can't create skeleton dir " + String.valueOf(mySkeletonsPath)); } @@ -265,28 +275,28 @@ public String getSkeletonsPath() throws InvalidSdkException { } public List regenerateSkeletons(@Nullable SkeletonVersionChecker cachedChecker) throws InvalidSdkException { - final List errorList = new SmartList<>(); - final String homePath = mySdk.getHomePath(); - final String skeletonsPath = getSkeletonsPath(); - final File skeletonsDir = new File(skeletonsPath); + List errorList = new SmartList<>(); + String homePath = mySdk.getHomePath(); + String skeletonsPath = getSkeletonsPath(); + File skeletonsDir = new File(skeletonsPath); if (!skeletonsDir.exists()) { //noinspection ResultOfMethodCallIgnored skeletonsDir.mkdirs(); } - final String readablePath = UserHomeFileUtil.getLocationRelativeToUserHome(homePath); + String readablePath = UserHomeFileUtil.getLocationRelativeToUserHome(homePath); mySkeletonsGenerator.prepare(); myBlacklist = loadBlacklist(); - indicate(PyBundle.message("sdk.gen.querying.$0", readablePath)); + indicate(PyLocalize.sdkGenQuerying$0(readablePath)); // get generator version and binary libs list in one go - final String extraSysPath = calculateExtraSysPath(mySdk, getSkeletonsPath()); - final PySkeletonGenerator.ListBinariesResult binaries = mySkeletonsGenerator.listBinaries(mySdk, extraSysPath); + String extraSysPath = calculateExtraSysPath(mySdk, getSkeletonsPath()); + PySkeletonGenerator.ListBinariesResult binaries = mySkeletonsGenerator.listBinaries(mySdk, extraSysPath); myGeneratorVersion = binaries.generatorVersion; myPregeneratedSkeletons = findPregeneratedSkeletons(); - indicate(PyBundle.message("sdk.gen.reading.versions.file")); + indicate(PyLocalize.sdkGenReadingVersionsFile()); if (cachedChecker != null) { myVersionChecker = cachedChecker.withDefaultVersionIfUnknown(myGeneratorVersion); } @@ -295,11 +305,11 @@ public List regenerateSkeletons(@Nullable SkeletonVersionChecker cachedC } // check builtins - final String builtinsFileName = PythonSdkType.getBuiltinsFileName(mySdk); - final File builtinsFile = new File(skeletonsPath, builtinsFileName); + String builtinsFileName = PythonSdkType.getBuiltinsFileName(mySdk); + File builtinsFile = new File(skeletonsPath, builtinsFileName); - final SkeletonHeader oldHeader = readSkeletonHeader(builtinsFile); - final boolean oldOrNonExisting = oldHeader == null || oldHeader.getVersion() == 0; + SkeletonHeader oldHeader = readSkeletonHeader(builtinsFile); + boolean oldOrNonExisting = oldHeader == null || oldHeader.getVersion() == 0; if (myPregeneratedSkeletons != null && oldOrNonExisting) { unpackPreGeneratedSkeletons(); @@ -309,11 +319,11 @@ public List regenerateSkeletons(@Nullable SkeletonVersionChecker cachedC copyBaseSdkSkeletonsToVirtualEnv(skeletonsPath, binaries); } - final boolean builtinsUpdated = updateSkeletonsForBuiltins(readablePath, builtinsFile); + boolean builtinsUpdated = updateSkeletonsForBuiltins(readablePath, builtinsFile); if (!binaries.modules.isEmpty()) { - indicate(PyBundle.message("sdk.gen.updating.$0", readablePath)); - final List updateErrors = updateOrCreateSkeletons(binaries.modules); + indicate(PyLocalize.sdkGenUpdating$0(readablePath)); + List updateErrors = updateOrCreateSkeletons(binaries.modules); if (updateErrors.size() > 0) { indicateMinor(BLACKLIST_FILE_NAME); for (UpdateResult error : updateErrors) { @@ -329,26 +339,27 @@ public List regenerateSkeletons(@Nullable SkeletonVersionChecker cachedC } } - indicate(PyBundle.message("sdk.gen.reloading")); + indicate(PyLocalize.sdkGenReloading()); mySkeletonsGenerator.refreshGeneratedSkeletons(); if (!oldOrNonExisting) { - indicate(PyBundle.message("sdk.gen.cleaning.$0", readablePath)); + indicate(PyLocalize.sdkGenCleaning$0(readablePath)); cleanUpSkeletons(skeletonsDir); } if ((builtinsUpdated || PySdkUtil.isRemote(mySdk)) && myProject != null) { - ApplicationManager.getApplication().invokeLater(() -> DaemonCodeAnalyzer.getInstance(myProject).restart(), myProject.getDisposed()); + Application.get().invokeLater(() -> DaemonCodeAnalyzer.getInstance(myProject).restart(), myProject.getDisposed()); } return errorList; } private boolean updateSkeletonsForBuiltins(String readablePath, File builtinsFile) throws InvalidSdkException { - final SkeletonHeader newHeader = readSkeletonHeader(builtinsFile); - final boolean mustUpdateBuiltins = myPregeneratedSkeletons == null && (newHeader == null || newHeader.getVersion() < myVersionChecker.getBuiltinVersion()); + SkeletonHeader newHeader = readSkeletonHeader(builtinsFile); + boolean mustUpdateBuiltins = + myPregeneratedSkeletons == null && (newHeader == null || newHeader.getVersion() < myVersionChecker.getBuiltinVersion()); if (mustUpdateBuiltins) { - indicate(PyBundle.message("sdk.gen.updating.builtins.$0", readablePath)); + indicate(PyLocalize.sdkGenUpdatingBuiltins$0(readablePath)); mySkeletonsGenerator.generateBuiltinSkeletons(mySdk); if (myProject != null) { PythonSdkPathCache.getInstance(myProject, mySdk).clearBuiltins(); @@ -357,21 +368,26 @@ private boolean updateSkeletonsForBuiltins(String readablePath, File builtinsFil return mustUpdateBuiltins; } - private void copyBaseSdkSkeletonsToVirtualEnv(String skeletonsPath, PySkeletonGenerator.ListBinariesResult binaries) throws InvalidSdkException { - final Sdk base = PythonSdkType.getInstance().getVirtualEnvBaseSdk(mySdk); + private void copyBaseSdkSkeletonsToVirtualEnv( + String skeletonsPath, + PySkeletonGenerator.ListBinariesResult binaries + ) throws InvalidSdkException { + Sdk base = PythonSdkType.getInstance().getVirtualEnvBaseSdk(mySdk); if (base != null) { - indicate("Copying base SDK skeletons for virtualenv..."); - final String baseSkeletonsPath = PythonSdkType.getSkeletonsPath(ContainerPathManager.get().getSystemPath(), base.getHomePath()); - final PySkeletonGenerator.ListBinariesResult baseBinaries = mySkeletonsGenerator.listBinaries(base, calculateExtraSysPath(base, baseSkeletonsPath)); + indicate(LocalizeValue.localizeTODO("Copying base SDK skeletons for virtualenv...")); + String baseSkeletonsPath = PythonSdkType.getSkeletonsPath(ContainerPathManager.get().getSystemPath(), base.getHomePath()); + PySkeletonGenerator.ListBinariesResult baseBinaries = + mySkeletonsGenerator.listBinaries(base, calculateExtraSysPath(base, baseSkeletonsPath)); for (Map.Entry entry : binaries.modules.entrySet()) { - final String module = entry.getKey(); - final PyBinaryItem binary = entry.getValue(); - final PyBinaryItem baseBinary = baseBinaries.modules.get(module); - final File fromFile = getSkeleton(module, baseSkeletonsPath); + String module = entry.getKey(); + PyBinaryItem binary = entry.getValue(); + PyBinaryItem baseBinary = baseBinaries.modules.get(module); + File fromFile = getSkeleton(module, baseSkeletonsPath); if (baseBinaries.modules.containsKey(module) && fromFile.exists() && binary.length() == baseBinary.length()) { // Weak binary modules equality check - final File toFile = fromFile.isDirectory() ? getPackageSkeleton(module, skeletonsPath) : getModuleSkeleton(module, skeletonsPath); + File toFile = + fromFile.isDirectory() ? getPackageSkeleton(module, skeletonsPath) : getModuleSkeleton(module, skeletonsPath); try { FileUtil.copy(fromFile, toFile, FilePermissionCopier.BY_NIO2); } @@ -384,9 +400,9 @@ private void copyBaseSdkSkeletonsToVirtualEnv(String skeletonsPath, PySkeletonGe } private void unpackPreGeneratedSkeletons() throws InvalidSdkException { - indicate("Unpacking pregenerated skeletons..."); + indicate(LocalizeValue.localizeTODO("Unpacking pregenerated skeletons...")); try { - final VirtualFile jar = ArchiveVfsUtil.getVirtualFileForJar(myPregeneratedSkeletons); + VirtualFile jar = ArchiveVfsUtil.getVirtualFileForJar(myPregeneratedSkeletons); if (jar != null) { ZipUtil.extract(new File(jar.getPath()), new File(getSkeletonsPath()), null); } @@ -399,8 +415,7 @@ private void unpackPreGeneratedSkeletons() throws InvalidSdkException { @Nullable public static SkeletonHeader readSkeletonHeader(@Nonnull File file) { try { - final LineNumberReader reader = new LineNumberReader(new FileReader(file)); - try { + try (LineNumberReader reader = new LineNumberReader(new FileReader(file))) { String line = null; // Read 3 lines, skip first 2: encoding, module name for (int i = 0; i < 3; i++) { @@ -410,26 +425,23 @@ public static SkeletonHeader readSkeletonHeader(@Nonnull File file) { } } // Try the old whitespace-unsafe header format v1 first - final Matcher v1Matcher = VERSION_LINE_V1.matcher(line); + Matcher v1Matcher = VERSION_LINE_V1.matcher(line); if (v1Matcher.matches()) { return new SkeletonHeader(v1Matcher.group(1), fromVersionString(v1Matcher.group(2))); } - final Matcher fromMatcher = FROM_LINE_V2.matcher(line); + Matcher fromMatcher = FROM_LINE_V2.matcher(line); if (fromMatcher.matches()) { - final String binaryFile = fromMatcher.group(1); + String binaryFile = fromMatcher.group(1); line = reader.readLine(); if (line != null) { - final Matcher byMatcher = BY_LINE_V2.matcher(line); + Matcher byMatcher = BY_LINE_V2.matcher(line); if (byMatcher.matches()) { - final int version = fromVersionString(byMatcher.group(1)); + int version = fromVersionString(byMatcher.group(1)); return new SkeletonHeader(binaryFile, version); } } } } - finally { - reader.close(); - } } catch (IOException ignored) { } @@ -463,8 +475,7 @@ private Map> loadBlacklist() { Reader input; try { input = new FileReader(blacklistFile); - LineNumberReader lines = new LineNumberReader(input); - try { + try (LineNumberReader lines = new LineNumberReader(input)) { String line; do { line = lines.readLine(); @@ -472,11 +483,11 @@ private Map> loadBlacklist() { Matcher matcher = BLACKLIST_LINE.matcher(line); boolean notParsed = true; if (matcher.matches()) { - final int version = fromVersionString(matcher.group(2)); + int version = fromVersionString(matcher.group(2)); if (version > 0) { try { - final long timestamp = Long.parseLong(matcher.group(3)); - final String filename = matcher.group(1); + long timestamp = Long.parseLong(matcher.group(3)); + String filename = matcher.group(1); ret.put(filename, new Pair<>(version, timestamp)); notParsed = false; } @@ -494,9 +505,6 @@ private Map> loadBlacklist() { catch (IOException ex) { LOG.warn("Failed to read blacklist in " + mySkeletonsPath, ex); } - finally { - lines.close(); - } } catch (IOException ignore) { } @@ -548,9 +556,9 @@ private static void removeBlacklist(File skeletonDir) { * and remove the skeleton if the module file does not exist. * Works recursively starting from dir. Removes dirs that become empty. */ - private void cleanUpSkeletons(final File dir) { + private void cleanUpSkeletons(File dir) { indicateMinor(dir.getPath()); - final File[] files = dir.listFiles(); + File[] files = dir.listFiles(); if (files == null) { return; } @@ -574,7 +582,7 @@ else if (remaining != null && remaining.length == 1) { //clean also if contains } else if (item.isFile()) { // clean up an individual file - final String itemName = item.getName(); + String itemName = item.getName(); if (PyNames.INIT_DOT_PY.equals(itemName) && item.length() == 0) { continue; // these are versionless } @@ -584,10 +592,10 @@ else if (item.isFile()) { if (PythonSdkType.getBuiltinsFileName(mySdk).equals(itemName)) { continue; } - final SkeletonHeader header = readSkeletonHeader(item); + SkeletonHeader header = readSkeletonHeader(item); boolean canLive = header != null; if (canLive) { - final String binaryFile = header.getBinaryFile(); + String binaryFile = header.getBinaryFile(); canLive = SkeletonVersionChecker.BUILTIN_NAME.equals(binaryFile) || mySkeletonsGenerator.exists(binaryFile); } if (!canLive) { @@ -638,17 +646,17 @@ public Long getTimestamp() { private List updateOrCreateSkeletons(Map modules) throws InvalidSdkException { long startTime = System.currentTimeMillis(); - final List names = Lists.newArrayList(modules.keySet()); + List names = Lists.newArrayList(modules.keySet()); Collections.sort(names); - final List results = new ArrayList<>(); - final int count = names.size(); + List results = new ArrayList<>(); + int count = names.size(); for (int i = 0; i < count; i++) { checkCanceled(); if (myIndicator != null) { - myIndicator.setFraction((double) i / count); + myIndicator.setFraction((double)i / count); } - final String name = names.get(i); - final PyBinaryItem module = modules.get(name); + String name = names.get(i); + PyBinaryItem module = modules.get(name); if (module != null) { updateOrCreateSkeleton(module, results); } @@ -668,25 +676,25 @@ private void finishSkeletonsGeneration() { } private static File getSkeleton(String moduleName, String skeletonsPath) { - final File module = getModuleSkeleton(moduleName, skeletonsPath); + File module = getModuleSkeleton(moduleName, skeletonsPath); return module.exists() ? module : getPackageSkeleton(moduleName, skeletonsPath); } private static File getModuleSkeleton(String module, String skeletonsPath) { - final String modulePath = module.replace('.', '/'); + String modulePath = module.replace('.', '/'); return new File(skeletonsPath, modulePath + ".py"); } private static File getPackageSkeleton(String pkg, String skeletonsPath) { - final String packagePath = pkg.replace('.', '/'); + String packagePath = pkg.replace('.', '/'); return new File(new File(skeletonsPath, packagePath), PyNames.INIT_DOT_PY); } - private boolean updateOrCreateSkeleton(final PyBinaryItem binaryItem, final List errorList) throws InvalidSdkException { - final String moduleName = binaryItem.getModule(); + private boolean updateOrCreateSkeleton(PyBinaryItem binaryItem, List errorList) throws InvalidSdkException { + String moduleName = binaryItem.getModule(); - final File skeleton = getSkeleton(moduleName, getSkeletonsPath()); - final SkeletonHeader header = readSkeletonHeader(skeleton); + File skeleton = getSkeleton(moduleName, getSkeletonsPath()); + SkeletonHeader header = readSkeletonHeader(skeleton); boolean mustRebuild = true; // guilty unless proven fresh enough if (header != null) { int requiredVersion = myVersionChecker.getRequiredVersion(moduleName); @@ -755,7 +763,7 @@ public long lastModified() { private boolean copyPregeneratedSkeleton(String moduleName) throws InvalidSdkException { File targetDir; - final String modulePath = moduleName.replace('.', '/'); + String modulePath = moduleName.replace('.', '/'); File skeletonsDir = new File(getSkeletonsPath()); VirtualFile pregenerated = myPregeneratedSkeletons.findFileByRelativePath(modulePath + ".py"); if (pregenerated == null) { @@ -768,7 +776,7 @@ private boolean copyPregeneratedSkeleton(String moduleName) throws InvalidSdkExc targetDir = skeletonsDir; } else { - final String moduleParentPath = modulePath.substring(0, pos); + String moduleParentPath = modulePath.substring(0, pos); targetDir = new File(skeletonsDir, moduleParentPath); } } @@ -776,13 +784,9 @@ private boolean copyPregeneratedSkeleton(String moduleName) throws InvalidSdkExc LOG.info("Pregenerated skeleton for " + moduleName); File target = new File(targetDir, pregenerated.getName()); try { - FileOutputStream fos = new FileOutputStream(target); - try { + try (FileOutputStream fos = new FileOutputStream(target)) { FileUtil.copy(pregenerated.getInputStream(), fos); } - finally { - fos.close(); - } } catch (IOException e) { LOG.info("Error copying pregenerated skeleton", e); @@ -795,12 +799,12 @@ private boolean copyPregeneratedSkeleton(String moduleName) throws InvalidSdkExc @Nullable private VirtualFile findPregeneratedSkeletons() { - final File root = findPregeneratedSkeletonsRoot(); + File root = findPregeneratedSkeletonsRoot(); if (root == null) { return null; } LOG.info("Pregenerated skeletons root is " + root); - @NonNls final String versionString = mySdk.getVersionString(); + String versionString = mySdk.getVersionString(); if (versionString == null) { return null; } @@ -809,9 +813,10 @@ private VirtualFile findPregeneratedSkeletons() { return null; } + PlatformOperatingSystem os = Platform.current().os(); String version = versionString.toLowerCase().replace(" ", "-"); File f; - if (SystemInfo.isMac) { + if (os.isMac()) { String osVersion = SystemInfo.OS_VERSION; int dot = osVersion.indexOf('.'); if (dot >= 0) { @@ -823,12 +828,12 @@ private VirtualFile findPregeneratedSkeletons() { f = new File(root, "skeletons-mac-" + myGeneratorVersion + "-" + osVersion + "-" + version + ".zip"); } else { - String os = SystemInfo.isWindows ? "win" : "nix"; - f = new File(root, "skeletons-" + os + "-" + myGeneratorVersion + "-" + version + ".zip"); + String osAbbr = os.isWindows() ? "win" : "nix"; + f = new File(root, "skeletons-" + osAbbr + "-" + myGeneratorVersion + "-" + version + ".zip"); } if (f.exists()) { LOG.info("Found pregenerated skeletons at " + f.getPath()); - final VirtualFile virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(f); + VirtualFile virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(f); if (virtualFile == null) { LOG.info("Could not find pregenerated skeletons in VFS"); return null; @@ -843,7 +848,7 @@ private VirtualFile findPregeneratedSkeletons() { @Nullable private static File findPregeneratedSkeletonsRoot() { - final String path = ContainerPathManager.get().getHomePath(); + String path = ContainerPathManager.get().getHomePath(); LOG.info("Home path is " + path); File f = new File(path, "python/skeletons"); // from sources if (f.exists()) { @@ -864,11 +869,15 @@ private static File findPregeneratedSkeletonsRoot() { * @param assemblyRefs refs that generator wants to know in .net environment, if applicable * @param resultConsumer accepts true if generation completed successfully */ - public void generateSkeleton(@Nonnull String modname, @Nullable String modfilename, @Nullable List assemblyRefs, Consumer resultConsumer) throws InvalidSdkException { + public void generateSkeleton( + @Nonnull String modname, + @Nullable String modfilename, + @Nullable List assemblyRefs, + Consumer resultConsumer + ) throws InvalidSdkException { mySkeletonsGenerator.generateSkeleton(modname, modfilename, assemblyRefs, getExtraSyspath(), mySdk.getHomePath(), resultConsumer); } - private String getExtraSyspath() { if (myExtraSyspath == null) { myExtraSyspath = calculateExtraSysPath(mySdk, mySkeletonsPath); diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/skeletons/SkeletonErrorsDialog.java b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/skeletons/SkeletonErrorsDialog.java index 048c1964..585f5572 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/skeletons/SkeletonErrorsDialog.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/skeletons/SkeletonErrorsDialog.java @@ -13,83 +13,76 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.jetbrains.python.impl.sdk.skeletons; +import consulo.python.impl.localize.PyLocalize; import consulo.ui.ex.awt.JBScrollPane; -import com.jetbrains.python.impl.PyBundle; import javax.swing.*; import javax.swing.border.EmptyBorder; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.util.List; import java.util.Map; public class SkeletonErrorsDialog extends JDialog { - private JPanel contentPane; - private JButton buttonOK; - private JBScrollPane myScroller; - private JTextPane myMessagePane; + private JPanel contentPane; + private JButton buttonOK; + private JBScrollPane myScroller; + private JTextPane myMessagePane; - public SkeletonErrorsDialog(Map> errors, List failed_sdks) { - setContentPane(contentPane); - setModal(true); - getRootPane().setDefaultButton(buttonOK); + public SkeletonErrorsDialog(Map> errors, List failed_sdks) { + setContentPane(contentPane); + setModal(true); + getRootPane().setDefaultButton(buttonOK); - buttonOK.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - dispose(); - } - }); + buttonOK.addActionListener(e -> dispose()); - // fill data - myMessagePane.setContentType("text/html"); - myMessagePane.setBorder(new EmptyBorder(0, 0, 0, 0)); - StringBuilder sb = new StringBuilder(""); + // fill data + myMessagePane.setContentType("text/html"); + myMessagePane.setBorder(new EmptyBorder(0, 0, 0, 0)); + StringBuilder sb = new StringBuilder(""); - if (failed_sdks.size() > 0) { - sb.append("

").append(PyBundle.message("sdk.error.dialog.failed.sdks")).append("

"); - sb.append("
    "); - for (String sdk_name : failed_sdks) { - sb.append("
  • ").append(sdk_name).append("
  • "); - } - sb.append("

"); - } + if (failed_sdks.size() > 0) { + sb.append("

").append(PyLocalize.sdkErrorDialogFailedSdks()).append("

"); + sb.append("
    "); + for (String sdk_name : failed_sdks) { + sb.append("
  • ").append(sdk_name).append("
  • "); + } + sb.append("

"); + } - if (errors.size() > 0) { - sb.append("

").append(PyBundle.message("sdk.error.dialog.failed.modules")).append("

"); - for (String sdk_name : errors.keySet()) { - sb.append("").append(sdk_name).append("
"); - sb.append("
    "); - for (String module_name : errors.get(sdk_name)) { - sb.append("
  • ").append(module_name).append("
  • "); + if (errors.size() > 0) { + sb.append("

    ").append(PyLocalize.sdkErrorDialogFailedModules()).append("

    "); + for (String sdk_name : errors.keySet()) { + sb.append("").append(sdk_name).append("
    "); + sb.append("
      "); + for (String module_name : errors.get(sdk_name)) { + sb.append("
    • ").append(module_name).append("
    • "); + } + sb.append("
    "); + } + sb.append(PyLocalize.sdkErrorDialogWereBlacklisted()); } - sb.append("
"); - } - sb.append(PyBundle.message("sdk.error.dialog.were.blacklisted")); - } - sb.append(""); - myMessagePane.setText(sb.toString()); + sb.append(""); + myMessagePane.setText(sb.toString()); - setTitle(PyBundle.message("sdk.error.dialog.problems")); + setTitle(PyLocalize.sdkErrorDialogProblems().get()); - pack(); - setLocationRelativeTo(getParent()); - } + pack(); + setLocationRelativeTo(getParent()); + } - private static String getHTMLColor(Color color) { - StringBuilder sb = new StringBuilder("#"); - sb.append(Integer.toHexString(color.getRGB() & 0xffffff)); - return sb.toString(); - } + private static String getHTMLColor(Color color) { + StringBuilder sb = new StringBuilder("#"); + sb.append(Integer.toHexString(color.getRGB() & 0xffffff)); + return sb.toString(); + } } diff --git a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/skeletons/SkeletonVersionChecker.java b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/skeletons/SkeletonVersionChecker.java index 6da59a99..30ffe4b8 100644 --- a/python-impl/src/main/java/com/jetbrains/python/impl/sdk/skeletons/SkeletonVersionChecker.java +++ b/python-impl/src/main/java/com/jetbrains/python/impl/sdk/skeletons/SkeletonVersionChecker.java @@ -16,10 +16,9 @@ package com.jetbrains.python.impl.sdk.skeletons; -import consulo.logging.Logger; import com.jetbrains.python.impl.PythonHelpersLocator; import consulo.language.psi.util.QualifiedName; -import org.jetbrains.annotations.NonNls; +import consulo.logging.Logger; import java.io.*; import java.util.Comparator; @@ -33,155 +32,160 @@ * Parses required_gen_version file. * Efficiently checks file versions against it. * Is immutable. - *
- * User: dcheryasov - * Date: 2/23/11 5:32 PM + * + * @author dcheryasov + * @since 2011-02-23 */ public class SkeletonVersionChecker { - private static final Logger LOG = Logger.getInstance("#com.jetbrains.python.sdk.PythonSdkType.SkeletonVersionChecker"); - - final static Pattern ONE_LINE = Pattern.compile("^(?:(\\w+(?:\\.\\w+)*|\\(built-in\\)|\\(default\\))\\s+(\\d+\\.\\d+))?\\s*(?:#.*)?$"); - - @NonNls static final String REQUIRED_VERSION_FNAME = "required_gen_version"; - @NonNls static final String DEFAULT_NAME = "(default)"; // version required if a package is not explicitly mentioned - @NonNls public static final String BUILTIN_NAME = "(built-in)"; // version required for built-ins - private TreeMap myExplicitVersion; // versions of regularly named packages - private Integer myDefaultVersion; // version of (default) - private Integer myBuiltinsVersion; // version of (built-it) - - /** - * Creates an instance, loads requirements file. - */ - public SkeletonVersionChecker(int defaultVersion) { - myExplicitVersion = createTreeMap(); - myDefaultVersion = defaultVersion; - load(); - } - - private static TreeMap createTreeMap() { - return new TreeMap(new Comparator() { - @Override - public int compare(QualifiedName left, QualifiedName right) { - Iterator lefts = left.getComponents().iterator(); - Iterator rights = right.getComponents().iterator(); - while (lefts.hasNext() && rights.hasNext()) { - int res = lefts.next().compareTo(rights.next()); - if (res != 0) return res; - } - if (lefts.hasNext()) return 1; - if (rights.hasNext()) return -1; - return 0; // equal - } - }); - } - - SkeletonVersionChecker(TreeMap explicit, Integer builtins) { - myExplicitVersion = explicit; - myBuiltinsVersion = builtins; - } - - /** - * @param version the new default version - * @return a shallow copy of this with different default version. - */ - public SkeletonVersionChecker withDefaultVersionIfUnknown(int version) { - SkeletonVersionChecker ret = new SkeletonVersionChecker(myExplicitVersion, myBuiltinsVersion); - ret.myDefaultVersion = myDefaultVersion != 0 ? myDefaultVersion : version; - return ret; - } - - private void load() { - // load the required versions file - File infile = PythonHelpersLocator.getHelperFile(REQUIRED_VERSION_FNAME); - try { - if (infile.canRead()) { - Reader input = new FileReader(infile); - LineNumberReader lines = new LineNumberReader(input); + private static final Logger LOG = Logger.getInstance("#com.jetbrains.python.sdk.PythonSdkType.SkeletonVersionChecker"); + + private static final Pattern ONE_LINE = + Pattern.compile("^(?:(\\w+(?:\\.\\w+)*|\\(built-in\\)|\\(default\\))\\s+(\\d+\\.\\d+))?\\s*(?:#.*)?$"); + + static final String REQUIRED_VERSION_FNAME = "required_gen_version"; + static final String DEFAULT_NAME = "(default)"; // version required if a package is not explicitly mentioned + public static final String BUILTIN_NAME = "(built-in)"; // version required for built-ins + private TreeMap myExplicitVersion; // versions of regularly named packages + private Integer myDefaultVersion; // version of (default) + private Integer myBuiltinsVersion; // version of (built-it) + + /** + * Creates an instance, loads requirements file. + */ + public SkeletonVersionChecker(int defaultVersion) { + myExplicitVersion = createTreeMap(); + myDefaultVersion = defaultVersion; + load(); + } + + private static TreeMap createTreeMap() { + return new TreeMap<>((Comparator)(left, right) -> { + Iterator lefts = left.getComponents().iterator(); + Iterator rights = right.getComponents().iterator(); + while (lefts.hasNext() && rights.hasNext()) { + int res = lefts.next().compareTo(rights.next()); + if (res != 0) { + return res; + } + } + if (lefts.hasNext()) { + return 1; + } + if (rights.hasNext()) { + return -1; + } + return 0; // equal + }); + } + + SkeletonVersionChecker(TreeMap explicit, Integer builtins) { + myExplicitVersion = explicit; + myBuiltinsVersion = builtins; + } + + /** + * @param version the new default version + * @return a shallow copy of this with different default version. + */ + public SkeletonVersionChecker withDefaultVersionIfUnknown(int version) { + SkeletonVersionChecker ret = new SkeletonVersionChecker(myExplicitVersion, myBuiltinsVersion); + ret.myDefaultVersion = myDefaultVersion != 0 ? myDefaultVersion : version; + return ret; + } + + private void load() { + // load the required versions file + File infile = PythonHelpersLocator.getHelperFile(REQUIRED_VERSION_FNAME); try { - String line; - do { - line = lines.readLine(); - if (line != null) { - Matcher matcher = ONE_LINE.matcher(line); - if (matcher.matches()) { - String package_name = matcher.group(1); - String ver = matcher.group(2); - if (package_name != null) { - final int version = fromVersionString(ver); - if (DEFAULT_NAME.equals(package_name)) { - myDefaultVersion = version; - } - else if (BUILTIN_NAME.equals(package_name)) { - myBuiltinsVersion = version; - } - else { - myExplicitVersion.put(QualifiedName.fromDottedString(package_name), version); - } - } // else the whole line is a valid comment, and both catch groups are null - } - else LOG.warn(REQUIRED_VERSION_FNAME + ":" + lines.getLineNumber() + " Incorrect line, ignored" ); + if (infile.canRead()) { + Reader input = new FileReader(infile); + try (LineNumberReader lines = new LineNumberReader(input)) { + String line; + do { + line = lines.readLine(); + if (line != null) { + Matcher matcher = ONE_LINE.matcher(line); + if (matcher.matches()) { + String package_name = matcher.group(1); + String ver = matcher.group(2); + if (package_name != null) { + int version = fromVersionString(ver); + if (DEFAULT_NAME.equals(package_name)) { + myDefaultVersion = version; + } + else if (BUILTIN_NAME.equals(package_name)) { + myBuiltinsVersion = version; + } + else { + myExplicitVersion.put(QualifiedName.fromDottedString(package_name), version); + } + } // else the whole line is a valid comment, and both catch groups are null + } + else { + LOG.warn(REQUIRED_VERSION_FNAME + ":" + lines.getLineNumber() + " Incorrect line, ignored"); + } + } + } + while (line != null); + if (myBuiltinsVersion == null) { + myBuiltinsVersion = myDefaultVersion; + LOG.warn("Assuming default version for built-ins"); + } + assert (myDefaultVersion != null) : "Default version not known somehow!"; + } } - } while (line != null); - if (myBuiltinsVersion == null) { - myBuiltinsVersion = myDefaultVersion; - LOG.warn("Assuming default version for built-ins"); - } - assert (myDefaultVersion != null) : "Default version not known somehow!"; } - finally { - lines.close(); + catch (IOException e) { + throw new LoadException(e); } - } } - catch (IOException e) { - throw new LoadException(e); + + public int getRequiredVersion(String package_name) { + QualifiedName qname = QualifiedName.fromDottedString(package_name); + Map.Entry found = myExplicitVersion.floorEntry(qname); + if (found != null && qname.matchesPrefix(found.getKey())) { + return found.getValue(); + } + return myDefaultVersion; } - } - public int getRequiredVersion(String package_name) { - QualifiedName qname = QualifiedName.fromDottedString(package_name); - Map.Entry found = myExplicitVersion.floorEntry(qname); - if (found != null && qname.matchesPrefix(found.getKey())) { - return found.getValue(); + public int getBuiltinVersion() { + if (myBuiltinsVersion == null) { + myBuiltinsVersion = myDefaultVersion; + // we could have started with no default and no builtins set, then default set by withDefaultVersionIfUnknown + } + return myBuiltinsVersion; } - return myDefaultVersion; - } - public int getBuiltinVersion() { - if (myBuiltinsVersion == null) { - myBuiltinsVersion = myDefaultVersion; - // we could have started with no default and no builtins set, then default set by withDefaultVersionIfUnknown + /** + * Transforms a string like "1.2" into an integer representing it. + * + * @param input + * @return an int representing the version: major number shifted 8 bit and minor number added. or 0 if version can't be parsed. + */ + public static int fromVersionString(String input) { + int dot_pos = input.indexOf('.'); + try { + if (dot_pos > 0) { + int major = Integer.parseInt(input.substring(0, dot_pos)); + int minor = Integer.parseInt(input.substring(dot_pos + 1)); + return (major << 8) + minor; + } + } + catch (NumberFormatException ignore) { + } + return 0; } - return myBuiltinsVersion; - } - - /** - * Transforms a string like "1.2" into an integer representing it. - * @param input - * @return an int representing the version: major number shifted 8 bit and minor number added. or 0 if version can't be parsed. - */ - public static int fromVersionString(final String input) { - int dot_pos = input.indexOf('.'); - try { - if (dot_pos > 0) { - int major = Integer.parseInt(input.substring(0, dot_pos)); - int minor = Integer.parseInt(input.substring(dot_pos+1)); - return (major << 8) + minor; - } + + public static String toVersionString(int input) { + int major = input >> 8; + int minor = input - (major << 8); + return String.valueOf(major) + "." + minor; } - catch (NumberFormatException ignore) { } - return 0; - } - - public static String toVersionString(final int input) { - int major = input >> 8; - int minor = input - (major << 8); - return String.valueOf(major) + "." + minor; - } - - public static class LoadException extends RuntimeException { - public LoadException(Throwable e) { - super(e); + + public static class LoadException extends RuntimeException { + public LoadException(Throwable e) { + super(e); + } } - } }