mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-17 20:11:25 +07:00
[python] Rewrite PythonHelpersLocator
1. `PythonHelpersLocator` is an API to get helpers. It is aware of PyCharm Community helpers but also aware of some EP that provides additional helper paths. 2. EP implementations for PyCharm Prof and Jupyter that provide additional (prof) helpers. It will help avoid problems with which Locator to use from Professional, Community or Jupiter plugins. Merge-request: IJ-MR-140027 Merged-by: Egor Eliseev <Egor.Eliseev@jetbrains.com> GitOrigin-RevId: c7c34f323247002699866f12f6ff5a08cf6a18ff
This commit is contained in:
committed by
intellij-monorepo-bot
parent
71e4ebad19
commit
0be08ded36
@@ -21,11 +21,17 @@ import com.intellij.openapi.application.PathManager
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.util.PathUtil
|
||||
import com.intellij.util.concurrency.annotations.RequiresBackgroundThread
|
||||
import org.jetbrains.annotations.ApiStatus.Internal
|
||||
import org.jetbrains.annotations.NonNls
|
||||
import java.io.File
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.io.path.absolutePathString
|
||||
import kotlin.io.path.exists
|
||||
import kotlin.io.path.pathString
|
||||
|
||||
abstract class PythonHelpersLocator {
|
||||
interface PythonHelpersLocator {
|
||||
companion object {
|
||||
val LOG = Logger.getInstance(PythonHelpersLocator::class.java)
|
||||
private const val PROPERTY_HELPERS_LOCATION = "idea.python.helpers.path"
|
||||
@@ -36,108 +42,117 @@ abstract class PythonHelpersLocator {
|
||||
/**
|
||||
* @return A list of Path objects representing the roots of the Python Helpers.
|
||||
*/
|
||||
@Internal
|
||||
@JvmStatic
|
||||
fun getHelpersRoots(): List<Path> = EP_NAME.extensionList.first().getRoots()
|
||||
fun getHelpersRoots(): List<Path> = EP_NAME.extensionList.mapNotNull { it.getRoot() }
|
||||
|
||||
/**
|
||||
* Retrieves the root file of the Community Helpers extension.
|
||||
* Community Helpers root always should be first in an extension list
|
||||
* Retrieves a path to the root file of the Community Helpers extension.
|
||||
*
|
||||
* @return The root File of the Community Helpers extension.
|
||||
* @return The root Path of the Community Helpers extension.
|
||||
*/
|
||||
@Internal
|
||||
@JvmStatic
|
||||
fun getCommunityHelpersRoot(): File = EP_NAME.extensionList.first().getRoots().first().toFile()
|
||||
fun getCommunityHelpersRoot(): Path = EP_NAME.extensionList.first().getCommunityHelpersRootPath()
|
||||
|
||||
/**
|
||||
* Retrieves File of a helper file given its resource name.
|
||||
* Retrieves Path 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.
|
||||
* @return Path of the helper file, or null if the file does not exist.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun findFileInHelpers(resourceName: String): File? {
|
||||
@RequiresBackgroundThread
|
||||
fun findPathInHelpers(resourceName: String): Path? {
|
||||
for (helperRoot in getHelpersRoots()) {
|
||||
val file = File(helperRoot.toFile(), resourceName)
|
||||
if (file.exists())
|
||||
return file
|
||||
val path = Path.of(helperRoot.pathString, resourceName)
|
||||
if (path.exists())
|
||||
return path
|
||||
}
|
||||
|
||||
LOG.warn("File $resourceName does not exist in helpers root")
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
@Internal
|
||||
@TestOnly
|
||||
@JvmStatic
|
||||
@RequiresBackgroundThread
|
||||
fun getPythonCommunityPath(): Path {
|
||||
val pathFromUltimate = Path.of(PathManager.getHomePath(), "community/python")
|
||||
if (pathFromUltimate.exists()) {
|
||||
return pathFromUltimate
|
||||
}
|
||||
return Path.of(PathManager.getHomePath(), "python")
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the absolute path of a helper file given its resource name.
|
||||
*
|
||||
* @param resourceName The name of the helper resource file.
|
||||
* @param resourceName The name of the helper resource file (for example, `pydev` or `jupyter_debug`).
|
||||
* @return The absolute path of the helper file, or null if the file does not exist.
|
||||
*/
|
||||
@Internal
|
||||
@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
|
||||
}
|
||||
@RequiresBackgroundThread
|
||||
fun findPathStringInHelpers(@NonNls resourceName: String): String = findPathInHelpers(resourceName)?.absolutePathString() ?: ""
|
||||
|
||||
@Deprecated("Use {@link PythonHelpersLocator#findPathInHelpers}.", ReplaceWith("findPathInHelpers(resourceName)"))
|
||||
@JvmStatic
|
||||
fun getHelperPath(@NonNls resourceName: String): String = findPathInHelpers(resourceName)
|
||||
fun getHelperPath(@NonNls resourceName: String): String = findPathStringInHelpers(resourceName)
|
||||
}
|
||||
|
||||
// Always add Community Helpers root on the first place of root's list
|
||||
protected open fun getRoots(): List<Path> = listOf(getCommunityHelpersRootFile().toPath().normalize())
|
||||
@Internal
|
||||
fun getRoot(): Path? = getCommunityHelpersRootPath().normalize()
|
||||
|
||||
private fun getCommunityHelpersRootFile(): File {
|
||||
private fun getCommunityHelpersRootPath(): Path {
|
||||
val property = System.getProperty(PROPERTY_HELPERS_LOCATION)
|
||||
return if (property != null) {
|
||||
File(property)
|
||||
Path.of(property)
|
||||
}
|
||||
else getHelpersRoot(COMMUNITY_HELPERS_MODULE_NAME, "/python/helpers").also {
|
||||
assertHelpersLayout(it)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun getHelpersRoot(moduleName: String, relativePath: String): File =
|
||||
@Internal
|
||||
@RequiresBackgroundThread
|
||||
fun getHelpersRoot(moduleName: String, relativePath: String): Path =
|
||||
findRootByJarPath(PathUtil.getJarPathForClass(PythonHelpersLocator::class.java), moduleName, relativePath)
|
||||
|
||||
|
||||
protected fun findRootByJarPath(jarPath: String, moduleName: String, relativePath: String): File {
|
||||
@Internal
|
||||
fun findRootByJarPath(jarPath: String, moduleName: String, relativePath: String): Path {
|
||||
return if (PluginManagerCore.isRunningFromSources()) {
|
||||
File(PathManager.getCommunityHomePath() + relativePath)
|
||||
Path.of(PathManager.getCommunityHomePath(), relativePath)
|
||||
}
|
||||
else {
|
||||
getPluginBaseDir(jarPath)?.let {
|
||||
File(it, PathUtil.getFileName(relativePath))
|
||||
} ?: File(File(jarPath).parentFile, moduleName)
|
||||
Path.of(it.absolutePathString(), PathUtil.getFileName(relativePath))
|
||||
} ?: Path.of(Path(jarPath).parent.absolutePathString(), moduleName)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPluginBaseDir(jarPath: String): File? {
|
||||
private fun getPluginBaseDir(jarPath: String): Path? {
|
||||
if (jarPath.endsWith(".jar")) {
|
||||
val jarFile = File(jarPath)
|
||||
val path = Path.of(jarPath)
|
||||
|
||||
LOG.assertTrue(jarFile.exists(), "jar file cannot be null")
|
||||
return jarFile.parentFile.parentFile
|
||||
LOG.assertTrue(path.exists(), "$path to plugin base bir does not exists")
|
||||
return path.parent.parent
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun assertHelpersLayout(root: File): File {
|
||||
val path = root.absolutePath
|
||||
|
||||
LOG.assertTrue(root.exists(), "Helpers root does not exist $path")
|
||||
@RequiresBackgroundThread
|
||||
private fun assertHelpersLayout(root: Path): Path {
|
||||
LOG.assertTrue(root.exists(), "Helpers root does not exist $root")
|
||||
listOf("generator3", "pycharm", "pycodestyle.py", "pydev", "syspath.py", "typeshed").forEach { child ->
|
||||
LOG.assertTrue(File(root, child).exists(), "No '$child' inside $path")
|
||||
LOG.assertTrue(root.resolve(child).exists(), "No '$child' inside $root")
|
||||
}
|
||||
|
||||
return root
|
||||
}
|
||||
}
|
||||
|
||||
internal class PythonHelpersLocatorDefault : PythonHelpersLocator()
|
||||
internal class PythonHelpersLocatorDefault : PythonHelpersLocator
|
||||
@@ -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.findPathInHelpers("/tools/stdlib_packages.txt");
|
||||
final String helperPath = PythonHelpersLocator.findPathStringInHelpers("/tools/stdlib_packages.txt");
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(helperPath), StandardCharsets.UTF_8))) {
|
||||
return reader.lines().collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ object PyTypeShed {
|
||||
get() {
|
||||
val paths = listOf("${PathManager.getConfigPath()}/typeshed",
|
||||
"${PathManager.getConfigPath()}/../typeshed",
|
||||
PythonHelpersLocator.findPathInHelpers("typeshed"))
|
||||
PythonHelpersLocator.findPathStringInHelpers("typeshed"))
|
||||
return paths.asSequence()
|
||||
.filter { File(it).exists() }
|
||||
.firstOrNull()
|
||||
|
||||
@@ -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.findPathInHelpers(USER_SKELETONS_DIR));
|
||||
result.add(PythonHelpersLocator.findPathStringInHelpers(USER_SKELETONS_DIR));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -203,7 +203,7 @@ public class PyDocumentationBuilder {
|
||||
|
||||
private void buildForKeyword(@NotNull String name) {
|
||||
try {
|
||||
try (FileReader reader = new FileReader(PythonHelpersLocator.findPathInHelpers("/tools/python_keywords/" + name),
|
||||
try (FileReader reader = new FileReader(PythonHelpersLocator.findPathStringInHelpers("/tools/python_keywords/" + name),
|
||||
StandardCharsets.UTF_8)) {
|
||||
final String text = FileUtil.loadTextAndClose(reader);
|
||||
final String converted = StringUtil.convertLineSeparators(text, "\n");
|
||||
|
||||
@@ -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.findPathInHelpers("/tools/class_method_versions.xml"))) {
|
||||
try (FileReader reader = new FileReader(PythonHelpersLocator.findPathStringInHelpers("/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.findPathInHelpers("/tools/versions.xml"))) {
|
||||
try (FileReader reader = new FileReader(PythonHelpersLocator.findPathStringInHelpers("/tools/versions.xml"))) {
|
||||
XMLReader xr = XMLReaderFactory.createXMLReader();
|
||||
VersionsParser parser = new VersionsParser();
|
||||
xr.setContentHandler(parser);
|
||||
|
||||
Reference in New Issue
Block a user