From f150638f28c386cb78de4f90f8a630d4e4f27533 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Sat, 18 Oct 2025 12:09:07 +0200 Subject: [PATCH] IJPL-157073 cleanup GitOrigin-RevId: dfa46a26291bc6d5cc2d10145d34837bc33ec3db --- .../ide/plugins/DisabledPluginsState.kt | 4 +- .../ide/plugins/PluginStringSetFile.kt | 62 ++++------ .../ide/bootstrap/ApplicationLoader.kt | 4 +- .../application/ConfigImportHelper.java | 4 +- .../ide/plugins/BundledPluginsState.kt | 111 +++++++++--------- .../ide/plugins/BundledPluginsStateTest.kt | 6 +- 6 files changed, 84 insertions(+), 107 deletions(-) diff --git a/platform/core-impl/src/com/intellij/ide/plugins/DisabledPluginsState.kt b/platform/core-impl/src/com/intellij/ide/plugins/DisabledPluginsState.kt index c7d835f7693a..bd6937d75697 100644 --- a/platform/core-impl/src/com/intellij/ide/plugins/DisabledPluginsState.kt +++ b/platform/core-impl/src/com/intellij/ide/plugins/DisabledPluginsState.kt @@ -72,7 +72,7 @@ class DisabledPluginsState internal constructor() : PluginEnabler.Headless { return emptySet() } - //remote dev host is supposed to be the paid feature, so when running the IDE as a remove dev backend we automatically enable the ultimate plugin if it was disabled + //remote dev host is supposed to be the paid feature, so when running the IDE as a remove dev backend, we automatically enable the ultimate plugin if it was disabled val requiredForCurrentMode = if (AppMode.isRemoteDevHost()) PluginManagerCore.ULTIMATE_PLUGIN_ID else null // ApplicationInfoImpl maybe loaded in another thread - get it after readPluginIdsFromFile @@ -172,7 +172,7 @@ class DisabledPluginsState internal constructor() : PluginEnabler.Headless { @TestOnly @Throws(IOException::class) fun saveDisabledPluginsAndInvalidate(configPath: Path, pluginIds: List = emptyList()) { - PluginStringSetFile.write(configPath.resolve(DISABLED_PLUGINS_FILENAME), pluginIds.toSet()) + writePluginStringSet(configPath.resolve(DISABLED_PLUGINS_FILENAME), pluginIds.toSet()) invalidate() } diff --git a/platform/core-impl/src/com/intellij/ide/plugins/PluginStringSetFile.kt b/platform/core-impl/src/com/intellij/ide/plugins/PluginStringSetFile.kt index 215204055ae7..b6483f638556 100644 --- a/platform/core-impl/src/com/intellij/ide/plugins/PluginStringSetFile.kt +++ b/platform/core-impl/src/com/intellij/ide/plugins/PluginStringSetFile.kt @@ -5,6 +5,7 @@ import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.extensions.PluginId import com.intellij.openapi.util.io.NioFiles import org.jetbrains.annotations.ApiStatus +import org.jetbrains.annotations.ApiStatus.Internal import java.io.IOException import java.nio.file.Files import java.nio.file.NoSuchFileException @@ -13,40 +14,27 @@ import java.nio.file.StandardOpenOption.* import java.util.* import kotlin.streams.asSequence +@Synchronized +@Internal +fun writePluginStringSet(path: Path, strings: Set) { + NioFiles.createDirectories(path.parent) + Files.write(path, TreeSet(strings)) +} + /** * DO NOT USE outside the plugins subsystem code, API can be changed arbitrarily without a notice. * * Persists a set of trimmed, non-empty strings to a file on disk. */ -@ApiStatus.Internal +@Internal object PluginStringSetFile { - @Synchronized - @Throws(IOException::class) - fun write(path: Path, strings: Set) { - NioFiles.createDirectories(path.parent) - // TODO: TreeSet demands comparable, probably we can drop Comparable on PluginId if we drop this usage - // wait, it's String, not PluginId - - Files.write(path, TreeSet(strings)) - } - - @Synchronized - fun writeSafe(path: Path, strings: Set, logger: Logger): Boolean { - try { - write(path, strings) - return true - } catch (e: IOException) { - logger.warn("failed to write plugin strings to $path", e) - return false - } - } - @Synchronized fun writeIdsSafe(path: Path, ids: Set, logger: Logger): Boolean { try { - write(path, ids.mapTo(mutableSetOf()) { it.idString }) + writePluginStringSet(path, ids.mapTo(mutableSetOf()) { it.idString }) return true - } catch (e: IOException) { + } + catch (e: IOException) { logger.warn("failed to write plugin strings to $path", e) return false } @@ -59,23 +47,13 @@ object PluginStringSetFile { Files.write(path, TreeSet(strings), CREATE, WRITE, APPEND) } - @Synchronized - fun appendSafe(path: Path, strings: Set, logger: Logger): Boolean { - try { - append(path, strings) - return true - } catch (e: IOException) { - logger.warn("failed to append plugin strings to $path", e) - return false - } - } - @Synchronized fun appendIdsSafe(path: Path, ids: Set, logger: Logger): Boolean { try { append(path, ids.mapTo(mutableSetOf()) { it.idString }) return true - } catch (e: IOException) { + } + catch (e: IOException) { logger.warn("failed to append plugin strings to $path", e) return false } @@ -83,16 +61,16 @@ object PluginStringSetFile { @Synchronized fun consumeSafe(path: Path, logger: Logger): Set { - return try { + try { val ids = read(path) if (!ids.isEmpty()) { Files.delete(path) // TODO may throw, but in that case we'll return emptySet, huh? } - ids + return ids } catch (e: IOException) { logger.error(path.toString(), e) - emptySet() + return emptySet() } } @@ -101,12 +79,12 @@ object PluginStringSetFile { @Synchronized fun readSafe(path: Path, log: Logger): Set { - return try { - read(path) + try { + return read(path) } catch (e: IOException) { log.warn("Unable to read plugin string set from: $path", e) - emptySet() + return emptySet() } } diff --git a/platform/platform-impl/bootstrap/src/com/intellij/platform/ide/bootstrap/ApplicationLoader.kt b/platform/platform-impl/bootstrap/src/com/intellij/platform/ide/bootstrap/ApplicationLoader.kt index 0c9d84c64296..51fd1e66afb7 100644 --- a/platform/platform-impl/bootstrap/src/com/intellij/platform/ide/bootstrap/ApplicationLoader.kt +++ b/platform/platform-impl/bootstrap/src/com/intellij/platform/ide/bootstrap/ApplicationLoader.kt @@ -7,11 +7,11 @@ import com.intellij.diagnostic.* import com.intellij.diagnostic.logs.LogLevelConfigurationManager import com.intellij.ide.* import com.intellij.ide.bootstrap.InitAppContext -import com.intellij.ide.plugins.BundledPluginsState import com.intellij.ide.plugins.PluginManagerCore import com.intellij.ide.plugins.PluginSet import com.intellij.ide.plugins.marketplace.statistics.PluginManagerUsageCollector import com.intellij.ide.plugins.marketplace.statistics.enums.DialogAcceptanceResultEnum +import com.intellij.ide.plugins.saveBundledPluginsState import com.intellij.ide.ui.IconMapLoader import com.intellij.ide.ui.LafManager import com.intellij.ide.ui.NotRoamableUiSettings @@ -239,7 +239,7 @@ internal suspend fun loadApp( delay(1.minutes) if (!ApplicationManagerEx.getApplicationEx().isExitInProgress) { span("save bundled plugin state") { - BundledPluginsState.saveBundledPluginsState() + saveBundledPluginsState() } } } diff --git a/platform/platform-impl/initial-config-import/src/com/intellij/openapi/application/ConfigImportHelper.java b/platform/platform-impl/initial-config-import/src/com/intellij/openapi/application/ConfigImportHelper.java index 160511eb772f..a860e21fbbcf 100644 --- a/platform/platform-impl/initial-config-import/src/com/intellij/openapi/application/ConfigImportHelper.java +++ b/platform/platform-impl/initial-config-import/src/com/intellij/openapi/application/ConfigImportHelper.java @@ -76,6 +76,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; +import static com.intellij.ide.plugins.BundledPluginsStateKt.BUNDLED_PLUGINS_FILENAME; + @ApiStatus.Internal public final class ConfigImportHelper { public static final String IMPORT_FROM_ENV_VAR = "JB_IMPORT_SETTINGS_FROM"; @@ -1566,7 +1568,7 @@ public final class ConfigImportHelper { private static boolean shouldSkipFileDuringImport(Path path, @Nullable ConfigImportSettings settings) { var fileName = path.getFileName().toString(); return SESSION_FILES.contains(fileName) || - fileName.equals(BundledPluginsState.BUNDLED_PLUGINS_FILENAME) || + fileName.equals(BUNDLED_PLUGINS_FILENAME) || fileName.equals(StoragePathMacros.APP_INTERNAL_STATE_DB) || fileName.equals(ExpiredPluginsState.EXPIRED_PLUGINS_FILENAME) || fileName.startsWith(SpecialConfigFiles.CHROME_USER_DATA) || diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/BundledPluginsState.kt b/platform/platform-impl/src/com/intellij/ide/plugins/BundledPluginsState.kt index 568814b397f1..3e639cc798e2 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/BundledPluginsState.kt +++ b/platform/platform-impl/src/com/intellij/ide/plugins/BundledPluginsState.kt @@ -13,73 +13,70 @@ import com.intellij.platform.settings.SettingsController import com.intellij.platform.settings.settingDescriptorFactory import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext -import org.jetbrains.annotations.ApiStatus +import org.jetbrains.annotations.ApiStatus.Internal import org.jetbrains.annotations.VisibleForTesting import java.io.IOException import java.nio.file.Path -@ApiStatus.Internal -object BundledPluginsState { - const val BUNDLED_PLUGINS_FILENAME: String = "bundled_plugins.txt" +@Internal +suspend fun saveBundledPluginsState() { + val settingsController = serviceAsync() + val settingDescriptor = settingDescriptorFactory(PluginManagerCore.CORE_ID).settingDescriptor("bundled.plugins.list.saved.version") { + tags = listOf(CacheTag) + } - suspend fun saveBundledPluginsState() { - val settingsController = serviceAsync() - val settingDescriptor = settingDescriptorFactory(PluginManagerCore.CORE_ID).settingDescriptor("bundled.plugins.list.saved.version") { - tags = listOf(CacheTag) + val savedBuildNumber = getSavedBuildNumber(settingsController, settingDescriptor) + val currentBuildNumber = ApplicationInfo.getInstance().build + + val shouldSave = savedBuildNumber == null || + savedBuildNumber < currentBuildNumber || + (!ApplicationManager.getApplication().isUnitTestMode && PluginManagerCore.isRunningFromSources()) + if (!shouldSave) { + return + } + + val bundledPluginIds = PluginManagerCore.loadedPlugins.filterTo(HashSet()) { it.isBundled } + withContext(Dispatchers.IO) { + try { + writePluginIdsToFile(bundledPluginIds, PathManager.getConfigDir()) + settingsController.setItem(settingDescriptor, currentBuildNumber.asString()) } - - val savedBuildNumber = getSavedBuildNumber(settingsController, settingDescriptor) - val currentBuildNumber = ApplicationInfo.getInstance().build - - val shouldSave = savedBuildNumber == null || - savedBuildNumber < currentBuildNumber || - (!ApplicationManager.getApplication().isUnitTestMode && PluginManagerCore.isRunningFromSources()) - if (!shouldSave) { - return - } - - val bundledPluginIds = PluginManagerCore.loadedPlugins.filterTo(HashSet()) { it.isBundled } - withContext(Dispatchers.IO) { - try { - writePluginIdsToFile(bundledPluginIds) - setSavedBuildNumber(currentBuildNumber, settingsController, settingDescriptor) - } - catch (e: IOException) { - PluginManagerCore.logger.warn("Unable to save bundled plugins list", e) - } + catch (e: IOException) { + PluginManagerCore.logger.warn("Unable to save bundled plugins list", e) } } +} - @VisibleForTesting - fun writePluginIdsToFile(pluginIds: Set, configDir: Path = PathManager.getConfigDir()) { - PluginStringSetFile.write( - path = configDir.resolve(BUNDLED_PLUGINS_FILENAME), - strings = pluginIds.mapTo(HashSet()) { "${it.pluginId.idString}|${it.category}" }, - ) - } +@Internal +fun readPluginIdsFromFile(configDir: Path): Set { + val path = configDir.resolve(BUNDLED_PLUGINS_FILENAME) + return PluginStringSetFile.readSafe(path, PluginManagerCore.logger) + .mapTo(LinkedHashSet()) { s -> + val splitResult = s.split('|') + val id = splitResult.first() + BundledPlugin(id = PluginId.getId(id), category = splitResult.getOrNull(1)?.takeIf { it != "null" }) + } +} - fun readPluginIdsFromFile(configDir: Path = PathManager.getConfigDir()): Set { - val path = configDir.resolve(BUNDLED_PLUGINS_FILENAME) - val bundledPlugins = PluginStringSetFile.readSafe(path, PluginManagerCore.logger) - .mapTo(mutableSetOf()) { - val splitResult = it.split('|') - val id = splitResult.first() - val category = splitResult.getOrNull(1) - BundledPlugin(PluginId.getId(id), if (category == "null") null else category) - } - return bundledPlugins - } +@Internal +const val BUNDLED_PLUGINS_FILENAME: String = "bundled_plugins.txt" - private fun getSavedBuildNumber(settingsController: SettingsController, - settingDescriptor: SettingDescriptor): BuildNumber? { - return settingsController.getItem(settingDescriptor)?.let { BuildNumber.fromString(it) } - } +@VisibleForTesting +@Internal +fun writePluginIdsToFile(pluginIds: Set, configDir: Path) { + writePluginStringSet( + path = configDir.resolve(BUNDLED_PLUGINS_FILENAME), + strings = pluginIds.mapTo(HashSet()) { "${it.pluginId.idString}|${it.category}" }, + ) +} - private fun setSavedBuildNumber(value: BuildNumber?, - settingsController: SettingsController, - settingDescriptor: SettingDescriptor) { - settingsController.setItem(settingDescriptor, value?.asString()) - } +@Internal +data class BundledPlugin(@JvmField val id: PluginId, @JvmField val category: String?) + +private fun getSavedBuildNumber( + settingsController: SettingsController, + settingDescriptor: SettingDescriptor, +): BuildNumber? { + return settingsController.getItem(settingDescriptor)?.let { BuildNumber.fromString(it) } +} - data class BundledPlugin(val id: PluginId, val category: String?) -} \ No newline at end of file diff --git a/platform/platform-tests/testSrc/com/intellij/ide/plugins/BundledPluginsStateTest.kt b/platform/platform-tests/testSrc/com/intellij/ide/plugins/BundledPluginsStateTest.kt index 063e1207397e..079b612a6e89 100644 --- a/platform/platform-tests/testSrc/com/intellij/ide/plugins/BundledPluginsStateTest.kt +++ b/platform/platform-tests/testSrc/com/intellij/ide/plugins/BundledPluginsStateTest.kt @@ -20,9 +20,9 @@ class BundledPluginsStateTest { getIdeaDescriptor(it.first, it.second) } - BundledPluginsState.writePluginIdsToFile(pluginIds = pluginIds, configDir = dir) - assertThat(BundledPluginsState.readPluginIdsFromFile(configDir = dir)) - .hasSameElementsAs(pluginIds.map { BundledPluginsState.BundledPlugin(it.pluginId, it.category) }) + writePluginIdsToFile(pluginIds = pluginIds, configDir = dir) + assertThat(readPluginIdsFromFile(configDir = dir)) + .hasSameElementsAs(pluginIds.map { BundledPlugin(it.pluginId, it.category) }) } @Test