Add Python Sdks update script (PY-64546)

also bump sdks.json to latest

(cherry picked from commit 14cc088c20a8b77ee49007d8f7b982920e40c6e6)

IJ-MR-121650

GitOrigin-RevId: db7c0d11a61e239e2f47bd2f1a8dd1156f3712b1
This commit is contained in:
Vitaly Legchilkin
2023-12-06 15:29:21 +01:00
committed by intellij-monorepo-bot
parent 4dfb4685eb
commit 3e1de3259e
4 changed files with 493 additions and 82 deletions

View File

@@ -11,7 +11,7 @@
<orderEntry type="module" module-name="intellij.idea.community.build" />
<orderEntry type="module" module-name="intellij.platform.buildScripts.testFramework" scope="TEST" />
<orderEntry type="library" name="kotlin-stdlib" level="project" />
<orderEntry type="module" module-name="intellij.platform.util" scope="TEST" />
<orderEntry type="module" module-name="intellij.platform.util" />
<orderEntry type="library" name="kotlinx-collections-immutable" level="project" />
<orderEntry type="library" name="kotlinx-coroutines-core" level="project" />
<orderEntry type="module" module-name="intellij.platform.buildScripts.downloader" />
@@ -19,5 +19,12 @@
<orderEntry type="library" name="opentelemetry" level="project" />
<orderEntry type="library" name="opentelemetry-extension-kotlin" level="project" />
<orderEntry type="library" scope="TEST" name="JUnit5" level="project" />
<orderEntry type="module" module-name="intellij.platform.core" />
<orderEntry type="module" module-name="intellij.platform.ide.util.io" />
<orderEntry type="module" module-name="intellij.platform.ide.core" />
<orderEntry type="module" module-name="intellij.python.sdk" />
<orderEntry type="module" module-name="intellij.python.parser" />
<orderEntry type="module" module-name="intellij.platform.jps.model" />
<orderEntry type="library" name="jsoup" level="project" />
</component>
</module>

View File

