mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
1. IDEA-326189 Cannot invoke "org.eclipse.jgit.lib.AnyObjectId.hashCode()" because "id" is null (Add init commit, if repo is empty)
2. Disable sync, if init failed GitOrigin-RevId: ec3e290d5b4a9aa926a0cfd4812a11edaf134f3d
This commit is contained in:
committed by
intellij-monorepo-bot
parent
edb8edf72c
commit
656937249f
@@ -12,7 +12,6 @@ import com.intellij.ui.JBAccountInfoService
|
||||
import com.intellij.util.io.createFile
|
||||
import com.intellij.util.io.readText
|
||||
import com.intellij.util.io.write
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.eclipse.jgit.api.Git
|
||||
@@ -60,8 +59,11 @@ internal class GitSettingsLog(private val settingsSyncStorage: Path,
|
||||
|
||||
override fun initialize() {
|
||||
configureJGit()
|
||||
initRepository()
|
||||
}
|
||||
|
||||
val dotGit = settingsSyncStorage.resolve(".git")
|
||||
private fun initRepository() {
|
||||
val dotGit: Path = settingsSyncStorage.resolve(".git")
|
||||
repository = FileRepositoryBuilder().setGitDir(dotGit.toFile()).setAutonomous(true).readEnvironment().build()
|
||||
git = Git(repository)
|
||||
|
||||
@@ -69,9 +71,11 @@ internal class GitSettingsLog(private val settingsSyncStorage: Path,
|
||||
if (newRepository) {
|
||||
LOG.info("Initializing new Git repository for Settings Sync at $settingsSyncStorage")
|
||||
repository.create()
|
||||
initRepository(repository)
|
||||
addInitialCommit(repository)
|
||||
}
|
||||
if (!repository.headCommitExists()) {
|
||||
addInitialCommit(repository)
|
||||
}
|
||||
|
||||
createBranchIfNeeded(MASTER_REF_NAME, newRepository)
|
||||
createBranchIfNeeded(CLOUD_REF_NAME, newRepository)
|
||||
createBranchIfNeeded(IDE_REF_NAME, newRepository)
|
||||
@@ -102,7 +106,7 @@ internal class GitSettingsLog(private val settingsSyncStorage: Path,
|
||||
applyState(IDE_REF_NAME, snapshot, "Copy current configs", warnAboutEmptySnapshot = false)
|
||||
}
|
||||
|
||||
private fun initRepository(repository: Repository?) {
|
||||
private fun addInitialCommit(repository: Repository) {
|
||||
val gitignore = settingsSyncStorage.resolve(".gitignore").createFile()
|
||||
gitignore.write("""
|
||||
event-log-metadata
|
||||
@@ -397,8 +401,7 @@ internal class GitSettingsLog(private val settingsSyncStorage: Path,
|
||||
cloudBranchTip: RevCommit,
|
||||
serializer: (T) -> String,
|
||||
deserializer: (String) -> T,
|
||||
merger: (T?, T, T) -> T): String
|
||||
{
|
||||
merger: (T?, T, T) -> T): String {
|
||||
val ideContent = getFileContentInBranch(relativePath, ideBranchTip)
|
||||
val ideState = deserializer(ideContent)
|
||||
val cloudContent = getFileContentInBranch(relativePath, cloudBranchTip)
|
||||
@@ -527,7 +530,7 @@ internal class GitSettingsLog(private val settingsSyncStorage: Path,
|
||||
override fun toString(): String = id.substring(0, 8)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
companion object {
|
||||
val LOG = logger<GitSettingsLog>()
|
||||
|
||||
const val MASTER_REF_NAME = "master"
|
||||
@@ -550,7 +553,12 @@ internal class GitSettingsLog(private val settingsSyncStorage: Path,
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Repository.headCommitExists(): Boolean {
|
||||
val ref = this.findRef(Constants.HEAD) ?: return false
|
||||
return ref.objectId != null
|
||||
}
|
||||
|
||||
internal fun Repository.headCommit(): RevCommit {
|
||||
val ref = this.findRef(Constants.HEAD)
|
||||
val ref = this.findRef(Constants.HEAD) ?: throw RuntimeException("No HEAD commit found for the repo")
|
||||
return this.parseCommit(ref.objectId)
|
||||
}
|
||||
|
||||
@@ -62,17 +62,21 @@ class SettingsSyncBridge(parentDisposable: Disposable,
|
||||
|
||||
@RequiresBackgroundThread
|
||||
internal fun initialize(initMode: InitMode) {
|
||||
saveIdeSettings()
|
||||
try {
|
||||
saveIdeSettings()
|
||||
|
||||
settingsLog.initialize()
|
||||
settingsLog.initialize()
|
||||
|
||||
// the queue is not activated initially => events will be collected but not processed until we perform all initialization tasks
|
||||
SettingsSyncEvents.getInstance().addListener(settingsChangeListener)
|
||||
ideMediator.activateStreamProvider()
|
||||
// the queue is not activated initially => events will be collected but not processed until we perform all initialization tasks
|
||||
SettingsSyncEvents.getInstance().addListener(settingsChangeListener)
|
||||
ideMediator.activateStreamProvider()
|
||||
|
||||
applyInitialChanges(initMode)
|
||||
applyInitialChanges(initMode)
|
||||
|
||||
queue.activate()
|
||||
queue.activate()
|
||||
} catch (ex: Exception) {
|
||||
stopSyncingAndRollback(null, ex)
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveIdeSettings() {
|
||||
@@ -276,16 +280,20 @@ class SettingsSyncBridge(parentDisposable: Disposable,
|
||||
val idePosition: SettingsLog.Position,
|
||||
val cloudPosition: SettingsLog.Position,
|
||||
val knownServerId: String?
|
||||
)
|
||||
) {
|
||||
override fun toString(): String {
|
||||
return "CurrentState(masterPosition=$masterPosition, idePosition=$idePosition, cloudPosition=$cloudPosition, knownServerId=$knownServerId)"
|
||||
}
|
||||
}
|
||||
|
||||
private fun collectCurrentState(): CurrentState = CurrentState(settingsLog.getMasterPosition(),
|
||||
settingsLog.getIdePosition(),
|
||||
settingsLog.getCloudPosition(),
|
||||
SettingsSyncLocalSettings.getInstance().knownAndAppliedServerId)
|
||||
|
||||
private fun stopSyncingAndRollback(previousState: CurrentState, exception: Throwable? = null) {
|
||||
private fun stopSyncingAndRollback(previousState: CurrentState?, exception: Throwable? = null) {
|
||||
if (exception != null) {
|
||||
LOG.error("Couldn't apply settings. Disabling sync and rolling back.", exception)
|
||||
LOG.error("Couldn't apply settings. Settings sync will be disabled.", exception)
|
||||
SettingsSyncEventsStatistics.DISABLED_AUTOMATICALLY.log(SettingsSyncEventsStatistics.AutomaticDisableReason.EXCEPTION)
|
||||
}
|
||||
else {
|
||||
@@ -299,12 +307,15 @@ class SettingsSyncBridge(parentDisposable: Disposable,
|
||||
ideMediator.removeStreamProvider()
|
||||
SettingsSyncEvents.getInstance().removeListener(settingsChangeListener)
|
||||
pendingEvents.clear()
|
||||
rollback(previousState)
|
||||
if (previousState != null) {
|
||||
rollback(previousState)
|
||||
}
|
||||
queue.deactivate() // for tests it is important to have it the last statement, otherwise waitForAllExecuted can finish before rollback
|
||||
}
|
||||
|
||||
private fun rollback(previousState: CurrentState) {
|
||||
try {
|
||||
LOG.warn("Rolling back to previous state: $previousState")
|
||||
SettingsSyncLocalSettings.getInstance().knownAndAppliedServerId = previousState.knownServerId
|
||||
settingsLog.setIdePosition(previousState.idePosition)
|
||||
settingsLog.setCloudPosition(previousState.cloudPosition)
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package com.intellij.settingsSync
|
||||
|
||||
import com.intellij.idea.TestFor
|
||||
import com.intellij.openapi.components.SettingsCategory
|
||||
import com.intellij.testFramework.LoggedErrorProcessor
|
||||
import com.intellij.testFramework.utils.io.createDirectory
|
||||
import com.intellij.util.ConcurrencyUtil
|
||||
import com.intellij.util.concurrency.AppExecutorUtil.createBoundedScheduledExecutorService
|
||||
import com.intellij.util.io.createFile
|
||||
import com.intellij.util.io.readText
|
||||
import com.intellij.util.io.write
|
||||
import org.eclipse.jgit.api.Git
|
||||
@@ -393,6 +396,37 @@ internal class SettingsSyncFlowTest : SettingsSyncTestBase() {
|
||||
}
|
||||
}
|
||||
|
||||
@TestFor(issues = ["IDEA-326189"])
|
||||
@Test fun `create initial commit for empty repo`(){
|
||||
val dotGit: Path = settingsSyncStorage.resolve(".git")
|
||||
val repository = FileRepositoryBuilder().setGitDir(dotGit.toFile()).setAutonomous(true).readEnvironment().build()
|
||||
repository.create()
|
||||
initSettingsSync()
|
||||
assertNotNull(repository.findRef(GitSettingsLog.CLOUD_REF_NAME))
|
||||
assertNotNull(repository.findRef(GitSettingsLog.IDE_REF_NAME))
|
||||
}
|
||||
|
||||
@Test fun `disable sync if init failed`(){
|
||||
SettingsSyncSettings.getInstance().syncEnabled = true
|
||||
val dotGit: Path = settingsSyncStorage.resolve(".git")
|
||||
val repository = FileRepositoryBuilder().setGitDir(dotGit.toFile()).setAutonomous(true).readEnvironment().build()
|
||||
repository.create()
|
||||
val gitignore = settingsSyncStorage.resolve(".gitignore").createFile()
|
||||
gitignore.write("""
|
||||
.idea/workspace.xml
|
||||
""".trimIndent())
|
||||
|
||||
val git = Git(repository)
|
||||
git.add().addFilepattern(".gitignore").call()
|
||||
git.commit().setMessage("init").setNoVerify(true).setSign(false).call()
|
||||
|
||||
(dotGit / "index").write("aaaaaaa")
|
||||
LoggedErrorProcessor.executeAndReturnLoggedError{
|
||||
initSettingsSync()
|
||||
}
|
||||
assertFalse(SettingsSyncSettings.getInstance().syncEnabled)
|
||||
}
|
||||
|
||||
private fun syncSettingsAndWait() {
|
||||
fireSettingsChanged()
|
||||
bridge.waitForAllExecuted()
|
||||
|
||||
Reference in New Issue
Block a user