Skip to content

#1548: avoid Windows plugin locks during IDE updates - #2363

Open
cap-juan wants to merge 1 commit into
devonfw:mainfrom
cap-juan:feature/1548-windows-fail-when-plugin-update
Open

#1548: avoid Windows plugin locks during IDE updates#2363
cap-juan wants to merge 1 commit into
devonfw:mainfrom
cap-juan:feature/1548-windows-fail-when-plugin-update

Conversation

@cap-juan

@cap-juan cap-juan commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

This PR fixes #1548

Implemented changes:

This PR changes plugin handling so that IDE updates on Windows no longer fail when the currently running IDE keeps files from an old plugin installation locked.

Previously, plugins were installed into one shared directory per IDE, for example:
plugins/intellij/

During an IntelliJ update, IDEasy reset this directory before installing plugins for the new IDE version. On Windows, this could fail when the currently running IntelliJ instance still had plugin files open, for example native files belonging to plugins such as GitHub Copilot.

Plugins are now stored per IDE version:

plugins/intellij/
├── 2026.1.4/
└── 2026.2/

This allows the new IDE version and its plugins to be installed independently from the plugin directory still used by the running old IDE.

Plugin directory handling

PluginBasedCommandlet now resolves the plugin installation path using the installed IDE version: plugins/<tool>/<version>

For example:

plugins/intellij/2026.2
plugins/pycharm/2026.2
plugins/android-studio/2024.1.1.1
plugins/eclipse/2024-09

Plugin marker files also contain the IDE version so plugin state is tracked independently for each installed IDE version. After plugins for the new IDE version have been installed, IDEasy tries to remove obsolete version directories (this cleanup is best-effort only).

If Windows prevents deletion because the old IDE still holds files open, IDEasy logs a warning such as:

Could not delete obsolete plugin directory ...\plugins\intellij\2026.1.4.
It may still be in use and will be cleaned up later.

The IDE update itself continues successfully. Once the old IDE is closed, a later install/update can remove the obsolete plugin directory.

JetBrains IDE plugin loading:

IntelliJ-based IDEs are configured to use the version-specific plugin path through:
-Didea.plugins.path=<IDE_HOME>/plugins/<tool>/<version>

The generated VM options therefore point each IDE version to its corresponding plugin directory. Example:
-Didea.plugins.path=C:\Users\...\IDEasy\plugins\intellij\2026.2

This applies to IntelliJ IDEA, PyCharm and Android Studio.

JetBrains Marketplace plugin installation:

Marketplace plugins are now downloaded directly instead of invoking the IDE's installPlugins command.

This is important because invoking IntelliJ while another IntelliJ instance is already running can fail with the single-instance restriction and therefore still prevent plugin installation during an IDE update.

Plugin archives are installed according to their archive type:

ZIP plugins are extracted directly into the version-specific plugin directory so their own directory structure is preserved. For example a Marketplace archive containing:

plantuml4idea/
└── lib/
    └── ...

becomes:

plugins/intellij/2026.2/
└── plantuml4idea/
    └── lib/
        └── ...

JAR plugins are extracted into a directory named after the plugin ID. This distinction is necessary because standalone plugin JARs do not necessarily contain their own surrounding plugin directory. Custom plugin repository URLs continue to use the existing IDE command-based installation mechanism.

Other IDEs:

VS Code now also uses the version-specific plugin directory through its --extensions-dir argument.

Eclipse configuration paths are based on the version-specific plugin installation directory, for example:
plugins/eclipse/2024-09/configuration

Tests were updated accordingly.


Testing instructions

Please add concise, understandable instructions on how a reviewer can test/verify the functionality of your contribution here:

The issue was reproduced using IntelliJ IDEA on Windows.

  1. Configure an older IntelliJ version, for example: INTELLIJ_VERSION=2026.1.4

  2. Install IntelliJ: ide install intellij

  3. Verify that the configured plugin is installed under the version-specific directory: ls -la "$IDE_HOME/plugins/intellij"

