diff --git a/HOW-TO-BUILD.md b/HOW-TO-BUILD.md index 3f1edad75173c..4c79238327a57 100644 --- a/HOW-TO-BUILD.md +++ b/HOW-TO-BUILD.md @@ -1,4 +1,11 @@ # How to build KorGE Forge? + 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` + +The build script provides an interactive interface with: +- 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/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", 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/community-resources/resources/idea/IdeaApplicationInfo.xml b/community-resources/resources/idea/IdeaApplicationInfo.xml index 51acf28f784f1..99e69f9022638 100644 --- a/community-resources/resources/idea/IdeaApplicationInfo.xml +++ b/community-resources/resources/idea/IdeaApplicationInfo.xml @@ -1,5 +1,5 @@ - + @@ -7,6 +7,7 @@ + com.intellij.java com.intellij.java.ide com.intellij.modules.json diff --git a/korge-forge-plugin b/korge-forge-plugin index 1d79667236ed7..0dd87965dcffb 160000 --- a/korge-forge-plugin +++ b/korge-forge-plugin @@ -1 +1 @@ -Subproject commit 1d79667236ed7d32bd2170d07b910b33baa0c0e7 +Subproject commit 0dd87965dcffb58d7f3000da39850934bfc3e7fb 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) } 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 @@ + + 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) 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 @@ - + 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 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; }