[maven] IDEA-272727 fix maven encoding configurer.

Revert to batch processing,
but use new EncodingProjectManagerImpl.setPointerMapping and VirtualFilePointers instead of VirtualFiles.

GitOrigin-RevId: 4a69146e2dfe192b7bfaf32bd00d5e71e0396ae2
This commit is contained in:
Nikita Skvortsov
2021-06-30 17:40:41 +03:00
committed by intellij-monorepo-bot
parent efda1da73e
commit 862f10fee6
4 changed files with 134 additions and 65 deletions

View File

@@ -3,7 +3,6 @@ package com.intellij.openapi.vfs.encoding;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.nio.charset.Charset;
@@ -31,12 +30,4 @@ public abstract class EncodingProjectManager extends EncodingManager {
*/
@Override
public abstract void setDefaultCharsetName(@NotNull String name);
/**
* Sets encoding by file / dir path.
* The target file or directory may not exist.
* @param fileOrDirPath target file / dir absolute path
* @param charset null to remove specific configuration.
*/
public abstract void setEncodingByPath(@NotNull final String fileOrDirPath, @Nullable final Charset charset);
}

View File

@@ -34,10 +34,6 @@ public class CoreEncodingProjectManager extends EncodingProjectManager {
public void setEncoding(@Nullable VirtualFile virtualFileOrDir, @Nullable Charset charset) {
}
@Override
public void setEncodingByPath(@NotNull String path, @Nullable Charset charset) {
}
@Override
public boolean isNative2AsciiForPropertiesFiles() {
return false;

View File

@@ -23,7 +23,10 @@ import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.startup.StartupActivity;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.text.StringUtilRt;
import com.intellij.openapi.vfs.*;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileVisitor;
import com.intellij.openapi.vfs.impl.LightFilePointer;
import com.intellij.openapi.vfs.newvfs.events.VFileContentChangeEvent;
import com.intellij.openapi.vfs.newvfs.impl.VirtualFileSystemEntry;
@@ -202,28 +205,6 @@ public final class EncodingProjectManagerImpl extends EncodingProjectManager imp
return myModificationTracker;
}
@Override
public void setEncodingByPath(@NotNull final String fileOrDirPath, @Nullable final Charset charset) {
final VirtualFile vf = LocalFileSystem.getInstance().findFileByPath(fileOrDirPath);
if (vf != null) {
setEncoding(vf, charset);
return;
}
Charset oldCharset;
VirtualFilePointer pointer = VirtualFilePointerManager.getInstance().create(VfsUtilCore.pathToUrl(fileOrDirPath), this, null);
if (charset == null) {
oldCharset = myMapping.remove(pointer);
}
else {
oldCharset = myMapping.put(pointer, charset);
}
if (!Comparing.equal(oldCharset, charset)) {
myModificationTracker.incModificationCount();
}
}
@Override
public void setEncoding(@Nullable final VirtualFile virtualFileOrDir, @Nullable final Charset charset) {
Charset oldCharset;
@@ -300,11 +281,18 @@ public final class EncodingProjectManagerImpl extends EncodingProjectManager imp
.collect(Collectors.toMap(p -> p.getFirst(), p -> p.getSecond(), (c1, c2) -> c1));
}
/**
* @return readonly map of current mappings. to modify mappings use {@link #setPointerMapping(Map)}
*/
@NotNull
public Map<? extends VirtualFilePointer, ? extends Charset> getAllPointersMappings() {
return Collections.unmodifiableMap(myMapping);
}
public void setMapping(@NotNull Map<? extends VirtualFile, ? extends Charset> mapping) {
ApplicationManager.getApplication().assertIsWriteThread();
FileDocumentManager.getInstance().saveAllDocuments(); // consider all files as unmodified
final Map<VirtualFilePointer, Charset> newMap = new HashMap<>(mapping.size());
final Map<VirtualFilePointer, Charset> oldMap = new HashMap<>(myMapping);
// ChangeFileEncodingAction should not start progress "reload files..."
suppressReloadDuring(() -> {
@@ -320,27 +308,47 @@ public final class EncodingProjectManagerImpl extends EncodingProjectManager imp
if (!fileIndex.isInContent(virtualFile)) continue;
VirtualFilePointer pointer = VirtualFilePointerManager.getInstance().create(virtualFile, this, null);
if (!virtualFile.isDirectory() && !Comparing.equal(charset, oldMap.get(pointer))) {
Document document;
byte[] bytes;
try {
document = FileDocumentManager.getInstance().getDocument(virtualFile);
if (document == null) throw new IOException();
bytes = virtualFile.contentsToByteArray();
}
catch (IOException e) {
continue;
}
// ask whether to reload/convert when in doubt
boolean changed = new ChangeFileEncodingAction().chosen(document, null, virtualFile, bytes, charset);
if (!changed) continue;
}
if (!fileEncodingChanged(virtualFile, myMapping.get(pointer), charset)) continue;
newMap.put(pointer, charset);
}
}
});
updateMapping(newMap);
}
public void setPointerMapping(@NotNull Map<? extends VirtualFilePointer, ? extends Charset> mapping) {
ApplicationManager.getApplication().assertIsWriteThread();
FileDocumentManager.getInstance().saveAllDocuments(); // consider all files as unmodified
final Map<VirtualFilePointer, Charset> newMap = new HashMap<>(mapping.size());
// ChangeFileEncodingAction should not start progress "reload files..."
suppressReloadDuring(() -> {
ProjectFileIndex fileIndex = ProjectRootManager.getInstance(myProject).getFileIndex();
for (Map.Entry<? extends VirtualFilePointer, ? extends Charset> entry : mapping.entrySet()) {
VirtualFilePointer filePointer = entry.getKey();
Charset charset = entry.getValue();
if (charset == null) throw new IllegalArgumentException("Null charset for " + filePointer + "; mapping: " + mapping);
if (filePointer == null) {
myProjectCharset = charset;
}
else {
final VirtualFile virtualFile = filePointer.getFile();
if (virtualFile != null) {
if (!fileIndex.isInContent(virtualFile)
|| !fileEncodingChanged(virtualFile, myMapping.get(filePointer), charset)) continue;
}
newMap.put(filePointer, charset);
}
}
});
updateMapping(newMap);
}
private void updateMapping(Map<VirtualFilePointer, Charset> newMap) {
Map<VirtualFilePointer, Charset> oldMap = new HashMap<>(myMapping);
myMapping.clear();
myMapping.putAll(newMap);
@@ -384,6 +392,26 @@ public final class EncodingProjectManagerImpl extends EncodingProjectManager imp
myModificationTracker.incModificationCount();
}
private static boolean fileEncodingChanged(@NotNull VirtualFile virtualFile,
@Nullable Charset oldCharset,
@NotNull Charset newCharset) {
if (!virtualFile.isDirectory() && !Comparing.equal(newCharset, oldCharset)) {
Document document;
byte[] bytes;
try {
document = FileDocumentManager.getInstance().getDocument(virtualFile);
if (document == null) throw new IOException();
bytes = virtualFile.contentsToByteArray();
}
catch (IOException e) {
return false;
}
// ask whether to reload/convert when in doubt
return new ChangeFileEncodingAction().chosen(document, null, virtualFile, bytes, newCharset);
}
return true;
}
@NotNull
private static Processor<VirtualFile> createChangeCharsetProcessor(@NotNull Project project) {
return file -> {

View File

@@ -15,9 +15,19 @@
*/
package org.jetbrains.idea.maven.importing.configurers
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.ReadAction
import com.intellij.openapi.components.service
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VfsUtil.fileToUrl
import com.intellij.openapi.vfs.VfsUtilCore.urlToPath
import com.intellij.openapi.vfs.encoding.EncodingProjectManager
import com.intellij.openapi.vfs.encoding.EncodingProjectManagerImpl
import com.intellij.openapi.vfs.pointers.VirtualFilePointer
import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager
import org.jetbrains.idea.maven.project.MavenProject
import org.jetbrains.idea.maven.utils.MavenLog
import java.io.File
@@ -29,26 +39,70 @@ import java.nio.charset.UnsupportedCharsetException
*/
class MavenEncodingConfigurer : MavenModuleConfigurer() {
override fun configure(mavenProject: MavenProject, project: Project, module: Module) {
fillSourceEncoding(mavenProject, EncodingProjectManager.getInstance(project))
fillResourceEncoding(project, mavenProject, EncodingProjectManager.getInstance(project))
val encodingCollector = EncodingCollector(project)
ReadAction.compute<Unit, Throwable> {
fillSourceEncoding(mavenProject, encodingCollector)
}
ReadAction.compute<Unit, Throwable> {
fillResourceEncoding(project, mavenProject, encodingCollector)
}
encodingCollector.applyCollectedInfo()
}
private fun fillResourceEncoding(project: Project,
mavenProject: MavenProject,
projectManager: EncodingProjectManager) {
mavenProject.getResourceEncoding(project)?.let(this::getCharset)?.let { charset ->
mavenProject.resources.forEach { resource ->
projectManager.setEncodingByPath(File(resource.directory).absolutePath, charset)
class EncodingCollector(project: Project) {
private val newPointerMappings = LinkedHashMap<VirtualFilePointer, Charset>()
private val oldPointerMappings = LinkedHashMap<VirtualFilePointer, Charset>()
private val encodingManager = (EncodingProjectManager.getInstance(project) as EncodingProjectManagerImpl)
fun processDir(directory: String, charset: Charset) {
val dirVfile = LocalFileSystem.getInstance().findFileByIoFile(File(directory))
val pointer = if (dirVfile != null) {
service<VirtualFilePointerManager>().create(dirVfile, encodingManager, null)
} else {
service<VirtualFilePointerManager>().create(fileToUrl(File(directory).absoluteFile), encodingManager, null)
}
newPointerMappings[pointer] = charset
encodingManager.allPointersMappings.forEach {
val filePointer = it.key
if (FileUtil.isAncestor(directory, urlToPath(filePointer.url), false)
|| newPointerMappings.containsKey(filePointer)) {
newPointerMappings[filePointer] = charset
oldPointerMappings.remove(filePointer)
}
else {
oldPointerMappings[filePointer] = it.value
}
}
}
fun applyCollectedInfo() {
if (newPointerMappings.isEmpty()) {
return
}
val pointerMapping = newPointerMappings + oldPointerMappings
ApplicationManager.getApplication().invokeAndWait {
encodingManager.setPointerMapping(pointerMapping)
}
}
}
private fun fillResourceEncoding(project: Project,
mavenProject: MavenProject,
encodingCollector: EncodingCollector) {
mavenProject.getResourceEncoding(project)?.let(this::getCharset)?.let { charset ->
mavenProject.resources.map { it.directory }.forEach { encodingCollector.processDir(it, charset) }
}
}
private fun fillSourceEncoding(mavenProject: MavenProject,
projectManager: EncodingProjectManager) {
encodingCollector: EncodingCollector) {
mavenProject.sourceEncoding?.let(this::getCharset)?.let { charset ->
mavenProject.sources.forEach { directory ->
projectManager.setEncodingByPath(File(directory).absolutePath, charset)
}
mavenProject.sources.forEach { encodingCollector.processDir(it, charset) }
}
}