PY-73525 Split HelpersLocator into Community/Pro versions

Merge-request: IJ-MR-138058
Merged-by: Egor Eliseev <Egor.Eliseev@jetbrains.com>

GitOrigin-RevId: cd82bc44337e7fdd182262c44ea5ca29e1804ad2
This commit is contained in:
Egor.Eliseev
2024-07-02 11:43:46 +00:00
committed by intellij-monorepo-bot
parent 780614edb7
commit 58d8eddeb8
26 changed files with 205 additions and 211 deletions

View File

@@ -64,21 +64,22 @@ object PythonCommunityPluginModules {
spec.directoryName = name
spec.mainJarName = "$name.jar"
spec.withModules(modules)
spec.withGeneratedResources { targetDir, context ->
val output = targetDir.resolve("helpers")
Files.createDirectories(output)
copyDir(
sourceDir = context.paths.communityHomeDir.resolve("python/helpers"), targetDir = output,
dirFilter = { path ->
when {
path.endsWith("tests") || path.endsWith(".idea") -> false
path.parent?.fileName?.toString() == "pydev" -> !path.fileName.toString().startsWith("pydev_test")
else -> true
}
},
fileFilter = { path -> !path.endsWith("setup.py") && !path.endsWith("conftest.py") }
)
if (mainModuleName == "intellij.python.community.plugin") {
spec.withGeneratedResources { targetDir, context ->
val output = targetDir.resolve("helpers")
Files.createDirectories(output)
copyDir(
sourceDir = context.paths.communityHomeDir.resolve("python/helpers"), targetDir = output,
dirFilter = { path ->
when {
path.endsWith("tests") || path.endsWith(".idea") -> false
path.parent?.fileName?.toString() == "pydev" -> !path.fileName.toString().startsWith("pydev_test")
else -> true
}
},
fileFilter = { path -> !path.endsWith("setup.py") && !path.endsWith("conftest.py") }
)
}
}
// required for "Python Console" in PythonCore plugin

View File

@@ -502,6 +502,9 @@
<extensionPoint qualifiedName="Pythonid.pyiStubSuppressor"
interface="com.jetbrains.python.pyi.PyiStubSuppressor"
dynamic="true"/>
<extensionPoint qualifiedName="com.jetbrains.python.pythonHelpersLocator"
interface="com.jetbrains.python.PythonHelpersLocator"
dynamic="true"/>
</extensionPoints>
<extensions defaultExtensionNs="Pythonid">
@@ -577,4 +580,8 @@
<pyiStubSuppressor implementation="com.jetbrains.python.tensorFlow.TensorflowPyiStubsSuppressor"/>
</extensions>
<extensions defaultExtensionNs="com.jetbrains.python">
<pythonHelpersLocator implementation="com.jetbrains.python.PythonHelpersLocatorDefault" />
</extensions>
</idea-plugin>

View File

@@ -1,148 +0,0 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.python;
import com.intellij.ide.plugins.PluginManagerCore;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.util.PathUtil;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.nio.file.Path;
import java.util.List;
public final class PythonHelpersLocator {
private static final Logger LOG = Logger.getInstance(PythonHelpersLocator.class);
private static final String PROPERTY_HELPERS_LOCATION = "idea.python.helpers.path";
private static final String EXPECTED_PRO_HELPER_PACKAGE = "jupyter_debug";
private static final String PRO_HELPERS_DIR = "helpers-pro";
private static final String PYTHON_PRO_PLUGIN_NAME = "python";
private PythonHelpersLocator() { }
/**
* @return the base directory under which various scripts, etc. are stored.
*/
public static @NotNull File getHelpersRoot() {
String property = System.getProperty(PROPERTY_HELPERS_LOCATION);
if (property != null) {
return new File(property);
}
return assertHelpersLayout(getHelperRoot("intellij.python.helpers", "/python/helpers"));
}
public static @NotNull Path getHelpersProRoot() {
return assertHelpersProLayout(getExpectedHelpersProRootLocation()).toPath().normalize();
}
@ApiStatus.Internal
public static boolean hasHelpersPro() {
return new File(getExpectedHelpersProRootLocation(), EXPECTED_PRO_HELPER_PACKAGE).exists();
}
private static @NotNull File getExpectedHelpersProRootLocation() {
return getHelperRoot("intellij.python.helpers.pro", "/../python/helpers-pro");
}
private static @NotNull File getHelperRoot(@NotNull String moduleName, @NotNull String relativePath) {
@NonNls String jarPath = PathUtil.getJarPathForClass(PythonHelpersLocator.class);
if (PluginManagerCore.isRunningFromSources()) {
return new File(PathManager.getCommunityHomePath() + relativePath);
}
else {
final File pluginBaseDir = getPluginBaseDir(jarPath);
if (pluginBaseDir != null) {
return createWithPluginBaseDir(pluginBaseDir, relativePath);
}
else {
return new File(new File(jarPath).getParentFile(), moduleName);
}
}
}
private static @NotNull File createWithPluginBaseDir(@NotNull File corePluginBaseDir, @NotNull String relativePath) {
if (relativePath.contains(PRO_HELPERS_DIR)) {
File proPluginBaseDir = new File(corePluginBaseDir.getParentFile(), PYTHON_PRO_PLUGIN_NAME);
return new File(proPluginBaseDir, PathUtil.getFileName(relativePath));
}
return new File(corePluginBaseDir, PathUtil.getFileName(relativePath));
}
private static @Nullable File getPluginBaseDir(@NonNls String jarPath) {
if (jarPath.endsWith(".jar")) {
final File jarFile = new File(jarPath);
LOG.assertTrue(jarFile.exists(), "jar file cannot be null");
return jarFile.getParentFile().getParentFile();
}
return null;
}
private static @NotNull File assertHelpersLayout(@NotNull File root) {
final String path = root.getAbsolutePath();
LOG.assertTrue(root.exists(), "Helpers root does not exist " + path);
for (String child : List.of("generator3", "pycharm", "pycodestyle.py", "pydev", "syspath.py", "typeshed")) {
LOG.assertTrue(new File(root, child).exists(), "No '" + child + "' inside " + path);
}
return root;
}
private static @NotNull File assertHelpersProLayout(@NotNull File root) {
final String path = root.getAbsolutePath();
LOG.assertTrue(root.exists(), "Helpers pro root does not exist " + path);
LOG.assertTrue(new File(root, EXPECTED_PRO_HELPER_PACKAGE).exists(),
"No '" + EXPECTED_PRO_HELPER_PACKAGE + "' inside " + path);
return root;
}
/**
* Find a resource by name under helper root.
*
* @param resourceName a path relative to helper root
* @return absolute path of the resource
*/
public static String getHelperPath(@NonNls @NotNull String resourceName) {
return getHelperFile(resourceName).getAbsolutePath();
}
/**
* Finds a resource file by name under helper root.
*
* @param resourceName a path relative to helper root
* @return a file object pointing to that path; existence is not checked.
*/
public static @NotNull File getHelperFile(@NotNull String resourceName) {
return new File(getHelpersRoot(), resourceName);
}
public static String getPythonCommunityPath() {
File pathFromUltimate = new File(PathManager.getHomePath(), "community/python");
if (pathFromUltimate.exists()) {
return pathFromUltimate.getPath();
}
return new File(PathManager.getHomePath(), "python").getPath();
}
}

View File

@@ -0,0 +1,143 @@
/*
* Copyright 2000-2024 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.python
import com.intellij.ide.plugins.PluginManagerCore
import com.intellij.openapi.application.PathManager
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.extensions.ExtensionPointName
import com.intellij.util.PathUtil
import org.jetbrains.annotations.NonNls
import java.io.File
import java.nio.file.Path
abstract class PythonHelpersLocator {
companion object {
val LOG = Logger.getInstance(PythonHelpersLocator::class.java)
private const val PROPERTY_HELPERS_LOCATION = "idea.python.helpers.path"
const val COMMUNITY_HELPERS_MODULE_NAME = "intellij.python.helpers"
private val EP_NAME: ExtensionPointName<PythonHelpersLocator> =
ExtensionPointName.create("com.jetbrains.python.pythonHelpersLocator")
/**
* @return A list of Path objects representing the roots of the Python Helpers.
*/
@JvmStatic
fun getHelpersRoots(): List<Path> = EP_NAME.extensionList.first().getRoots()
/**
* Retrieves the root file of the Community Helpers extension.
* Community Helpers root always should be first in an extension list
*
* @return The root File of the Community Helpers extension.
*/
@JvmStatic
fun getCommunityHelpersRoot(): File = EP_NAME.extensionList.first().getRoots().first().toFile()
/**
* Retrieves File of a helper file given its resource name.
*
* @param resourceName The name of the helper resource file.
* @return File of the helper file, or null if the file does not exist.
*/
@JvmStatic
fun findFileInHelpers(resourceName: String): File? {
for (helperRoot in getHelpersRoots()) {
val file = File(helperRoot.toFile(), resourceName)
if (file.exists())
return file
}
LOG.warn("File $resourceName does not exist in helpers root")
return null
}
/**
* Retrieves the absolute path of a helper file given its resource name.
*
* @param resourceName The name of the helper resource file.
* @return The absolute path of the helper file, or null if the file does not exist.
*/
@JvmStatic
fun findPathInHelpers(@NonNls resourceName: String): String = findFileInHelpers(resourceName)?.absolutePath ?: ""
@JvmStatic
fun getPythonCommunityPath(): String {
val pathFromUltimate = File(PathManager.getHomePath(), "community/python")
if (pathFromUltimate.exists()) {
return pathFromUltimate.path
}
return File(PathManager.getHomePath(), "python").path
}
@Deprecated("Use {@link PythonHelpersLocator#findPathInHelpers}.", ReplaceWith("findPathInHelpers(resourceName)"))
@JvmStatic
fun getHelperPath(@NonNls resourceName: String): String = findPathInHelpers(resourceName)
}
// Always add Community Helpers root on the first place of root's list
protected open fun getRoots(): List<Path> = listOf(getCommunityHelpersRootFile().toPath().normalize())
private fun getCommunityHelpersRootFile(): File {
val property = System.getProperty(PROPERTY_HELPERS_LOCATION)
return if (property != null) {
File(property)
}
else getHelpersRoot(COMMUNITY_HELPERS_MODULE_NAME, "/python/helpers").also {
assertHelpersLayout(it)
}
}
protected open fun getHelpersRoot(moduleName: String, relativePath: String): File =
findRootByJarPath(PathUtil.getJarPathForClass(PythonHelpersLocator::class.java), moduleName, relativePath)
protected fun findRootByJarPath(jarPath: String, moduleName: String, relativePath: String): File {
return if (PluginManagerCore.isRunningFromSources()) {
File(PathManager.getCommunityHomePath() + relativePath)
}
else {
getPluginBaseDir(jarPath)?.let {
File(it, PathUtil.getFileName(relativePath))
} ?: File(File(jarPath).parentFile, moduleName)
}
}
private fun getPluginBaseDir(jarPath: String): File? {
if (jarPath.endsWith(".jar")) {
val jarFile = File(jarPath)
LOG.assertTrue(jarFile.exists(), "jar file cannot be null")
return jarFile.parentFile.parentFile
}
return null
}
private fun assertHelpersLayout(root: File): File {
val path = root.absolutePath
LOG.assertTrue(root.exists(), "Helpers root does not exist $path")
listOf("generator3", "pycharm", "pycodestyle.py", "pydev", "syspath.py", "typeshed").forEach { child ->
LOG.assertTrue(File(root, child).exists(), "No '$child' inside $path")
}
return root
}
}
internal class PythonHelpersLocatorDefault : PythonHelpersLocator()

