diff --git a/README.md b/README.md index 6b2375be0674..06d60d0607a6 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ The following conventions will be used to refer to directories on your machine: ## Getting OpenIDE Source Code OpenIDE source code is available from `` by either cloning or -downloading a zip file (based on a branch) into ``. The default is the *243* branch. +downloading a zip file (based on a branch) into ``. The default is the *252* branch. These Git operations can also be done through the [IntelliJ IDEA user interface](https://www.jetbrains.com/help/idea/using-git-integration.html). @@ -27,7 +27,7 @@ These scripts clone their respective *master* branches. Make sure you are inside _**Note:**_ Always `git checkout` the `openide` and `android` Git repositories to the same branches/tags. ## Building OpenIDE -Version 2024.3 or newer of OpenIDE is required to build and develop +Version 2025.2 or newer of OpenIDE is required to build and develop for the IntelliJ Platform. ### Opening the OpenIDE Source Code for Build diff --git a/build/src/org/jetbrains/intellij/build/OpenIdeProperties.kt b/build/src/org/jetbrains/intellij/build/OpenIdeProperties.kt index 56a131c14c83..4b56bd45b02b 100644 --- a/build/src/org/jetbrains/intellij/build/OpenIdeProperties.kt +++ b/build/src/org/jetbrains/intellij/build/OpenIdeProperties.kt @@ -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 { - return super.generateExecutableFilesPatterns(context, includeRuntime, arch) + override fun generateExecutableFilesPatterns(context: BuildContext, includeRuntime: Boolean, arch: JvmArchitecture, targetLibcImpl: LibcImpl): Sequence = + super.generateExecutableFilesPatterns(context, includeRuntime, arch, targetLibcImpl) .plus(KotlinBinaries.kotlinCompilerExecutables) .filterNot { it == "plugins/**/*.sh" } - } } protected open inner class OpenIdeMacDistributionCustomizer : MacDistributionCustomizer() { diff --git a/idea/customization/base/resources/intellij.idea.customization.base.xml b/idea/customization/base/resources/intellij.idea.customization.base.xml index 0ab8e24da7c3..5fad31d9c377 100644 --- a/idea/customization/base/resources/intellij.idea.customization.base.xml +++ b/idea/customization/base/resources/intellij.idea.customization.base.xml @@ -6,7 +6,7 @@ diff --git a/openide/openide.iml b/openide/openide.iml index b88c7309130b..db4f01e6d38d 100644 --- a/openide/openide.iml +++ b/openide/openide.iml @@ -14,5 +14,6 @@ + \ No newline at end of file diff --git a/openide/src/ru/openide/OpenIdePluginBundler.kt b/openide/src/ru/openide/OpenIdePluginBundler.kt index e76103dbcd93..7483d3224a15 100644 --- a/openide/src/ru/openide/OpenIdePluginBundler.kt +++ b/openide/src/ru/openide/OpenIdePluginBundler.kt @@ -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 diff --git a/idea/customization/base/src/OpenIdeExternalResourceUrls.kt b/platform/platform-impl/src/com/intellij/platform/ide/impl/customization/OpenIdeExternalResourceUrls.kt similarity index 94% rename from idea/customization/base/src/OpenIdeExternalResourceUrls.kt rename to platform/platform-impl/src/com/intellij/platform/ide/impl/customization/OpenIdeExternalResourceUrls.kt index 724c40fd59f3..b643b8ac8543 100644 --- a/idea/customization/base/src/OpenIdeExternalResourceUrls.kt +++ b/platform/platform-impl/src/com/intellij/platform/ide/impl/customization/OpenIdeExternalResourceUrls.kt @@ -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 diff --git a/platform/statistics/uploader/intellij.platform.statistics.uploader.iml b/platform/statistics/uploader/intellij.platform.statistics.uploader.iml index 4c7eade35cc5..508dbc128786 100644 --- a/platform/statistics/uploader/intellij.platform.statistics.uploader.iml +++ b/platform/statistics/uploader/intellij.platform.statistics.uploader.iml @@ -18,5 +18,6 @@ + \ No newline at end of file diff --git a/platform/statistics/uploader/src/com/intellij/internal/statistic/eventLog/connection/ConfigurationClientFactory.kt b/platform/statistics/uploader/src/com/intellij/internal/statistic/eventLog/connection/ConfigurationClientFactory.kt new file mode 100644 index 000000000000..4af27c8f863e --- /dev/null +++ b/platform/statistics/uploader/src/com/intellij/internal/statistic/eventLog/connection/ConfigurationClientFactory.kt @@ -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) + + } +} \ No newline at end of file diff --git a/platform/statistics/uploader/src/com/intellij/internal/statistic/eventLog/connection/EventLogSettingsClient.kt b/platform/statistics/uploader/src/com/intellij/internal/statistic/eventLog/connection/EventLogSettingsClient.kt index 40b4953902fe..41ef425b67fe 100644 --- a/platform/statistics/uploader/src/com/intellij/internal/statistic/eventLog/connection/EventLogSettingsClient.kt +++ b/platform/statistics/uploader/src/com/intellij/internal/statistic/eventLog/connection/EventLogSettingsClient.kt @@ -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 diff --git a/platform/statistics/uploader/src/com/intellij/internal/statistic/eventLog/connection/EventLogUploadSettingsClient.kt b/platform/statistics/uploader/src/com/intellij/internal/statistic/eventLog/connection/EventLogUploadSettingsClient.kt index 99803c620873..b6b75b87ec65 100644 --- a/platform/statistics/uploader/src/com/intellij/internal/statistic/eventLog/connection/EventLogUploadSettingsClient.kt +++ b/platform/statistics/uploader/src/com/intellij/internal/statistic/eventLog/connection/EventLogUploadSettingsClient.kt @@ -1,9 +1,11 @@ // 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 import com.jetbrains.fus.reporting.configuration.ConfigurationClient -import com.jetbrains.fus.reporting.configuration.ConfigurationClientFactory import com.jetbrains.fus.reporting.configuration.RegionCode import org.jetbrains.annotations.ApiStatus import org.jetbrains.annotations.VisibleForTesting @@ -30,7 +32,5 @@ open class EventLogUploadSettingsClient( applicationInfo.productVersion, applicationInfo.isTestConfig, applicationInfo.connectionSettings, - if (applicationInfo.regionalCode == chinaRegion) - RegionCode.CN else RegionCode.ALL, cacheTimeoutMs) } diff --git a/platform/statistics/uploader/src/com/intellij/internal/statistic/eventLog/connection/OpenIdeStatisticsQueryParameters.java b/platform/statistics/uploader/src/com/intellij/internal/statistic/eventLog/connection/OpenIdeStatisticsQueryParameters.java new file mode 100644 index 000000000000..beb4da33c0ab --- /dev/null +++ b/platform/statistics/uploader/src/com/intellij/internal/statistic/eventLog/connection/OpenIdeStatisticsQueryParameters.java @@ -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; + } +} diff --git a/platform/statistics/uploader/src/com/intellij/internal/statistic/eventLog/connection/RemoteConfigurationClient.kt b/platform/statistics/uploader/src/com/intellij/internal/statistic/eventLog/connection/RemoteConfigurationClient.kt new file mode 100644 index 000000000000..a67df0889637 --- /dev/null +++ b/platform/statistics/uploader/src/com/intellij/internal/statistic/eventLog/connection/RemoteConfigurationClient.kt @@ -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 = + 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 { + 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 + } +} \ No newline at end of file