@@ -0,0 +1,180 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.intellij.build.pycharm
import com.intellij.openapi.application.PathManager
import com.intellij.openapi.util.Version
import com.intellij.openapi.util.io.FileUtil
import com.intellij.util.PathUtilRt
import com.intellij.util.Urls
import com.intellij.util.io.HttpRequests
import com.intellij.util.system.CpuArch
import com.intellij.util.system.OS
import com.jetbrains.python.psi.LanguageLevel
import com.jetbrains.python.sdk.*
import org.jetbrains.jps.util.JpsChecksumUtil
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import java.nio.file.Paths
import java.util.concurrent.TimeUnit
import kotlin.io.path.Path
import kotlin.io.path.fileSize
const val BASE_URL = "https://www.python.org/ftp/python/"
val SDKS_JSON_PATH = Path(".", "community", "python", "python-sdk", "resources", "sdks.json")
/**
* Resources we are currently tracking.
*/
enum class TrackedResource(val filename: (String) -> String, val os: OS?, val cpuArch: CpuArch?, val source: Boolean = false) {
SRC_TAR_XZ({ "Python-${it}.tar.xz" }, null, null, true),
SRC_TGZ({ "Python-${it}.tgz" }, null, null, true),
WINDOWS_X86_64({ "python-${it}-amd64.exe" }, OS.Windows, CpuArch.X86_64),
WINDOWS_X86({ "python-${it}.exe" }, OS.Windows, CpuArch.X86),
WINDOWS_ARM64({ "python-${it}-arm64.exe" }, OS.Windows, CpuArch.ARM64),
MACOS({ "python-${it}-macos11.pkg" }, OS.macOS, null);
companion object {
fun resolve(version: String, filename: String): TrackedResource? {
return TrackedResource.entries.firstOrNull { it.filename(version) == filename }
}
}
}
/**
* All resources from sdks.json (there is no need to load and count hashes / sizes again)
*/
val RESOURCE_CACHE = SdksKeeper.sdks.python.flatMap { release ->
buildList {
release.sources?.let { addAll(it) }
release.binaries?.let { bin -> addAll(bin.flatMap { it.resources }) }
}
}.associateBy { r -> r.url }
/**
* Retrieve all versions listed in the https://www.python.org/ftp/python/ grouped by Language Level
*/
fun getRemoteVersions(): Map<LanguageLevel, List<String>> {
val doc: Document = Jsoup.connect(BASE_URL).get()
val versions = doc.body().select("a").map { it.attr("href").removeSuffix("/") }
return versions
.filter { it.isNotBlank() and it[0].isDigit() }
.groupBy { Version.parseVersion(it)!!.toLanguageLevel()!! }
}
/**
* Retrieve filtered tracked resources from https://www.python.org/ftp/python/{version}
*/
fun getVersionResources(version: String): List<TrackedResource> {
val doc: Document = Jsoup.connect("$BASE_URL/$version").get()
val files = doc.body().select("a").map { it.attr("href") }
return files.mapNotNull { TrackedResource.resolve(version, it) }
}
/**
* Tries to get from the cache first. If it is a new resources then it downloads the resource file and the GPG signature of it.
* Generates SHA256 and fileSize fields right after the GPG signature check.
*/
fun buildResource(version: String, trackedResource: TrackedResource): Resource {
val resUrl = Urls.parseEncoded("$BASE_URL/$version/${trackedResource.filename(version)}")!!
RESOURCE_CACHE[resUrl]?.let { return it }
println("New resource was found ${resUrl}")
val ascUrl = Urls.parseEncoded("${resUrl}.asc")!!
val tempPath = PathManager.getTempPath()
val files = listOf(resUrl, ascUrl).associateWith { url ->
val fileName = PathUtilRt.getFileName(url.getPath())
Paths.get(tempPath, "${System.nanoTime()}-${fileName}")
}
try {
for ((url, path) in files) {
HttpRequests.request(url).saveToFile(path.toFile(), null)
}
val (resFilePath, ascFilePath) = files.values.map { it.toAbsolutePath().toString() }.toTypedArray()
runCommand("gpg", "--verify", ascFilePath, resFilePath)
val file = files[resUrl]!!
val sha256 = JpsChecksumUtil.getSha256Checksum(file)
return Resource(resUrl, file.fileSize(), sha256)
}
finally {
files.values.forEach { runCatching { FileUtil.delete(it) } }
}
}
fun buildBinary(version: String, trackedResource: TrackedResource): Binary {
return Binary(trackedResource.os!!, trackedResource.cpuArch, listOf(buildResource(version, trackedResource)))
}
fun buildRelease(version: String, resources: List<TrackedResource>, product: Product = Product.CPython): Release {
val sources = resources.filter { it.source }.map { buildResource(version, it) }.takeIf { it.isNotEmpty() }
val binaries = resources.filter { !it.source }.map { buildBinary(version, it) }.takeIf { it.isNotEmpty() }
return Release(
version = Version.parseVersion(version)!!,
product = product,
sources = sources,
binaries = binaries,
)
}
/**
* 'OpenPGP Public Keys' section from https://www.python.org/downloads/
*/
val GPG_KEYS = arrayOf(
"A821E680E5FA6305", // Thomas Wouters (3.12.x and 3.13.x source files and tags)
"64E628F8D684696D", // Pablo Galindo Salgado (3.10.x and 3.11.x source files and tags)
"FC624643487034E5", // Steve Dower (Windows binaries)
"B26995E310250568", // Łukasz Langa (3.8.x and 3.9.x source files and tags)
"2D347EA6AA65421D", "FB9921286F5E1540", // Ned Deily (macOS binaries, 3.7.x / 3.6.x source files and tags)
"3A5CA953F73C700D", // Larry Hastings (3.5.x source files and tags)
"04C367C218ADD4FF", // Benjamin Peterson (2.7.z source files and tags)
)
fun runCommand(vararg args: String) {
val process = ProcessBuilder(*args)
.redirectOutput(ProcessBuilder.Redirect.INHERIT)
.redirectError(ProcessBuilder.Redirect.INHERIT)
.start()
val isFinished = process.waitFor(10, TimeUnit.SECONDS)
if (!isFinished) throw RuntimeException("Timeout on execute")
if (process.exitValue() != 0) throw RuntimeException("Non-Zero exit code")
}
/**
* - Updates gpg keys on startup
* - For each Language Level and Tracked Resource gets the latest Version available
* - Groups all Tracked Resources into bundles by version
* -
*/
fun main() {
runCommand("gpg", "--recv-keys", *GPG_KEYS)
val remoteVersions = getRemoteVersions()
val releases = mutableListOf<Release>()
fun getLangLevelReleases(languageLevel: LanguageLevel): Map<String, List<TrackedResource>> {
val remoteVersionsSortedDesc = remoteVersions[languageLevel]!!
.sortedWith(Comparator.comparing<String?, Version?> { Version.parseVersion(it) }.reversed())
val resolvedResources = mutableMapOf<TrackedResource, String>()
for (version in remoteVersionsSortedDesc) {
val resources = getVersionResources(version)
resources.filter { it !in resolvedResources }.associateWithTo(resolvedResources) { version }
}
return resolvedResources.entries.groupBy({ (_, v) -> v }, { (k, _) -> k })
}
for (languageLevel in LanguageLevel.SUPPORTED_LEVELS.reversed()) {
println("Update local versions for ${languageLevel.toPythonVersion()}")
val langLevelReleases = getLangLevelReleases(languageLevel)
langLevelReleases.forEach { (version, resources) ->
releases.add(buildRelease(version, resources.sorted()))
}
}
// get PyPy from the current list, we have no update logic for it
releases.addAll(SdksKeeper.sdks.python.filter { it.product == Product.PyPy })
val sdks = Sdks(python = releases)
val sdksJson = SdksKeeper.serialize(sdks)
SDKS_JSON_PATH.toFile().writeText(sdksJson)
}