View File

@@ -30,7 +30,7 @@ public final class PyStdlibUtil {
@Nullable
private static Set<String> loadStdlibPackagesList() {
final Logger log = Logger.getInstance(PyStdlibUtil.class.getName());
final String helperPath = PythonHelpersLocator.getHelperPath("/tools/stdlib_packages.txt");
final String helperPath = PythonHelpersLocator.findPathInHelpers("/tools/stdlib_packages.txt");
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(helperPath), StandardCharsets.UTF_8))) {
return reader.lines().collect(Collectors.toSet());
}

View File

@@ -158,7 +158,7 @@ object PyTypeShed {
get() {
val paths = listOf("${PathManager.getConfigPath()}/typeshed",
"${PathManager.getConfigPath()}/../typeshed",
PythonHelpersLocator.getHelperPath("typeshed"))
PythonHelpersLocator.findPathInHelpers("typeshed"))
return paths.asSequence()
.filter { File(it).exists() }
.firstOrNull()

View File

@@ -81,7 +81,7 @@ public final class PyUserSkeletonsUtil {
private static List<String> getPossibleUserSkeletonsPaths() {
final List<String> result = new ArrayList<>();
result.add(PathManager.getConfigPath() + File.separator + USER_SKELETONS_DIR);
result.add(PythonHelpersLocator.getHelperPath(USER_SKELETONS_DIR));
result.add(PythonHelpersLocator.findPathInHelpers(USER_SKELETONS_DIR));
return result;
}

View File

@@ -203,7 +203,7 @@ public class PyDocumentationBuilder {
private void buildForKeyword(@NotNull String name) {
try {
try (FileReader reader = new FileReader(PythonHelpersLocator.getHelperPath("/tools/python_keywords/" + name),
try (FileReader reader = new FileReader(PythonHelpersLocator.findPathInHelpers("/tools/python_keywords/" + name),
StandardCharsets.UTF_8)) {
final String text = FileUtil.loadTextAndClose(reader);
final String converted = StringUtil.convertLineSeparators(text, "\n");

View File

@@ -42,7 +42,7 @@ public final class UnsupportedFeaturesUtil {
private static void fillTestCaseMethods() throws IOException {
final Logger log = Logger.getInstance(UnsupportedFeaturesUtil.class.getName());
try (FileReader reader = new FileReader(PythonHelpersLocator.getHelperPath("/tools/class_method_versions.xml"))) {
try (FileReader reader = new FileReader(PythonHelpersLocator.findPathInHelpers("/tools/class_method_versions.xml"))) {
final XMLReader xr = XMLReaderFactory.createXMLReader();
final ClassMethodsParser parser = new ClassMethodsParser();
xr.setContentHandler(parser);
@@ -55,7 +55,7 @@ public final class UnsupportedFeaturesUtil {
private static void fillMaps() throws IOException {
Logger log = Logger.getInstance(UnsupportedFeaturesUtil.class.getName());
try (FileReader reader = new FileReader(PythonHelpersLocator.getHelperPath("/tools/versions.xml"))) {
try (FileReader reader = new FileReader(PythonHelpersLocator.findPathInHelpers("/tools/versions.xml"))) {
XMLReader xr = XMLReaderFactory.createXMLReader();
VersionsParser parser = new VersionsParser();
xr.setContentHandler(parser);

View File

@@ -97,7 +97,7 @@ public class PyLegacySkeletonGenerator extends PySkeletonGenerator {
public List<String> getCommandLine() {
final List<String> commandLine = new ArrayList<>();
commandLine.add(mySdk.getHomePath());
commandLine.add(PythonHelpersLocator.getHelperPath(GENERATOR3));
commandLine.add(PythonHelpersLocator.findPathInHelpers(GENERATOR3));
commandLine.add("-d");
commandLine.add(mySkeletonsPath);
if (!ContainerUtil.isEmpty(myAssemblyRefs)) {

View File

@@ -18,8 +18,7 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static com.jetbrains.python.PythonHelpersLocator.getHelperFile;
import static com.jetbrains.python.PythonHelpersLocator.getHelpersRoot;
import static com.jetbrains.python.PythonHelpersLocator.*;
public enum PythonHelper implements HelperPackage {
GENERATOR3("generator3/__main__.py"),
@@ -91,12 +90,12 @@ public enum PythonHelper implements HelperPackage {
private static @NotNull PathHelperPackage findModule(String moduleEntryPoint, String path, boolean asModule, String[] thirdPartyDependencies) {
List<HelperDependency> dependencies = HelperDependency.findThirdPartyDependencies(thirdPartyDependencies);
if (getHelperFile(path + ".zip").isFile()) {
if (findFileInHelpers(path + ".zip") != null) {
return new ModuleHelperPackage(moduleEntryPoint, path + ".zip", dependencies);
}
if (!asModule && new File(getHelperFile(path), moduleEntryPoint + ".py").isFile()) {
return new ScriptPythonHelper(moduleEntryPoint + ".py", getHelperFile(path), dependencies);
if (!asModule && new File(findFileInHelpers(path), moduleEntryPoint + ".py").isFile()) {
return new ScriptPythonHelper(moduleEntryPoint + ".py", findFileInHelpers(path), dependencies);
}
return new ModuleHelperPackage(moduleEntryPoint, path, dependencies);
@@ -113,7 +112,7 @@ public enum PythonHelper implements HelperPackage {
}
PythonHelper(String helperScript) {
myModule = new ScriptPythonHelper(helperScript, getHelpersRoot(), Collections.emptyList());
myModule = new ScriptPythonHelper(helperScript, getCommunityHelpersRoot(), Collections.emptyList());
}
public abstract static class PathHelperPackage implements HelperPackage {
@@ -187,7 +186,7 @@ public enum PythonHelper implements HelperPackage {
private final String myModuleName;
public ModuleHelperPackage(String moduleName, String relativePath, @NotNull List<HelperDependency> dependencies) {
super(getHelperFile(relativePath).getAbsolutePath(), dependencies);
super(findPathInHelpers(relativePath), dependencies);
this.myModuleName = moduleName;
}
@@ -255,7 +254,7 @@ public enum PythonHelper implements HelperPackage {
}
private static @NotNull File getHelpersThirdPartyDir() {
return getHelperFile("third_party");
return findFileInHelpers("third_party");
}
}

View File

@@ -215,7 +215,8 @@ open class PydevConsoleRunnerFactory : PythonConsoleRunnerFactory() {
paths.add(getTargetEnvironmentValueForLocalPath(Path.of(projectRoot)))
val targetEnvironmentRequest = findPythonTargetInterpreter(sdk, project)
val (communityHelpers) = targetEnvironmentRequest.preparePyCharmHelpers()
// // Community Helpers root should be first in the list
val communityHelpers = targetEnvironmentRequest.preparePyCharmHelpers().helpers.first()
for (helper in listOf("pycharm", "pydev")) {
paths.add(communityHelpers.targetPathFun.getRelativeTargetPath(helper))
}

View File

@@ -113,7 +113,7 @@ public final class PyCythonExtensionWarning {
throw new ExecutionException(PyBundle.message("debugger.cython.python.run.configuration.should.be.selected"));
}
final String interpreterPath = runConfiguration.getInterpreterPath();
final String helpersPath = PythonHelpersLocator.getHelpersRoot().getPath();
final String helpersPath = PythonHelpersLocator.getCommunityHelpersRoot().getPath();
final String cythonExtensionsDir = PyDebugRunner.CYTHON_EXTENSIONS_DIR;
final String[] cythonArgs =

View File

@@ -230,7 +230,7 @@ public abstract class PyPackageManagerImplBase extends PyPackageManager {
}
protected @Nullable String getHelperPath(final @NotNull String helper) throws ExecutionException {
return PythonHelpersLocator.getHelperPath(helper);
return PythonHelpersLocator.findPathInHelpers(helper);
}
protected static @NotNull List<String> makeSafeToDisplayCommand(@NotNull List<String> cmdline) {

View File

@@ -374,7 +374,7 @@ public class PyTargetEnvironmentPackageManager extends PyPackageManagerImplBase
private static @NotNull HelperPackage getPipHelperPackage() {
return new PythonHelper.ScriptPythonHelper(PIP_WHEEL_NAME + "/" + PyPackageUtil.PIP,
PythonHelpersLocator.getHelpersRoot(),
PythonHelpersLocator.getCommunityHelpersRoot(),
Collections.emptyList());
}

View File

@@ -46,7 +46,7 @@ class CondaPackageCache : PythonPackageCache<String> {
.first { it.envIdentity is PyCondaEnvIdentity.UnnamedEnv && it.envIdentity.isBase }
val helpersAware = PythonInterpreterTargetEnvironmentFactory.findPythonTargetInterpreter(sdk, project)
val (communityHelpers) = helpersAware.preparePyCharmHelpers()
val communityHelpers = helpersAware.preparePyCharmHelpers().helpers.first()
val targetReq = targetConfig?.createEnvironmentRequest(project) ?: LocalTargetEnvironmentRequest()

View File

@@ -266,8 +266,8 @@ class PyPackagingToolWindowService(val project: Project, val serviceScope: Corou
// todo[akniazev]: this workaround should can be removed when PY-57134 is fixed
val helperLocation = if (localSdk.sdkFlavor.getLanguageLevel(localSdk).isPython2) "py2only" else "py3only"
val path = PythonHelpersLocator.getHelpersRoot().toPath().resolve(helperLocation)
pythonExecution.applyHelperPackageToPythonPath(listOf(path.toString()), helpersAwareTargetRequest)
val path = PythonHelpersLocator.findPathInHelpers(helperLocation)
pythonExecution.applyHelperPackageToPythonPath(listOf(path), helpersAwareTargetRequest)
pythonExecution.addParameter("rst2html_no_code")
val targetProgressIndicator = TargetProgressIndicator.EMPTY

View File

@@ -62,7 +62,7 @@ public abstract class PythonRemoteInterpreterManager {
}
public static void addHelpersMapping(@NotNull RemoteSdkProperties data, @NotNull PyRemotePathMapper pathMapper) {
pathMapper.addMapping(PythonHelpersLocator.getHelpersRoot().getPath(), data.getHelpersPath(), PyPathMappingType.HELPERS);
pathMapper.addMapping(PythonHelpersLocator.getCommunityHelpersRoot().getPath(), data.getHelpersPath(), PyPathMappingType.HELPERS);
}
public static @NotNull PyRemotePathMapper appendBasicMappings(@Nullable Project project,

View File

@@ -878,8 +878,8 @@ public abstract class PythonCommandLineState extends CommandLineState {
if (isDebug && PythonSdkFlavor.getFlavor(sdkHome) instanceof JythonSdkFlavor) {
//that fixes Jython problem changing sys.argv on execfile, see PY-8164
pythonPath.add(PythonHelpersLocator.getHelperPath("pycharm"));
pythonPath.add(PythonHelpersLocator.getHelperPath("pydev"));
pythonPath.add(PythonHelpersLocator.findPathInHelpers("pycharm"));
pythonPath.add(PythonHelpersLocator.findPathInHelpers("pydev"));
}
return pythonPath;

View File

@@ -147,12 +147,7 @@ fun addHelperEntriesToPythonPath(envs: MutableMap<String, TargetEnvironmentFunct
failOnError: Boolean = true): List<PathMapping> {
val targetPlatform = helpersAwareTargetRequest.targetEnvironmentRequest.targetPlatform
val pythonHelpersMappings = helpersAwareTargetRequest.preparePyCharmHelpers()
val pythonHelpersRoots =
listOfNotNull(
pythonHelpersMappings.communityHelpers,
pythonHelpersMappings.proHelpers
)
.map(PathMapping::localPath)
val pythonHelpersRoots = pythonHelpersMappings.helpers.map(PathMapping::localPath)
val targetPathSeparator = targetPlatform.platform.pathSeparator
fun <T> T?.onResolutionFailure(message: String): T? {

View File

@@ -95,7 +95,7 @@ private fun collectPythonPath(context: Context,
if (isDebug && context.sdk?.let { PythonSdkFlavor.getFlavor(it) } is JythonSdkFlavor) {
//that fixes Jython problem changing sys.argv on execfile, see PY-8164
for (helpersResource in listOf("pycharm", "pydev")) {
val helperPath = PythonHelpersLocator.getHelperPath(helpersResource)
val helperPath = PythonHelpersLocator.findPathInHelpers(helpersResource)
val targetHelperPath = targetPath(Path.of(helperPath))
pythonPath.add(targetHelperPath)
}

View File

@@ -12,8 +12,7 @@ class HelpersAwareLocalTargetEnvironmentRequest : HelpersAwareTargetEnvironmentR
override fun preparePyCharmHelpers(): PythonHelpersMappings =
PythonHelpersMappings(
communityHelpers = getPythonHelpers().mapToSelf(),
proHelpers = getPythonProHelpers()?.mapToSelf(),
getPythonHelpers().map { it.mapToSelf() }
)
}

View File

@@ -14,7 +14,7 @@ import kotlin.io.path.absolutePathString
data class PathMapping(val localPath: Path, val targetPathFun: TargetEnvironmentFunction<FullPathOnTarget>)
data class PythonHelpersMappings(val communityHelpers: PathMapping, val proHelpers: PathMapping?)
data class PythonHelpersMappings(val helpers: List<PathMapping>)
/**
* The target request for Python interpreter configured in PyCharm on a
@@ -31,27 +31,22 @@ interface HelpersAwareTargetEnvironmentRequest {
fun preparePyCharmHelpers(): PythonHelpersMappings
}
fun getPythonHelpers(): Path = PythonHelpersLocator.getHelpersRoot().toPath()
fun getPythonProHelpers(): Path? = if (PythonHelpersLocator.hasHelpersPro()) PythonHelpersLocator.getHelpersProRoot() else null
fun getPythonHelpers(): List<Path> = PythonHelpersLocator.getHelpersRoots()
/**
* Returns the mappings where Python helpers of Community and Professional versions are mapped to a single directory.
* For example, when their contents are uploaded to the same directory on the SSH machine.
*/
fun singleDirectoryPythonHelpersMappings(targetPathFun: TargetEnvironmentFunction<FullPathOnTarget>): PythonHelpersMappings =
PythonHelpersMappings(
communityHelpers = getPythonHelpers() to targetPathFun,
proHelpers = getPythonProHelpers()?.let { pythonProHelpers -> pythonProHelpers to targetPathFun },
)
PythonHelpersMappings(getPythonHelpers().map { it to targetPathFun })
infix fun Path.to(targetPathFun: TargetEnvironmentFunction<FullPathOnTarget>): PathMapping =
PathMapping(localPath = this, targetPathFun)
fun String.tryResolveAsPythonHelperDir(mappings: PythonHelpersMappings): PathMapping? {
val (communityHelpers, proHelpers) = mappings
val thisLocalPath = Path.of(this)
val rootPaths = listOfNotNull(communityHelpers, proHelpers)
val rootPaths = mappings.helpers
.filter { (localPath) -> FileUtil.isAncestor(localPath.absolutePathString(), this, false) }
return rootPaths
.firstNotNullOfOrNull { (localPath, targetPathFun) ->

View File

@@ -69,7 +69,7 @@ public class WinPythonSdkFlavor extends CPythonSdkFlavor<PyFlavorData.Empty> {
public @NotNull Collection<@NotNull Path> suggestLocalHomePaths(final @Nullable Module module, final @Nullable UserDataHolder context) {
Set<String> candidates = new TreeSet<>();
findInCandidatePaths(candidates, "python.exe", "jython.bat", "pypy.exe");
findInstallations(candidates, "python.exe", PythonHelpersLocator.getHelpersRoot().getParent());
findInstallations(candidates, "python.exe", PythonHelpersLocator.getCommunityHelpersRoot().getParent());
return ContainerUtil.map(candidates, Path::of);
}

View File

@@ -187,7 +187,7 @@ public class PySkeletonRefresher {
}
private static int readGeneratorVersion() {
File versionFile = PythonHelpersLocator.getHelperFile("generator3/version.txt");
File versionFile = PythonHelpersLocator.findFileInHelpers("generator3/version.txt");
try (Reader reader = new InputStreamReader(new FileInputStream(versionFile), StandardCharsets.UTF_8)) {
return PySkeletonHeader.fromVersionString(StreamUtil.readText(reader).trim());
}

View File

@@ -236,7 +236,7 @@ public abstract class PythonTestCommandLineStateBase<T extends AbstractPythonRun
@Override
public void customizeEnvironmentVars(Map<String, String> envs, boolean passParentEnvs) {
super.customizeEnvironmentVars(envs, passParentEnvs);
envs.put("PYCHARM_HELPERS_DIR", PythonHelpersLocator.getHelperPath("pycharm"));
envs.put("PYCHARM_HELPERS_DIR", PythonHelpersLocator.findPathInHelpers("pycharm"));
}
@Override
@@ -245,8 +245,10 @@ public abstract class PythonTestCommandLineStateBase<T extends AbstractPythonRun
boolean passParentEnvs) {
super.customizePythonExecutionEnvironmentVars(helpersAwareTargetRequest, envs, passParentEnvs);
var helpersTargetPath = helpersAwareTargetRequest.preparePyCharmHelpers();
// Community Helpers root should be first in the list
var communityTargetPathFun = helpersTargetPath.getHelpers().get(0).getTargetPathFun();
Function<TargetEnvironment, String> targetPycharmHelpersPath =
TargetEnvironmentFunctions.getRelativeTargetPath(helpersTargetPath.getCommunityHelpers().getTargetPathFun(), "pycharm");
TargetEnvironmentFunctions.getRelativeTargetPath(communityTargetPathFun, "pycharm");
envs.put("PYCHARM_HELPERS_DIR", targetPycharmHelpersPath);
}