[maven] IDEA-336904 archetype module, fix Slow operations on EDT

GitOrigin-RevId: 85ba9c21f09491c688999f0cbb7518b02084bd2e
This commit is contained in:
Dmitry Kichinsky
2023-11-01 22:17:47 +00:00
committed by intellij-monorepo-bot
parent 71cdc9a13d
commit 93eec7cce1
2 changed files with 162 additions and 194 deletions
@@ -45,7 +45,8 @@ class MavenKotlinModuleBuilderHelper(
override fun configure(project: Project, root: VirtualFile, isInteractive: Boolean) {
val psiFiles = if (myAggregatorProject != null) arrayOf(getPsiFile(project, myAggregatorProject.file)) else PsiFile.EMPTY_ARRAY
val aggregatorProject = myAggregatorProject
val psiFiles = if (aggregatorProject != null) arrayOf(getPsiFile(project, aggregatorProject.file)) else PsiFile.EMPTY_ARRAY
val pom =
WriteCommandAction.writeCommandAction(project, *psiFiles).withName(myCommandName).compute<VirtualFile?, RuntimeException> {
@@ -1,268 +1,235 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.idea.maven.wizards;
package org.jetbrains.idea.maven.wizards
import com.intellij.ide.util.EditorHelper;
import com.intellij.openapi.GitSilentFileAdder;
import com.intellij.openapi.GitSilentFileAdderProvider;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.NlsContexts;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.xml.XmlElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.VisibleForTesting;
import org.jetbrains.idea.maven.dom.MavenDomUtil;
import org.jetbrains.idea.maven.dom.model.MavenDomModule;
import org.jetbrains.idea.maven.dom.model.MavenDomProjectModel;
import org.jetbrains.idea.maven.execution.MavenRunner;
import org.jetbrains.idea.maven.execution.MavenRunnerParameters;
import org.jetbrains.idea.maven.execution.MavenRunnerSettings;
import org.jetbrains.idea.maven.model.MavenArchetype;
import org.jetbrains.idea.maven.model.MavenConstants;
import org.jetbrains.idea.maven.model.MavenId;
import org.jetbrains.idea.maven.project.MavenProject;
import org.jetbrains.idea.maven.project.MavenProjectBundle;
import org.jetbrains.idea.maven.project.MavenProjectsManager;
import org.jetbrains.idea.maven.statistics.MavenActionsUsagesCollector;
import org.jetbrains.idea.maven.utils.MavenLog;
import org.jetbrains.idea.maven.utils.MavenUtil;
import com.intellij.ide.util.EditorHelper
import com.intellij.openapi.GitSilentFileAdderProvider
import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.command.WriteCommandAction
import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.NlsContexts
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VfsUtil
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiManager
import com.intellij.psi.codeStyle.CodeStyleManager
import org.jetbrains.annotations.VisibleForTesting
import org.jetbrains.idea.maven.dom.MavenDomUtil
import org.jetbrains.idea.maven.execution.MavenRunner
import org.jetbrains.idea.maven.execution.MavenRunnerParameters
import org.jetbrains.idea.maven.model.MavenArchetype
import org.jetbrains.idea.maven.model.MavenConstants
import org.jetbrains.idea.maven.model.MavenId
import org.jetbrains.idea.maven.project.MavenProject
import org.jetbrains.idea.maven.project.MavenProjectBundle
import org.jetbrains.idea.maven.project.MavenProjectsManager
import org.jetbrains.idea.maven.statistics.MavenActionsUsagesCollector
import org.jetbrains.idea.maven.statistics.MavenActionsUsagesCollector.Companion.trigger
import org.jetbrains.idea.maven.utils.MavenLog
import org.jetbrains.idea.maven.utils.MavenUtil
import java.io.File
import java.io.IOException
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
open class MavenModuleBuilderHelper(protected val myProjectId: MavenId,
protected val myAggregatorProject: MavenProject?,
private val myParentProject: MavenProject?,
private val myInheritGroupId: Boolean,
private val myInheritVersion: Boolean,
private val myArchetype: MavenArchetype?,
private val myPropertiesToCreateByArtifact: Map<String, String>?,
protected val myCommandName: @NlsContexts.Command String?) {
open fun configure(project: Project, root: VirtualFile, isInteractive: Boolean) {
trigger(project, MavenActionsUsagesCollector.CREATE_MAVEN_PROJECT)
public class MavenModuleBuilderHelper {
protected final MavenId myProjectId;
protected final MavenProject myAggregatorProject;
private final MavenProject myParentProject;
private final boolean myInheritGroupId;
private final boolean myInheritVersion;
private final MavenArchetype myArchetype;
private final Map<String, String> myPropertiesToCreateByArtifact;
@NlsContexts.Command protected final String myCommandName;
public MavenModuleBuilderHelper(@NotNull MavenId projectId,
MavenProject aggregatorProject,
MavenProject parentProject,
boolean inheritGroupId,
boolean inheritVersion,
MavenArchetype archetype,
Map<String, String> propertiesToCreateByArtifact,
@NlsContexts.Command String commandName) {
myProjectId = projectId;
myAggregatorProject = aggregatorProject;
myParentProject = parentProject;
myInheritGroupId = inheritGroupId;
myInheritVersion = inheritVersion;
myArchetype = archetype;
myPropertiesToCreateByArtifact = propertiesToCreateByArtifact;
myCommandName = commandName;
}
public void configure(final Project project, final VirtualFile root, final boolean isInteractive) {
MavenActionsUsagesCollector.trigger(project, MavenActionsUsagesCollector.CREATE_MAVEN_PROJECT);
PsiFile[] psiFiles = myAggregatorProject != null
? new PsiFile[]{getPsiFile(project, myAggregatorProject.getFile())}
: PsiFile.EMPTY_ARRAY;
final VirtualFile pom = WriteCommandAction.writeCommandAction(project, psiFiles).withName(myCommandName).compute(() -> {
GitSilentFileAdder vcsFileAdder = GitSilentFileAdderProvider.create(project);
VirtualFile file = null;
val psiFiles = if (myAggregatorProject != null
) arrayOf(getPsiFile(project, myAggregatorProject.file))
else PsiFile.EMPTY_ARRAY
val pom = WriteCommandAction.writeCommandAction(project, *psiFiles).withName(myCommandName).compute<VirtualFile?, RuntimeException> {
val vcsFileAdder = GitSilentFileAdderProvider.create(project)
var file: VirtualFile? = null
try {
try {
file = root.findChild(MavenConstants.POM_XML);
if (file != null) file.delete(this);
file = root.createChildData(this, MavenConstants.POM_XML);
vcsFileAdder.markFileForAdding(file);
MavenUtil.runOrApplyMavenProjectFileTemplate(project, file, myProjectId, isInteractive);
file = root.findChild(MavenConstants.POM_XML)
file?.delete(this)
file = root.createChildData(this, MavenConstants.POM_XML)
vcsFileAdder.markFileForAdding(file)
MavenUtil.runOrApplyMavenProjectFileTemplate(project, file, myProjectId, isInteractive)
}
catch (IOException e) {
showError(project, e);
return file;
catch (e: IOException) {
showError(project, e)
return@compute file
}
updateProjectPom(project, file);
updateProjectPom(project, file)
}
finally {
vcsFileAdder.finish();
vcsFileAdder.finish()
}
if (myAggregatorProject != null) {
setPomPackagingForAggregatorProject(project, file);
setPomPackagingForAggregatorProject(project, file)
}
return file;
});
file
}
if (pom == null) return;
if (pom == null) return
if (myAggregatorProject == null) {
MavenProjectsManager manager = MavenProjectsManager.getInstance(project);
manager.addManagedFilesOrUnignore(Collections.singletonList(pom));
val manager = MavenProjectsManager.getInstance(project)
manager.addManagedFilesOrUnignore(listOf(pom))
}
if (myArchetype == null) {
try {
VfsUtil.createDirectories(root.getPath() + "/src/main/java");
VfsUtil.createDirectories(root.getPath() + "/src/main/resources");
VfsUtil.createDirectories(root.getPath() + "/src/test/java");
VfsUtil.createDirectories(root.path + "/src/main/java")
VfsUtil.createDirectories(root.path + "/src/main/resources")
VfsUtil.createDirectories(root.path + "/src/test/java")
}
catch (IOException e) {
MavenLog.LOG.info(e);
catch (e: IOException) {
MavenLog.LOG.info(e)
}
}
MavenProjectsManager.getInstance(project).forceUpdateAllProjectsOrFindAllAvailablePomFiles();
MavenProjectsManager.getInstance(project).forceUpdateAllProjectsOrFindAllAvailablePomFiles()
// execute when current dialog is closed (e.g. Project Structure)
MavenUtil.invokeLater(project, ModalityState.nonModal(), () -> {
if (!pom.isValid()) {
showError(project, new RuntimeException("Project is not valid"));
return;
MavenUtil.invokeLater(project, ModalityState.nonModal()) {
if (!pom.isValid) {
showError(project, RuntimeException("Project is not valid"))
return@invokeLater
}
EditorHelper.openInEditor(getPsiFile(project, pom));
if (myArchetype != null) generateFromArchetype(project, pom);
});
}
protected void setPomPackagingForAggregatorProject(Project project, VirtualFile file) {
VirtualFile aggregatorProjectFile = myAggregatorProject.getFile();
MavenDomProjectModel model = MavenDomUtil.getMavenDomProjectModel(project, aggregatorProjectFile);
if (model != null) {
model.getPackaging().setStringValue("pom");
MavenDomModule module = model.getModules().addModule();
module.setValue(getPsiFile(project, file));
unblockAndSaveDocuments(project, aggregatorProjectFile);
EditorHelper.openInEditor(getPsiFile(project, pom)!!)
if (myArchetype != null) generateFromArchetype(project, pom)
}
}
protected void updateProjectPom(final Project project, final VirtualFile pom) {
if (myParentProject == null) return;
protected fun setPomPackagingForAggregatorProject(project: Project, file: VirtualFile?) {
val aggregatorProjectFile = myAggregatorProject!!.file
val model = MavenDomUtil.getMavenDomProjectModel(project, aggregatorProjectFile)
if (model != null) {
model.packaging.stringValue = "pom"
val module = model.modules.addModule()
module.value = getPsiFile(project, file)
unblockAndSaveDocuments(project, aggregatorProjectFile)
}
}
WriteCommandAction.writeCommandAction(project).withName(myCommandName).run(() -> {
PsiDocumentManager.getInstance(project).commitAllDocuments();
protected fun updateProjectPom(project: Project, pom: VirtualFile?) {
if (myParentProject == null) return
MavenDomProjectModel model = MavenDomUtil.getMavenDomProjectModel(project, pom);
if (model == null) return;
WriteCommandAction.writeCommandAction(project).withName(myCommandName).run<RuntimeException> {
PsiDocumentManager.getInstance(project).commitAllDocuments()
val model = MavenDomUtil.getMavenDomProjectModel(project, pom!!)
if (model == null) return@run
MavenDomUtil.updateMavenParent(model, myParentProject);
MavenDomUtil.updateMavenParent(model, myParentProject)
if (myInheritGroupId) {
XmlElement el = model.getGroupId().getXmlElement();
if (el != null) el.delete();
val el = model.groupId.xmlElement
el?.delete()
}
if (myInheritVersion) {
XmlElement el = model.getVersion().getXmlElement();
if (el != null) el.delete();
val el = model.version.xmlElement
el?.delete()
}
CodeStyleManager.getInstance(project).reformat(getPsiFile(project, pom));
CodeStyleManager.getInstance(project).reformat(getPsiFile(project, pom)!!)
List<VirtualFile> pomFiles = new ArrayList<>(2);
pomFiles.add(pom);
val pomFiles: MutableList<VirtualFile> = ArrayList(2)
pomFiles.add(pom)
if (!FileUtil.namesEqual(MavenConstants.POM_XML, myParentProject.getFile().getName())) {
pomFiles.add(myParentProject.getFile());
MavenProjectsManager.getInstance(project).scheduleForceUpdateMavenProject(myParentProject);
if (!FileUtil.namesEqual(MavenConstants.POM_XML, myParentProject.file.name)) {
pomFiles.add(myParentProject.file)
MavenProjectsManager.getInstance(project).scheduleForceUpdateMavenProject(myParentProject)
}
unblockAndSaveDocuments(project, pomFiles.toArray(VirtualFile.EMPTY_ARRAY));
});
}
protected static void unblockAndSaveDocuments(@NotNull Project project, VirtualFile @NotNull ... files) {
FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(project);
for (VirtualFile file : files) {
Document document = fileDocumentManager.getDocument(file);
if (document == null) continue;
psiDocumentManager.doPostponedOperationsAndUnblockDocument(document);
fileDocumentManager.saveDocument(document);
unblockAndSaveDocuments(project, *pomFiles.toTypedArray())
}
}
protected static PsiFile getPsiFile(Project project, VirtualFile pom) {
return PsiManager.getInstance(project).findFile(pom);
}
private fun generateFromArchetype(project: Project, pom: VirtualFile) {
trigger(project, MavenActionsUsagesCollector.CREATE_MAVEN_PROJECT_FROM_ARCHETYPE)
private void generateFromArchetype(final Project project, final VirtualFile pom) {
MavenActionsUsagesCollector.trigger(project, MavenActionsUsagesCollector.CREATE_MAVEN_PROJECT_FROM_ARCHETYPE);
final File workingDir;
val workingDir: File
try {
workingDir = FileUtil.createTempDirectory("archetype", "tmp");
workingDir.deleteOnExit();
workingDir = FileUtil.createTempDirectory("archetype", "tmp")
workingDir.deleteOnExit()
}
catch (IOException e) {
showError(project, e);
return;
catch (e: IOException) {
showError(project, e)
return
}
MavenRunnerParameters params = new MavenRunnerParameters(
false, workingDir.getPath(), (String)null,
Collections.singletonList("org.apache.maven.plugins:maven-archetype-plugin:RELEASE:generate"),
Collections.emptyList());
val params = MavenRunnerParameters(
false, workingDir.path, null as String?,
listOf("org.apache.maven.plugins:maven-archetype-plugin:RELEASE:generate"),
emptyList())
MavenRunner runner = MavenRunner.getInstance(project);
MavenRunnerSettings settings = runner.getState().clone();
val runner = MavenRunner.getInstance(project)
val settings = runner.state.clone()
Map<String, String> props = settings.getMavenProperties();
props.put("interactiveMode", "false");
val props = settings.mavenProperties
props["interactiveMode"] = "false"
if (null != myPropertiesToCreateByArtifact) {
props.putAll(myPropertiesToCreateByArtifact);
props.putAll(myPropertiesToCreateByArtifact)
}
runner.run(params, settings, () -> copyGeneratedFiles(workingDir, pom, project, props.get("artifactId")));
runner.run(params, settings) { copyGeneratedFiles(workingDir, pom, project, props["artifactId"]) }
}
@VisibleForTesting
void copyGeneratedFiles(File workingDir, VirtualFile pom, Project project, String artifactId) {
GitSilentFileAdder vcsFileAdder = GitSilentFileAdderProvider.create(project);
fun copyGeneratedFiles(workingDir: File?, pom: VirtualFile, project: Project, artifactId: String?) {
var artifactId = artifactId
val vcsFileAdder = GitSilentFileAdderProvider.create(project)
try {
try {
artifactId = artifactId != null ? artifactId : myProjectId.getArtifactId();
artifactId = artifactId ?: myProjectId.artifactId
if (artifactId != null) {
File sourceDir = new File(workingDir, artifactId);
File targetDir = new File(pom.getParent().getPath());
vcsFileAdder.markFileForAdding(targetDir, true); // VFS is refreshed below
FileUtil.copyDir(sourceDir, targetDir);
val sourceDir = File(workingDir, artifactId)
val targetDir = File(pom.parent.path)
vcsFileAdder.markFileForAdding(targetDir, true) // VFS is refreshed below
FileUtil.copyDir(sourceDir, targetDir)
}
FileUtil.delete(workingDir);
FileUtil.delete(workingDir!!)
}
catch (Exception e) {
showError(project, e);
return;
catch (e: Exception) {
showError(project, e)
return
}
pom.getParent().refresh(false, false);
pom.refresh(false, false);
updateProjectPom(project, pom);
pom.parent.refresh(false, false)
pom.refresh(false, false)
updateProjectPom(project, pom)
LocalFileSystem.getInstance().refreshWithoutFileWatcher(true);
LocalFileSystem.getInstance().refreshWithoutFileWatcher(true)
}
finally {
vcsFileAdder.finish();
vcsFileAdder.finish()
}
}
protected static void showError(Project project, Throwable e) {
MavenUtil.showError(project, MavenProjectBundle.message("notification.title.failed.to.create.maven.project"), e);
companion object {
private fun unblockAndSaveDocuments(project: Project, vararg files: VirtualFile) {
val fileDocumentManager = FileDocumentManager.getInstance()
val psiDocumentManager = PsiDocumentManager.getInstance(project)
for (file in files) {
val document = fileDocumentManager.getDocument(file)
if (document == null) continue
psiDocumentManager.doPostponedOperationsAndUnblockDocument(document)
fileDocumentManager.saveDocument(document)
}
}
@JvmStatic
protected fun getPsiFile(project: Project?, pom: VirtualFile?): PsiFile? {
return PsiManager.getInstance(project!!).findFile(pom!!)
}
@JvmStatic
protected fun showError(project: Project?, e: Throwable?) {
MavenUtil.showError(project, MavenProjectBundle.message("notification.title.failed.to.create.maven.project"), e)
}
}
}