IJPL-157073 cleanup

GitOrigin-RevId: dfa46a26291bc6d5cc2d10145d34837bc33ec3db
This commit is contained in:
Vladimir Krivosheev
2025-10-18 13:53:51 +00:00
committed by intellij-monorepo-bot
parent c58e6c594d
commit f150638f28
6 changed files with 84 additions and 107 deletions
@@ -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<String> = emptyList()) {
PluginStringSetFile.write(configPath.resolve(DISABLED_PLUGINS_FILENAME), pluginIds.toSet())
writePluginStringSet(configPath.resolve(DISABLED_PLUGINS_FILENAME), pluginIds.toSet())
invalidate()
}
@@ -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<String>) {
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<String>) {
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<String>, 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<PluginId>, 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<String>, 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<PluginId>, 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<String> {
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<String> {
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()
}
}
@@ -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()
}
}
}
@@ -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) ||
@@ -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<SettingsController>()
val settingDescriptor = settingDescriptorFactory(PluginManagerCore.CORE_ID).settingDescriptor("bundled.plugins.list.saved.version") {
tags = listOf(CacheTag)
}
suspend fun saveBundledPluginsState() {
val settingsController = serviceAsync<SettingsController>()
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<IdeaPluginDescriptor>, 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<BundledPlugin> {
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<BundledPlugin> {
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<String>): BuildNumber? {
return settingsController.getItem(settingDescriptor)?.let { BuildNumber.fromString(it) }
}
@VisibleForTesting
@Internal
fun writePluginIdsToFile(pluginIds: Set<IdeaPluginDescriptor>, 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<String>) {
settingsController.setItem(settingDescriptor, value?.asString())
}
@Internal
data class BundledPlugin(@JvmField val id: PluginId, @JvmField val category: String?)
private fun getSavedBuildNumber(
settingsController: SettingsController,
settingDescriptor: SettingDescriptor<String>,
): BuildNumber? {
return settingsController.getItem(settingDescriptor)?.let { BuildNumber.fromString(it) }
}
data class BundledPlugin(val id: PluginId, val category: String?)
}
@@ -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