mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-83031 Packaging toolwindow: Remove Package Ranking and sorted map for pypi cache
Signed-off-by: Nikita.Ashihmin <nikita.ashihmin@jetbrains.com> GitOrigin-RevId: 66a41bb255fee3f58a9ff2171d626a4de580f855
This commit is contained in:
committed by
intellij-monorepo-bot
parent
7116084db0
commit
63fcd9f096
File diff suppressed because one or more lines are too long
@@ -1,45 +0,0 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.python.packaging
|
||||
|
||||
import com.google.common.io.Resources
|
||||
import com.google.gson.Gson
|
||||
import com.intellij.openapi.components.Service
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import java.util.*
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.read
|
||||
import kotlin.concurrent.write
|
||||
|
||||
@Service
|
||||
@ApiStatus.Internal
|
||||
class PyPIPackageRanking {
|
||||
private val lock = ReentrantReadWriteLock()
|
||||
private var myPackageRank: Map<String, Int> = emptyMap()
|
||||
get() = lock.read { field }
|
||||
set(value) {
|
||||
lock.write { field = value }
|
||||
}
|
||||
|
||||
val packageRank: Map<String, Int>
|
||||
get() = myPackageRank
|
||||
val names: Sequence<String>
|
||||
get() = myPackageRank.asSequence().map { it.key }
|
||||
|
||||
suspend fun reload() {
|
||||
withContext(Dispatchers.IO) {
|
||||
val gson = Gson()
|
||||
val resource = PyPIPackageRanking::class.java.getResource("/packaging/pypi-ranking.json") ?: error("Python package ranking not found")
|
||||
val array = Resources.asCharSource(resource, Charsets.UTF_8).openBufferedStream().use {
|
||||
gson.fromJson(it, Array<Array<String>>::class.java)
|
||||
}
|
||||
val newRanked = array.asSequence()
|
||||
.map { Pair(it[0].lowercase(), it[1].toInt()) }
|
||||
.toMap(LinkedHashMap())
|
||||
withContext(Dispatchers.Default) {
|
||||
myPackageRank = Collections.unmodifiableMap(newRanked)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.python.packaging.common
|
||||
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.jetbrains.python.packaging.PyPIPackageRanking
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Experimental
|
||||
@@ -11,20 +9,6 @@ interface PythonPackageManagementListener {
|
||||
fun packagesChanged(sdk: Sdk) {}
|
||||
|
||||
@ApiStatus.Internal
|
||||
fun outdatedPackagesChanged(sdk: Sdk) {}
|
||||
}
|
||||
|
||||
internal class PythonRankingAwarePackageNameComparator : Comparator<String> {
|
||||
val ranking = service<PyPIPackageRanking>().packageRank
|
||||
override fun compare(name1: String, name2: String): Int {
|
||||
val rank1 = ranking[name1.lowercase()]
|
||||
val rank2 = ranking[name2.lowercase()]
|
||||
return when {
|
||||
rank1 != null && rank2 == null -> -1
|
||||
rank1 == null && rank2 != null -> 1
|
||||
rank1 != null && rank2 != null && rank1 != rank2 -> rank2 - rank1
|
||||
else -> String.CASE_INSENSITIVE_ORDER.compare(name1, name2)
|
||||
}
|
||||
fun outdatedPackagesChanged(sdk: Sdk) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,7 +15,6 @@ import com.jetbrains.python.PyBundle
|
||||
import com.jetbrains.python.getOrThrow
|
||||
import com.jetbrains.python.packaging.PyPackageVersionComparator
|
||||
import com.jetbrains.python.packaging.cache.PythonPackageCache
|
||||
import com.jetbrains.python.packaging.common.PythonRankingAwarePackageNameComparator
|
||||
import com.jetbrains.python.run.PythonInterpreterTargetEnvironmentFactory
|
||||
import com.jetbrains.python.sdk.flavors.conda.PyCondaEnv
|
||||
import com.jetbrains.python.sdk.flavors.conda.PyCondaEnvIdentity
|
||||
@@ -103,7 +102,7 @@ internal class CondaPackageCache : PythonPackageCache<String> {
|
||||
.filterNot { it[0].startsWith("r-") } // todo[akniazev]: make sure it's the best way to get rid of R packages
|
||||
.groupBy({ it[0] }, { it[1] })
|
||||
.mapValues { it.value.distinct().sortedWith(PyPackageVersionComparator.STR_COMPARATOR.reversed()) }
|
||||
.toSortedMap(PythonRankingAwarePackageNameComparator())
|
||||
.toMap()
|
||||
|
||||
cache = packages
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.startup.ProjectActivity
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import com.jetbrains.python.Result
|
||||
import com.jetbrains.python.packaging.PyPIPackageRanking
|
||||
import com.jetbrains.python.packaging.pip.PypiPackageCache
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
@@ -25,7 +24,6 @@ private class PythonPackagesUpdater : ProjectActivity {
|
||||
override suspend fun execute(project: Project) {
|
||||
withContext(Dispatchers.IO) {
|
||||
thisLogger().debug("Updating PyPI cache and ranking")
|
||||
serviceAsync<PyPIPackageRanking>().reload()
|
||||
when (val r = serviceAsync<PypiPackageCache>().reloadCache()) {
|
||||
is Result.Success -> Unit
|
||||
is Result.Failure -> {
|
||||
|
||||
@@ -14,7 +14,6 @@ import com.intellij.util.io.SafeFileOutputStream
|
||||
import com.jetbrains.python.Result
|
||||
import com.jetbrains.python.packaging.PyPIPackageUtil
|
||||
import com.jetbrains.python.packaging.cache.PythonPackageCache
|
||||
import com.jetbrains.python.packaging.common.PythonRankingAwarePackageNameComparator
|
||||
import com.jetbrains.python.packaging.normalizePackageName
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
@@ -30,7 +29,6 @@ import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
import java.util.*
|
||||
import kotlin.io.path.exists
|
||||
|
||||
private val LOG = logger<PypiPackageCache>()
|
||||
@@ -116,10 +114,7 @@ open class PypiPackageCache : PythonPackageCache<String> {
|
||||
withContext(Dispatchers.IO) {
|
||||
LOG.info("Loading python packages from PyPi")
|
||||
val pypiList = service<PypiPackageLoader>().loadPackages().getOr { return@withContext it }
|
||||
val newCache = TreeSet(PythonRankingAwarePackageNameComparator())
|
||||
newCache.addAll(pypiList)
|
||||
|
||||
cache = newCache
|
||||
cache = pypiList.toSet()
|
||||
store()
|
||||
}
|
||||
return Result.success(Unit)
|
||||
|
||||
+6
-17
@@ -21,14 +21,17 @@ import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.jetbrains.python.PyBundle.message
|
||||
import com.jetbrains.python.getOrNull
|
||||
import com.jetbrains.python.packaging.*
|
||||
import com.jetbrains.python.packaging.PyPackageService
|
||||
import com.jetbrains.python.packaging.PyPackageVersionNormalizer
|
||||
import com.jetbrains.python.packaging.cache.PythonSimpleRepositoryCache
|
||||
import com.jetbrains.python.packaging.common.*
|
||||
import com.jetbrains.python.packaging.conda.CondaPackage
|
||||
import com.jetbrains.python.packaging.management.*
|
||||
import com.jetbrains.python.packaging.management.ui.PythonPackageManagerUI
|
||||
import com.jetbrains.python.packaging.normalizePackageName
|
||||
import com.jetbrains.python.packaging.packageRequirements.PackageNode
|
||||
import com.jetbrains.python.packaging.packageRequirements.PythonPackageRequirementsTreeExtractor
|
||||
import com.jetbrains.python.packaging.pyRequirement
|
||||
import com.jetbrains.python.packaging.repository.*
|
||||
import com.jetbrains.python.packaging.statistics.PythonPackagesToolwindowStatisticsCollector
|
||||
import com.jetbrains.python.packaging.toolwindow.model.*
|
||||
@@ -58,7 +61,6 @@ class PyPackagingToolWindowService(val project: Project, val serviceScope: Corou
|
||||
fun initialize(toolWindowPanel: PyPackagingToolWindowPanel) {
|
||||
this.toolWindowPanel = toolWindowPanel
|
||||
serviceScope.launch(Dispatchers.IO) {
|
||||
service<PyPIPackageRanking>().reload()
|
||||
initForSdk(project.modules.firstOrNull()?.pythonSdk)
|
||||
}
|
||||
subscribeToChanges()
|
||||
@@ -89,7 +91,8 @@ class PyPackagingToolWindowService(val project: Project, val serviceScope: Corou
|
||||
|
||||
return if (shouldUseStraightComparison) {
|
||||
StringUtil.containsIgnoreCase(pkg.name, query)
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
StringUtil.containsIgnoreCase(normalizePackageName(pkg.name), normalizePackageName(query))
|
||||
}
|
||||
}
|
||||
@@ -486,20 +489,6 @@ class PyPackagingToolWindowService(val project: Project, val serviceScope: Corou
|
||||
}
|
||||
}
|
||||
|
||||
if (PyPIPackageUtil.isPyPIRepository(url)) {
|
||||
val ranking = service<PyPIPackageRanking>().packageRank
|
||||
return Comparator { p1, p2 ->
|
||||
val rank1 = ranking[p1.lowercase()]
|
||||
val rank2 = ranking[p2.lowercase()]
|
||||
return@Comparator when {
|
||||
rank1 != null && rank2 == null -> -1
|
||||
rank1 == null && rank2 != null -> 1
|
||||
rank1 != null && rank2 != null -> rank2 - rank1
|
||||
else -> nameComparator.compare(p1, p2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nameComparator
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -13,7 +13,6 @@ import com.intellij.platform.util.progress.reportRawProgress
|
||||
import com.intellij.python.community.helpersLocator.PythonHelpersLocator
|
||||
import com.jetbrains.python.PyBundle.message
|
||||
import com.jetbrains.python.PythonHelper
|
||||
import com.jetbrains.python.packaging.PyPIPackageRanking
|
||||
import com.jetbrains.python.packaging.common.PythonPackageDetails
|
||||
import com.jetbrains.python.run.PythonInterpreterTargetEnvironmentFactory
|
||||
import com.jetbrains.python.run.applyHelperPackageToPythonPath
|
||||
@@ -99,7 +98,7 @@ class PyPackageDetailsHtmlRender(val project: Project, val currentSdk: Sdk?) {
|
||||
}
|
||||
|
||||
private fun markdownToHtml(text: String): String {
|
||||
val mdHtml = PyPIPackageRanking::class.java.getResource("/packaging/md.template.html")?.readText() ?: error("Cannot get md template")
|
||||
val mdHtml = this::class.java.getResource("/packaging/md.template.html")?.readText() ?: error("Cannot get md template")
|
||||
val quotedText = text.replace("`", "\\`")
|
||||
|
||||
val prepared = mdHtml.replace("{MD_TEXT}", "\n" + quotedText)
|
||||
|
||||
@@ -8,7 +8,6 @@ import com.intellij.util.io.delete
|
||||
import com.intellij.util.io.write
|
||||
import com.jetbrains.python.Result
|
||||
import com.jetbrains.python.fixtures.PyTestCase
|
||||
import com.jetbrains.python.packaging.PyPIPackageRanking
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.mockito.Mockito
|
||||
@@ -19,39 +18,29 @@ import kotlin.io.path.setLastModifiedTime
|
||||
|
||||
class PypiPackageCacheTest : PyTestCase() {
|
||||
|
||||
fun testCachedPackagesShouldBeOrdered() {
|
||||
withPypiPackages(listOf("c-pkg", "b-pkg", "a-pkg"))
|
||||
withPypiPackagesRanking(mapOf("c-pkg" to 2, "b-pkg" to 1, "a-pkg" to 1))
|
||||
withEmptyCacheStorage()
|
||||
val cache = PypiPackageCache()
|
||||
runBlocking { cache.reloadCache().orThrow() }
|
||||
assertThat(cache.packages).containsExactly("c-pkg", "a-pkg", "b-pkg")
|
||||
}
|
||||
|
||||
fun testCacheShouldNotBeUpdatedIfLocalStorageIsntExpired() {
|
||||
withLocalStoredPackages(listOf("c-pkg", "a-pkg", "b-pkg"), Instant.now())
|
||||
withPypiLoaderThrowingError()
|
||||
val cache = PypiPackageCache()
|
||||
runBlocking { cache.reloadCache().orThrow() }
|
||||
assertThat(cache.packages).containsExactly("c-pkg", "a-pkg", "b-pkg")
|
||||
assertThat(cache.packages).contains("c-pkg", "a-pkg", "b-pkg")
|
||||
}
|
||||
|
||||
fun testCacheShouldBeUpdatedIfLocalStorageIsExpired() {
|
||||
withLocalStoredPackages(listOf("a-pkg"), Instant.now().minus(Duration.ofDays(2)))
|
||||
withPypiPackages(listOf("c-pkg", "b-pkg", "a-pkg"))
|
||||
withPypiPackagesRanking(mapOf("c-pkg" to 2, "b-pkg" to 1, "a-pkg" to 1))
|
||||
val cache = PypiPackageCache()
|
||||
runBlocking { cache.reloadCache().orThrow() }
|
||||
assertThat(cache.packages).containsExactly("c-pkg", "a-pkg", "b-pkg")
|
||||
assertThat(cache.packages).contains("c-pkg", "a-pkg", "b-pkg")
|
||||
}
|
||||
|
||||
fun testBrokenLocalStorageShouldBeGracefullyHandled() {
|
||||
withBrokenLocalStorage()
|
||||
withPypiPackages(listOf("c-pkg", "b-pkg", "a-pkg"))
|
||||
withPypiPackagesRanking(mapOf("c-pkg" to 2, "b-pkg" to 1, "a-pkg" to 1))
|
||||
val cache = PypiPackageCache()
|
||||
runBlocking { cache.reloadCache().orThrow() }
|
||||
assertThat(cache.packages).containsExactly("c-pkg", "a-pkg", "b-pkg")
|
||||
assertThat(cache.packages).contains("c-pkg", "a-pkg", "b-pkg")
|
||||
}
|
||||
|
||||
private fun withEmptyCacheStorage() {
|
||||
@@ -87,13 +76,4 @@ class PypiPackageCacheTest : PyTestCase() {
|
||||
mock
|
||||
)
|
||||
}
|
||||
|
||||
private fun withPypiPackagesRanking(ranking: Map<String, Int>) {
|
||||
val mock = Mockito.mock(PyPIPackageRanking::class.java)
|
||||
Mockito.`when`(mock.packageRank).thenReturn(ranking)
|
||||
ApplicationManager.getApplication().registerServiceInstance(
|
||||
PyPIPackageRanking::class.java,
|
||||
mock
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user