From 84b80798434f9d82248cb9feabdea3435824c7dc Mon Sep 17 00:00:00 2001 From: Pavel Karateev Date: Thu, 10 Jul 2025 17:04:56 +0200 Subject: [PATCH 01/14] PY-81113 support Python 3.14 in PyCharm debugger backend (cherry picked from commit dd980256f072d0d8e723fba8cb30277c713940a8) IJ-MR-171824 GitOrigin-RevId: 74aa0aa0ad484fce4cfcc9a9b88774aeca205ae1 --- .../_pydev_bundle/pydev_is_thread_alive.py | 17 +++++++----- .../_pydevd_bundle/pydevd_pep_669_tracing.py | 24 ++++++++++------- .../pydevd_pep_669_tracing_cython.pyx | 23 ++++++++++------ .../test_pydev_is_thread_alive.py | 26 +++++++++++++++++++ 4 files changed, 67 insertions(+), 23 deletions(-) create mode 100644 python/helpers/pydev/tests/_pydev_bundle/test_pydev_is_thread_alive.py diff --git a/python/helpers/pydev/_pydev_bundle/pydev_is_thread_alive.py b/python/helpers/pydev/_pydev_bundle/pydev_is_thread_alive.py index 25cfe2f79c148..0d49f36279bf5 100644 --- a/python/helpers/pydev/_pydev_bundle/pydev_is_thread_alive.py +++ b/python/helpers/pydev/_pydev_bundle/pydev_is_thread_alive.py @@ -5,8 +5,18 @@ # It is required to debug threads started by start_new_thread in Python 3.4 _temp = threading.Thread() +# Python >=3.14 +if hasattr(_temp, "_os_thread_handle") and hasattr(_temp, "_started"): + def is_thread_alive(t): + return not t._os_thread_handle.is_done() + +# Python ==3.13 +elif hasattr(_temp, "_handle") and hasattr(_temp, "_started"): + def is_thread_alive(t): + return not t._handle.is_done() + # Python <=3.12 -if hasattr(_temp, '_is_stopped'): +elif hasattr(_temp, '_is_stopped'): def is_thread_alive(t): return not t._is_stopped @@ -20,11 +30,6 @@ def is_thread_alive(t): def is_thread_alive(t): return t.isAlive() -# Python >=3.13 -elif hasattr(_temp, 'is_alive'): - def is_thread_alive(t): - return t.is_alive() - else: def is_thread_alive(t): raise RuntimeError('Cannot determine how to check if thread is alive') diff --git a/python/helpers/pydev/_pydevd_bundle/pydevd_pep_669_tracing.py b/python/helpers/pydev/_pydevd_bundle/pydevd_pep_669_tracing.py index 61f0436904570..79f6896f42353 100644 --- a/python/helpers/pydev/_pydevd_bundle/pydevd_pep_669_tracing.py +++ b/python/helpers/pydev/_pydevd_bundle/pydevd_pep_669_tracing.py @@ -9,7 +9,6 @@ from os.path import splitext, basename from _pydev_bundle import pydev_log -from _pydev_bundle.pydev_is_thread_alive import is_thread_alive from _pydevd_bundle.pydevd_breakpoints import stop_on_unhandled_exception from _pydevd_bundle.pydevd_bytecode_utils import ( find_last_call_name, find_last_func_call_order) @@ -104,14 +103,24 @@ def __init__(self, thread, thread_ident, trace, additional_info): self.thread_ident = thread_ident self.additional_info = additional_info self.trace = trace - self._use_is_stopped = hasattr(thread, '_is_stopped') + + self._use_handle = hasattr(thread, "_handle") + self._use_started = hasattr(thread, "_started") + self._use_os_thread_handle = hasattr(thread, "_os_thread_handle") def is_thread_alive(self): - if self._use_is_stopped: - return not self.thread._is_stopped - else: + # Python >=3.14 + if self._use_os_thread_handle and self._use_started: + return not self.thread._os_thread_handle.is_done() + + # Python ==3.13 + elif self._use_handle and self._use_started: return not self.thread._handle.is_done() + # Python ==3.12 + else: + return not self.thread._is_stopped + class _DeleteDummyThreadOnDel: """ @@ -445,10 +454,7 @@ def call_callback(code, instruction_offset, callable, arg0): if thread_info is None: return - thread = thread_info.thread - - - if not is_thread_alive(thread): + if not thread_info.is_thread_alive(): return frame_cache_key = _make_frame_cache_key(code) diff --git a/python/helpers/pydev/_pydevd_bundle/pydevd_pep_669_tracing_cython.pyx b/python/helpers/pydev/_pydevd_bundle/pydevd_pep_669_tracing_cython.pyx index 75859461ee918..9f53600d842d4 100644 --- a/python/helpers/pydev/_pydevd_bundle/pydevd_pep_669_tracing_cython.pyx +++ b/python/helpers/pydev/_pydevd_bundle/pydevd_pep_669_tracing_cython.pyx @@ -15,7 +15,6 @@ import traceback from os.path import splitext, basename from _pydev_bundle import pydev_log -from _pydev_bundle.pydev_is_thread_alive import is_thread_alive from _pydevd_bundle.pydevd_breakpoints import stop_on_unhandled_exception from _pydevd_bundle.pydevd_bytecode_utils import ( find_last_call_name, find_last_func_call_order) @@ -110,14 +109,24 @@ class ThreadInfo: self.thread_ident = thread_ident self.additional_info = additional_info self.trace = trace - self._use_is_stopped = hasattr(thread, '_is_stopped') + + self._use_handle = hasattr(thread, "_handle") + self._use_started = hasattr(thread, "_started") + self._use_os_thread_handle = hasattr(thread, "_os_thread_handle") def is_thread_alive(self): - if self._use_is_stopped: - return not self.thread._is_stopped - else: + # Python >=3.14 + if self._use_os_thread_handle and self._use_started: + return not self.thread._os_thread_handle.is_done() + + # Python ==3.13 + elif self._use_handle and self._use_started: return not self.thread._handle.is_done() + # Python ==3.12 + else: + return not self.thread._is_stopped + class _DeleteDummyThreadOnDel: """ @@ -451,10 +460,8 @@ def call_callback(code, instruction_offset, callable, arg0): if thread_info is None: return - thread = thread_info.thread - - if not is_thread_alive(thread): + if not thread_info.is_thread_alive(): return frame_cache_key = _make_frame_cache_key(code) diff --git a/python/helpers/pydev/tests/_pydev_bundle/test_pydev_is_thread_alive.py b/python/helpers/pydev/tests/_pydev_bundle/test_pydev_is_thread_alive.py new file mode 100644 index 0000000000000..5a25d04caee9e --- /dev/null +++ b/python/helpers/pydev/tests/_pydev_bundle/test_pydev_is_thread_alive.py @@ -0,0 +1,26 @@ +# Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. + +import threading + +from _pydev_bundle.pydev_is_thread_alive import is_thread_alive + + +def test_id_thread_alive(): + start_event = threading.Event() + end_event = threading.Event() + + def worker(): + start_event.set() + end_event.wait() + + t = threading.Thread(target=worker) + + t.start() + start_event.wait() + + assert is_thread_alive(t) + + end_event.set() + t.join() + + assert not is_thread_alive(t) From 6422a26cb7f580d06cf406f5e5343b469c9170bd Mon Sep 17 00:00:00 2001 From: Karina Kazaryan Date: Mon, 1 Sep 2025 14:43:10 +0000 Subject: [PATCH 02/14] IDEA 2025.2.1 Community changing minor v to 2.1.1 (cherry picked from commit 96873bdfdd5532fbb991b696a596ac4cf576dd63) IJ-MR-174206 GitOrigin-RevId: f29b6da4c13deffa18e070f7649356bdb635aa06 --- community-resources/resources/idea/IdeaApplicationInfo.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/community-resources/resources/idea/IdeaApplicationInfo.xml b/community-resources/resources/idea/IdeaApplicationInfo.xml index f1d782b508368..0aba58e452bc7 100644 --- a/community-resources/resources/idea/IdeaApplicationInfo.xml +++ b/community-resources/resources/idea/IdeaApplicationInfo.xml @@ -1,5 +1,5 @@ - + From c12515074505caa2014684dda5f824862bda605a Mon Sep 17 00:00:00 2001 From: Pavel Karateev Date: Thu, 10 Jul 2025 17:04:56 +0200 Subject: [PATCH 03/14] PY-81113 support Python 3.14 in PyCharm debugger backend (cherry picked from commit dd980256f072d0d8e723fba8cb30277c713940a8) IJ-MR-171824 GitOrigin-RevId: 74aa0aa0ad484fce4cfcc9a9b88774aeca205ae1 --- .../_pydev_bundle/pydev_is_thread_alive.py | 17 +++++++----- .../_pydevd_bundle/pydevd_pep_669_tracing.py | 24 ++++++++++------- .../pydevd_pep_669_tracing_cython.pyx | 23 ++++++++++------ .../test_pydev_is_thread_alive.py | 26 +++++++++++++++++++ 4 files changed, 67 insertions(+), 23 deletions(-) create mode 100644 python/helpers/pydev/tests/_pydev_bundle/test_pydev_is_thread_alive.py diff --git a/python/helpers/pydev/_pydev_bundle/pydev_is_thread_alive.py b/python/helpers/pydev/_pydev_bundle/pydev_is_thread_alive.py index 25cfe2f79c148..0d49f36279bf5 100644 --- a/python/helpers/pydev/_pydev_bundle/pydev_is_thread_alive.py +++ b/python/helpers/pydev/_pydev_bundle/pydev_is_thread_alive.py @@ -5,8 +5,18 @@ # It is required to debug threads started by start_new_thread in Python 3.4 _temp = threading.Thread() +# Python >=3.14 +if hasattr(_temp, "_os_thread_handle") and hasattr(_temp, "_started"): + def is_thread_alive(t): + return not t._os_thread_handle.is_done() + +# Python ==3.13 +elif hasattr(_temp, "_handle") and hasattr(_temp, "_started"): + def is_thread_alive(t): + return not t._handle.is_done() + # Python <=3.12 -if hasattr(_temp, '_is_stopped'): +elif hasattr(_temp, '_is_stopped'): def is_thread_alive(t): return not t._is_stopped @@ -20,11 +30,6 @@ def is_thread_alive(t): def is_thread_alive(t): return t.isAlive() -# Python >=3.13 -elif hasattr(_temp, 'is_alive'): - def is_thread_alive(t): - return t.is_alive() - else: def is_thread_alive(t): raise RuntimeError('Cannot determine how to check if thread is alive') diff --git a/python/helpers/pydev/_pydevd_bundle/pydevd_pep_669_tracing.py b/python/helpers/pydev/_pydevd_bundle/pydevd_pep_669_tracing.py index 61f0436904570..79f6896f42353 100644 --- a/python/helpers/pydev/_pydevd_bundle/pydevd_pep_669_tracing.py +++ b/python/helpers/pydev/_pydevd_bundle/pydevd_pep_669_tracing.py @@ -9,7 +9,6 @@ from os.path import splitext, basename from _pydev_bundle import pydev_log -from _pydev_bundle.pydev_is_thread_alive import is_thread_alive from _pydevd_bundle.pydevd_breakpoints import stop_on_unhandled_exception from _pydevd_bundle.pydevd_bytecode_utils import ( find_last_call_name, find_last_func_call_order) @@ -104,14 +103,24 @@ def __init__(self, thread, thread_ident, trace, additional_info): self.thread_ident = thread_ident self.additional_info = additional_info self.trace = trace - self._use_is_stopped = hasattr(thread, '_is_stopped') + + self._use_handle = hasattr(thread, "_handle") + self._use_started = hasattr(thread, "_started") + self._use_os_thread_handle = hasattr(thread, "_os_thread_handle") def is_thread_alive(self): - if self._use_is_stopped: - return not self.thread._is_stopped - else: + # Python >=3.14 + if self._use_os_thread_handle and self._use_started: + return not self.thread._os_thread_handle.is_done() + + # Python ==3.13 + elif self._use_handle and self._use_started: return not self.thread._handle.is_done() + # Python ==3.12 + else: + return not self.thread._is_stopped + class _DeleteDummyThreadOnDel: """ @@ -445,10 +454,7 @@ def call_callback(code, instruction_offset, callable, arg0): if thread_info is None: return - thread = thread_info.thread - - - if not is_thread_alive(thread): + if not thread_info.is_thread_alive(): return frame_cache_key = _make_frame_cache_key(code) diff --git a/python/helpers/pydev/_pydevd_bundle/pydevd_pep_669_tracing_cython.pyx b/python/helpers/pydev/_pydevd_bundle/pydevd_pep_669_tracing_cython.pyx index 75859461ee918..9f53600d842d4 100644 --- a/python/helpers/pydev/_pydevd_bundle/pydevd_pep_669_tracing_cython.pyx +++ b/python/helpers/pydev/_pydevd_bundle/pydevd_pep_669_tracing_cython.pyx @@ -15,7 +15,6 @@ import traceback from os.path import splitext, basename from _pydev_bundle import pydev_log -from _pydev_bundle.pydev_is_thread_alive import is_thread_alive from _pydevd_bundle.pydevd_breakpoints import stop_on_unhandled_exception from _pydevd_bundle.pydevd_bytecode_utils import ( find_last_call_name, find_last_func_call_order) @@ -110,14 +109,24 @@ class ThreadInfo: self.thread_ident = thread_ident self.additional_info = additional_info self.trace = trace - self._use_is_stopped = hasattr(thread, '_is_stopped') + + self._use_handle = hasattr(thread, "_handle") + self._use_started = hasattr(thread, "_started") + self._use_os_thread_handle = hasattr(thread, "_os_thread_handle") def is_thread_alive(self): - if self._use_is_stopped: - return not self.thread._is_stopped - else: + # Python >=3.14 + if self._use_os_thread_handle and self._use_started: + return not self.thread._os_thread_handle.is_done() + + # Python ==3.13 + elif self._use_handle and self._use_started: return not self.thread._handle.is_done() + # Python ==3.12 + else: + return not self.thread._is_stopped + class _DeleteDummyThreadOnDel: """ @@ -451,10 +460,8 @@ def call_callback(code, instruction_offset, callable, arg0): if thread_info is None: return - thread = thread_info.thread - - if not is_thread_alive(thread): + if not thread_info.is_thread_alive(): return frame_cache_key = _make_frame_cache_key(code) diff --git a/python/helpers/pydev/tests/_pydev_bundle/test_pydev_is_thread_alive.py b/python/helpers/pydev/tests/_pydev_bundle/test_pydev_is_thread_alive.py new file mode 100644 index 0000000000000..5a25d04caee9e --- /dev/null +++ b/python/helpers/pydev/tests/_pydev_bundle/test_pydev_is_thread_alive.py @@ -0,0 +1,26 @@ +# Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. + +import threading + +from _pydev_bundle.pydev_is_thread_alive import is_thread_alive + + +def test_id_thread_alive(): + start_event = threading.Event() + end_event = threading.Event() + + def worker(): + start_event.set() + end_event.wait() + + t = threading.Thread(target=worker) + + t.start() + start_event.wait() + + assert is_thread_alive(t) + + end_event.set() + t.join() + + assert not is_thread_alive(t) From d85702f22b82cfe3b64601c9c0b97bd251101c08 Mon Sep 17 00:00:00 2001 From: Karina Kazaryan Date: Mon, 1 Sep 2025 14:43:10 +0000 Subject: [PATCH 04/14] IDEA 2025.2.1 Community changing minor v to 2.1.1 (cherry picked from commit 96873bdfdd5532fbb991b696a596ac4cf576dd63) IJ-MR-174206 GitOrigin-RevId: f29b6da4c13deffa18e070f7649356bdb635aa06 --- community-resources/resources/idea/IdeaApplicationInfo.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/community-resources/resources/idea/IdeaApplicationInfo.xml b/community-resources/resources/idea/IdeaApplicationInfo.xml index 51acf28f784f1..193dc2576cdd6 100644 --- a/community-resources/resources/idea/IdeaApplicationInfo.xml +++ b/community-resources/resources/idea/IdeaApplicationInfo.xml @@ -1,5 +1,5 @@ - + From ddecaa3800c3ae7ee57208e495c792ab1bb83385 Mon Sep 17 00:00:00 2001 From: Nikolay Egorov Date: Fri, 20 Jun 2025 12:17:46 +0300 Subject: [PATCH 05/14] KTIJ-34640: Fall back to the file itself if neither an original nor a delegate is found (cherry picked from commit 33f3f20055b420d9bca4c58c09a784fd626bd6e7) IJ-CR-174133 GitOrigin-RevId: 43796ad8bd6e93ddadd784a0712859c97e7e86cc --- .../util/src/org/jetbrains/kotlin/idea/util/FileUtils.kt | 5 ++++- .../idea/fir/extensions/KtCompilerPluginsProviderIdeImpl.kt | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/plugins/kotlin/base/util/src/org/jetbrains/kotlin/idea/util/FileUtils.kt b/plugins/kotlin/base/util/src/org/jetbrains/kotlin/idea/util/FileUtils.kt index e4e8b26da6fbc..501d4a2487174 100644 --- a/plugins/kotlin/base/util/src/org/jetbrains/kotlin/idea/util/FileUtils.kt +++ b/plugins/kotlin/base/util/src/org/jetbrains/kotlin/idea/util/FileUtils.kt @@ -28,7 +28,10 @@ fun VirtualFile.isJavaFileType(): Boolean { FileTypeManager.getInstance().getFileTypeByFileName(nameSequence) == JavaFileType.INSTANCE } -fun VirtualFile.getOriginalOrDelegateFile(): VirtualFile = +fun VirtualFile.getOriginalOrDelegateFileOrSelf(): VirtualFile = + getOriginalOrDelegateFile() ?: this + +fun VirtualFile.getOriginalOrDelegateFile(): VirtualFile? = when (this) { is VirtualFileWindow -> delegate.getOriginalOrDelegateFile() is LightVirtualFileBase -> originalFile diff --git a/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/fir/extensions/KtCompilerPluginsProviderIdeImpl.kt b/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/fir/extensions/KtCompilerPluginsProviderIdeImpl.kt index 1698c58ab9aaf..ff8287dde4c40 100644 --- a/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/fir/extensions/KtCompilerPluginsProviderIdeImpl.kt +++ b/plugins/kotlin/fir/src/org/jetbrains/kotlin/idea/fir/extensions/KtCompilerPluginsProviderIdeImpl.kt @@ -53,7 +53,7 @@ import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCommonCompilerArgu import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCompilerSettingsListener import org.jetbrains.kotlin.idea.facet.KotlinFacet import org.jetbrains.kotlin.idea.facet.isKotlinFacet -import org.jetbrains.kotlin.idea.util.getOriginalOrDelegateFile +import org.jetbrains.kotlin.idea.util.getOriginalOrDelegateFileOrSelf import org.jetbrains.kotlin.idea.workspaceModel.KotlinSettingsEntity import org.jetbrains.kotlin.scripting.compiler.plugin.impl.makeScriptCompilerArguments import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition @@ -152,7 +152,7 @@ internal class KtCompilerPluginsProviderIdeImpl( is KaScriptModule -> { val registrarForModule = pluginsCache?.registrarForScriptModule ?: return emptyList() val cacheKey = module.file.virtualFile - .getOriginalOrDelegateFile() + .getOriginalOrDelegateFileOrSelf() module.getExtensionsForModule(registrarForModule, cacheKey, extensionType) } From 7be51459be7f79902ddca0a77eaf797742038737 Mon Sep 17 00:00:00 2001 From: Egor Eliseev Date: Thu, 28 Aug 2025 10:09:35 +0000 Subject: [PATCH 06/14] PY-81317 Debugger fails with 'Argument for @NotNull parameter 'module' must not be null' Merge-request: IJ-MR-173816 Merged-by: Egor Eliseev (cherry picked from commit 726dd1849e7988d33d4937188542ba10fdb9617b) IJ-MR-173816 GitOrigin-RevId: da21302cabc66d4defd88ac060d3b4e5b3aa36c1 --- .../com/jetbrains/python/run/PythonScripts.kt | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/python/src/com/jetbrains/python/run/PythonScripts.kt b/python/src/com/jetbrains/python/run/PythonScripts.kt index 45272d5f5b1c3..455b6082cbaaa 100644 --- a/python/src/com/jetbrains/python/run/PythonScripts.kt +++ b/python/src/com/jetbrains/python/run/PythonScripts.kt @@ -300,19 +300,21 @@ fun TargetedCommandLine.execute(env: TargetEnvironment, indicator: ProgressIndic * Checks whether the base directory of [project] is registered in [this] request. Adds it if it is not. * You can also provide [modules] to add its content roots and [Sdk] for which user added custom paths */ -fun TargetEnvironmentRequest.ensureProjectSdkAndModuleDirsAreOnTarget(project: Project, vararg modules: Module) { +fun TargetEnvironmentRequest.ensureProjectSdkAndModuleDirsAreOnTarget(project: Project, vararg modules: Module?) { fun TargetEnvironmentRequest.addPathToVolume(basePath: Path) { if (uploadVolumes.none { basePath.startsWith(it.localRootPath) }) { uploadVolumes += UploadRoot(localRootPath = basePath, targetRootPath = TargetPath.Temporary()) } } for (module in modules) { - ModuleRootManager.getInstance(module).contentRoots.forEach { - try { - addPathToVolume(it.toNioPath()) - } - catch (_: UnsupportedOperationException) { - // VirtualFile.toNioPath throws UOE if VirtualFile has no associated path which is common case for JupyterRemoteVirtualFile + if (module != null) { + ModuleRootManager.getInstance(module).contentRoots.forEach { + try { + addPathToVolume(it.toNioPath()) + } + catch (_: UnsupportedOperationException) { + // VirtualFile.toNioPath throws UOE if VirtualFile has no associated path which is common case for JupyterRemoteVirtualFile + } } } } From 8462fb504d5caef7a19dca47345ececbf41d0888 Mon Sep 17 00:00:00 2001 From: Egor Eliseev Date: Mon, 1 Sep 2025 17:43:21 +0000 Subject: [PATCH 07/14] PY-81317 Debugger fails with 'Argument for @NotNull parameter 'module' must not be null' Fix callers Merge-request: IJ-MR-174209 Merged-by: Egor Eliseev (cherry picked from commit 751bea82479695737e6319d2145fca095c8af35c) IJ-MR-174209 GitOrigin-RevId: 8f8161f71e387ee6c8b8e24e813a8c186809323b --- .../python/run/PythonCommandLineState.java | 4 +++- .../com/jetbrains/python/run/PythonScripts.kt | 16 +++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/python/src/com/jetbrains/python/run/PythonCommandLineState.java b/python/src/com/jetbrains/python/run/PythonCommandLineState.java index c4e6bcab89db9..b75de8c95b2e6 100644 --- a/python/src/com/jetbrains/python/run/PythonCommandLineState.java +++ b/python/src/com/jetbrains/python/run/PythonCommandLineState.java @@ -366,7 +366,9 @@ public void processTerminated(@NotNull ProcessEvent event) { pythonExecution.setWorkingDir(getPythonExecutionWorkingDir(targetEnvironmentRequest)); initEnvironment(myConfig.getProject(), pythonExecution, myConfig, createRemotePathMapper(), isDebug(), helpersAwareTargetRequest, sdk); customizePythonExecutionEnvironmentVars(helpersAwareTargetRequest, pythonExecution.getEnvs(), myConfig.isPassParentEnvs()); - PythonScripts.ensureProjectSdkAndModuleDirsAreOnTarget(targetEnvironmentRequest, myConfig.getProject(), myConfig.getModule()); + PythonScripts.ensureProjectSdkAndModuleDirsAreOnTarget(targetEnvironmentRequest, + myConfig.getProject(), + myConfig.getModule() != null ? new Module[]{myConfig.getModule()} : Module.EMPTY_ARRAY); return pythonExecution; } diff --git a/python/src/com/jetbrains/python/run/PythonScripts.kt b/python/src/com/jetbrains/python/run/PythonScripts.kt index 455b6082cbaaa..45272d5f5b1c3 100644 --- a/python/src/com/jetbrains/python/run/PythonScripts.kt +++ b/python/src/com/jetbrains/python/run/PythonScripts.kt @@ -300,21 +300,19 @@ fun TargetedCommandLine.execute(env: TargetEnvironment, indicator: ProgressIndic * Checks whether the base directory of [project] is registered in [this] request. Adds it if it is not. * You can also provide [modules] to add its content roots and [Sdk] for which user added custom paths */ -fun TargetEnvironmentRequest.ensureProjectSdkAndModuleDirsAreOnTarget(project: Project, vararg modules: Module?) { +fun TargetEnvironmentRequest.ensureProjectSdkAndModuleDirsAreOnTarget(project: Project, vararg modules: Module) { fun TargetEnvironmentRequest.addPathToVolume(basePath: Path) { if (uploadVolumes.none { basePath.startsWith(it.localRootPath) }) { uploadVolumes += UploadRoot(localRootPath = basePath, targetRootPath = TargetPath.Temporary()) } } for (module in modules) { - if (module != null) { - ModuleRootManager.getInstance(module).contentRoots.forEach { - try { - addPathToVolume(it.toNioPath()) - } - catch (_: UnsupportedOperationException) { - // VirtualFile.toNioPath throws UOE if VirtualFile has no associated path which is common case for JupyterRemoteVirtualFile - } + ModuleRootManager.getInstance(module).contentRoots.forEach { + try { + addPathToVolume(it.toNioPath()) + } + catch (_: UnsupportedOperationException) { + // VirtualFile.toNioPath throws UOE if VirtualFile has no associated path which is common case for JupyterRemoteVirtualFile } } } From d99d33c9dda50bda488e39ce4cd8baf70aed8f8e Mon Sep 17 00:00:00 2001 From: Vitaly Legchilkin Date: Tue, 2 Sep 2025 17:04:24 +0200 Subject: [PATCH 08/14] [python][sdk] don't cancel lazyInitialization job while cancelling of await job (PY-83799) (cherry picked from commit c84b85c2af157a61206fcd18ddd0676fb648407c) IJ-MR-174328 GitOrigin-RevId: dc0d5a216177a4c222609a47dbdf3df27863466c --- .../packaging/management/PythonPackageManager.kt | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/python/src/com/jetbrains/python/packaging/management/PythonPackageManager.kt b/python/src/com/jetbrains/python/packaging/management/PythonPackageManager.kt index 77c2b3e5009ae..9472015e8aa59 100644 --- a/python/src/com/jetbrains/python/packaging/management/PythonPackageManager.kt +++ b/python/src/com/jetbrains/python/packaging/management/PythonPackageManager.kt @@ -23,12 +23,11 @@ import com.jetbrains.python.packaging.dependencies.PythonDependenciesManager import com.jetbrains.python.packaging.normalizePackageName import com.jetbrains.python.packaging.requirement.PyRequirementVersionSpec import com.jetbrains.python.sdk.PythonSdkCoroutineService -import kotlinx.coroutines.future.asCompletableFuture -import kotlinx.coroutines.future.await +import kotlinx.coroutines.Deferred +import kotlinx.coroutines.async import kotlinx.coroutines.launch import org.jetbrains.annotations.ApiStatus import org.jetbrains.annotations.CheckReturnValue -import java.util.concurrent.CompletableFuture /** @@ -37,8 +36,8 @@ import java.util.concurrent.CompletableFuture */ @ApiStatus.Experimental abstract class PythonPackageManager(val project: Project, val sdk: Sdk) { - private val lazyInitialization: CompletableFuture by lazy { - service().cs.launch { + private val lazyInitialization: Deferred by lazy { + service().cs.async { try { repositoryManager.initCaches() reloadPackages() @@ -47,7 +46,7 @@ abstract class PythonPackageManager(val project: Project, val sdk: Sdk) { catch (t: Throwable) { thisLogger().error("Failed to initialize PythonPackageManager for $sdk", t) } - }.asCompletableFuture() + } } @get:ApiStatus.Internal From 08b6c703d96f877035490d7681f7519ce8f6e64d Mon Sep 17 00:00:00 2001 From: "Hlib.Saliuk" Date: Tue, 2 Sep 2025 21:23:43 +0200 Subject: [PATCH 09/14] RELEASE-393: PyCharm 2025.2.1.1 (cherry picked from commit 10ad96109428f795fc1522dd04544318ecab1249) IJ-MR-174364 GitOrigin-RevId: 1d2cf082f40ae2fd131018b94c62685c08aa37bc --- python/ide-common/resources/idea/PyCharmCoreApplicationInfo.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ide-common/resources/idea/PyCharmCoreApplicationInfo.xml b/python/ide-common/resources/idea/PyCharmCoreApplicationInfo.xml index 947f89b1b234d..ae8381ef9f498 100644 --- a/python/ide-common/resources/idea/PyCharmCoreApplicationInfo.xml +++ b/python/ide-common/resources/idea/PyCharmCoreApplicationInfo.xml @@ -1,6 +1,6 @@ - + From 917b28f78c531a03e00cb0f3f34ec8afafd26c9a Mon Sep 17 00:00:00 2001 From: Ferdinand Saurenbach Date: Sat, 6 Sep 2025 10:24:07 +0200 Subject: [PATCH 10/14] Remove K2 mode --- build/src/org/jetbrains/intellij/build/KorgeForgeProperties.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/src/org/jetbrains/intellij/build/KorgeForgeProperties.kt b/build/src/org/jetbrains/intellij/build/KorgeForgeProperties.kt index 259e155114a48..da9247eab021a 100644 --- a/build/src/org/jetbrains/intellij/build/KorgeForgeProperties.kt +++ b/build/src/org/jetbrains/intellij/build/KorgeForgeProperties.kt @@ -37,7 +37,8 @@ open class IdeaCommunityProperties(communityHomeDir: Path) : BaseIdeaCommunityPr "intellij.eclipse", "intellij.sh.python", "intellij.ant", - "intellij.gdpr" + "intellij.gdpr", + "intellij.modules.kotlin.k2" ////////////// //"intellij.vcs.gitlab", //"intellij.groovy", From c8218295b3aa96ca8a81c8843dd86fe16f74d6db Mon Sep 17 00:00:00 2001 From: Elena Shaverdova Date: Thu, 28 Aug 2025 15:14:59 +0200 Subject: [PATCH 11/14] IJPL-202715 Jira Task Server integration fails: "The requested API has been removed" error when fetching tasks (cherry picked from commit b1ef765175e99e32ac4277bd7316891ebebc2bf9) IJ-CR-174067 GitOrigin-RevId: fd5437597aec2d894cb87ea023e73c497c576886 --- .../src/com/intellij/tasks/jira/rest/JiraRestApi.java | 11 +++++++++-- .../tasks/tasks-core/resources/META-INF/plugin.xml | 3 +++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/rest/JiraRestApi.java b/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/rest/JiraRestApi.java index 4dc2344558b6e..15e17be102070 100644 --- a/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/rest/JiraRestApi.java +++ b/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/rest/JiraRestApi.java @@ -1,7 +1,8 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.tasks.jira.rest; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.tasks.CustomTaskState; import com.intellij.tasks.Task; @@ -75,7 +76,13 @@ protected JiraRestApi(@NotNull JiraRepository repository) { } protected @NotNull GetMethod getMultipleIssuesSearchMethod(String jql, int max) { - GetMethod method = new GetMethod(myRepository.getRestUrl("search")); + GetMethod method; + if (Registry.is("tasks.use.search.jql.api", true)) { + method = new GetMethod(myRepository.getRestUrl("search/jql")); + } + else { + method = new GetMethod(myRepository.getRestUrl("search")); + } method.setQueryString(new NameValuePair[]{ new NameValuePair("jql", jql), new NameValuePair("maxResults", String.valueOf(max)) diff --git a/plugins/tasks/tasks-core/resources/META-INF/plugin.xml b/plugins/tasks/tasks-core/resources/META-INF/plugin.xml index b62abc60f38ce..7c7b8c0abf9bf 100644 --- a/plugins/tasks/tasks-core/resources/META-INF/plugin.xml +++ b/plugins/tasks/tasks-core/resources/META-INF/plugin.xml @@ -154,5 +154,8 @@ + + From e7219c86b9fe383dfc64d82de639b7e83b8be24f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Dec 2025 16:45:25 +0000 Subject: [PATCH 12/14] Initial plan From f4485ec384c178b874e7844dcda4158297ffe118 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Dec 2025 16:55:29 +0000 Subject: [PATCH 13/14] Add interactive build script for KorGE Forge Co-authored-by: FSaurenbach <87531743+FSaurenbach@users.noreply.github.com> --- HOW-TO-BUILD.md | 18 ++- build_forge_interactive.sh | 221 +++++++++++++++++++++++++++++++++++++ 2 files changed, 237 insertions(+), 2 deletions(-) create mode 100755 build_forge_interactive.sh diff --git a/HOW-TO-BUILD.md b/HOW-TO-BUILD.md index 3f1edad75173c..2b65bd68915c7 100644 --- a/HOW-TO-BUILD.md +++ b/HOW-TO-BUILD.md @@ -1,4 +1,18 @@ # How to build KorGE Forge? + +## Quick Build 1. Clone korge-forge plugin: git clone https://github.com/korlibs/korge-forge-plugin.git -2. ./gradlew doForgeRelease in korge-forge-plugin -3. Execute ./build_forge.sh \ No newline at end of file +2. Run `./gradlew doForgeRelease` in korge-forge-plugin +3. Execute `./build_forge.sh` + +## Interactive Build (Recommended) +For a more user-friendly experience with platform selection and build options: +```bash +./build_forge_interactive.sh +``` + +This interactive script provides: +- Automatic Java detection +- Platform selection (current platform or all platforms) +- Incremental build option +- Colored output for better visibility \ No newline at end of file diff --git a/build_forge_interactive.sh b/build_forge_interactive.sh new file mode 100755 index 0000000000000..36c9e28ab66fb --- /dev/null +++ b/build_forge_interactive.sh @@ -0,0 +1,221 @@ +#!/usr/bin/env bash +# +# KorGE Forge Interactive Build Script +# This script provides an interactive menu to build KorGE Forge +# + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +BOLD='\033[1m' +NC='\033[0m' # No Color + +# Default values +BUILD_PLATFORM="current" +JAVA_HOME_PATH="" +INCREMENTAL_BUILD="false" + +# Print colored header +print_header() { + echo -e "${CYAN}" + echo "╔════════════════════════════════════════════════════════════╗" + echo "║ KorGE Forge Interactive Build Script ║" + echo "╚════════════════════════════════════════════════════════════╝" + echo -e "${NC}" +} + +# Print info message +info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +# Print success message +success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +# Print warning message +warn() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +# Print error message +error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Detect Java installation +detect_java() { + info "Detecting Java installation..." + + if [ -n "$JAVA_HOME" ]; then + if [ -x "$JAVA_HOME/bin/java" ]; then + JAVA_VERSION=$("$JAVA_HOME/bin/java" -version 2>&1 | head -n 1 | cut -d'"' -f2) + success "Found Java at JAVA_HOME: $JAVA_HOME (Version: $JAVA_VERSION)" + JAVA_HOME_PATH="$JAVA_HOME" + return 0 + fi + fi + + if command -v java &> /dev/null; then + JAVA_PATH=$(which java) + JAVA_VERSION=$(java -version 2>&1 | head -n 1 | cut -d'"' -f2) + success "Found Java in PATH: $JAVA_PATH (Version: $JAVA_VERSION)" + # Try to determine JAVA_HOME from java path + JAVA_REAL_PATH=$(readlink -f "$JAVA_PATH" 2>/dev/null || echo "$JAVA_PATH") + JAVA_BIN_DIR=$(dirname "$JAVA_REAL_PATH") + JAVA_HOME_PATH=$(dirname "$JAVA_BIN_DIR") + return 0 + fi + + error "Java not found. Please install JDK 21 or set JAVA_HOME." + return 1 +} + +# Platform selection menu +select_platform() { + echo -e "\n${BOLD}Select Build Platform:${NC}" + echo " 1) Current platform only (faster)" + echo " 2) All platforms (Windows, macOS, Linux)" + echo "" + + while true; do + read -p "Enter choice [1-2]: " choice + case $choice in + 1) + BUILD_PLATFORM="current" + info "Selected: Build for current platform only" + break + ;; + 2) + BUILD_PLATFORM="all" + info "Selected: Build for all platforms" + break + ;; + *) + warn "Invalid choice. Please enter 1 or 2." + ;; + esac + done +} + +# Incremental build option +select_incremental() { + echo -e "\n${BOLD}Incremental Build:${NC}" + echo " 1) Full build (clean)" + echo " 2) Incremental build (faster, may have issues)" + echo "" + + while true; do + read -p "Enter choice [1-2]: " choice + case $choice in + 1) + INCREMENTAL_BUILD="false" + info "Selected: Full build" + break + ;; + 2) + INCREMENTAL_BUILD="true" + info "Selected: Incremental build" + break + ;; + *) + warn "Invalid choice. Please enter 1 or 2." + ;; + esac + done +} + +# Confirmation prompt +confirm_build() { + echo -e "\n${BOLD}Build Configuration Summary:${NC}" + echo " • Platform: $BUILD_PLATFORM" + echo " • Incremental: $INCREMENTAL_BUILD" + echo " • Java Home: $JAVA_HOME_PATH" + echo "" + + while true; do + read -p "Proceed with build? [y/n]: " yn + case $yn in + [Yy]* ) + return 0 + ;; + [Nn]* ) + info "Build cancelled by user." + exit 0 + ;; + * ) + warn "Please answer y or n." + ;; + esac + done +} + +# Run the build +run_build() { + echo -e "\n${CYAN}═══════════════════════════════════════════════════════════════${NC}" + info "Starting KorGE Forge build..." + echo -e "${CYAN}═══════════════════════════════════════════════════════════════${NC}\n" + + # Set JAVA_HOME + export JAVA_HOME="$JAVA_HOME_PATH" + export PATH="$JAVA_HOME/bin:$PATH" + + # Build arguments + BUILD_ARGS="" + + if [ "$BUILD_PLATFORM" = "current" ]; then + BUILD_ARGS="$BUILD_ARGS -Dintellij.build.target.os=current" + fi + + if [ "$INCREMENTAL_BUILD" = "true" ]; then + BUILD_ARGS="$BUILD_ARGS -Dintellij.build.incremental.compilation=true" + fi + + info "Running: ./installers.cmd $BUILD_ARGS" + echo "" + + # Run the build (using eval to properly handle empty BUILD_ARGS) + if [ -n "$BUILD_ARGS" ]; then + eval "./installers.cmd $BUILD_ARGS" + else + ./installers.cmd + fi + + echo "" + success "Build completed!" + echo -e "\n${GREEN}Find the built KorGE Forge in out/korgeforge/artifacts/${NC}" + echo -e "${GREEN}Extract and run with ./korge.sh in bin/${NC}\n" +} + +# Main function +main() { + print_header + + # Check we're in the right directory + if [ ! -f "installers.cmd" ]; then + error "This script must be run from the korge-forge root directory." + exit 1 + fi + + # Detect Java + if ! detect_java; then + exit 1 + fi + + # Interactive menu + select_platform + select_incremental + + # Confirm and build + confirm_build + run_build +} + +# Run main +main "$@" From b721b2f4a9d777b84ce0b1f20cc8a49a670790f9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Dec 2025 17:02:16 +0000 Subject: [PATCH 14/14] Merge interactive features into build_forge.sh and remove separate script Co-authored-by: FSaurenbach <87531743+FSaurenbach@users.noreply.github.com> --- HOW-TO-BUILD.md | 9 +- build_forge.sh | 236 ++++++++++++++++++++++++++++++++++--- build_forge_interactive.sh | 221 ---------------------------------- 3 files changed, 221 insertions(+), 245 deletions(-) delete mode 100755 build_forge_interactive.sh diff --git a/HOW-TO-BUILD.md b/HOW-TO-BUILD.md index 2b65bd68915c7..4c79238327a57 100644 --- a/HOW-TO-BUILD.md +++ b/HOW-TO-BUILD.md @@ -1,17 +1,10 @@ # How to build KorGE Forge? -## Quick Build 1. Clone korge-forge plugin: git clone https://github.com/korlibs/korge-forge-plugin.git 2. Run `./gradlew doForgeRelease` in korge-forge-plugin 3. Execute `./build_forge.sh` -## Interactive Build (Recommended) -For a more user-friendly experience with platform selection and build options: -```bash -./build_forge_interactive.sh -``` - -This interactive script provides: +The build script provides an interactive interface with: - Automatic Java detection - Platform selection (current platform or all platforms) - Incremental build option diff --git a/build_forge.sh b/build_forge.sh index e5ebb5b43811a..c1d27e782a5c8 100755 --- a/build_forge.sh +++ b/build_forge.sh @@ -1,18 +1,222 @@ #!/usr/bin/env bash +# +# KorGE Forge Interactive Build Script +# This script provides an interactive menu to build KorGE Forge +# + set -e -export JAVA_HOME=/home/sauron/.jdks/jbr-21.0.8 -export PATH=$JAVA_HOME/bin:$PATH -BUILD_ONLY_CURRENT_PLATFORM=true - -echo 'Starting KorGE Forge build script!' - -if [ "$BUILD_ONLY_CURRENT_PLATFORM" = "true" ]; then - echo 'Starting building for current platform...' - ./installers.cmd -Dintellij.build.target.os=current -else - echo 'Starting building for all platforms...' - ./installers.cmd -fi - -echo 'Find the built KorGE Forge in out/korgeforge/artifacts/ and extract it' -echo 'Run with ./korge.sh in bin/' + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +BOLD='\033[1m' +NC='\033[0m' # No Color + +# Default values +BUILD_PLATFORM="current" +JAVA_HOME_PATH="" +INCREMENTAL_BUILD="false" + +# Print colored header +print_header() { + echo -e "${CYAN}" + echo "╔════════════════════════════════════════════════════════════╗" + echo "║ KorGE Forge Interactive Build Script ║" + echo "╚════════════════════════════════════════════════════════════╝" + echo -e "${NC}" +} + +# Print info message +info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +# Print success message +success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +# Print warning message +warn() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +# Print error message +error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Get Java version from a java binary +get_java_version() { + "$1" -version 2>&1 | head -n 1 | cut -d'"' -f2 +} + +# Detect Java installation +detect_java() { + info "Detecting Java installation..." + + if [ -n "$JAVA_HOME" ]; then + if [ -x "$JAVA_HOME/bin/java" ]; then + JAVA_VERSION=$(get_java_version "$JAVA_HOME/bin/java") + success "Found Java at JAVA_HOME: $JAVA_HOME (Version: $JAVA_VERSION)" + JAVA_HOME_PATH="$JAVA_HOME" + return 0 + fi + fi + + if command -v java &> /dev/null; then + JAVA_PATH=$(which java) + JAVA_VERSION=$(get_java_version java) + success "Found Java in PATH: $JAVA_PATH (Version: $JAVA_VERSION)" + # Try to determine JAVA_HOME from java path + JAVA_REAL_PATH=$(readlink -f "$JAVA_PATH" 2>/dev/null || echo "$JAVA_PATH") + JAVA_BIN_DIR=$(dirname "$JAVA_REAL_PATH") + JAVA_HOME_PATH=$(dirname "$JAVA_BIN_DIR") + return 0 + fi + + error "Java not found. Please install JDK 21 or set JAVA_HOME." + return 1 +} + +# Platform selection menu +select_platform() { + echo -e "\n${BOLD}Select Build Platform:${NC}" + echo " 1) Current platform only (faster)" + echo " 2) All platforms (Windows, macOS, Linux)" + echo "" + + while true; do + read -p "Enter choice [1-2]: " choice + case $choice in + 1) + BUILD_PLATFORM="current" + info "Selected: Build for current platform only" + break + ;; + 2) + BUILD_PLATFORM="all" + info "Selected: Build for all platforms" + break + ;; + *) + warn "Invalid choice. Please enter 1 or 2." + ;; + esac + done +} + +# Incremental build option +select_incremental() { + echo -e "\n${BOLD}Incremental Build:${NC}" + echo " 1) Full build (clean)" + echo " 2) Incremental build (faster, may have issues)" + echo "" + + while true; do + read -p "Enter choice [1-2]: " choice + case $choice in + 1) + INCREMENTAL_BUILD="false" + info "Selected: Full build" + break + ;; + 2) + INCREMENTAL_BUILD="true" + info "Selected: Incremental build" + break + ;; + *) + warn "Invalid choice. Please enter 1 or 2." + ;; + esac + done +} + +# Confirmation prompt +confirm_build() { + echo -e "\n${BOLD}Build Configuration Summary:${NC}" + echo " • Platform: $BUILD_PLATFORM" + echo " • Incremental: $INCREMENTAL_BUILD" + echo " • Java Home: $JAVA_HOME_PATH" + echo "" + + while true; do + read -p "Proceed with build? [y/n]: " yn + case $yn in + [Yy]* ) + return 0 + ;; + [Nn]* ) + info "Build cancelled by user." + exit 0 + ;; + * ) + warn "Please answer y or n." + ;; + esac + done +} + +# Run the build +run_build() { + echo -e "\n${CYAN}═══════════════════════════════════════════════════════════════${NC}" + info "Starting KorGE Forge build..." + echo -e "${CYAN}═══════════════════════════════════════════════════════════════${NC}\n" + + # Set JAVA_HOME + export JAVA_HOME="$JAVA_HOME_PATH" + export PATH="$JAVA_HOME/bin:$PATH" + + # Build arguments as array for safe argument passing + BUILD_ARGS=() + + if [ "$BUILD_PLATFORM" = "current" ]; then + BUILD_ARGS+=("-Dintellij.build.target.os=current") + fi + + if [ "$INCREMENTAL_BUILD" = "true" ]; then + BUILD_ARGS+=("-Dintellij.build.incremental.compilation=true") + fi + + info "Running: ./installers.cmd ${BUILD_ARGS[*]}" + echo "" + + # Run the build with array expansion + ./installers.cmd "${BUILD_ARGS[@]}" + + echo "" + success "Build completed!" + echo -e "\n${GREEN}Find the built KorGE Forge in out/korgeforge/artifacts/${NC}" + echo -e "${GREEN}Extract and run with ./korge.sh in bin/${NC}\n" +} + +# Main function +main() { + print_header + + # Check we're in the right directory + if [ ! -f "installers.cmd" ]; then + error "This script must be run from the korge-forge root directory." + exit 1 + fi + + # Detect Java + if ! detect_java; then + exit 1 + fi + + # Interactive menu + select_platform + select_incremental + + # Confirm and build + confirm_build + run_build +} + +# Run main +main "$@" diff --git a/build_forge_interactive.sh b/build_forge_interactive.sh deleted file mode 100755 index 36c9e28ab66fb..0000000000000 --- a/build_forge_interactive.sh +++ /dev/null @@ -1,221 +0,0 @@ -#!/usr/bin/env bash -# -# KorGE Forge Interactive Build Script -# This script provides an interactive menu to build KorGE Forge -# - -set -e - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -CYAN='\033[0;36m' -BOLD='\033[1m' -NC='\033[0m' # No Color - -# Default values -BUILD_PLATFORM="current" -JAVA_HOME_PATH="" -INCREMENTAL_BUILD="false" - -# Print colored header -print_header() { - echo -e "${CYAN}" - echo "╔════════════════════════════════════════════════════════════╗" - echo "║ KorGE Forge Interactive Build Script ║" - echo "╚════════════════════════════════════════════════════════════╝" - echo -e "${NC}" -} - -# Print info message -info() { - echo -e "${BLUE}[INFO]${NC} $1" -} - -# Print success message -success() { - echo -e "${GREEN}[SUCCESS]${NC} $1" -} - -# Print warning message -warn() { - echo -e "${YELLOW}[WARNING]${NC} $1" -} - -# Print error message -error() { - echo -e "${RED}[ERROR]${NC} $1" -} - -# Detect Java installation -detect_java() { - info "Detecting Java installation..." - - if [ -n "$JAVA_HOME" ]; then - if [ -x "$JAVA_HOME/bin/java" ]; then - JAVA_VERSION=$("$JAVA_HOME/bin/java" -version 2>&1 | head -n 1 | cut -d'"' -f2) - success "Found Java at JAVA_HOME: $JAVA_HOME (Version: $JAVA_VERSION)" - JAVA_HOME_PATH="$JAVA_HOME" - return 0 - fi - fi - - if command -v java &> /dev/null; then - JAVA_PATH=$(which java) - JAVA_VERSION=$(java -version 2>&1 | head -n 1 | cut -d'"' -f2) - success "Found Java in PATH: $JAVA_PATH (Version: $JAVA_VERSION)" - # Try to determine JAVA_HOME from java path - JAVA_REAL_PATH=$(readlink -f "$JAVA_PATH" 2>/dev/null || echo "$JAVA_PATH") - JAVA_BIN_DIR=$(dirname "$JAVA_REAL_PATH") - JAVA_HOME_PATH=$(dirname "$JAVA_BIN_DIR") - return 0 - fi - - error "Java not found. Please install JDK 21 or set JAVA_HOME." - return 1 -} - -# Platform selection menu -select_platform() { - echo -e "\n${BOLD}Select Build Platform:${NC}" - echo " 1) Current platform only (faster)" - echo " 2) All platforms (Windows, macOS, Linux)" - echo "" - - while true; do - read -p "Enter choice [1-2]: " choice - case $choice in - 1) - BUILD_PLATFORM="current" - info "Selected: Build for current platform only" - break - ;; - 2) - BUILD_PLATFORM="all" - info "Selected: Build for all platforms" - break - ;; - *) - warn "Invalid choice. Please enter 1 or 2." - ;; - esac - done -} - -# Incremental build option -select_incremental() { - echo -e "\n${BOLD}Incremental Build:${NC}" - echo " 1) Full build (clean)" - echo " 2) Incremental build (faster, may have issues)" - echo "" - - while true; do - read -p "Enter choice [1-2]: " choice - case $choice in - 1) - INCREMENTAL_BUILD="false" - info "Selected: Full build" - break - ;; - 2) - INCREMENTAL_BUILD="true" - info "Selected: Incremental build" - break - ;; - *) - warn "Invalid choice. Please enter 1 or 2." - ;; - esac - done -} - -# Confirmation prompt -confirm_build() { - echo -e "\n${BOLD}Build Configuration Summary:${NC}" - echo " • Platform: $BUILD_PLATFORM" - echo " • Incremental: $INCREMENTAL_BUILD" - echo " • Java Home: $JAVA_HOME_PATH" - echo "" - - while true; do - read -p "Proceed with build? [y/n]: " yn - case $yn in - [Yy]* ) - return 0 - ;; - [Nn]* ) - info "Build cancelled by user." - exit 0 - ;; - * ) - warn "Please answer y or n." - ;; - esac - done -} - -# Run the build -run_build() { - echo -e "\n${CYAN}═══════════════════════════════════════════════════════════════${NC}" - info "Starting KorGE Forge build..." - echo -e "${CYAN}═══════════════════════════════════════════════════════════════${NC}\n" - - # Set JAVA_HOME - export JAVA_HOME="$JAVA_HOME_PATH" - export PATH="$JAVA_HOME/bin:$PATH" - - # Build arguments - BUILD_ARGS="" - - if [ "$BUILD_PLATFORM" = "current" ]; then - BUILD_ARGS="$BUILD_ARGS -Dintellij.build.target.os=current" - fi - - if [ "$INCREMENTAL_BUILD" = "true" ]; then - BUILD_ARGS="$BUILD_ARGS -Dintellij.build.incremental.compilation=true" - fi - - info "Running: ./installers.cmd $BUILD_ARGS" - echo "" - - # Run the build (using eval to properly handle empty BUILD_ARGS) - if [ -n "$BUILD_ARGS" ]; then - eval "./installers.cmd $BUILD_ARGS" - else - ./installers.cmd - fi - - echo "" - success "Build completed!" - echo -e "\n${GREEN}Find the built KorGE Forge in out/korgeforge/artifacts/${NC}" - echo -e "${GREEN}Extract and run with ./korge.sh in bin/${NC}\n" -} - -# Main function -main() { - print_header - - # Check we're in the right directory - if [ ! -f "installers.cmd" ]; then - error "This script must be run from the korge-forge root directory." - exit 1 - fi - - # Detect Java - if ! detect_java; then - exit 1 - fi - - # Interactive menu - select_platform - select_incremental - - # Confirm and build - confirm_build - run_build -} - -# Run main -main "$@"