Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Leveraging IntelliJ IDEA for Android Studio's Cloud Settings Sync #2833

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions plugins/settings-sync/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
provider="com.intellij.settingsSync.config.SettingsSyncConfigurableProvider"
groupId="root"
groupWeight="5"/>
<applicationService serviceInterface="com.intellij.settingsSync.SettingsSyncMain"
serviceImplementation="com.intellij.settingsSync.SettingsSyncMainImpl"/>
<applicationService serviceInterface="com.intellij.settingsSync.auth.SettingsSyncAuthService"
serviceImplementation="com.intellij.settingsSync.auth.SettingsSyncDefaultAuthService"
testServiceImplementation="com.intellij.settingsSync.SettingsSyncTestAuthService"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import java.util.function.Consumer
import java.util.stream.Collectors
import kotlin.io.path.*

internal object SettingsSnapshotZipSerializer {
object SettingsSnapshotZipSerializer {
private const val METAINFO = ".metainfo"
private const val INFO = "info.json"
const val PLUGINS = "plugins.json"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import java.util.function.Predicate
import kotlin.concurrent.withLock
import kotlin.io.path.*

internal class SettingsSyncIdeMediatorImpl(private val componentStore: ComponentStoreImpl,
class SettingsSyncIdeMediatorImpl(private val componentStore: ComponentStoreImpl,
private val rootConfig: Path,
private val enabledCondition: () -> Boolean) : StreamProvider, SettingsSyncIdeMediator {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import com.intellij.configurationStore.ComponentStoreImpl
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.PathManager
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.intellij.openapi.components.serviceIfCreated
import com.intellij.openapi.components.impl.stores.stateStore
import com.intellij.settingsSync.SettingsSyncMain.Companion.isAvailable
import com.intellij.settingsSync.auth.SettingsSyncAuthService
import com.intellij.util.SystemProperties
import kotlinx.coroutines.CoroutineScope
Expand All @@ -24,11 +24,28 @@ fun isSettingsSyncEnabledInSettings(): Boolean = SettingsSyncSettings.getInstanc

internal const val SETTINGS_SYNC_STORAGE_FOLDER: String = "settingsSync"

@ApiStatus.Internal
@Service
class SettingsSyncMain(coroutineScope: CoroutineScope) : Disposable {

interface SettingsSyncMain {
fun getRemoteCommunicator(): SettingsSyncRemoteCommunicator

fun disableSyncing()

val controls: SettingsSyncControls

companion object {
fun isAvailable(): Boolean {
return ApplicationManager.getApplication().serviceIfCreated<SettingsSyncMain>() != null
}

fun getInstance(): SettingsSyncMain = service<SettingsSyncMain>()

}
}

@ApiStatus.Internal
class SettingsSyncMainImpl(coroutineScope: CoroutineScope) : SettingsSyncMain, Disposable {
override val controls: SettingsSyncControls

init {
val appConfigPath = PathManager.getConfigDir()
val componentStore = ApplicationManager.getApplication().stateStore as ComponentStoreImpl
Expand All @@ -46,19 +63,13 @@ class SettingsSyncMain(coroutineScope: CoroutineScope) : Disposable {
override fun dispose() {
}

internal fun getRemoteCommunicator(): SettingsSyncRemoteCommunicator = controls.remoteCommunicator
override fun getRemoteCommunicator(): SettingsSyncRemoteCommunicator = controls.remoteCommunicator

fun disableSyncing() {
override fun disableSyncing() {
controls.ideMediator.removeStreamProvider()
}

companion object {
fun isAvailable(): Boolean {
return ApplicationManager.getApplication().serviceIfCreated<SettingsSyncMain>() != null
}

fun getInstance(): SettingsSyncMain = service<SettingsSyncMain>()

// Extracted to simplify testing, otherwise it is fast and is called from the service initializer
internal fun init(
coroutineScope: CoroutineScope,
Expand All @@ -78,10 +89,10 @@ class SettingsSyncMain(coroutineScope: CoroutineScope) : Disposable {
return SettingsSyncControls(ideMediator, updateChecker, bridge, remoteCommunicator, settingsSyncStorage)
}
}

class SettingsSyncControls(val ideMediator: SettingsSyncIdeMediator,
val updateChecker: SettingsSyncUpdateChecker,
val bridge: SettingsSyncBridge,
val remoteCommunicator: SettingsSyncRemoteCommunicator,
val settingsSyncStorage: Path)
}

class SettingsSyncControls(val ideMediator: SettingsSyncIdeMediator,
val updateChecker: SettingsSyncUpdateChecker,
val bridge: SettingsSyncBridge,
val remoteCommunicator: SettingsSyncRemoteCommunicator,
val settingsSyncStorage: Path)
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import org.jetbrains.annotations.Nls
import java.util.*

@Service
internal class SettingsSyncStatusTracker {
class SettingsSyncStatusTracker {
private var lastSyncTime = -1L
private var errorMessage: String? = null

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package com.intellij.settingsSync.auth
import com.intellij.openapi.application.ApplicationManager
import com.intellij.ui.JBAccountInfoService

internal interface SettingsSyncAuthService {
interface SettingsSyncAuthService {
companion object {
fun getInstance(): SettingsSyncAuthService = ApplicationManager.getApplication().getService(SettingsSyncAuthService::class.java)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import com.intellij.util.EventDispatcher
import kotlinx.coroutines.*
import java.util.*

internal class SettingsSyncEnabler {
class SettingsSyncEnabler {
private val eventDispatcher = EventDispatcher.create(Listener::class.java)

object State {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ internal class SettingsSyncAuthTest : BasePlatformTestCase() {
@TestFor(issues = ["IDEA-307565"])
fun `idToken is invalidated after unauthorized exception`() {
val authServiceSpy = spy<SettingsSyncDefaultAuthService>()
ApplicationManager.getApplication().replaceService(SettingsSyncAuthService::class.java, authServiceSpy, SettingsSyncMain.getInstance())
ApplicationManager.getApplication().replaceService(
SettingsSyncAuthService::class.java,
authServiceSpy,
SettingsSyncMain.getInstance() as SettingsSyncMainImpl
)

val accountInfoService = mock<JBAccountInfoService>()
`when`(accountInfoService.idToken).thenReturn("OLD-ID-TOKEN")
Expand Down Expand Up @@ -84,7 +88,11 @@ internal class SettingsSyncAuthTest : BasePlatformTestCase() {
assertTrue(SettingsSyncSettings.getInstance().syncEnabled)

val authServiceSpy = spy<SettingsSyncDefaultAuthService>()
ApplicationManager.getApplication().replaceService(SettingsSyncAuthService::class.java, authServiceSpy, SettingsSyncMain.getInstance())
ApplicationManager.getApplication().replaceService(
SettingsSyncAuthService::class.java,
authServiceSpy,
SettingsSyncMain.getInstance() as SettingsSyncMainImpl
)

val accountInfoService = mock<JBAccountInfoService>()
`when`(accountInfoService.idToken).thenReturn(null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ internal class SettingsSyncFlowTest : SettingsSyncTestBase() {
waitForInit: Boolean = true,
) {
SettingsSyncSettings.getInstance().state = SettingsSyncSettings.getInstance().state.withSyncEnabled(true)
val controls = SettingsSyncMain.init(currentThreadCoroutineScope(), disposable, settingsSyncStorage, configDir, remoteCommunicator, ideMediator)
val controls = SettingsSyncMainImpl.init(currentThreadCoroutineScope(), disposable, settingsSyncStorage, configDir, remoteCommunicator, ideMediator)
updateChecker = controls.updateChecker
bridge = controls.bridge
bridge.initialize(initMode)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ internal abstract class SettingsSyncRealIdeTestBase : SettingsSyncTestBase() {
SettingsSyncSettings.getInstance().syncEnabled = true
SettingsSyncLocalSettings.getInstance().state.crossIdeSyncEnabled = crossIdeSync;
val ideMediator = SettingsSyncIdeMediatorImpl(componentStore, configDir, enabledCondition = { true })
val controls = SettingsSyncMain.init(currentThreadCoroutineScope(), disposable, settingsSyncStorage, configDir, remoteCommunicator, ideMediator)
val controls = SettingsSyncMainImpl.init(currentThreadCoroutineScope(), disposable, settingsSyncStorage, configDir, remoteCommunicator, ideMediator)
updateChecker = controls.updateChecker
bridge = controls.bridge
bridge.initialize(initMode)
Expand Down