public static void migratePlugins(Path oldPluginsDir,
                                    Path oldConfigDir,
                                    Path newPluginsDir,
                                    Path newConfigDir,
                                    ConfigImportOptions options,
                                    Predicate<IdeaPluginDescriptor> hasPendingUpdate) throws IOException {
    Logger log = options.log;

    List<IdeaPluginDescriptor> pluginsToMigrate = new ArrayList<>();
    List<IdeaPluginDescriptor> pluginsToDownload = new ArrayList<>();

    try {
      Map<PluginId, Set<String>> brokenPluginVersions = options.brokenPluginVersions;
      PluginLoadingResult result = PluginDescriptorLoader.loadDescriptorsFromOtherIde(
        oldPluginsDir, options.bundledPluginPath, brokenPluginVersions, options.compatibleBuildNumber);

      partitionNonBundled(result.getIdMap().values(), pluginsToDownload, pluginsToMigrate, descriptor -> {
        Set<String> brokenVersions = brokenPluginVersions != null ? brokenPluginVersions.get(descriptor.getPluginId()) : null;
        return brokenVersions != null && brokenVersions.contains(descriptor.getVersion());
      });

      partitionNonBundled(result.getIncompleteIdMap().values(), pluginsToDownload, pluginsToMigrate, __ -> true);
    }
    catch (ExecutionException | InterruptedException e) {
      log.info("Error loading list of plugins from old dir, migrating entire plugin directory");
      FileUtil.copyDir(oldPluginsDir.toFile(), newPluginsDir.toFile());
      return;
    }
    catch (IOException e) {
      log.info("Non-existing plugins directory: " + oldPluginsDir, e);
    }
    Path disabledPluginsFile = oldConfigDir.resolve(DisabledPluginsState.DISABLED_PLUGINS_FILENAME);
    Set<PluginId> disabledPlugins =
      Files.exists(disabledPluginsFile) ? DisabledPluginsState.Companion.loadDisabledPlugins(disabledPluginsFile) : Set.of();
    for (IdeaPluginDescriptor pluginToMigrate : pluginsToMigrate) {
      if (disabledPlugins.contains(pluginToMigrate.getPluginId())) {
        pluginToMigrate.setEnabled(false);
      }
    }
    if (options.importSettings != null) {
      options.importSettings.processPluginsToMigrate(newConfigDir, oldConfigDir, pluginsToMigrate, pluginsToDownload);
    }

    migrateGlobalPlugins(newConfigDir, oldConfigDir, pluginsToMigrate, pluginsToDownload, options.log);

    pluginsToMigrate.removeIf(hasPendingUpdate);
    if (!pluginsToMigrate.isEmpty()) {
      migratePlugins(newPluginsDir, pluginsToMigrate, log);
    }

    pluginsToDownload.removeIf(hasPendingUpdate);
    if (!pluginsToDownload.isEmpty()) {
      downloadUpdatesForIncompatiblePlugins(newPluginsDir, options, pluginsToDownload);

      // migrating plugins for which we weren't able to download updates
      migratePlugins(newPluginsDir, pluginsToDownload, log);
    }
  }
public static void migratePlugins(Path oldPluginsDir,
                                    Path oldConfigDir,
                                    Path newPluginsDir,
                                    Path newConfigDir,
                                    ConfigImportOptions options,
                                    Predicate<IdeaPluginDescriptor> hasPendingUpdate)