View File

@@ -7,12 +7,16 @@
{
"url": "https://www.python.org/ftp/python/3.12.0/Python-3.12.0.tar.xz",
"size": 20575020,
"sha256": "795c34f44df45a0e9b9710c8c71c15c671871524cd412ca14def212e8ccb155d"
"sha256": "795c34f44df45a0e9b9710c8c71c15c671871524cd412ca14def212e8ccb155d",
"fileName": "Python-3.12.0.tar.xz",
"type": "COMPRESSED"
},
{
"url": "https://www.python.org/ftp/python/3.12.0/Python-3.12.0.tgz",
"size": 27195214,
"sha256": "51412956d24a1ef7c97f1cb5f70e185c13e3de1f50d131c0aac6338080687afb"
"sha256": "51412956d24a1ef7c97f1cb5f70e185c13e3de1f50d131c0aac6338080687afb",
"fileName": "Python-3.12.0.tgz",
"type": "COMPRESSED"
}
],
"binaries": [
@@ -23,7 +27,9 @@
{
"url": "https://www.python.org/ftp/python/3.12.0/python-3.12.0-amd64.exe",
"size": 26507904,
"sha256": "c6bdf93f4b2de6dfa1a3a847e7c24ae10edf7f6318653d452cd4381415700ada"
"sha256": "c6bdf93f4b2de6dfa1a3a847e7c24ae10edf7f6318653d452cd4381415700ada",
"fileName": "python-3.12.0-amd64.exe",
"type": "MICROSOFT_WINDOWS_EXECUTABLE"
}
]
},
@@ -34,7 +40,9 @@
{
"url": "https://www.python.org/ftp/python/3.12.0/python-3.12.0.exe",
"size": 25173976,
"sha256": "78fe137b4b78274e455ce678ba2e296ca7c3c6a0e53806bf09e4f8986b64c632"
"sha256": "78fe137b4b78274e455ce678ba2e296ca7c3c6a0e53806bf09e4f8986b64c632",
"fileName": "python-3.12.0.exe",
"type": "MICROSOFT_WINDOWS_EXECUTABLE"
}
]
},
@@ -45,7 +53,9 @@
{
"url": "https://www.python.org/ftp/python/3.12.0/python-3.12.0-arm64.exe",
"size": 25742528,
"sha256": "05eb076ce9fe248d4a6295f75be328808b22877f9538cf9effe89938aebc9532"
"sha256": "05eb076ce9fe248d4a6295f75be328808b22877f9538cf9effe89938aebc9532",
"fileName": "python-3.12.0-arm64.exe",
"type": "MICROSOFT_WINDOWS_EXECUTABLE"
}
]
},
@@ -55,25 +65,32 @@
{
"url": "https://www.python.org/ftp/python/3.12.0/python-3.12.0-macos11.pkg",
"size": 45371285,
"sha256": "d18c9ba65137b6f2ef2f4083b647273639f17e390f7439b3c2e35686040745db"
"sha256": "d18c9ba65137b6f2ef2f4083b647273639f17e390f7439b3c2e35686040745db",
"fileName": "python-3.12.0-macos11.pkg",
"type": "APPLE_SOFTWARE_PACKAGE"
}
]
}
]
],
"title": "Python 3.12.0"
},
{
"version": "3.11.6",
"version": "3.11.7",
"product": "CPython",
"sources": [
{
"url": "https://www.python.org/ftp/python/3.11.6/Python-3.11.6.tar.xz",
"size": 20067204,
"sha256": "0fab78fa7f133f4f38210c6260d90d7c0d5c7198446419ce057ec7ac2e6f5f38"
"url": "https://www.python.org/ftp/python/3.11.7/Python-3.11.7.tar.xz",
"size": 20074108,
"sha256": "18e1aa7e66ff3a58423d59ed22815a6954e53342122c45df20c96877c062b9b7",
"fileName": "Python-3.11.7.tar.xz",
"type": "COMPRESSED"
},
{
"url": "https://www.python.org/ftp/python/3.11.6/Python-3.11.6.tgz",
"size": 26590303,
"sha256": "c049bf317e877cbf9fce8c3af902436774ecef5249a29d10984ca3a37f7f4736"
"url": "https://www.python.org/ftp/python/3.11.7/Python-3.11.7.tgz",
"size": 26601929,
"sha256": "068c05f82262e57641bd93458dfa883128858f5f4997aad7a36fd25b13b29209",
"fileName": "Python-3.11.7.tgz",
"type": "COMPRESSED"
}
],
"binaries": [
@@ -82,9 +99,11 @@
"cpuArch": "X86_64",
"resources": [
{
"url": "https://www.python.org/ftp/python/3.11.6/python-3.11.6-amd64.exe",
"size": 25962920,
"sha256": "8d0fd1c7bab34dd26fb89327cf7b7c2c7dc57c4d2a7bea58eae198aa9dd5b4ef"
"url": "https://www.python.org/ftp/python/3.11.7/python-3.11.7-amd64.exe",
"size": 26009544,
"sha256": "c117c6444494bbe4cc937e8a5a61899d53f7f5c5bc573c5d130304e457d54024",
"fileName": "python-3.11.7-amd64.exe",
"type": "MICROSOFT_WINDOWS_EXECUTABLE"
}
]
},
@@ -93,9 +112,11 @@
"cpuArch": "X86",
"resources": [
{
"url": "https://www.python.org/ftp/python/3.11.6/python-3.11.6.exe",
"size": 24691136,
"sha256": "d19857c64d2ec2d2db67e308b5a1f87be677e7e8ef870e2271f5c573c7eaf314"
"url": "https://www.python.org/ftp/python/3.11.7/python-3.11.7.exe",
"size": 24722192,
"sha256": "88705c0dfb1d432fbec5d9d2799cf0cd90758acbcf34195bd0580718195189bc",
"fileName": "python-3.11.7.exe",
"type": "MICROSOFT_WINDOWS_EXECUTABLE"
}
]
},
@@ -104,9 +125,11 @@
"cpuArch": "ARM64",
"resources": [
{
"url": "https://www.python.org/ftp/python/3.11.6/python-3.11.6-arm64.exe",
"size": 25253752,
"sha256": "46c43c1628fb6885e91f937b73510ddf30379fe6bc08f3648cd14962c9408cfc"
"url": "https://www.python.org/ftp/python/3.11.7/python-3.11.7-arm64.exe",
"size": 25272216,
"sha256": "44b97d8f15c7a39899bacb54cb759963ecba0e496055e0b91c58046ec0b1c80b",
"fileName": "python-3.11.7-arm64.exe",
"type": "MICROSOFT_WINDOWS_EXECUTABLE"
}
]
},
@@ -114,13 +137,16 @@
"os": "macOS",
"resources": [
{
"url": "https://www.python.org/ftp/python/3.11.6/python-3.11.6-macos11.pkg",
"size": 44266709,
"sha256": "c06ff46fa6159da61862ff2b6cde130bee093a5d547281876c9f1f41cc60376d"
"url": "https://www.python.org/ftp/python/3.11.7/python-3.11.7-macos11.pkg",
"size": 44555492,
"sha256": "05c59ef9cdef850ea7133d955eeee59b82e008509a1c44ab66039cda127094a9",
"fileName": "python-3.11.7-macos11.pkg",
"type": "APPLE_SOFTWARE_PACKAGE"
}
]
}
]
],
"title": "Python 3.11.7"
},
{
"version": "3.10.13",
@@ -129,14 +155,19 @@
{
"url": "https://www.python.org/ftp/python/3.10.13/Python-3.10.13.tar.xz",
"size": 19663088,
"sha256": "5c88848668640d3e152b35b4536ef1c23b2ca4bd2c957ef1ecbb053f571dd3f6"
"sha256": "5c88848668640d3e152b35b4536ef1c23b2ca4bd2c957ef1ecbb053f571dd3f6",
"fileName": "Python-3.10.13.tar.xz",
"type": "COMPRESSED"
},
{
"url": "https://www.python.org/ftp/python/3.10.13/Python-3.10.13.tgz",
"size": 26111363,
"sha256": "698ec55234c1363bd813b460ed53b0f108877c7a133d48bde9a50a1eb57b7e65"
"sha256": "698ec55234c1363bd813b460ed53b0f108877c7a133d48bde9a50a1eb57b7e65",
"fileName": "Python-3.10.13.tgz",
"type": "COMPRESSED"
}
]
],
"title": "Python 3.10.13"
},
{
"version": "3.10.11",
@@ -149,7 +180,9 @@
{
"url": "https://www.python.org/ftp/python/3.10.11/python-3.10.11-amd64.exe",
"size": 29037240,
"sha256": "d8dede5005564b408ba50317108b765ed9c3c510342a598f9fd42681cbe0648b"
"sha256": "d8dede5005564b408ba50317108b765ed9c3c510342a598f9fd42681cbe0648b",
"fileName": "python-3.10.11-amd64.exe",
"type": "MICROSOFT_WINDOWS_EXECUTABLE"
}
]
},
@@ -160,7 +193,9 @@
{
"url": "https://www.python.org/ftp/python/3.10.11/python-3.10.11.exe",
"size": 27865760,
"sha256": "bd115a575e86e61cea9136c5a2c47e090ba484dc2dee8b51a34111bb094266d5"
"sha256": "bd115a575e86e61cea9136c5a2c47e090ba484dc2dee8b51a34111bb094266d5",
"fileName": "python-3.10.11.exe",
"type": "MICROSOFT_WINDOWS_EXECUTABLE"
}
]
},
@@ -170,40 +205,14 @@
{
"url": "https://www.python.org/ftp/python/3.10.11/python-3.10.11-macos11.pkg",
"size": 41017419,
"sha256": "767ed35ad688d28ea4494081ae96408a0318d0d5bb9ca0139d74d6247b231cfc"
"sha256": "767ed35ad688d28ea4494081ae96408a0318d0d5bb9ca0139d74d6247b231cfc",
"fileName": "python-3.10.11-macos11.pkg",
"type": "APPLE_SOFTWARE_PACKAGE"
}
]
}
]
},
{
"version": "3.10.7313",
"product": "PyPy",
"sources": [
{
"url": "https://downloads.python.org/pypy/pypy3.10-v7.3.13-src.zip",
"size": 30067315,
"sha256": "828fc66eca1c097e44bc910c78ab773a98747268c7ce264da97022e5aca358dc"
},
{
"url": "https://downloads.python.org/pypy/pypy3.10-v7.3.13-src.tar.bz2",
"size": 23067819,
"sha256": "4ac1733c19d014d3193c804e7f40ffccbf6924bcaaee1b6089b82b9bf9353a6d"
}
],
"binaries": [
{
"os": "Windows",
"cpuArch": "X86_64",
"resources": [
{
"url": "https://downloads.python.org/pypy/pypy3.10-v7.3.13-win64.zip",
"size": 31510169,
"sha256": "5b99422fb8978b2f4bbf97961bca49963a82dc47c2fa51b7d23c493db3a2e0f0"
}
]
}
]
"title": "Python 3.10.11"
},
{
"version": "3.9.18",
@@ -212,14 +221,19 @@
{
"url": "https://www.python.org/ftp/python/3.9.18/Python-3.9.18.tar.xz",
"size": 19673928,
"sha256": "01597db0132c1cf7b331eff68ae09b5a235a3c3caa9c944c29cac7d1c4c4c00a"
"sha256": "01597db0132c1cf7b331eff68ae09b5a235a3c3caa9c944c29cac7d1c4c4c00a",
"fileName": "Python-3.9.18.tar.xz",
"type": "COMPRESSED"
},
{
"url": "https://www.python.org/ftp/python/3.9.18/Python-3.9.18.tgz",
"size": 26294072,
"sha256": "504ce8cfd59addc04c22f590377c6be454ae7406cb1ebf6f5a350149225a9354"
"sha256": "504ce8cfd59addc04c22f590377c6be454ae7406cb1ebf6f5a350149225a9354",
"fileName": "Python-3.9.18.tgz",
"type": "COMPRESSED"
}
]
],
"title": "Python 3.9.18"
},
{
"version": "3.9.13",
@@ -232,7 +246,9 @@
{
"url": "https://www.python.org/ftp/python/3.9.13/python-3.9.13-amd64.exe",
"size": 29235432,
"sha256": "fb3d0466f3754752ca7fd839a09ffe53375ff2c981279fd4bc23a005458f7f5d"
"sha256": "fb3d0466f3754752ca7fd839a09ffe53375ff2c981279fd4bc23a005458f7f5d",
"fileName": "python-3.9.13-amd64.exe",
"type": "MICROSOFT_WINDOWS_EXECUTABLE"
}
]
},
@@ -243,7 +259,9 @@
{
"url": "https://www.python.org/ftp/python/3.9.13/python-3.9.13.exe",
"size": 28096840,
"sha256": "f363935897bf32adf6822ba15ed1bfed7ae2ae96477f0262650055b6e9637c35"
"sha256": "f363935897bf32adf6822ba15ed1bfed7ae2ae96477f0262650055b6e9637c35",
"fileName": "python-3.9.13.exe",
"type": "MICROSOFT_WINDOWS_EXECUTABLE"
}
]
},
@@ -253,11 +271,14 @@
{
"url": "https://www.python.org/ftp/python/3.9.13/python-3.9.13-macos11.pkg",
"size": 38821163,
"sha256": "351fe18f4fb03be7afac5e4012fc0a51345f43202af43ef620cf1eee5ee36578"
"sha256": "351fe18f4fb03be7afac5e4012fc0a51345f43202af43ef620cf1eee5ee36578",
"fileName": "python-3.9.13-macos11.pkg",
"type": "APPLE_SOFTWARE_PACKAGE"
}
]
}
]
],
"title": "Python 3.9.13"
},
{
"version": "3.8.18",
@@ -266,14 +287,19 @@
{
"url": "https://www.python.org/ftp/python/3.8.18/Python-3.8.18.tar.xz",
"size": 20696952,
"sha256": "3ffb71cd349a326ba7b2fadc7e7df86ba577dd9c4917e52a8401adbda7405e3f"
"sha256": "3ffb71cd349a326ba7b2fadc7e7df86ba577dd9c4917e52a8401adbda7405e3f",
"fileName": "Python-3.8.18.tar.xz",
"type": "COMPRESSED"
},
{
"url": "https://www.python.org/ftp/python/3.8.18/Python-3.8.18.tgz",
"size": 27337549,
"sha256": "7c5df68bab1be81a52dea0cc2e2705ea00553b67107a301188383d7b57320b16"
"sha256": "7c5df68bab1be81a52dea0cc2e2705ea00553b67107a301188383d7b57320b16",
"fileName": "Python-3.8.18.tgz",
"type": "COMPRESSED"
}
]
],
"title": "Python 3.8.18"
},
{
"version": "3.8.10",
@@ -286,7 +312,9 @@
{
"url": "https://www.python.org/ftp/python/3.8.10/python-3.8.10-amd64.exe",
"size": 28296784,
"sha256": "7628244cb53408b50639d2c1287c659f4e29d3dfdb9084b11aed5870c0c6a48a"
"sha256": "7628244cb53408b50639d2c1287c659f4e29d3dfdb9084b11aed5870c0c6a48a",
"fileName": "python-3.8.10-amd64.exe",
"type": "MICROSOFT_WINDOWS_EXECUTABLE"
}
]
},
@@ -297,7 +325,9 @@
{
"url": "https://www.python.org/ftp/python/3.8.10/python-3.8.10.exe",
"size": 27204536,
"sha256": "ad07633a1f0cd795f3bf9da33729f662281df196b4567fa795829f3bb38a30ac"
"sha256": "ad07633a1f0cd795f3bf9da33729f662281df196b4567fa795829f3bb38a30ac",
"fileName": "python-3.8.10.exe",
"type": "MICROSOFT_WINDOWS_EXECUTABLE"
}
]
},
@@ -305,13 +335,181 @@
"os": "macOS",
"resources": [
{
"url": "https://www.python.org/ftp/python/3.8.10/python-3.8.10-macosx10.9.pkg",
"size": 29896827,
"sha256": "4c65bc7534d5f07edacbe0fbd609b5734dbf3ac02f5444f9bd97963d589d8afd"
"url": "https://www.python.org/ftp/python/3.8.10/python-3.8.10-macos11.pkg",
"size": 37300939,
"sha256": "86b2cb995297ab7d446ec6bd71c65238f3d74d8d8e02f936991d6d10bcfe7160",
"fileName": "python-3.8.10-macos11.pkg",
"type": "APPLE_SOFTWARE_PACKAGE"
}
]
}
]
],
"title": "Python 3.8.10"
},
{
"version": "3.7.17",
"product": "CPython",
"sources": [
{
"url": "https://www.python.org/ftp/python/3.7.17/Python-3.7.17.tar.xz",
"size": 18066196,
"sha256": "7911051ed0422fd54b8f59ffc030f7cf2ae30e0f61bda191800bb040dce4f9d2",
"fileName": "Python-3.7.17.tar.xz",
"type": "COMPRESSED"
},
{
"url": "https://www.python.org/ftp/python/3.7.17/Python-3.7.17.tgz",
"size": 24007497,
"sha256": "fd50161bc2a04f4c22a0971ff0f3856d98b4bf294f89740a9f06b520aae63b49",
"fileName": "Python-3.7.17.tgz",
"type": "COMPRESSED"
}
],
"title": "Python 3.7.17"
},
{
"version": "3.7.9",
"product": "CPython",
"binaries": [
{
"os": "Windows",
"cpuArch": "X86_64",
"resources": [
{
"url": "https://www.python.org/ftp/python/3.7.9/python-3.7.9-amd64.exe",
"size": 26940592,
"sha256": "e69ed52afb5a722e5c56f6c21d594e85c17cb29f12f18bb69751cf1714e0f987",
"fileName": "python-3.7.9-amd64.exe",
"type": "MICROSOFT_WINDOWS_EXECUTABLE"
}
]
},
{
"os": "Windows",
"cpuArch": "X86",
"resources": [
{
"url": "https://www.python.org/ftp/python/3.7.9/python-3.7.9.exe",
"size": 25875560,
"sha256": "769bb7c74ad1df6d7d74071cc16a984ff6182e4016e11b8949b93db487977220",
"fileName": "python-3.7.9.exe",
"type": "MICROSOFT_WINDOWS_EXECUTABLE"
}
]
}
],
"title": "Python 3.7.9"
},
{
"version": "3.6.15",
"product": "CPython",
"sources": [
{
"url": "https://www.python.org/ftp/python/3.6.15/Python-3.6.15.tar.xz",
"size": 17223796,
"sha256": "6e28d7cdd6dd513dd190e49bca3972e20fcf455090ccf2ef3f1a227614135d91",
"fileName": "Python-3.6.15.tar.xz",
"type": "COMPRESSED"
},
{
"url": "https://www.python.org/ftp/python/3.6.15/Python-3.6.15.tgz",
"size": 23035095,
"sha256": "54570b7e339e2cfd72b29c7e2fdb47c0b7b18b7412e61de5b463fc087c13b043",
"fileName": "Python-3.6.15.tgz",
"type": "COMPRESSED"
}
],
"title": "Python 3.6.15"
},
{
"version": "3.6.8",
"product": "CPython",
"binaries": [
{
"os": "Windows",
"cpuArch": "X86_64",
"resources": [
{
"url": "https://www.python.org/ftp/python/3.6.8/python-3.6.8-amd64.exe",
"size": 31830944,
"sha256": "96088a58b7c43bc83b84e6b67f15e8706c614023dd64f9a5a14e81ff824adadc",
"fileName": "python-3.6.8-amd64.exe",
"type": "MICROSOFT_WINDOWS_EXECUTABLE"
}
]
},
{
"os": "Windows",
"cpuArch": "X86",
"resources": [
{
"url": "https://www.python.org/ftp/python/3.6.8/python-3.6.8.exe",
"size": 30807656,
"sha256": "89871d432bc06e4630d7b64cb1a8451e53c80e68de29029976b12aad7dbfa5a0",
"fileName": "python-3.6.8.exe",
"type": "MICROSOFT_WINDOWS_EXECUTABLE"
}
]
}
],
"title": "Python 3.6.8"
},
{
"version": "2.7.18",
"product": "CPython",
"sources": [
{
"url": "https://www.python.org/ftp/python/2.7.18/Python-2.7.18.tar.xz",
"size": 12854736,
"sha256": "b62c0e7937551d0cc02b8fd5cb0f544f9405bafc9a54d3808ed4594812edef43",
"fileName": "Python-2.7.18.tar.xz",
"type": "COMPRESSED"
},
{
"url": "https://www.python.org/ftp/python/2.7.18/Python-2.7.18.tgz",
"size": 17539408,
"sha256": "da3080e3b488f648a3d7a4560ddee895284c3380b11d6de75edb986526b9a814",
"fileName": "Python-2.7.18.tgz",
"type": "COMPRESSED"
}
],
"title": "Python 2.7.18"
},
{
"version": "3.10.7313",
"product": "PyPy",
"sources": [
{
"url": "https://downloads.python.org/pypy/pypy3.10-v7.3.13-src.zip",
"size": 30067315,
"sha256": "828fc66eca1c097e44bc910c78ab773a98747268c7ce264da97022e5aca358dc",
"fileName": "pypy3.10-v7.3.13-src.zip",
"type": "COMPRESSED"
},
{
"url": "https://downloads.python.org/pypy/pypy3.10-v7.3.13-src.tar.bz2",
"size": 23067819,
"sha256": "4ac1733c19d014d3193c804e7f40ffccbf6924bcaaee1b6089b82b9bf9353a6d",
"fileName": "pypy3.10-v7.3.13-src.tar.bz2",
"type": "COMPRESSED"
}
],
"binaries": [
{
"os": "Windows",
"cpuArch": "X86_64",
"resources": [
{
"url": "https://downloads.python.org/pypy/pypy3.10-v7.3.13-win64.zip",
"size": 31510169,
"sha256": "5b99422fb8978b2f4bbf97961bca49963a82dc47c2fa51b7d23c493db3a2e0f0",
"fileName": "pypy3.10-v7.3.13-win64.zip",
"type": "COMPRESSED"
}
]
}
],
"title": "PyPy 3.10.7313"
}
]
}
}