Expected: 2026.1.4

  1. Start IntelliJ: ide intellij

  2. Keep the old IntelliJ instance running.

  3. Change the configured IntelliJ version to a newer supported version, for example: INTELLIJ_VERSION=2026.2

  4. While the old IntelliJ instance is still running, execute: ide update

  5. Verify that:

IntelliJ 2026.2 is installed successfully.
Plugins for 2026.2 are installed into: plugins/intellij/2026.2
the running IntelliJ instance may keep the old plugin directory locked;
IDEasy only logs a warning when deletion of the old directory fails;
the overall ide update still completes successfully.

Example warning:

Could not delete obsolete plugin directory ...\plugins\intellij\2026.1.4.
It may still be in use and will be cleaned up later.
  1. Close the old IntelliJ instance and start the new one: ide intellij

  2. Verify:

Help -> About shows the new IntelliJ version.
the configured plugin is available under Settings -> Plugins -> Installed.
the generated VM options contain the new version-specific plugin path.

Example:
-Didea.plugins.path=...\plugins\intellij\2026.2

  1. Close IntelliJ and run another update: ide update

  2. Verify that the obsolete plugin directory can now be removed and only the current plugin directory remains: ls -la "$IDE_HOME/plugins/intellij"

Expected: 2026.2


Checklist for this PR

Make sure everything is checked before merging this PR. For further info please also see
our DoD.

  • When running mvn clean test locally all tests pass and build is successful
  • PR title is of the form #«issue-id»: «brief summary» (e.g. #921: fixed setup.bat and not feature/921 fixed setup.bat). If no issue ID exists, title only.
  • PR top-level comment summaries what has been done and contains link to addressed issue(s)
  • PR and issue(s) have suitable labels
  • Issue is set to In Progress and assigned to you or there is no issue (might happen for very small PRs)
  • You followed all coding conventions
  • You have added the issue implemented by your PR in CHANGELOG.adoc unless issue is labelled
    with internal
  • You have not changed any dependency in pom.xml files or otherwise if runtime dependencies changed, you have updated our LICENSE.asciidoc
  • You have formulated clear instructions on how to test your contribution under "Testing instructions"

Checklist for tool commandlets

Have you added a new «tool» as commandlet? There are the following additional checks:

  • The tool can be installed automatically (during setup via settings) or via the commandlet call
  • The tool is isolated in its IDEasy project, see Sandbox Principle
  • The new tool is added to the table of tools in LICENSE.asciidoc
  • The new commandlet is a command-wrapper for «tool»
  • Proper help texts for all supported languages are added here
  • The new commandlet installs potential dependencies automatically
  • The variables «TOOL»_VERSION and «TOOL»_EDITION are honored by your commandlet
  • The new commandlet is tested on all platforms it is available for or tested on all platforms that are in scope of the linked issue

@github-project-automation github-project-automation Bot moved this to 🆕 New in IDEasy board Aug 24, 2026
@cap-juan
cap-juan force-pushed the feature/1548-windows-fail-when-plugin-update branch from e9f3936 to 169e2f7 Compare August 24, 2026 12:49
@cap-juan cap-juan assigned cap-juan and unassigned cap-juan Aug 24, 2026
@cap-juan cap-juan added update related to updating software or the entire ide windows specific for Microsoft Windows OS plugins related to plugins (for Eclipse, Intellij, VSCode, etc.) labels Aug 24, 2026
@coveralls

coveralls commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator

Coverage Report for CI Build 33384691425

Coverage decreased (-0.03%) to 73.597%

Details

  • Coverage decreased (-0.03%) from the base build.
  • Patch coverage: No coverable lines changed in this PR.
  • 63 coverage regressions across 5 files.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

63 previously-covered lines in 5 files lost coverage.

File Lines Losing Coverage Coverage
com/devonfw/tools/ide/tool/ide/IdeaPluginDownloader.java 32 58.33%
com/devonfw/tools/ide/tool/plugin/PluginBasedCommandlet.java 17 88.45%
com/devonfw/tools/ide/tool/ide/IdeaBasedIdeToolCommandlet.java 12 81.94%
com/devonfw/tools/ide/io/FileAccessImpl.java 1 70.08%
com/devonfw/tools/ide/version/VersionSegment.java 1 91.08%

