diff --git a/plugins/settings-repository/src/ReadOnlySourceManager.kt b/plugins/settings-repository/src/ReadOnlySourceManager.kt index 98ae2bc50427..39047b749f0c 100644 --- a/plugins/settings-repository/src/ReadOnlySourceManager.kt +++ b/plugins/settings-repository/src/ReadOnlySourceManager.kt @@ -20,11 +20,16 @@ import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.util.AtomicClearableLazyValue import com.intellij.util.containers.mapSmartNotNull import com.intellij.util.io.exists +import gnu.trove.THashSet +import org.eclipse.jgit.diff.DiffEntry +import org.eclipse.jgit.diff.DiffFormatter import org.eclipse.jgit.lib.Repository import org.eclipse.jgit.storage.file.FileRepositoryBuilder +import org.eclipse.jgit.util.io.DisabledOutputStream import org.jetbrains.settingsRepository.git.GitRepositoryClientImpl import org.jetbrains.settingsRepository.git.Pull import org.jetbrains.settingsRepository.git.upstream +import org.jetbrains.settingsRepository.git.use import java.nio.file.Path class ReadOnlySourceManager(private val settings: IcsSettings, val rootDir: Path) { @@ -62,16 +67,50 @@ class ReadOnlySourceManager(private val settings: IcsSettings, val rootDir: Path repositoryList.drop() } - fun update(indicator: ProgressIndicator? = null): Boolean { - var isChanged = false + fun update(indicator: ProgressIndicator? = null): Set? { + var changedRootDirs: MutableSet? = null + + fun addChangedPath(path: String?) { + if (path == null || path == DiffEntry.DEV_NULL) { + return + } + + var firstSlash = path.indexOf('/') + if (firstSlash < 0) { + // path must use only /, but who knows + firstSlash = path.indexOf('\\') + } + + if (firstSlash > 0) { + if (changedRootDirs == null) { + changedRootDirs = THashSet() + } + + changedRootDirs!!.add(path.substring(0, firstSlash)) + } + } + for (repo in repositories) { indicator?.checkCanceled() LOG.debug { "Pull changes from read-only repo ${repo.upstream}" } - if (Pull(GitRepositoryClientImpl(repo, icsManager.credentialsStore), indicator).fetch() != null) { - isChanged = true - } + Pull(GitRepositoryClientImpl(repo, icsManager.credentialsStore), indicator).fetch(refUpdateProcessor = { refUpdate -> + val diffFormatter = DiffFormatter(DisabledOutputStream.INSTANCE) + diffFormatter.setRepository(repo) + diffFormatter.use { + val result = diffFormatter.scan(refUpdate.oldObjectId, refUpdate.newObjectId) + for (e in result) { + if (e.changeType == DiffEntry.ChangeType.DELETE) { + addChangedPath(e.oldPath) + } + else { + addChangedPath(e.oldPath) + addChangedPath(e.newPath) + } + } + } + }) } - return isChanged + return changedRootDirs } } \ No newline at end of file diff --git a/plugins/settings-repository/src/git/pull.kt b/plugins/settings-repository/src/git/pull.kt index 20a3e35fcb1a..287e28d67c4a 100644 --- a/plugins/settings-repository/src/git/pull.kt +++ b/plugins/settings-repository/src/git/pull.kt @@ -40,6 +40,7 @@ import org.eclipse.jgit.revwalk.RevWalk import org.eclipse.jgit.revwalk.RevWalkUtils import org.eclipse.jgit.transport.CredentialsProvider import org.eclipse.jgit.transport.RemoteConfig +import org.eclipse.jgit.transport.TrackingRefUpdate import org.eclipse.jgit.treewalk.FileTreeIterator import org.jetbrains.settingsRepository.* import java.io.IOException @@ -87,7 +88,7 @@ open internal class Pull(val manager: GitRepositoryClient, val indicator: Progre } } - fun fetch(prevRefUpdateResult: RefUpdate.Result? = null): Ref? { + fun fetch(prevRefUpdateResult: RefUpdate.Result? = null, refUpdateProcessor: ((TrackingRefUpdate) -> Unit)? = null): Ref? { indicator?.checkCanceled() val fetchResult = repository.fetch(remoteConfig, manager.credentialsProvider, indicator.asProgressMonitor()) ?: return null @@ -128,6 +129,8 @@ open internal class Pull(val manager: GitRepositoryClient, val indicator: Progre if (!hasChanges) { hasChanges = refUpdateResult != RefUpdate.Result.NO_CHANGE } + + refUpdateProcessor?.invoke(refUpdate) } if (!hasChanges) { diff --git a/plugins/settings-repository/src/sync.kt b/plugins/settings-repository/src/sync.kt index 77419c6a1df2..e403160dc03d 100644 --- a/plugins/settings-repository/src/sync.kt +++ b/plugins/settings-repository/src/sync.kt @@ -22,6 +22,7 @@ import com.intellij.openapi.application.invokeAndWaitIfNeed import com.intellij.openapi.components.StateStorage import com.intellij.openapi.components.stateStore import com.intellij.openapi.progress.ProcessCanceledException +import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.progress.runModalTask import com.intellij.openapi.project.Project import com.intellij.util.SmartList @@ -105,14 +106,7 @@ internal class SyncManager(private val icsManager: IcsManager, private val autoS } } - if (icsManager.readOnlySourcesManager.update(indicator)) { - invokeAndWaitIfNeed { - icsManager.schemeManagerFactory.value.process { - @Suppress("ConvertLambdaToReference") - it.reload() - } - } - } + updateCloudSchemes(indicator) } catch (e: ProcessCanceledException) { LOG.debug("Canceled") @@ -148,6 +142,25 @@ internal class SyncManager(private val icsManager: IcsManager, private val autoS } return updateResult } + + private fun updateCloudSchemes(indicator: ProgressIndicator) { + val changedRootDirs = icsManager.readOnlySourcesManager.update(indicator) ?: return + val schemeManagersToReload = SmartList>() + icsManager.schemeManagerFactory.value.process { + val fileSpec = toRepositoryPath(it.fileSpec, it.roamingType) + if (changedRootDirs.contains(fileSpec)) { + schemeManagersToReload.add(it) + } + } + + if (schemeManagersToReload.isNotEmpty()) { + invokeAndWaitIfNeed { + for (schemeManager in schemeManagersToReload) { + schemeManager.reload() + } + } + } + } } internal fun updateStoragesFromStreamProvider(store: ComponentStoreImpl, updateResult: UpdateResult, messageBus: MessageBus, reloadAllSchemes: Boolean = false): Boolean {