From 2a9e37cd6f60c230caca0d4d81969ee226de9918 Mon Sep 17 00:00:00 2001 From: Alexey Katsman Date: Tue, 28 Jul 2026 18:46:18 +0200 Subject: [PATCH] PY-91190 Fix legacy Python SDK migration at startup Wait for workspace model synchronization before migrating global Python SDKs so delayed JPS synchronization cannot overwrite the migrated entities. Use ASSOCIATED_PROJECT_PATH as the effective non-canonical working directory until migration writes WORKING_DIRECTORY. This keeps legacy interpreters visible while preserving the original XML before migration. (cherry picked from commit ae7a7953e379f76ac777d653109cc1a3984c4386) IJ-MR-215819 GitOrigin-RevId: 027bb719540e88f5907d266e96ef4dc2ed1f2425 --- .../python/sdk/PythonSdkAdditionalData.java | 12 +++++++++++- .../sdk/PythonSdkAdditionalDataMigrationActivity.kt | 6 ++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/python/python-sdk/src/com/jetbrains/python/sdk/PythonSdkAdditionalData.java b/python/python-sdk/src/com/jetbrains/python/sdk/PythonSdkAdditionalData.java index edd740711386..f1af77fe25d1 100644 --- a/python/python-sdk/src/com/jetbrains/python/sdk/PythonSdkAdditionalData.java +++ b/python/python-sdk/src/com/jetbrains/python/sdk/PythonSdkAdditionalData.java @@ -11,6 +11,7 @@ import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.SdkAdditionalData; import com.intellij.openapi.util.JDOMExternalizer; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.io.NioPathUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; @@ -274,9 +275,10 @@ public class PythonSdkAdditionalData implements SdkAdditionalData { } } - if (!hasValidWorkingDirectory()) { + if (!hasValidWorkingDirectory() || !myWorkingDirectoryIsCanonical) { Path workingDirectory = flavorMigration.workingDirectory(); if (workingDirectory == null) workingDirectory = requirementsWorkingDirectory; + if (workingDirectory == null && hasValidWorkingDirectory()) workingDirectory = myWorkingDirectory; if (workingDirectory == null) workingDirectory = fallbackWorkingDirectory; if (workingDirectory != null && !workingDirectory.toString().isBlank()) { @@ -321,6 +323,14 @@ public class PythonSdkAdditionalData implements SdkAdditionalData { myWorkingDirectoryIsCanonical = false; myMigrationRequired = true; } + else if (myAssociatedModulePath != null) { + Path associatedModulePath = NioPathUtil.toNioPathOrNull(myAssociatedModulePath); + if (associatedModulePath != null && !Objects.equals(associatedModulePath, EMPTY_WORKING_DIRECTORY)) { + myWorkingDirectory = associatedModulePath; + myWorkingDirectoryIsCanonical = false; + myMigrationRequired = true; + } + } myRequirementsFile = element.getAttributeValue(REQUIREMENTS_FILE); String legacyRequiredTxtPath = element.getAttributeValue(ASSOCIATED_REQUIRED_TXT_PATH); myLegacyRequiredTxtPath = legacyRequiredTxtPath == null ? null : Path.of(legacyRequiredTxtPath); diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkAdditionalDataMigrationActivity.kt b/python/src/com/jetbrains/python/sdk/PythonSdkAdditionalDataMigrationActivity.kt index 314bf22b1b32..ed23957c14a2 100644 --- a/python/src/com/jetbrains/python/sdk/PythonSdkAdditionalDataMigrationActivity.kt +++ b/python/src/com/jetbrains/python/sdk/PythonSdkAdditionalDataMigrationActivity.kt @@ -10,6 +10,8 @@ import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.roots.ModuleRootManager import com.intellij.openapi.roots.ProjectRootManager import com.intellij.openapi.startup.ProjectActivity +import com.intellij.platform.backend.workspace.WorkspaceModel +import com.intellij.platform.backend.workspace.impl.WorkspaceModelInternal import com.intellij.util.concurrency.annotations.RequiresWriteLock import org.jetbrains.annotations.ApiStatus import java.nio.file.Path @@ -19,6 +21,10 @@ class PythonSdkAdditionalDataMigrationActivity : ProjectActivity, DumbAware { override suspend fun execute(project: Project) { if (project.isDisposed) return + @Suppress("UnsafeOpenServiceCast") + (WorkspaceModel.getInstance(project) as WorkspaceModelInternal).awaitSynchronizationWithJpsModel() + if (project.isDisposed) return + val pythonSdks = ProjectJdkTable.getInstance().allJdks.filter { PythonSdkUtil.isPythonSdk(it) } writeAction { migratePythonSdkAdditionalData(project, pythonSdks)