extend CommandLineInspectionProjectConfigurator API to pass more options into extensions

GitOrigin-RevId: 04db41ad3e5bdce2c2504b6bb5fdc129ead1297a
This commit is contained in:
Eugene Petrenko
2020-05-13 13:11:20 +02:00
committed by intellij-monorepo-bot
parent a4b7bcacc1
commit 86618d10a8
5 changed files with 134 additions and 75 deletions

View File

@@ -1,6 +1,7 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.codeInspection;
import com.google.common.base.Predicates;
import com.google.common.collect.Lists;
import com.intellij.analysis.AnalysisScope;
import com.intellij.codeInspection.ex.*;
@@ -62,6 +63,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.LockSupport;
import java.util.function.Predicate;
@SuppressWarnings("UseOfSystemOutOrSystemErr")
public final class InspectionApplication implements CommandLineInspectionProgressReporter {
@@ -138,6 +140,41 @@ public final class InspectionApplication implements CommandLineInspectionProgres
myHelpProvider.printHelpAndExit();
}
@NotNull
private CommandLineInspectionProjectConfigurator.ConfiguratorContext configuratorContext(@NotNull Path projectPath, @Nullable AnalysisScope scope) {
return new CommandLineInspectionProjectConfigurator.ConfiguratorContext() {
@Override
public @NotNull ProgressIndicator getProgressIndicator() {
return new ProgressIndicatorBase();
}
@Override
public @Nullable AnalysisScope getAnalyzerScope() {
return scope;
}
@Override
public @NotNull CommandLineInspectionProgressReporter getLogger() {
return InspectionApplication.this;
}
@Override
public @NotNull Path getProjectPath() {
return projectPath;
}
@Override
public @NotNull Predicate<Path> getFilesFilter() {
return Predicates.alwaysTrue();
}
@Override
public @NotNull Predicate<VirtualFile> getVirtualFilesFilter() {
return Predicates.alwaysTrue();
}
};
}
private void run(@NotNull Path projectPath, @NotNull Disposable parentDisposable) throws IOException, JDOMException {
VirtualFile vfsProject = LocalFileSystem.getInstance().findFileByPath(FileUtil.toSystemIndependentName(projectPath.toString()));
if (vfsProject == null) {
@@ -152,8 +189,9 @@ public final class InspectionApplication implements CommandLineInspectionProgres
}
for (CommandLineInspectionProjectConfigurator configurator : CommandLineInspectionProjectConfigurator.EP_NAME.getExtensionList()) {
if (configurator.isApplicable(projectPath, this)) {
configurator.configureEnvironment(projectPath, this);
CommandLineInspectionProjectConfigurator.ConfiguratorContext context = configuratorContext(projectPath, null);
if (configurator.isApplicable(context)) {
configurator.configureEnvironment(context);
}
}
@@ -275,8 +313,9 @@ public final class InspectionApplication implements CommandLineInspectionProgres
private void configureProject(@NotNull Path projectPath, @NotNull Project project, @NotNull AnalysisScope scope) {
for (CommandLineInspectionProjectConfigurator configurator : CommandLineInspectionProjectConfigurator.EP_NAME.getIterable()) {
if (configurator.isApplicable(projectPath, this)) {
configurator.configureProject(project, scope, this);
CommandLineInspectionProjectConfigurator.ConfiguratorContext context = configuratorContext(projectPath, scope);
if (configurator.isApplicable(context)) {
configurator.configureProject(project, context);
}
}
}

View File

@@ -1,15 +1,12 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.openapi.projectRoots.impl
import com.intellij.ide.CommandLineInspectionProgressReporter
import com.intellij.ide.CommandLineInspectionProjectConfigurator
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.invokeAndWaitIfNeeded
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.progress.util.ProgressIndicatorBase
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ui.configuration.UnknownSdk
import com.intellij.openapi.roots.ui.configuration.UnknownSdkResolver
@@ -17,33 +14,23 @@ import com.intellij.openapi.util.registry.Registry
import com.intellij.util.Consumer
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.suspendCancellableCoroutine
import java.nio.file.Path
import kotlin.coroutines.resume
class UnknownSdkInspectionCommandLineConfigurator : CommandLineInspectionProjectConfigurator {
private val LOG: Logger = logger<UnknownSdkInspectionCommandLineConfigurator>()
override fun isApplicable(projectPath: Path, logger: CommandLineInspectionProgressReporter): Boolean {
override fun isApplicable(context: CommandLineInspectionProjectConfigurator.ConfiguratorContext): Boolean {
return !ApplicationManager.getApplication().isUnitTestMode
}
override fun configureEnvironment(projectPath: Path, logger: CommandLineInspectionProgressReporter) {
Registry.get("unknown.sdk").setValue(false) //forbid UnknownSdkTracker post startup activity
override fun configureEnvironment(context: CommandLineInspectionProjectConfigurator.ConfiguratorContext) {
Registry.get("unknown.sdk").setValue(false) // forbid UnknownSdkTracker post startup activity as we run it here
}
override fun configureProject(project: Project,
logger: CommandLineInspectionProgressReporter
) = runBlocking {
override fun configureProject(project: Project, context: CommandLineInspectionProjectConfigurator.ConfiguratorContext) = runBlocking {
require(!ApplicationManager.getApplication().isWriteThread) { "The code below uses the same GUI thread to complete operations." +
"Running from EDT would deadlock" }
val indicator = ProgressManager.getInstance().progressIndicator ?: ProgressIndicatorBase()
indicator.pushState()
try {
resolveUnknownSdks(project, ProgressIndicatorBase())
} finally {
indicator.popState()
}
resolveUnknownSdks(project, context.progressIndicator)
}
private suspend fun resolveUnknownSdks(project: Project, indicator: ProgressIndicator) {

View File

@@ -2,48 +2,87 @@
package com.intellij.ide;
import com.intellij.analysis.AnalysisScope;
import com.intellij.ide.impl.PatchProjectUtil;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.nio.file.Path;
import java.util.function.Predicate;
/**
* Extension point that helps prepare project for opening in headless or automated environments.
* Implementation must be stateless.
* @author yole
*/
public interface CommandLineInspectionProjectConfigurator {
ExtensionPointName<CommandLineInspectionProjectConfigurator> EP_NAME = ExtensionPointName.create("com.intellij.commandLineInspectionProjectConfigurator");
/**
* Returns true if any additional configuration is required to inspect the project at the given path.
*/
boolean isApplicable(@NotNull Path projectPath, @NotNull CommandLineInspectionProgressReporter logger);
interface ConfiguratorContext {
@NotNull CommandLineInspectionProgressReporter getLogger();
/**
* Invoked before a project is imported.
*/
default void configureEnvironment(@NotNull Path projectPath, @NotNull CommandLineInspectionProgressReporter logger) {
/**
* progress indicator can be used in the actions to report updates or check for cancellation
*/
@NotNull ProgressIndicator getProgressIndicator();
/**
* Project that is about to be open
*/
@NotNull Path getProjectPath();
/**
* Use this filter in the implementation to avoid configuring parts of the project
* that are not intended to be (e.g. testData). It is up to user to provide filters.
*
* @see PatchProjectUtil#patchProject(com.intellij.openapi.project.Project)
*/
@NotNull Predicate<Path> getFilesFilter();
/**
* The same predicate as {@link #getFilesFilter()} but for {@link VirtualFile}
*/
default @NotNull Predicate<VirtualFile> getVirtualFilesFilter() {
Predicate<Path> filesPredicate = getFilesFilter();
return file -> {
Path path = file.getFileSystem().getNioPath(file);
return path != null && filesPredicate.test(path);
};
}
/**
* Allows to grab additional information from the context about the current inspections running,
* if available
*/
@Nullable
default AnalysisScope getAnalyzerScope() {
return null;
}
}
/**
* This method is for {@link #isApplicable(Path, CommandLineInspectionProgressReporter)} inspections
* after project is opened. In addition to the method, you may implement the
* {@link #configureProject(Project, AnalysisScope, CommandLineInspectionProgressReporter)}
* that is executed to prepare inspections run.
*
* @see #configureProject(Project, AnalysisScope, CommandLineInspectionProgressReporter)
* @returns true if any additional configuration is required to inspect the project at the given path.
*/
default void configureProject(@NotNull Project project, @NotNull CommandLineInspectionProgressReporter logger) {
default boolean isApplicable(@NotNull ConfiguratorContext context) {
return true;
}
/**
* Invoked after the project has been imported and before the analysis on the specified scope
* is started.
*
* @see #configureProject(Project, CommandLineInspectionProgressReporter)
* Invoked before a project is imported on the project directory. Only for {@link #isApplicable(ConfiguratorContext)}
* extensions
*/
default void configureProject(@NotNull Project project, @NotNull AnalysisScope scope, @NotNull CommandLineInspectionProgressReporter logger) {
configureProject(project, logger);
default void configureEnvironment(@NotNull ConfiguratorContext context) {
}
/**
* This method is for {@link #isApplicable(ConfiguratorContext)} inspections
* after project is opened.
*/
default void configureProject(@NotNull Project project,
@NotNull ConfiguratorContext context) {
}
}

View File

@@ -1,9 +1,8 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.plugins.gradle
import com.intellij.analysis.AnalysisScope
import com.intellij.ide.CommandLineInspectionProgressReporter
import com.intellij.ide.CommandLineInspectionProjectConfigurator
import com.intellij.ide.CommandLineInspectionProjectConfigurator.ConfiguratorContext
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.externalSystem.importing.ImportSpecBuilder
import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode.MODAL_SYNC
@@ -17,25 +16,16 @@ import org.jetbrains.plugins.gradle.settings.GradleImportHintService
import org.jetbrains.plugins.gradle.settings.GradleSettings
import org.jetbrains.plugins.gradle.util.GradleConstants
import java.io.File
import java.nio.file.Path
class GradleCommandLineProjectConfigurator : CommandLineInspectionProjectConfigurator {
private val LOG = Logger.getInstance(GradleManager::class.java)
private var wasAlreadyImported = false
override fun isApplicable(projectPath: Path, logger: CommandLineInspectionProgressReporter): Boolean {
return true
}
override fun configureEnvironment(projectPath: Path, logger: CommandLineInspectionProgressReporter) {
wasAlreadyImported = projectPath.resolve(".idea").exists()
override fun configureEnvironment(context: ConfiguratorContext) = context.run {
Registry.get("external.system.auto.import.disabled").setValue(true)
}
override fun configureProject(project: Project, logger: CommandLineInspectionProgressReporter) {
override fun configureProject(project: Project, context: ConfiguratorContext) {
val basePath = project.basePath ?: return
val state = GradleImportHintService.getInstance(project).state
if (state.skip) return
@@ -50,6 +40,8 @@ class GradleCommandLineProjectConfigurator : CommandLineInspectionProjectConfigu
}
return
}
val wasAlreadyImported = context.projectPath.resolve(".idea").exists()
if (wasAlreadyImported && !GradleSettings.getInstance(project).linkedProjectsSettings.isEmpty()) {
refreshProjects(ImportSpecBuilder(project, GradleConstants.SYSTEM_ID).use(MODAL_SYNC))
return

View File

@@ -27,16 +27,16 @@ import java.util.List;
public class PythonPluginCommandLineInspectionProjectConfigurator implements CommandLineInspectionProjectConfigurator {
@Override
public boolean isApplicable(@NotNull Path projectPath, @NotNull CommandLineInspectionProgressReporter logger) {
public boolean isApplicable(@NotNull ConfiguratorContext context) {
List<Sdk> sdks = PythonSdkUtil.getAllSdks();
if (!sdks.isEmpty()) return false;
try {
boolean hasAnyPythonFiles = Files.walk(projectPath).anyMatch(f -> {
boolean hasAnyPythonFiles = Files.walk(context.getProjectPath()).anyMatch(f -> {
return f.toString().endsWith(".py");
});
if (!hasAnyPythonFiles) {
logger.reportMessage(3, "Skipping Python interpreter autodetection because the project doesn't contain any Python files");
context.getLogger().reportMessage(3, "Skipping Python interpreter autodetection because the project doesn't contain any Python files");
}
return hasAnyPythonFiles;
@@ -47,7 +47,8 @@ public class PythonPluginCommandLineInspectionProjectConfigurator implements Com
}
@Override
public void configureEnvironment(@NotNull Path projectPath, @NotNull CommandLineInspectionProgressReporter logger) {
public void configureEnvironment(@NotNull ConfiguratorContext context) {
CommandLineInspectionProgressReporter logger = context.getLogger();
logger.reportMessage(3, "Python environment configuration...");
List<Sdk> sdks = PythonSdkUtil.getAllSdks();
logger.reportMessage(3, "Python interpreters detected:");
@@ -55,7 +56,7 @@ public class PythonPluginCommandLineInspectionProjectConfigurator implements Com
logger.reportMessage(3, sdk.getHomePath());
}
if (sdks.isEmpty()) {
final List<Sdk> detectedSdks = PySdkExtKt.findAllPythonSdks(projectPath);
final List<Sdk> detectedSdks = PySdkExtKt.findAllPythonSdks(context.getProjectPath());
if (detectedSdks.size() > 0) {
for (Sdk sdk : detectedSdks) {
@@ -76,21 +77,22 @@ public class PythonPluginCommandLineInspectionProjectConfigurator implements Com
}
@Override
public void configureProject(@NotNull Project project,
@NotNull AnalysisScope scope,
@NotNull CommandLineInspectionProgressReporter logger) {
public void configureProject(@NotNull Project project, @NotNull ConfiguratorContext context) {
List<Sdk> sdks = PythonSdkUtil.getAllSdks();
if (!sdks.isEmpty()) {
PythonFacetType facetType = PythonFacetType.getInstance();
for (VirtualFile f : scope.getFiles()) {
if (FileTypeRegistry.getInstance().isFileOfType(f, PythonFileType.INSTANCE)) {
if (sdks.isEmpty()) return;
Module m = ModuleUtilCore.findModuleForFile(f, project);
if (m != null && FacetManager.getInstance(m).getFacetByType(facetType.getId()) == null) {
WriteAction.runAndWait(() -> {
FacetManager.getInstance(m).addFacet(facetType, facetType.getPresentableName(), null);
});
}
AnalysisScope scope = context.getAnalyzerScope();
if (scope == null) return;
PythonFacetType facetType = PythonFacetType.getInstance();
for (VirtualFile f : scope.getFiles()) {
if (FileTypeRegistry.getInstance().isFileOfType(f, PythonFileType.INSTANCE)) {
Module m = ModuleUtilCore.findModuleForFile(f, project);
if (m != null && FacetManager.getInstance(m).getFacetByType(facetType.getId()) == null) {
WriteAction.runAndWait(() -> {
FacetManager.getInstance(m).addFacet(facetType, facetType.getPresentableName(), null);
});
}
}
}