OPENIDE #199 Create 252 branch to support OpenIDE 2025.2

(cherry picked from commit ec727d8347)
This commit is contained in:
Nikita Iarychenko
2025-07-10 11:46:35 +04:00
parent 36e6c3a576
commit eeaffab74e
10 changed files with 200 additions and 11 deletions

View File

@@ -50,11 +50,10 @@ open class OpenIdeProperties(val communityHomeDir: Path): IdeaCommunityPropertie
override fun getRootDirectoryName(appInfo: ApplicationInfoProperties, buildNumber: String) = "openIDE-$buildNumber"
override fun generateExecutableFilesPatterns(context: BuildContext, includeRuntime: Boolean, arch: JvmArchitecture): Sequence<String> {
return super.generateExecutableFilesPatterns(context, includeRuntime, arch)
override fun generateExecutableFilesPatterns(context: BuildContext, includeRuntime: Boolean, arch: JvmArchitecture, targetLibcImpl: LibcImpl): Sequence<String> =
super.generateExecutableFilesPatterns(context, includeRuntime, arch, targetLibcImpl)
.plus(KotlinBinaries.kotlinCompilerExecutables)
.filterNot { it == "plugins/**/*.sh" }
}
}
protected open inner class OpenIdeMacDistributionCustomizer : MacDistributionCustomizer() {

View File

@@ -6,7 +6,7 @@
<idea-plugin>
<extensions defaultExtensionNs="com.intellij">
<applicationService serviceInterface="com.intellij.platform.ide.customization.ExternalProductResourceUrls"
serviceImplementation="com.intellij.idea.customization.base.OpenIdeExternalResourceUrls"
serviceImplementation="com.intellij.platform.ide.impl.customization.OpenIdeExternalResourceUrls"
overrides="true"/>
<applicationActivity implementation="com.intellij.internal.statistic.updater.StatisticsJobsScheduler"/>
<applicationActivity implementation="com.intellij.internal.statistic.updater.StatisticsStateCollectorsScheduler"/>

View File

@@ -14,5 +14,6 @@
<orderEntry type="module" module-name="intellij.platform.buildScripts" />
<orderEntry type="module" module-name="intellij.platform.util" />
<orderEntry type="module" module-name="intellij.platform.ide.util.io" />
<orderEntry type="library" name="kotlinx-coroutines-core" level="project" />
</component>
</module>

View File

@@ -14,6 +14,8 @@
package ru.openide
import com.intellij.util.Urls
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import org.jetbrains.intellij.build.BuildContext
import org.jetbrains.intellij.build.BuildPaths.Companion.COMMUNITY_ROOT
import org.jetbrains.intellij.build.dependencies.BuildDependenciesDownloader
@@ -41,10 +43,12 @@ object OpenIdePluginBundler {
}
fun bundlePlugins(context: BuildContext) {
plugins.forEach { bundlePluginFromMarketplace(context, it) }
runBlocking(Dispatchers.Default) {
plugins.forEach { bundlePluginFromMarketplace(context, it) }
}
}
private fun bundlePluginFromMarketplace(context: BuildContext, pluginInfo: PluginInfo) {
private suspend fun bundlePluginFromMarketplace(context: BuildContext, pluginInfo: PluginInfo) {
val parameters = hashMapOf(
"id" to pluginInfo.pluginId,
"build" to context.fullBuildNumber

View File

@@ -11,14 +11,12 @@
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see http://www.gnu.org/licenses/.
package com.intellij.idea.customization.base
package com.intellij.platform.ide.impl.customization
import com.intellij.openapi.application.ApplicationInfo
import com.intellij.openapi.updateSettings.impl.PatchInfo
import com.intellij.openapi.util.BuildNumber
import com.intellij.openapi.util.SystemInfo
import com.intellij.platform.ide.customization.ExternalProductResourceUrls
import com.intellij.platform.ide.impl.customization.OpenIdeFeedbackReporter
import com.intellij.util.Url
import com.intellij.util.Urls
import com.intellij.util.system.CpuArch

View File

@@ -0,0 +1,53 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
//
// Modified by Nikita Iarychenko at 2025 as part of the OpenIDE project(https://openide.ru).
// Any modifications are available on the same license terms as the original source code.
package com.intellij.internal.statistic.eventLog.connection
import com.jetbrains.fus.reporting.configuration.ConfigurationClient
import com.jetbrains.fus.reporting.model.http.StatsConnectionSettings
import java.util.concurrent.TimeUnit
class ConfigurationClientFactory {
companion object {
/**
* The remote client periodically downloads configuration.
* The frequency can be set, it is 10 minutes by default.
* Use the test configuration url in test cases.
* */
@JvmStatic
fun create(
recorderId: String,
productCode: String,
productVersion: String,
isTestConfig: Boolean,
connectionSettings: StatsConnectionSettings,
cacheTimeoutMs: Long = TimeUnit.MINUTES.toMillis(10)
): ConfigurationClient {
val eventLogSettingsURLTemplate = "https://stats.openide.ru/storage/fus/config/v4/%s/%s.json"
val configurationUrl: String =
if (isTestConfig) {
String.format(eventLogSettingsURLTemplate, "test/$recorderId", productCode)
} else {
String.format(eventLogSettingsURLTemplate, recorderId, productCode)
}
return RemoteConfigurationClient(configurationUrl, productCode, productVersion, connectionSettings, cacheTimeoutMs)
}
/**
* The test client periodically downloads configuration from the given test configuration url.
* The frequency can be set, it is 10 minutes by default.
* */
@JvmStatic
fun createTest(
productCode: String,
productVersion: String,
connectionSettings: StatsConnectionSettings,
cacheTimeoutMs: Long = TimeUnit.MINUTES.toMillis(10),
configurationUrl: String
): ConfigurationClient =
RemoteConfigurationClient(configurationUrl, productCode, productVersion, connectionSettings, cacheTimeoutMs)
}
}

View File

@@ -1,4 +1,7 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
//
// Modified by Nikita Iarychenko at 2025 as part of the OpenIDE project(https://openide.ru).
// Any modifications are available on the same license terms as the original source code.
package com.intellij.internal.statistic.eventLog.connection
import com.intellij.internal.statistic.config.eventLog.EventLogBuildType
@@ -94,7 +97,10 @@ abstract class EventLogSettingsClient {
*/
fun provideServiceUrl(): String? {
val result = logError {
configurationClient.provideSendEndpoint()
val endpoint = configurationClient.provideSendEndpoint()
return@logError if (endpoint != null) {
endpoint + "?" + OpenIdeStatisticsQueryParameters.QUERY_SUFFIX
} else endpoint
}
applicationInfo.logger.info("Statistics. Configuration service url: $result")
return result

View File

@@ -1,4 +1,7 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
//
// Modified by Nikita Iarychenko at 2025 as part of the OpenIDE project(https://openide.ru).
// Any modifications are available on the same license terms as the original source code.
package com.intellij.internal.statistic.eventLog.connection
import com.intellij.internal.statistic.eventLog.EventLogApplicationInfo
@@ -43,7 +46,6 @@ open class EventLogUploadSettingsClient(
httpRequestBuilder = JavaHttpRequestBuilder()
.setExtraHeaders(applicationInfo.connectionSettings.provideExtraHeaders())
.setUserAgent(applicationInfo.connectionSettings.provideUserAgent()),
regionCode = if (applicationInfo.regionalCode == chinaRegion) RegionCode.CN else RegionCode.ALL,
serializer = FusKotlinSerializer(),
cacheTimeoutMs = cacheTimeoutMs
)

View File

@@ -0,0 +1,50 @@
// OpenIDE Project
// Copyright (C) 2025 “Open Development Platform” Ltd. (https://openide.ru)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License version 3 or later as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see http://www.gnu.org/licenses/.
package com.intellij.internal.statistic.eventLog.connection;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
// copy-paste from com.intellij.openapi.util.SystemInfo
public final class OpenIdeStatisticsQueryParameters {
public static final String QUERY_SUFFIX;
private static String toValidQueryValue(String value) {
return URLEncoder.encode(value, StandardCharsets.UTF_8);
}
static {
String name = System.getProperty("os.name");
String version = System.getProperty("os.version").toLowerCase(Locale.ENGLISH);
if (name.startsWith("Windows") && name.matches("Windows \\d+")) {
// for whatever reason, JRE reports "Windows 11" as a name and "10.0" as a version on Windows 11
try {
String version2 = name.substring("Windows".length() + 1) + ".0";
if (Float.parseFloat(version2) > Float.parseFloat(version)) {
version = version2;
}
}
catch (NumberFormatException ignored) { }
name = "Windows";
}
String QUERY_OS_NAME = toValidQueryValue(name);
String QUERY_OS_VERSION = toValidQueryValue(version);
String QUERY_OS_ARCH = toValidQueryValue(System.getProperty("os.arch"));
QUERY_SUFFIX = "os_name=" + QUERY_OS_NAME + "&os_version=" + QUERY_OS_VERSION + "&os_arch=" + QUERY_OS_ARCH;
}
}

View File

@@ -0,0 +1,76 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
//
// Modified by Nikita Iarychenko at 2025 as part of the OpenIDE project(https://openide.ru).
// Any modifications are available on the same license terms as the original source code.
package com.intellij.internal.statistic.eventLog.connection
import com.jetbrains.fus.reporting.configuration.ConfigurationClient
import com.jetbrains.fus.reporting.connection.StatsHttpClient
import com.jetbrains.fus.reporting.connection.StatsHttpResponse
import com.jetbrains.fus.reporting.connection.StatsRequestBuilder
import com.jetbrains.fus.reporting.connection.StatsResponseProcessor
import com.jetbrains.fus.reporting.model.config.v4.Configuration
import com.jetbrains.fus.reporting.model.config.v4.ConfigurationVersion
import com.jetbrains.fus.reporting.model.exceptions.StatsResponseException
import com.jetbrains.fus.reporting.model.http.StatsConnectionSettings
import com.jetbrains.fus.reporting.serialization.FusKotlinSerializer
import java.io.InputStream
import java.nio.charset.StandardCharsets
/**
* The remote client periodically downloads configuration from the given url.
* The download frequency can be set.
* */
internal class RemoteConfigurationClient internal constructor(
override val configurationUrl: String,
override val productCode: String,
private val productVersion: String,
connectionSettings: StatsConnectionSettings,
cacheTimeoutMs: Long
) : ConfigurationClient() {
private val httpClient = StatsHttpClient.newClient(connectionSettings, configurationUrl)
private val httpRequest = StatsRequestBuilder.newGetRequest(connectionSettings, configurationUrl)
private val cachedConfigurationVersion: StatisticsCachingSupplier<ConfigurationVersion?> =
StatisticsCachingSupplier(::loadConfiguration, cacheTimeoutMs)
override fun calculateConfigurationVersion(): ConfigurationVersion? = cachedConfigurationVersion.get()
/**
* Downloads configuration from the given url and deserializes the given JSON [String] it into a value
* of type [Configuration].
*
* @throws[java.io.IOException] if an I/O error occurs when sending request to the server or receiving response
* from the server.
* @throws[InterruptedException] if the http client operation is interrupted.
* @throws[SecurityException] If a security manager has been installed, and it denies
* {@link java.net.URLPermission access} to the URL in the given request, or proxy if one is configured.
* @throws [StatsResponseException] if the server response code isn't 200.
* @throws [SerializationException] if the given JSON string is not a valid JSON input for the type [Configuration].
*/
private fun loadConfiguration(): ConfigurationVersion? {
val function = object : StatsResponseProcessor<ConfigurationVersion?> {
override fun onSucceed(response: StatsHttpResponse): ConfigurationVersion? {
val responseContent: InputStream? = response.read()
if (responseContent != null) {
val content = responseContent.bufferedReader(StandardCharsets.UTF_8).use { reader ->
reader.readText()
}
val configuration = FusKotlinSerializer().deserializeConfigurationV4(content)
return configuration.findProductVersion(productVersion)
}
return null
}
}
val statsRequestResult = StatsHttpClient(httpClient).send(function, httpRequest)
if (statsRequestResult.errorCode != -1)
throw StatsResponseException(
"Http response status code to get fus reporting " +
"configuration: ${statsRequestResult.errorCode}. " +
"Configuration url: $configurationUrl. " +
"Product code: $productCode. " +
"Product version: $productVersion."
)
return statsRequestResult.result
}
}