python packages toolwindow review fixes (PY-47449)

- synchronization around package rank loading
- more compact package rank storage

(cherry picked from commit 259e28c780fe0edd5601bdce54bd42a4783c3cc4)

IJ-CR-9914

GitOrigin-RevId: 3a563f8c63aa83f92f274efa882c7aecf89e429f
This commit is contained in:
Aleksei Kniazev
2021-06-12 16:50:54 +00:00
committed by intellij-monorepo-bot
parent ba0a350cba
commit f99b63d804
4 changed files with 32 additions and 16024 deletions
File diff suppressed because one or more lines are too long
@@ -4,23 +4,34 @@ package com.jetbrains.python.packaging
import com.google.common.io.Resources
import com.google.gson.Gson
import com.google.gson.annotations.SerializedName
import com.intellij.openapi.application.ApplicationManager
import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.concurrent.read
import kotlin.concurrent.write
object PyPIPackageRanking {
private val lock = ReentrantReadWriteLock()
private var myPackageRank: Map<String, Int> = LinkedHashMap()
get() = lock.read { field }
set(value) {
lock.write { field = value }
}
val packageRank = mutableMapOf<String, Int>()
val packageRank: Map<String, Int>
get() = myPackageRank
val names: Sequence<String>
get() = myPackageRank.asSequence().map { it.key }
fun reload() {
packageRank.clear()
assert(!ApplicationManager.getApplication().isDispatchThread)
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<PyPackageRankingEntry>::class.java)
}
array.forEach {
packageRank[it.name.toLowerCase()] = it.downloads
gson.fromJson(it, Array<Array<String>>::class.java)
}
val newRanked = array.asSequence()
.map { Pair(it[0].toLowerCase(), it[1].toInt()) }
.toMap(LinkedHashMap())
myPackageRank = newRanked
}
class PyPackageRankingEntry(@SerializedName("project") val name: String, @SerializedName("download_count") val downloads: Int)
}
@@ -13,6 +13,7 @@ import com.intellij.openapi.ui.popup.JBPopupFactory
import com.intellij.openapi.ui.popup.PopupStep
import com.intellij.openapi.ui.popup.util.BaseListPopupStep
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.NlsContexts
import com.intellij.openapi.util.NlsSafe
import com.intellij.openapi.wm.ToolWindow
import com.intellij.openapi.wm.ToolWindowManager
@@ -89,8 +90,7 @@ class PyPackagingToolWindowPanel(service: PyPackagingToolWindowService, toolWind
val versions = listOf(latestText) + (currentPackageInfo?.availableVersions ?: emptyList())
JBPopupFactory.getInstance().createListPopup(
object : BaseListPopupStep<String>(null, versions) {
override fun onChosen(@NlsSafe selectedValue: String?, finalChoice: Boolean): PopupStep<*>? {
@Suppress("HardCodedStringLiteral")
override fun onChosen(@NlsContexts.Label selectedValue: String, finalChoice: Boolean): PopupStep<*>? {
this@apply.text = selectedValue
return FINAL_CHOICE
}
@@ -130,10 +130,7 @@ class PyPackagingToolWindowService(val project: Project) : Disposable {
val repository = PyPackageRepository(entry.key)
val (packagesSeq, size) = when {
PyPIPackageUtil.isPyPIRepository(entry.key) -> {
val pypiPackages = PyPIPackageRanking.packageRank.asSequence().map { it.key }
Pair(pypiPackages, PyPIPackageCache.getInstance().packageNames.size)
}
PyPIPackageUtil.isPyPIRepository(entry.key) -> Pair(PyPIPackageRanking.names, PyPIPackageCache.getInstance().packageNames.size)
else -> Pair(entry.value.asSequence().map { it.name }, entry.value.size)
}
@@ -345,18 +342,19 @@ class PyPackagingToolWindowService(val project: Project) : Disposable {
// The number of items to skip might be more than the number of ranked packages we store,
// so we need to include the remaining packages from pypi, filtering out those, that are already shown.
if (PyPIPackageUtil.isPyPIRepository(repository.url)) {
val ranked = PyPIPackageRanking.packageRank.asSequence().map { it.key }
val ranked = PyPIPackageRanking.packageRank
val names = PyPIPackageRanking.names
val rankedSize = PyPIPackageRanking.packageRank.size
val pypiAdjusted = when {
skipItems > rankedSize -> fromCurrentRepo.asSequence().drop(skipItems - rankedSize).map { it.name }
skipItems + PACKAGES_LIMIT > rankedSize -> {
val pypiRemaining = fromCurrentRepo.asSequence()
.map { it.name }
.filterNot { it in PyPIPackageRanking.packageRank }
.filterNot { it in ranked }
ranked.asSequence().drop(skipItems) + pypiRemaining
names.drop(skipItems) + pypiRemaining
}
else -> ranked.drop(skipItems)
else -> names.drop(skipItems)
}
@@ -414,9 +412,10 @@ class PyPackagingToolWindowService(val project: Project) : Disposable {
}
if (PyPIPackageUtil.isPyPIRepository(url)) {
val ranking = PyPIPackageRanking.packageRank
return Comparator { p1, p2 ->
val rank1 = PyPIPackageRanking.packageRank[p1.name.toLowerCase()]
val rank2 = PyPIPackageRanking.packageRank[p2.name.toLowerCase()]
val rank1 = ranking[p1.name.toLowerCase()]
val rank2 = ranking[p2.name.toLowerCase()]
return@Comparator when {
rank1 != null && rank2 == null -> -1
rank1 == null && rank2 != null -> 1