DBE-21397: Add integration with Settings Sync

GitOrigin-RevId: 1af910d9a504606ffffda333cfbc6d349bb5a9c0
This commit is contained in:
Ilia Epelbaum
2026-02-05 19:32:19 +00:00
committed by intellij-monorepo-bot
parent 05a2331ee0
commit f7ef8dc089
6 changed files with 35 additions and 16 deletions
@@ -16,6 +16,7 @@ import com.intellij.openapi.util.NlsContexts;
import com.intellij.openapi.wm.ex.IdeFocusTraversalPolicy;
import com.intellij.ui.IdeUICustomization;
import com.intellij.util.Alarm;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -154,7 +155,7 @@ public class SingleConfigurableEditor extends DialogWrapper {
}
}
catch (ConfigurationException e) {
if (e.getMessage() != null) {
if (!processException(e) && e.getMessage() != null) {
if (myProject != null) {
Messages.showMessageDialog(myProject, e.getMessage(), e.getTitle(), Messages.getErrorIcon());
}
@@ -168,6 +169,11 @@ public class SingleConfigurableEditor extends DialogWrapper {
super.doOKAction();
}
@ApiStatus.Internal
protected boolean processException(ConfigurationException configurationException) {
return false;
}
protected static String createDimensionKey(Configurable configurable) {
String displayName = configurable.getDisplayName();
displayName = displayName.replaceAll("\n", "_").replaceAll(" ", "_");
@@ -71,7 +71,7 @@ abstract class AbstractServerCommunicator : SettingsSyncRemoteCommunicator, Disp
* @throws IOException If an I/O error occurs while attempting to retrieve the version information.
*/
@Throws(IOException::class)
protected abstract fun getLatestVersion(filePath: String) : String?
abstract fun getLatestVersion(filePath: String) : String?
@Throws(IOException::class)
protected abstract fun deleteFileInternal(filePath: String)
@@ -79,7 +79,7 @@ abstract class AbstractServerCommunicator : SettingsSyncRemoteCommunicator, Disp
@VisibleForTesting
@Throws(IOException::class, SecurityException::class)
protected fun currentSnapshotFilePath(): Pair<String, Boolean>? {
protected open fun currentSnapshotFilePath(): Pair<String, Boolean>? {
try {
val crossIdeSyncEnabled = isFileExists(CROSS_IDE_SYNC_MARKER_FILE)
if (!myTemporary && crossIdeSyncEnabled != SettingsSyncLocalSettings.getInstance().isCrossIdeSyncEnabled) {
@@ -106,7 +106,7 @@ abstract class AbstractServerCommunicator : SettingsSyncRemoteCommunicator, Disp
@VisibleForTesting
internal fun sendSnapshotFile(
fun sendSnapshotFile(
inputStream: InputStream,
knownServerVersion: String?,
force: Boolean,
@@ -143,6 +143,10 @@ abstract class AbstractServerCommunicator : SettingsSyncRemoteCommunicator, Disp
// errors are thrown as exceptions and are handled above
return SettingsSyncPushResult.Success(pushedVersion)
}
catch (ive: InvalidVersionIdException) {
LOG.info("Rejected: version doesn't match the version on server: ${ive.message}")
return SettingsSyncPushResult.Rejected
}
catch (e: Throwable) {
return SettingsSyncPushResult.Error(e.message ?: defaultMessage)
}
@@ -156,7 +160,7 @@ abstract class AbstractServerCommunicator : SettingsSyncRemoteCommunicator, Disp
requestSuccessful()
when (latestVersion) {
null -> return ServerState.FileNotExists
SettingsSyncLocalSettings.getInstance().knownAndAppliedServerId -> return ServerState.UpToDate
getKnownAndAppliedServerId() -> return ServerState.UpToDate
else -> return ServerState.UpdateNeeded
}
}
@@ -166,6 +170,8 @@ abstract class AbstractServerCommunicator : SettingsSyncRemoteCommunicator, Disp
}
}
open fun getKnownAndAppliedServerId(): String? = SettingsSyncLocalSettings.getInstance().knownAndAppliedServerId
override fun receiveUpdates(): UpdateResult {
LOG.info("Receiving settings snapshot from the cloud config server...")
try {
@@ -214,10 +220,6 @@ abstract class AbstractServerCommunicator : SettingsSyncRemoteCommunicator, Disp
requestSuccessful()
return pushResult
}
catch (ive: InvalidVersionIdException) {
LOG.info("Rejected: version doesn't match the version on server: ${ive.message}")
return SettingsSyncPushResult.Rejected
}
catch (e: Throwable) {
val message = handleRemoteError(e)
return SettingsSyncPushResult.Error(message)
@@ -23,7 +23,7 @@ import kotlin.io.path.isRegularFile
import kotlin.io.path.name
import kotlin.io.path.readText
internal object SettingsSnapshotZipSerializer {
object SettingsSnapshotZipSerializer {
private const val METAINFO = ".metainfo"
private const val INFO = "info.json"
const val PLUGINS = "plugins.json"
@@ -147,7 +147,7 @@ internal object SettingsSnapshotZipSerializer {
return SettingsSyncPluginsState(emptyMap())
}
private fun serializeMetaInfo(snapshotMetaInfo: SettingsSnapshot.MetaInfo): ByteArray {
fun serializeMetaInfo(snapshotMetaInfo: SettingsSnapshot.MetaInfo): ByteArray {
val formattedDate = DateTimeFormatter.ISO_INSTANT.format(snapshotMetaInfo.dateCreated)
val metaInfo = MetaInfo().apply {
date = formattedDate
@@ -186,7 +186,7 @@ internal object SettingsSnapshotZipSerializer {
return SettingsSnapshot.MetaInfo(Instant.now(), appInfo = null)
}
private class MetaInfo {
class MetaInfo {
lateinit var date: String
lateinit var applicationId: String
var buildNumber: String = ""
@@ -5,6 +5,7 @@ import com.intellij.ide.plugins.PluginManagerCore.isRunningFromSources
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.util.JDOMUtil
import com.intellij.settingsSync.core.AbstractServerCommunicator
import com.intellij.settingsSync.core.InvalidVersionIdException
import com.intellij.settingsSync.core.SettingsSyncBundle
import com.intellij.settingsSync.core.SettingsSyncEventListener
import com.intellij.settingsSync.core.SettingsSyncEvents
@@ -26,7 +27,7 @@ import java.net.URI
import java.net.http.HttpResponse
import java.util.concurrent.atomic.AtomicReference
internal open class CloudConfigServerCommunicator(private val serverUrl: String?, private val jbaAuthService: JBAAuthService)
open class CloudConfigServerCommunicator(private val serverUrl: String?, private val jbaAuthService: JBAAuthService)
: AbstractServerCommunicator()
{
private val clientVersionContext = CloudConfigVersionContext()
@@ -128,7 +129,13 @@ internal open class CloudConfigServerCommunicator(private val serverUrl: String?
override fun writeFileInternal(filePath: String, versionId: String?, content: InputStream) : String? {
return clientVersionContext.doWithVersion(filePath, versionId) { filePath ->
client.write(filePath, content)
try {
client.write(filePath, content)
}
catch (e: com.jetbrains.cloudconfig.exception.InvalidVersionIdException) {
throw InvalidVersionIdException(e.message ?: "Invalid version id exception from server", e)
}
val actualVersion: String? = clientVersionContext.get(filePath)
if (actualVersion == null) {
@@ -12,7 +12,7 @@ class JbaCommunicatorProvider(cs: CoroutineScope) : SettingsSyncCommunicatorProv
private val authServiceLazy = lazy<JBAAuthService> { JBAAuthService(cs) }
override val providerCode: String
get() = "jba"
get() = JBA_PROVIDER_CODE
override val authService: SettingsSyncAuthService
get() {
@@ -27,4 +27,8 @@ class JbaCommunicatorProvider(cs: CoroutineScope) : SettingsSyncCommunicatorProv
}.value
override fun dispose() {}
companion object {
const val JBA_PROVIDER_CODE: String = "jba"
}
}
@@ -79,7 +79,7 @@ private val LOG = logger<JBAAuthService>()
private const val JBA_USER_ID = "jba"
private const val JBA_PROVIDER_CODE = "jba"
internal class JBAAuthService(private val cs: CoroutineScope) : SettingsSyncAuthService {
class JBAAuthService(private val cs: CoroutineScope) : SettingsSyncAuthService {
@Volatile
private var invalidatedIdToken: String? = null