Coverage Stats

Coverage Status
Relevant Lines: 18465
Covered Lines: 14211
Line Coverage: 76.96%
Relevant Branches: 8195
Covered Branches: 5410
Branch Coverage: 66.02%
Branches in Coverage %: Yes
Coverage Strength: 3.28 hits per line

💛 - Coveralls

@cap-juan cap-juan moved this from 🆕 New to 🏗 In progress in IDEasy board Aug 24, 2026
@hohwille hohwille moved this from 🏗 In progress to Team Review in IDEasy board Aug 25, 2026
@hohwille hohwille moved this from Team Review to 🏗 In progress in IDEasy board Aug 25, 2026
@cap-juan
cap-juan force-pushed the feature/1548-windows-fail-when-plugin-update branch from 169e2f7 to 74f0388 Compare August 27, 2026 07:34
@cap-juan cap-juan moved this from 🏗 In progress to Team Review in IDEasy board Aug 27, 2026

@laert-ll laert-ll left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work! The approach matches what was suggested in the issue, and I like that you updated all the places that use the plugin folder (Eclipse config, VS Code extensions dir, JetBrains VM options). The -Didea.plugins.path bit fits well into the existing VM args merging, and the testing steps in the description are really clear, thank you for that! I left some comments for some concerns I had, but otherwise LGTM :)

Comment on lines +48 to +53
public boolean installPlugin(ToolPluginDescriptor plugin, Step step, ProcessContext pc) {

if (plugin.url() == null) {
IdeaPluginDownloader pluginDownloader = new IdeaPluginDownloader(this.context, this);
return pluginDownloader.installPlugin(plugin, step, pc);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Marketplace plugins no longer go through the IDE's installPlugins, so I'm concerned that problems might come up if there's plugins with dependencies, this might need to be tested further imo.

Comment thread CHANGELOG.adoc

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget to rebase and bump this up to the latest release.

if (fileName.endsWith(".zip")) {
// Marketplace ZIP already contains the actual plugin root folder,
// e.g. plantuml4idea/lib/...
fileAccess.extractZip(downloadedFile, installationPath);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unzipping directly means the folder gets its name from the archive instead of the plugin ID. uninstallPlugin searches by plugin ID, so there could potentially be a problem with finding the plugins when trying to uninstall them. A test for uninstall might be useful in this case to make sure.

return "";
}

return switch (contentType.get()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only accepts the exact strings application/zip and application/java-archive and anything else returns "" and the install fails with "Unknown file type" at line 153. Something like application/zip;charset=utf-8 or application/octet-stream would break it. This was for Android Studio only before, now it affects JetBrains plugins, thus could we instead match on the prefix and fall back to the filename?

LOG.debug("Omitting installation of inactive plugin {} ({}).", plugin.name(), plugin.id());
}

private void cleanupOldPluginVersions(VersionIdentifier currentVersion) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We delete the old version folder here, but not its marker files in .ide/, so those pile up with every update. Could we delete the matching markers here too?

Related: --force-plugin-reinstall now only resets the current version's markers, so the "Resetting all installed plugins..." message at line 152 isn't quite accurate anymore.

@cap-juan
cap-juan force-pushed the feature/1548-windows-fail-when-plugin-update branch from 74f0388 to ab69d8e Compare August 31, 2026 10:54
@cap-juan
cap-juan force-pushed the feature/1548-windows-fail-when-plugin-update branch from ab69d8e to 1cc23e9 Compare August 31, 2026 10:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

plugins related to plugins (for Eclipse, Intellij, VSCode, etc.) update related to updating software or the entire ide windows specific for Microsoft Windows OS

Projects

Status: Team Review

Development

Successfully merging this pull request may close these issues.

Windows file locking error on update with plugins

4 participants