View File

@@ -1,9 +1,10 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.sdk
import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonDeserializer
import com.fasterxml.jackson.databind.*
import com.fasterxml.jackson.databind.module.SimpleModule
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.google.common.io.Resources
@@ -114,6 +115,13 @@ class VersionDeserializer : JsonDeserializer<Version>() {
return Version.parseVersion(p!!.valueAsString)!!
}
}
class VersionSerializer : JsonSerializer<Version>() {
override fun serialize(value: Version?, gen: JsonGenerator?, serializers: SerializerProvider?) {
value?.let {
gen?.writeString(it.toString())
}
}
}
/**
* This class replaces missed String-arg constructor in Url class for jackson deserialization.
@@ -126,6 +134,14 @@ class UrlDeserializer : JsonDeserializer<Url>() {
}
}
class UrlSerializer : JsonSerializer<Url>() {
override fun serialize(value: Url?, gen: JsonGenerator?, serializers: SerializerProvider?) {
value?.let {
gen?.writeString(it.toString())
}
}
}
object SdksKeeper {
private val configUrl: URL? = Sdks::class.java.getResource("/sdks.json")
@@ -151,6 +167,16 @@ object SdksKeeper {
LOG.error("Json syntax error in the $configUrl", ex)
Sdks()
}
fun serialize(sdks: Sdks): String {
return jacksonObjectMapper()
.registerModule(
SimpleModule()
.addSerializer(Version::class.java, VersionSerializer())
.addSerializer(Url::class.java, UrlSerializer())
)
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
.writeValueAsString(sdks)
}
private fun load() = configUrl?.let { Resources.toString(it, StandardCharsets.UTF_8) }
}