mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[eclipse] support loading and saving module configuration in '.classpath' format (IDEA-246236)
ModuleEntity loaded from .classpath file uses special EclipseProjectFile entity source. Additional properties are stored in EclipseProjectPropertiesEntity (a replacement for EclipseModuleManager in the workspace model). Few things aren't implemented yet: * reloading module configuration when .classpath or *.eml file is changed; * using line separator configured in the project; * proper handling of invalid references to JDK. GitOrigin-RevId: c71b84c783543070c7f3594668e4d52a987355cc
This commit is contained in:
committed by
intellij-monorepo-bot
parent
d8cf763564
commit
d7136f71ee
+9
@@ -29,6 +29,7 @@ import com.intellij.workspaceModel.ide.impl.recordModuleLoadingActivity
|
||||
import com.intellij.workspaceModel.storage.*
|
||||
import com.intellij.workspaceModel.storage.bridgeEntities.ModuleDependencyItem
|
||||
import com.intellij.workspaceModel.storage.bridgeEntities.ModuleId
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.jps.util.JpsPathUtil
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
@@ -218,6 +219,14 @@ class JpsProjectModelSynchronizer(private val project: Project) : Disposable {
|
||||
data.saveEntities(storage, affectedSources, writer)
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
fun markAllEntitiesAsDirty() {
|
||||
val allSources = WorkspaceModel.getInstance(project).entityStorage.current.entitiesBySource { true }.keys
|
||||
synchronized(sourcesToSave) {
|
||||
sourcesToSave.addAll(allSources)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAndResetIncomingChanges(): JpsConfigurationFilesChange? {
|
||||
synchronized(incomingChanges) {
|
||||
if (incomingChanges.isEmpty()) return null
|
||||
|
||||
@@ -112,7 +112,7 @@ public abstract class AbstractEclipseClasspathReader<T> {
|
||||
catch (PatternSyntaxException e) {
|
||||
isTestFolder = false;
|
||||
}
|
||||
String linked = expandLinkedResourcesPath(macroMap, path);
|
||||
String linked = expandLinkedResourcesPath(myRootPath, macroMap, path);
|
||||
if (linked == null) {
|
||||
addSourceFolderToCurrentContentRoot(rootModel, srcUrl, isTestFolder);
|
||||
}
|
||||
@@ -132,7 +132,7 @@ public abstract class AbstractEclipseClasspathReader<T> {
|
||||
}
|
||||
else if (kind.equals(EclipseXml.OUTPUT_KIND)) {
|
||||
String output = getPathRelativeToRoot(path);
|
||||
String linked = expandLinkedResourcesPath(macroMap, path);
|
||||
String linked = expandLinkedResourcesPath(myRootPath, macroMap, path);
|
||||
if (linked != null) {
|
||||
output = linked;
|
||||
if (eclipseModuleManager != null) {
|
||||
@@ -142,7 +142,7 @@ public abstract class AbstractEclipseClasspathReader<T> {
|
||||
setupOutput(rootModel, output);
|
||||
}
|
||||
else if (kind.equals(EclipseXml.LIB_KIND)) {
|
||||
String linked = expandLinkedResourcesPath(macroMap, path);
|
||||
String linked = expandLinkedResourcesPath(myRootPath, macroMap, path);
|
||||
String url;
|
||||
if (linked != null) {
|
||||
url = prepareValidUrlInsideJar(pathToUrl(linked));
|
||||
@@ -161,7 +161,7 @@ public abstract class AbstractEclipseClasspathReader<T> {
|
||||
final String sourcePath = element.getAttributeValue(EclipseXml.SOURCEPATH_ATTR);
|
||||
String srcUrl = null;
|
||||
if (sourcePath != null) {
|
||||
final String linkedSrc = expandLinkedResourcesPath(macroMap, sourcePath);
|
||||
final String linkedSrc = expandLinkedResourcesPath(myRootPath, macroMap, sourcePath);
|
||||
if (linkedSrc != null) {
|
||||
srcUrl = prepareValidUrlInsideJar(pathToUrl(linkedSrc));
|
||||
if (eclipseModuleManager != null) {
|
||||
@@ -248,7 +248,7 @@ public abstract class AbstractEclipseClasspathReader<T> {
|
||||
return path.isEmpty() ? myRootPath : (myRootPath + "/" + path);
|
||||
}
|
||||
|
||||
private static String getNativeLibraryRoot(Element element) {
|
||||
public static String getNativeLibraryRoot(Element element) {
|
||||
final Element attributes = element.getChild(EclipseXml.ATTRIBUTES_TAG);
|
||||
if (attributes != null) {
|
||||
for (Element attributeElement : attributes.getChildren(EclipseXml.ATTRIBUTE_TAG)) {
|
||||
@@ -260,17 +260,17 @@ public abstract class AbstractEclipseClasspathReader<T> {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected static int srcVarStart(String srcPath) {
|
||||
public static int srcVarStart(String srcPath) {
|
||||
return srcPath.startsWith("/") ? 1 : 0;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected static String getPresentableName(@NotNull String path) {
|
||||
public static String getPresentableName(@NotNull String path) {
|
||||
return getPresentableName(path, null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected static String getPresentableName(@NotNull String path, Set<? super String> names) {
|
||||
public static String getPresentableName(@NotNull String path, Set<? super String> names) {
|
||||
String pathComponent = getLastPathComponent(path);
|
||||
if (pathComponent != null && names != null && !names.add(pathComponent)) {
|
||||
return path;
|
||||
@@ -287,7 +287,7 @@ public abstract class AbstractEclipseClasspathReader<T> {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected static String getVariableRelatedPath(@NotNull String var, String path) {
|
||||
public static String getVariableRelatedPath(@NotNull String var, String path) {
|
||||
return "$" + var + "$" + (path == null ? "" : "/" + path);
|
||||
}
|
||||
|
||||
@@ -296,7 +296,7 @@ public abstract class AbstractEclipseClasspathReader<T> {
|
||||
return "file://" + FileUtil.toSystemIndependentName(path);
|
||||
}
|
||||
|
||||
protected static EPathVariable createEPathVariable(String pathAttr, int varStart) {
|
||||
public static EPathVariable createEPathVariable(String pathAttr, int varStart) {
|
||||
int slash = pathAttr.indexOf("/", varStart);
|
||||
if (slash > 0) {
|
||||
return new EPathVariable(pathAttr.substring(varStart, slash), pathAttr.substring(slash + 1));
|
||||
@@ -313,9 +313,9 @@ public abstract class AbstractEclipseClasspathReader<T> {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected String expandLinkedResourcesPath(final ExpandMacroToPathMap macroMap,
|
||||
final String path) {
|
||||
final EclipseProjectFinder.LinkedResource linkedResource = EclipseProjectFinder.findLinkedResource(myRootPath, path);
|
||||
public static String expandLinkedResourcesPath(String rootPath, final ExpandMacroToPathMap macroMap,
|
||||
final String path) {
|
||||
final EclipseProjectFinder.LinkedResource linkedResource = EclipseProjectFinder.findLinkedResource(rootPath, path);
|
||||
if (linkedResource != null) {
|
||||
if (linkedResource.containsPathVariable()) {
|
||||
final String toPathVariableFormat =
|
||||
@@ -375,7 +375,7 @@ public abstract class AbstractEclipseClasspathReader<T> {
|
||||
}
|
||||
}
|
||||
|
||||
protected static class EPathVariable {
|
||||
public static class EPathVariable {
|
||||
@NotNull
|
||||
private final String myVariable;
|
||||
private final String myRelatedPath;
|
||||
@@ -384,5 +384,13 @@ public abstract class AbstractEclipseClasspathReader<T> {
|
||||
myVariable = variable;
|
||||
myRelatedPath = relatedPath;
|
||||
}
|
||||
|
||||
public @NotNull String getVariable() {
|
||||
return myVariable;
|
||||
}
|
||||
|
||||
public String getRelatedPath() {
|
||||
return myRelatedPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,5 +23,6 @@
|
||||
<orderEntry type="module" module-name="intellij.eclipse.common" />
|
||||
<orderEntry type="module" module-name="intellij.platform.testExtensions" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.core.ui" />
|
||||
<orderEntry type="module" module-name="intellij.platform.workspaceModel.ide" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -20,6 +20,8 @@
|
||||
<depends>com.intellij.modules.java</depends>
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<classpathStorageProvider implementation="org.jetbrains.idea.eclipse.config.EclipseClasspathStorageProvider"/>
|
||||
<workspaceModel.customModuleRootsSerializer implementation="org.jetbrains.idea.eclipse.config.EclipseModuleRootsSerializer"/>
|
||||
<workspaceModel.customModuleComponentSerializer implementation="org.jetbrains.idea.eclipse.config.EclipseModuleManagerSerializer"/>
|
||||
<compileServer.plugin classpath="eclipse-jps.jar;eclipse-common.jar"/>
|
||||
<projectImportProvider implementation="org.jetbrains.idea.eclipse.importWizard.EclipseProjectImportProvider"/>
|
||||
<projectOpenProcessor id="EclipseProjectOpenProcessor" implementation="org.jetbrains.idea.eclipse.importWizard.EclipseProjectOpenProcessor"/>
|
||||
|
||||
@@ -34,7 +34,10 @@ public final class EclipseJDOMUtil {
|
||||
}
|
||||
|
||||
public static void output(@NotNull Element element, @NotNull @NonNls Writer writer, @NotNull Project project) throws IOException {
|
||||
String lineSeparator = CodeStyle.getSettings(project).getLineSeparator();
|
||||
output(element, writer, CodeStyle.getSettings(project).getLineSeparator());
|
||||
}
|
||||
|
||||
public static void output(@NotNull Element element, @NonNls @NotNull Writer writer, String lineSeparator) throws IOException {
|
||||
writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
writer.write(lineSeparator);
|
||||
createOutputter(lineSeparator).output(element, writer);
|
||||
|
||||
+13
-13
@@ -21,25 +21,25 @@ import java.util.Set;
|
||||
|
||||
@State(name = "EclipseModuleManager")
|
||||
public class EclipseModuleManagerImpl implements EclipseModuleManager, PersistentStateComponent<Element>, StateStorageChooserEx {
|
||||
@NonNls private static final String VALUE_ATTR = "value";
|
||||
@NonNls private static final String VARELEMENT = "varelement";
|
||||
@NonNls private static final String VAR_ATTRIBUTE = "var";
|
||||
@NonNls private static final String CONELEMENT = "conelement";
|
||||
@NonNls private static final String FORCED_JDK = "forced_jdk";
|
||||
@NonNls private static final String SRC_DESCRIPTION = "src_description";
|
||||
@NonNls private static final String EXPECTED_POSITION = "expected_position";
|
||||
@NonNls private static final String SRC_FOLDER = "src_folder";
|
||||
@NonNls static final String VALUE_ATTR = "value";
|
||||
@NonNls static final String VARELEMENT = "varelement";
|
||||
@NonNls static final String VAR_ATTRIBUTE = "var";
|
||||
@NonNls static final String CONELEMENT = "conelement";
|
||||
@NonNls static final String FORCED_JDK = "forced_jdk";
|
||||
@NonNls static final String SRC_DESCRIPTION = "src_description";
|
||||
@NonNls static final String EXPECTED_POSITION = "expected_position";
|
||||
@NonNls static final String SRC_FOLDER = "src_folder";
|
||||
private CachedXmlDocumentSet myDocumentSet;
|
||||
private final Map<String, String> myEclipseVariablePaths = new LinkedHashMap<>();
|
||||
private final Set<String> myEclipseUrls = new LinkedHashSet<>();
|
||||
private final Set<String> myUnknownCons = new LinkedHashSet<>();
|
||||
private boolean myForceConfigureJDK;
|
||||
@NonNls private static final String SRC_PREFIX = "src:";
|
||||
@NonNls private static final String SRC_LINK_PREFIX = "linksrc:";
|
||||
@NonNls private static final String LINK_PREFIX = "link:";
|
||||
@NonNls private static final String PREFIX_ATTR = "kind";
|
||||
@NonNls static final String SRC_PREFIX = "src:";
|
||||
@NonNls static final String SRC_LINK_PREFIX = "linksrc:";
|
||||
@NonNls static final String LINK_PREFIX = "link:";
|
||||
@NonNls static final String PREFIX_ATTR = "kind";
|
||||
private final Module myModule;
|
||||
@NonNls private static final String LIBELEMENT = "libelement";
|
||||
@NonNls static final String LIBELEMENT = "libelement";
|
||||
private int myExpectedModuleSourcePlace;
|
||||
private final Map<String, Integer> mySrcPlace = new LinkedHashMap<>();
|
||||
private String myInvalidJdk;
|
||||
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
// 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.idea.eclipse.config
|
||||
|
||||
import com.intellij.workspaceModel.ide.impl.jps.serialization.CustomModuleComponentSerializer
|
||||
import com.intellij.workspaceModel.ide.impl.jps.serialization.ErrorReporter
|
||||
import com.intellij.workspaceModel.ide.impl.jps.serialization.JpsFileContentReader
|
||||
import com.intellij.workspaceModel.ide.impl.jps.serialization.JpsFileContentWriter
|
||||
import com.intellij.workspaceModel.storage.VirtualFileUrl
|
||||
import com.intellij.workspaceModel.storage.VirtualFileUrlManager
|
||||
import com.intellij.workspaceModel.storage.WorkspaceEntityStorageBuilder
|
||||
import com.intellij.workspaceModel.storage.bridgeEntities.ModuleEntity
|
||||
import org.jdom.Element
|
||||
import org.jetbrains.idea.eclipse.config.EclipseModuleManagerImpl.*
|
||||
import org.jetbrains.jps.eclipse.model.JpsEclipseClasspathSerializer
|
||||
import org.jetbrains.jps.model.serialization.JDomSerializationUtil
|
||||
import org.jetbrains.jps.model.serialization.JpsProjectLoader
|
||||
|
||||
/**
|
||||
* Implements loading and saving configuration from [EclipseModuleManagerImpl] in iml file when workspace model is used
|
||||
*/
|
||||
class EclipseModuleManagerSerializer : CustomModuleComponentSerializer {
|
||||
override fun loadComponent(builder: WorkspaceEntityStorageBuilder,
|
||||
moduleEntity: ModuleEntity,
|
||||
reader: JpsFileContentReader,
|
||||
imlFileUrl: VirtualFileUrl,
|
||||
errorReporter: ErrorReporter,
|
||||
virtualFileManager: VirtualFileUrlManager) {
|
||||
val componentTag = reader.loadComponent(imlFileUrl.url, "EclipseModuleManager") ?: return
|
||||
val entity = builder.addEclipseProjectPropertiesEntity(moduleEntity, moduleEntity.entitySource)
|
||||
builder.modifyEntity(ModifiableEclipseProjectPropertiesEntity::class.java, entity) {
|
||||
componentTag.getChildren(LIBELEMENT).forEach {
|
||||
eclipseUrls.add(virtualFileManager.fromUrl(it.getAttributeValue(VALUE_ATTR)!!))
|
||||
}
|
||||
componentTag.getChildren(VARELEMENT).forEach {
|
||||
variablePaths[it.getAttributeValue(VAR_ATTRIBUTE)!!] =
|
||||
it.getAttributeValue(PREFIX_ATTR, "") + it.getAttributeValue(VALUE_ATTR)
|
||||
}
|
||||
componentTag.getChildren(CONELEMENT).forEach {
|
||||
unknownCons.add(it.getAttributeValue(VALUE_ATTR)!!)
|
||||
}
|
||||
forceConfigureJdk = componentTag.getAttributeValue(FORCED_JDK)?.toBoolean() ?: false
|
||||
val srcDescriptionTag = componentTag.getChild(SRC_DESCRIPTION)
|
||||
if (srcDescriptionTag != null) {
|
||||
expectedModuleSourcePlace = srcDescriptionTag.getAttributeValue(EXPECTED_POSITION)?.toInt() ?: 0
|
||||
srcDescriptionTag.getChildren(SRC_FOLDER).forEach {
|
||||
srcPlace[it.getAttributeValue(VALUE_ATTR)!!] = it.getAttributeValue(EXPECTED_POSITION)!!.toInt()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun saveComponent(moduleEntity: ModuleEntity, imlFileUrl: VirtualFileUrl, writer: JpsFileContentWriter) {
|
||||
val moduleOptions = moduleEntity.customImlData?.customModuleOptions
|
||||
if (moduleOptions != null && moduleOptions[JpsProjectLoader.CLASSPATH_ATTRIBUTE] == JpsEclipseClasspathSerializer.CLASSPATH_STORAGE_ID) {
|
||||
return
|
||||
}
|
||||
val eclipseProperties = moduleEntity.eclipseProperties
|
||||
if (eclipseProperties == null || eclipseProperties.eclipseUrls.isEmpty() && eclipseProperties.variablePaths.isEmpty()
|
||||
&& !eclipseProperties.forceConfigureJdk && eclipseProperties.unknownCons.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
val componentTag = JDomSerializationUtil.createComponentElement("EclipseModuleManager")
|
||||
eclipseProperties.eclipseUrls.forEach {
|
||||
componentTag.addContent(Element(LIBELEMENT).setAttribute(VALUE_ATTR, it.url))
|
||||
}
|
||||
eclipseProperties.variablePaths.forEach { name, path ->
|
||||
val prefix = listOf(SRC_PREFIX, SRC_LINK_PREFIX, LINK_PREFIX).firstOrNull { name.startsWith(it) } ?: ""
|
||||
val varTag = Element(VARELEMENT)
|
||||
varTag.setAttribute(VAR_ATTRIBUTE, name.removePrefix(prefix))
|
||||
if (prefix != "") {
|
||||
varTag.setAttribute(PREFIX_ATTR, prefix)
|
||||
}
|
||||
varTag.setAttribute(VALUE_ATTR, path)
|
||||
componentTag.addContent(varTag)
|
||||
}
|
||||
eclipseProperties.unknownCons.forEach {
|
||||
componentTag.addContent(Element(CONELEMENT).setAttribute(VALUE_ATTR, it))
|
||||
}
|
||||
if (eclipseProperties.forceConfigureJdk) {
|
||||
componentTag.setAttribute(FORCED_JDK, true.toString())
|
||||
}
|
||||
val srcDescriptionTag = Element(SRC_DESCRIPTION)
|
||||
srcDescriptionTag.setAttribute(EXPECTED_POSITION, eclipseProperties.expectedModuleSourcePlace.toString())
|
||||
eclipseProperties.srcPlace.forEach { url, position ->
|
||||
srcDescriptionTag.addContent(Element(SRC_FOLDER).setAttribute(VALUE_ATTR, url).setAttribute(EXPECTED_POSITION, position.toString()))
|
||||
}
|
||||
componentTag.addContent(srcDescriptionTag)
|
||||
writer.saveComponent(imlFileUrl.url, "EclipseModuleManager", componentTag)
|
||||
}
|
||||
}
|
||||
+578
@@ -0,0 +1,578 @@
|
||||
// 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.idea.eclipse.config
|
||||
|
||||
import com.intellij.configurationStore.StorageManagerFileWriteRequestor
|
||||
import com.intellij.configurationStore.getOrCreateVirtualFile
|
||||
import com.intellij.configurationStore.runAsWriteActionIfNeeded
|
||||
import com.intellij.openapi.application.WriteAction
|
||||
import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.openapi.roots.OrderRootType
|
||||
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar
|
||||
import com.intellij.openapi.util.JDOMUtil
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.intellij.util.Function
|
||||
import com.intellij.util.SystemProperties
|
||||
import com.intellij.workspaceModel.ide.JpsFileEntitySource
|
||||
import com.intellij.workspaceModel.ide.impl.jps.serialization.*
|
||||
import com.intellij.workspaceModel.storage.*
|
||||
import com.intellij.workspaceModel.storage.bridgeEntities.*
|
||||
import org.jdom.Element
|
||||
import org.jdom.output.EclipseJDOMUtil
|
||||
import org.jetbrains.idea.eclipse.AbstractEclipseClasspathReader
|
||||
import org.jetbrains.idea.eclipse.AbstractEclipseClasspathReader.expandLinkedResourcesPath
|
||||
import org.jetbrains.idea.eclipse.EclipseXml
|
||||
import org.jetbrains.idea.eclipse.IdeaXml
|
||||
import org.jetbrains.idea.eclipse.conversion.EJavadocUtil
|
||||
import org.jetbrains.idea.eclipse.conversion.EclipseClasspathReader
|
||||
import org.jetbrains.idea.eclipse.conversion.EclipseClasspathWriter
|
||||
import org.jetbrains.idea.eclipse.conversion.EclipseClasspathWriter.addOrderEntry
|
||||
import org.jetbrains.idea.eclipse.importWizard.EclipseNatureImporter
|
||||
import org.jetbrains.jps.eclipse.model.JpsEclipseClasspathSerializer
|
||||
import org.jetbrains.jps.model.serialization.module.JpsModuleRootModelSerializer.JAVA_SOURCE_ROOT_TYPE_ID
|
||||
import org.jetbrains.jps.util.JpsPathUtil
|
||||
import java.io.IOException
|
||||
import java.io.OutputStreamWriter
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
|
||||
/**
|
||||
* Implements loading and saving module configuration from workspace model in '.classpath' file
|
||||
*/
|
||||
class EclipseModuleRootsSerializer : CustomModuleRootsSerializer, StorageManagerFileWriteRequestor {
|
||||
override val id: String
|
||||
get() = JpsEclipseClasspathSerializer.CLASSPATH_STORAGE_ID
|
||||
|
||||
companion object {
|
||||
private val LOG = logger<EclipseModuleRootsSerializer>()
|
||||
}
|
||||
|
||||
override fun createEntitySource(imlFileUrl: VirtualFileUrl,
|
||||
internalEntitySource: JpsFileEntitySource,
|
||||
customDir: String?,
|
||||
virtualFileManager: VirtualFileUrlManager): EntitySource? {
|
||||
val storageRootUrl = getStorageRoot(imlFileUrl, customDir, virtualFileManager)
|
||||
val classpathUrl = storageRootUrl.append(EclipseXml.CLASSPATH_FILE)
|
||||
return EclipseProjectFile(classpathUrl, internalEntitySource)
|
||||
}
|
||||
|
||||
override fun loadRoots(builder: WorkspaceEntityStorageBuilder,
|
||||
moduleEntity: ModuleEntity,
|
||||
reader: JpsFileContentReader,
|
||||
customDir: String?,
|
||||
imlFileUrl: VirtualFileUrl,
|
||||
internalModuleListSerializer: JpsModuleListSerializer?,
|
||||
errorReporter: ErrorReporter,
|
||||
virtualFileManager: VirtualFileUrlManager) {
|
||||
val storageRootUrl = getStorageRoot(imlFileUrl, customDir, virtualFileManager)
|
||||
val entitySource = moduleEntity.entitySource as EclipseProjectFile
|
||||
val contentRootEntity = builder.addContentRootEntity(storageRootUrl, emptyList(), emptyList(), moduleEntity)
|
||||
|
||||
val classpathTag = reader.loadComponent(entitySource.classpathFile.url, "", null)
|
||||
if (classpathTag != null) {
|
||||
val relativePathResolver = ModuleRelativePathResolver(internalModuleListSerializer, reader, virtualFileManager)
|
||||
loadClasspathTags(classpathTag, builder, contentRootEntity, storageRootUrl, reader, relativePathResolver, errorReporter, imlFileUrl,
|
||||
virtualFileManager)
|
||||
}
|
||||
else {
|
||||
builder.addJavaModuleSettingsEntity(false, true, storageRootUrl.append("bin"), null,
|
||||
moduleEntity, entitySource)
|
||||
}
|
||||
|
||||
val emlUrl = getEmlFileUrl(imlFileUrl)
|
||||
val emlTag = reader.loadComponent(emlUrl, "", null)
|
||||
if (emlTag != null) {
|
||||
reader.getExpandMacroMap(imlFileUrl.url).substitute(emlTag, SystemInfo.isFileSystemCaseSensitive)
|
||||
EmlFileLoader(moduleEntity, builder, reader.getExpandMacroMap(emlUrl), errorReporter, virtualFileManager).loadEml(emlTag, contentRootEntity)
|
||||
}
|
||||
else {
|
||||
val javaSettings = moduleEntity.javaSettings
|
||||
if (javaSettings != null) {
|
||||
builder.modifyEntity(ModifiableJavaModuleSettingsEntity::class.java, javaSettings) {
|
||||
excludeOutput = false
|
||||
}
|
||||
}
|
||||
else {
|
||||
builder.addJavaModuleSettingsEntity(true, false, null, null, moduleEntity, entitySource)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getEmlFileUrl(imlFileUrl: VirtualFileUrl) = imlFileUrl.url.removeSuffix(".iml") + EclipseXml.IDEA_SETTINGS_POSTFIX
|
||||
|
||||
private fun loadClasspathTags(classpathTag: Element,
|
||||
builder: WorkspaceEntityStorageBuilder,
|
||||
contentRootEntity: ContentRootEntity,
|
||||
storageRootUrl: VirtualFileUrl,
|
||||
reader: JpsFileContentReader,
|
||||
relativePathResolver: ModuleRelativePathResolver,
|
||||
errorReporter: ErrorReporter,
|
||||
imlFileUrl: VirtualFileUrl,
|
||||
virtualUrlManager: VirtualFileUrlManager) {
|
||||
fun reportError(message: String) {
|
||||
errorReporter.reportError(message, storageRootUrl.append(EclipseXml.CLASSPATH_FILE))
|
||||
}
|
||||
fun getUrlByRelativePath(path: String): VirtualFileUrl {
|
||||
return if (path.isEmpty()) storageRootUrl else storageRootUrl.append(FileUtil.toSystemIndependentName(path))
|
||||
}
|
||||
|
||||
val moduleEntity = contentRootEntity.module
|
||||
fun editEclipseProperties(action: (ModifiableEclipseProjectPropertiesEntity) -> Unit) {
|
||||
val eclipseProperties = moduleEntity.eclipseProperties ?: builder.addEclipseProjectPropertiesEntity(moduleEntity,
|
||||
moduleEntity.entitySource)
|
||||
builder.modifyEntity(ModifiableEclipseProjectPropertiesEntity::class.java, eclipseProperties) {
|
||||
action(this)
|
||||
}
|
||||
}
|
||||
|
||||
val storageRootPath = JpsPathUtil.urlToPath(storageRootUrl.url)
|
||||
val libraryNames = HashSet<String>()
|
||||
val expandMacroMap = reader.getExpandMacroMap(imlFileUrl.url)
|
||||
|
||||
val dependencies = ArrayList<ModuleDependencyItem>()
|
||||
dependencies.add(ModuleDependencyItem.ModuleSourceDependency)
|
||||
|
||||
classpathTag.getChildren(EclipseXml.CLASSPATHENTRY_TAG).forEachIndexed { index, entryTag ->
|
||||
val kind = entryTag.getAttributeValue(EclipseXml.KIND_ATTR)
|
||||
if (kind == null) {
|
||||
reportError("'${EclipseXml.KIND_ATTR}' attribute is missing in '${EclipseXml.CLASSPATHENTRY_TAG}' tag")
|
||||
return@forEachIndexed
|
||||
}
|
||||
val path = entryTag.getAttributeValue(EclipseXml.PATH_ATTR)
|
||||
if (path == null) {
|
||||
reportError("'${EclipseXml.PATH_ATTR}' attribute is missing in '${EclipseXml.CLASSPATHENTRY_TAG}' tag")
|
||||
return@forEachIndexed
|
||||
}
|
||||
val exported = EclipseXml.TRUE_VALUE == entryTag.getAttributeValue(EclipseXml.EXPORTED_ATTR)
|
||||
|
||||
when (kind) {
|
||||
EclipseXml.SRC_KIND -> {
|
||||
if (path.startsWith("/")) {
|
||||
dependencies.add(ModuleDependencyItem.Exportable.ModuleDependency(ModuleId(path.removePrefix("/")), exported,
|
||||
ModuleDependencyItem.DependencyScope.COMPILE, false))
|
||||
}
|
||||
else {
|
||||
val linkedPath = expandLinkedResourcesPath(storageRootPath, expandMacroMap, path)
|
||||
val srcUrl: VirtualFileUrl
|
||||
if (linkedPath == null) {
|
||||
srcUrl = getUrlByRelativePath(path)
|
||||
builder.addSourceRootEntity(contentRootEntity, srcUrl, false, JAVA_SOURCE_ROOT_TYPE_ID,
|
||||
contentRootEntity.entitySource)
|
||||
}
|
||||
else {
|
||||
srcUrl = convertToRootUrl(linkedPath, virtualUrlManager)
|
||||
editEclipseProperties {
|
||||
it.setVariable(EclipseModuleManagerImpl.SRC_LINK_PREFIX, path, srcUrl.url)
|
||||
}
|
||||
val newContentRoot = moduleEntity.contentRoots.firstOrNull { it.url == srcUrl }
|
||||
?: builder.addContentRootEntity(srcUrl, emptyList(), emptyList(), moduleEntity)
|
||||
builder.addSourceRootEntity(newContentRoot, srcUrl, false, JAVA_SOURCE_ROOT_TYPE_ID, newContentRoot.entitySource)
|
||||
}
|
||||
dependencies.removeIf { it is ModuleDependencyItem.ModuleSourceDependency }
|
||||
dependencies.add(ModuleDependencyItem.ModuleSourceDependency)
|
||||
editEclipseProperties {
|
||||
it.expectedModuleSourcePlace = dependencies.size - 1
|
||||
it.srcPlace[srcUrl.url] = index
|
||||
}
|
||||
}
|
||||
}
|
||||
EclipseXml.OUTPUT_KIND -> {
|
||||
val linked = expandLinkedResourcesPath(storageRootPath, expandMacroMap, path)
|
||||
val outputUrl: VirtualFileUrl
|
||||
if (linked != null) {
|
||||
outputUrl = virtualUrlManager.fromUrl(pathToUrl(linked))
|
||||
editEclipseProperties {
|
||||
it.setVariable(EclipseModuleManagerImpl.LINK_PREFIX, path, outputUrl.url)
|
||||
}
|
||||
}
|
||||
else {
|
||||
outputUrl = getUrlByRelativePath(path)
|
||||
}
|
||||
builder.addJavaModuleSettingsEntity(false, true, outputUrl, null,
|
||||
moduleEntity, contentRootEntity.entitySource)
|
||||
}
|
||||
EclipseXml.LIB_KIND -> {
|
||||
val linked = expandLinkedResourcesPath(storageRootPath, expandMacroMap, path)
|
||||
val url: VirtualFileUrl
|
||||
if (linked != null) {
|
||||
url = convertToRootUrl(linked, virtualUrlManager)
|
||||
editEclipseProperties {
|
||||
it.setVariable(EclipseModuleManagerImpl.LINK_PREFIX, path, url.url)
|
||||
}
|
||||
}
|
||||
else {
|
||||
url = convertRelativePathToUrl(path, contentRootEntity, relativePathResolver, virtualUrlManager)
|
||||
}
|
||||
editEclipseProperties {
|
||||
it.eclipseUrls.add(url)
|
||||
}
|
||||
val sourcePath = entryTag.getAttributeValue(EclipseXml.SOURCEPATH_ATTR)
|
||||
val srcUrl: VirtualFileUrl?
|
||||
if (sourcePath != null) {
|
||||
val linkedSrc = expandLinkedResourcesPath(storageRootPath, expandMacroMap, sourcePath)
|
||||
if (linkedSrc != null) {
|
||||
srcUrl = convertToRootUrl(linkedSrc, virtualUrlManager)
|
||||
editEclipseProperties {
|
||||
it.setVariable(EclipseModuleManagerImpl.SRC_LINK_PREFIX, path, srcUrl.url)
|
||||
}
|
||||
}
|
||||
else {
|
||||
srcUrl = convertRelativePathToUrl(sourcePath, contentRootEntity, relativePathResolver, virtualUrlManager)
|
||||
}
|
||||
}
|
||||
else {
|
||||
srcUrl = null
|
||||
}
|
||||
val nativeRoot = AbstractEclipseClasspathReader.getNativeLibraryRoot(entryTag)?.let {
|
||||
convertRelativePathToUrl(it, contentRootEntity, relativePathResolver, virtualUrlManager)
|
||||
}
|
||||
val name = AbstractEclipseClasspathReader.getPresentableName(path, libraryNames)
|
||||
val roots = createLibraryRoots(url, srcUrl, nativeRoot, entryTag, moduleEntity, relativePathResolver, virtualUrlManager)
|
||||
val libraryEntity = builder.addLibraryEntity(name, LibraryTableId.ModuleLibraryTableId(moduleEntity.persistentId()), roots,
|
||||
emptyList(), contentRootEntity.entitySource)
|
||||
dependencies.add(ModuleDependencyItem.Exportable.LibraryDependency(libraryEntity.persistentId(), exported,
|
||||
ModuleDependencyItem.DependencyScope.COMPILE))
|
||||
}
|
||||
EclipseXml.VAR_KIND -> {
|
||||
val slash = path.indexOf('/')
|
||||
if (slash == 0) {
|
||||
reportError("'${EclipseXml.PATH_ATTR}' attribute format is incorrect for '${EclipseXml.VAR_KIND}': $path")
|
||||
return@forEachIndexed
|
||||
}
|
||||
val libName = AbstractEclipseClasspathReader.getPresentableName(path, libraryNames)
|
||||
val url = convertVariablePathToUrl(expandMacroMap, path, 0, virtualUrlManager)
|
||||
editEclipseProperties {
|
||||
it.setVariable("", path, url.url)
|
||||
}
|
||||
val srcPath = entryTag.getAttributeValue(EclipseXml.SOURCEPATH_ATTR)
|
||||
val srcUrl: VirtualFileUrl?
|
||||
if (srcPath != null) {
|
||||
srcUrl = convertVariablePathToUrl(expandMacroMap, srcPath, AbstractEclipseClasspathReader.srcVarStart(srcPath),
|
||||
virtualUrlManager)
|
||||
editEclipseProperties {
|
||||
it.setVariable(EclipseModuleManagerImpl.SRC_LINK_PREFIX, srcPath, srcUrl.url)
|
||||
}
|
||||
}
|
||||
else {
|
||||
srcUrl = null
|
||||
}
|
||||
|
||||
val nativeRoot = AbstractEclipseClasspathReader.getNativeLibraryRoot(entryTag)?.let {
|
||||
convertRelativePathToUrl(it, contentRootEntity, relativePathResolver, virtualUrlManager)
|
||||
}
|
||||
val roots = createLibraryRoots(url, srcUrl, nativeRoot, entryTag, moduleEntity, relativePathResolver, virtualUrlManager)
|
||||
val libraryEntity = builder.addLibraryEntity(libName, LibraryTableId.ModuleLibraryTableId(moduleEntity.persistentId()),
|
||||
roots, emptyList(), contentRootEntity.entitySource)
|
||||
dependencies.add(ModuleDependencyItem.Exportable.LibraryDependency(libraryEntity.persistentId(), exported,
|
||||
ModuleDependencyItem.DependencyScope.COMPILE))
|
||||
|
||||
}
|
||||
EclipseXml.CON_KIND -> {
|
||||
if (path == EclipseXml.ECLIPSE_PLATFORM) {
|
||||
val libraryId = LibraryId(IdeaXml.ECLIPSE_LIBRARY,
|
||||
LibraryTableId.GlobalLibraryTableId(LibraryTablesRegistrar.APPLICATION_LEVEL))
|
||||
dependencies.add(ModuleDependencyItem.Exportable.LibraryDependency(libraryId, exported,
|
||||
ModuleDependencyItem.DependencyScope.COMPILE))
|
||||
}
|
||||
else if (path.startsWith(EclipseXml.JRE_CONTAINER)) {
|
||||
val jdkName = AbstractEclipseClasspathReader.getLastPathComponent(path)
|
||||
dependencies.removeIf { it is ModuleDependencyItem.SdkDependency || it == ModuleDependencyItem.InheritedSdkDependency }
|
||||
dependencies.add(if (jdkName != null) ModuleDependencyItem.SdkDependency(jdkName, IdeaXml.JAVA_SDK_TYPE)
|
||||
else ModuleDependencyItem.InheritedSdkDependency)
|
||||
}
|
||||
else if (path.startsWith(EclipseXml.USER_LIBRARY)) {
|
||||
val libraryId = LibraryId(AbstractEclipseClasspathReader.getPresentableName(path), LibraryTableId.ProjectLibraryTableId)
|
||||
dependencies.add(ModuleDependencyItem.Exportable.LibraryDependency(libraryId, exported,
|
||||
ModuleDependencyItem.DependencyScope.COMPILE))
|
||||
|
||||
}
|
||||
else if (path.startsWith(EclipseXml.JUNIT_CONTAINER)) {
|
||||
val junitName = IdeaXml.JUNIT + AbstractEclipseClasspathReader.getPresentableName(path)
|
||||
val url = EclipseClasspathReader.getJunitClsUrl(junitName.contains("4"))
|
||||
val roots = listOf(LibraryRoot(virtualUrlManager.fromUrl(url),
|
||||
LibraryRootTypeId(OrderRootType.CLASSES.name()),
|
||||
LibraryRoot.InclusionOptions.ROOT_ITSELF))
|
||||
val libraryEntity = builder.addLibraryEntity(junitName, LibraryTableId.ModuleLibraryTableId(moduleEntity.persistentId()),
|
||||
roots, emptyList(), contentRootEntity.entitySource)
|
||||
dependencies.add(ModuleDependencyItem.Exportable.LibraryDependency(libraryEntity.persistentId(), exported,
|
||||
ModuleDependencyItem.DependencyScope.COMPILE))
|
||||
}
|
||||
else {
|
||||
val definedCons = EclipseNatureImporter.getAllDefinedCons()
|
||||
if (path in definedCons) {
|
||||
editEclipseProperties {
|
||||
it.knownCons.add(path)
|
||||
it.srcPlace[path] = index
|
||||
}
|
||||
}
|
||||
else {
|
||||
editEclipseProperties {
|
||||
it.unknownCons.add(path)
|
||||
}
|
||||
val libraryId = LibraryId(path, LibraryTableId.GlobalLibraryTableId(LibraryTablesRegistrar.APPLICATION_LEVEL))
|
||||
dependencies.add(ModuleDependencyItem.Exportable.LibraryDependency(libraryId, exported,
|
||||
ModuleDependencyItem.DependencyScope.COMPILE))
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
reportError("Unknown '${EclipseXml.KIND_ATTR}' in '${EclipseXml.CLASSPATHENTRY_TAG}': $kind")
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dependencies.none { it is ModuleDependencyItem.SdkDependency || it == ModuleDependencyItem.InheritedSdkDependency }) {
|
||||
editEclipseProperties {
|
||||
it.forceConfigureJdk = true
|
||||
it.expectedModuleSourcePlace++
|
||||
}
|
||||
dependencies.add(0, ModuleDependencyItem.InheritedSdkDependency)
|
||||
}
|
||||
|
||||
builder.modifyEntity(ModifiableModuleEntity::class.java, moduleEntity) {
|
||||
this.dependencies = dependencies
|
||||
}
|
||||
}
|
||||
|
||||
private fun createLibraryRoots(url: VirtualFileUrl,
|
||||
srcUrl: VirtualFileUrl?,
|
||||
nativeRoot: VirtualFileUrl?,
|
||||
entryTag: Element,
|
||||
moduleEntity: ModuleEntity,
|
||||
relativePathResolver: ModuleRelativePathResolver,
|
||||
virtualUrlManager: VirtualFileUrlManager): ArrayList<LibraryRoot> {
|
||||
val roots = ArrayList<LibraryRoot>()
|
||||
roots.add(LibraryRoot(url, LibraryRootTypeId(OrderRootType.CLASSES.name()), LibraryRoot.InclusionOptions.ROOT_ITSELF))
|
||||
if (srcUrl != null) {
|
||||
roots.add(LibraryRoot(srcUrl, LibraryRootTypeId(OrderRootType.SOURCES.name()), LibraryRoot.InclusionOptions.ROOT_ITSELF))
|
||||
}
|
||||
if (nativeRoot != null) {
|
||||
roots.add(LibraryRoot(nativeRoot, LibraryRootTypeId("NATIVE"), LibraryRoot.InclusionOptions.ROOT_ITSELF))
|
||||
}
|
||||
entryTag.getChild("attributes")?.getChildren("attribute")
|
||||
?.filter { it.getAttributeValue("name") == EclipseXml.JAVADOC_LOCATION }
|
||||
?.mapTo(roots) {
|
||||
LibraryRoot(convertToJavadocUrl(it.getAttributeValue("value")!!, moduleEntity, relativePathResolver, virtualUrlManager), LibraryRootTypeId("JAVADOC"),
|
||||
LibraryRoot.InclusionOptions.ROOT_ITSELF)
|
||||
}
|
||||
return roots
|
||||
}
|
||||
|
||||
override fun saveRoots(module: ModuleEntity,
|
||||
entities: Map<Class<out WorkspaceEntity>, List<WorkspaceEntity>>,
|
||||
writer: JpsFileContentWriter,
|
||||
customDir: String?,
|
||||
imlFileUrl: VirtualFileUrl,
|
||||
storage: WorkspaceEntityStorage) {
|
||||
fun saveXmlFile(path: Path, root: Element) {
|
||||
//todo get rid of WriteAction here
|
||||
WriteAction.runAndWait<RuntimeException> {
|
||||
getOrCreateVirtualFile(path, this).getOutputStream(this).use {
|
||||
//todo use proper line separator
|
||||
EclipseJDOMUtil.output(root, OutputStreamWriter(it, StandardCharsets.UTF_8), SystemProperties.getLineSeparator())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val contentRoots = entities[ContentRootEntity::class.java] as List<ContentRootEntity>? ?: emptyList()
|
||||
val entitySource = contentRoots.asSequence().map { it.entitySource }.filterIsInstance<EclipseProjectFile>().firstOrNull() ?: return
|
||||
val classpathFile = VirtualFileManager.getInstance().findFileByUrl(entitySource.classpathFile.url)
|
||||
val oldClasspath = classpathFile?.inputStream?.use { JDOMUtil.load(it) }
|
||||
val pathShortener = ModulePathShortener(storage)
|
||||
if (oldClasspath != null || !entities[SourceRootEntity::class.java].isNullOrEmpty() || module.dependencies.size > 2) {
|
||||
val newClasspath = saveClasspathTags(module, entities, entitySource, oldClasspath, pathShortener)
|
||||
if (oldClasspath == null || !JDOMUtil.areElementsEqual(newClasspath, oldClasspath)) {
|
||||
saveXmlFile(Paths.get(entitySource.classpathFile.filePath!!), newClasspath)
|
||||
}
|
||||
}
|
||||
|
||||
val emlFileUrl = getEmlFileUrl(imlFileUrl)
|
||||
val emlRoot = EmlFileSaver(module, entities, pathShortener, writer.getReplacePathMacroMap(imlFileUrl.url)).saveEml()
|
||||
if (emlRoot != null) {
|
||||
saveXmlFile(Paths.get(JpsPathUtil.urlToPath(emlFileUrl)), emlRoot)
|
||||
}
|
||||
else {
|
||||
val emlFile = VirtualFileManager.getInstance().findFileByUrl(emlFileUrl)
|
||||
if (emlFile != null) {
|
||||
runAsWriteActionIfNeeded {
|
||||
try {
|
||||
emlFile.delete(this)
|
||||
}
|
||||
catch (e: IOException) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveClasspathTags(module: ModuleEntity,
|
||||
entities: Map<Class<out WorkspaceEntity>, List<WorkspaceEntity>>,
|
||||
entitySource: EclipseProjectFile,
|
||||
oldClasspath: Element?,
|
||||
pathShortener: ModulePathShortener): Element {
|
||||
val classpathTag = Element(EclipseXml.CLASSPATH_TAG)
|
||||
val oldEntries = oldClasspath?.getChildren(EclipseXml.CLASSPATHENTRY_TAG)?.associateBy {
|
||||
it.getAttributeValue(EclipseXml.KIND_ATTR)!! + EclipseClasspathWriter.getJREKey(it.getAttributeValue(EclipseXml.PATH_ATTR))
|
||||
} ?: emptyMap()
|
||||
|
||||
fun addClasspathEntry(kind: String, path: String?, index: Int = -1): Element {
|
||||
return addOrderEntry(kind, path, classpathTag, index, oldEntries)
|
||||
}
|
||||
|
||||
val eclipseProperties = module.eclipseProperties
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val sourceRoots = entities[SourceRootEntity::class.java] as List<SourceRootEntity>? ?: emptyList()
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val moduleLibraries = (entities[LibraryEntity::class.java] as List<LibraryEntity>? ?: emptyList()).associateBy { it.name }
|
||||
|
||||
for ((itemIndex, item) in module.dependencies.withIndex()) {
|
||||
when (item) {
|
||||
ModuleDependencyItem.ModuleSourceDependency -> {
|
||||
val shouldPlaceSeparately = eclipseProperties?.expectedModuleSourcePlace == itemIndex
|
||||
for (sourceRoot in sourceRoots) {
|
||||
var relativePath = convertToEclipsePath(sourceRoot.url, module, entitySource, pathShortener)
|
||||
if (sourceRoot.contentRoot.url != module.mainContentRoot?.url) {
|
||||
val linkedPath = eclipseProperties?.getVariable(EclipseModuleManagerImpl.SRC_LINK_PREFIX, sourceRoot.url.url)
|
||||
if (linkedPath != null) {
|
||||
relativePath = linkedPath
|
||||
}
|
||||
}
|
||||
val index = eclipseProperties?.srcPlace?.get(sourceRoot.url.url) ?: -1
|
||||
addClasspathEntry(EclipseXml.SRC_KIND, relativePath, if (shouldPlaceSeparately) index else -1)
|
||||
}
|
||||
}
|
||||
is ModuleDependencyItem.Exportable.ModuleDependency -> {
|
||||
val path = "/${item.module.name}"
|
||||
val oldElement = EclipseClasspathWriter.getOldElement(EclipseXml.SRC_KIND, path, oldEntries)
|
||||
val classpathEntry = addClasspathEntry(EclipseXml.SRC_KIND, path)
|
||||
if (oldElement == null) {
|
||||
EclipseClasspathWriter.setAttributeIfAbsent(classpathEntry, EclipseXml.COMBINEACCESSRULES_ATTR, EclipseXml.FALSE_VALUE)
|
||||
}
|
||||
EclipseClasspathWriter.setExported(classpathEntry, item.exported)
|
||||
}
|
||||
is ModuleDependencyItem.Exportable.LibraryDependency -> {
|
||||
val libraryName = item.library.name
|
||||
if (item.library.tableId is LibraryTableId.ModuleLibraryTableId) {
|
||||
val libraryRoots = moduleLibraries[libraryName]?.roots ?: emptyList()
|
||||
val libraryClassesRoots = libraryRoots.filter { it.type.name == OrderRootType.CLASSES.name() }
|
||||
val firstRoot = libraryClassesRoots.firstOrNull()?.url
|
||||
if (firstRoot != null) {
|
||||
val firstUrl = firstRoot.url
|
||||
if (libraryName.contains(IdeaXml.JUNIT) && firstUrl == EclipseClasspathReader.getJunitClsUrl(libraryName.contains("4"))) {
|
||||
val classpathEntry = addClasspathEntry(EclipseXml.CON_KIND,
|
||||
EclipseXml.JUNIT_CONTAINER + "/" + libraryName.substring(IdeaXml.JUNIT.length))
|
||||
EclipseClasspathWriter.setExported(classpathEntry, item.exported)
|
||||
}
|
||||
else {
|
||||
var newVarLibrary = false
|
||||
var link = false
|
||||
var eclipseVariablePath: String? = eclipseProperties?.getVariable("", firstUrl)
|
||||
if (eclipseVariablePath == null) {
|
||||
eclipseVariablePath = eclipseProperties?.getVariable(EclipseModuleManagerImpl.LINK_PREFIX, firstUrl)
|
||||
link = eclipseVariablePath != null
|
||||
}
|
||||
if (eclipseVariablePath == null && eclipseProperties?.eclipseUrls?.contains(firstRoot) != true) { //new library was added
|
||||
newVarLibrary = true
|
||||
eclipseVariablePath = convertToEclipsePathWithVariable(libraryClassesRoots)
|
||||
}
|
||||
var classpathEntry = if (eclipseVariablePath != null) {
|
||||
addClasspathEntry(if (link) EclipseXml.LIB_KIND else EclipseXml.VAR_KIND, eclipseVariablePath)
|
||||
}
|
||||
else {
|
||||
LOG.assertTrue(!StringUtil.isEmptyOrSpaces(firstUrl), "Library: $libraryName")
|
||||
addClasspathEntry(EclipseXml.LIB_KIND, convertToEclipsePath(firstRoot, module, entitySource, pathShortener))
|
||||
}
|
||||
|
||||
val srcRelativePath: String?
|
||||
var eclipseSrcVariablePath: String? = null
|
||||
var addSrcRoots = true
|
||||
val librarySourceRoots = libraryRoots.filter { it.type.name == OrderRootType.SOURCES.name() }
|
||||
val firstSrcRoot = librarySourceRoots.firstOrNull()?.url
|
||||
if (firstSrcRoot == null) {
|
||||
srcRelativePath = null
|
||||
}
|
||||
else {
|
||||
val firstSrcUrl = firstSrcRoot.url
|
||||
srcRelativePath = convertToEclipsePath(firstSrcRoot, module, entitySource, pathShortener)
|
||||
if (eclipseVariablePath != null) {
|
||||
eclipseSrcVariablePath = eclipseProperties?.getVariable(EclipseModuleManagerImpl.SRC_PREFIX, firstSrcUrl)
|
||||
if (eclipseSrcVariablePath == null) {
|
||||
eclipseSrcVariablePath = eclipseProperties?.getVariable(EclipseModuleManagerImpl.SRC_LINK_PREFIX, firstSrcUrl)
|
||||
}
|
||||
if (eclipseSrcVariablePath == null) {
|
||||
eclipseSrcVariablePath = convertToEclipsePathWithVariable(librarySourceRoots)
|
||||
if (eclipseSrcVariablePath != null) {
|
||||
eclipseSrcVariablePath = "/$eclipseSrcVariablePath"
|
||||
}
|
||||
else {
|
||||
if (newVarLibrary) { //new library which cannot be replaced with vars
|
||||
classpathEntry.detach()
|
||||
classpathEntry = addClasspathEntry(EclipseXml.LIB_KIND,
|
||||
convertToEclipsePath(firstRoot, module, entitySource, pathShortener))
|
||||
}
|
||||
else {
|
||||
LOG.info("Added root $srcRelativePath (in existing var library) can't be replaced with any variable; src roots placed in .eml only")
|
||||
addSrcRoots = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EclipseClasspathWriter.setOrRemoveAttribute(classpathEntry, EclipseXml.SOURCEPATH_ATTR,
|
||||
if (addSrcRoots) eclipseSrcVariablePath ?: srcRelativePath else null)
|
||||
EJavadocUtil.setupAttributes(classpathEntry,
|
||||
{ convertToEclipseJavadocPath(it, module, entitySource.internalSource.projectLocation, pathShortener) },
|
||||
EclipseXml.JAVADOC_LOCATION,
|
||||
libraryRoots.filter { it.type.name == "JAVADOC" }.map { it.url }.toList().toTypedArray())
|
||||
val nativeRoots = libraryRoots.asSequence().filter { it.type.name == "NATIVE" }.map { it.url }.toList().toTypedArray()
|
||||
if (nativeRoots.isNotEmpty()) {
|
||||
EJavadocUtil.setupAttributes(classpathEntry, Function { convertToEclipsePath(it, module, entitySource, pathShortener)!! }, EclipseXml.DLL_LINK,
|
||||
nativeRoots)
|
||||
}
|
||||
EclipseClasspathWriter.setExported(classpathEntry, item.exported)
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
val path = when {
|
||||
eclipseProperties?.unknownCons?.contains(libraryName) == true -> libraryName
|
||||
libraryName == IdeaXml.ECLIPSE_LIBRARY -> EclipseXml.ECLIPSE_PLATFORM
|
||||
else -> EclipseXml.USER_LIBRARY + '/' + libraryName
|
||||
}
|
||||
val classpathEntry = addClasspathEntry(EclipseXml.CON_KIND, path)
|
||||
EclipseClasspathWriter.setExported(classpathEntry, item.exported)
|
||||
}
|
||||
|
||||
}
|
||||
ModuleDependencyItem.InheritedSdkDependency -> {
|
||||
if (eclipseProperties?.forceConfigureJdk != true) {
|
||||
addClasspathEntry(EclipseXml.CON_KIND, EclipseXml.JRE_CONTAINER)
|
||||
}
|
||||
}
|
||||
is ModuleDependencyItem.SdkDependency -> {
|
||||
val jdkLink = "${EclipseXml.JRE_CONTAINER}${if (item.sdkType == "JavaSDK") EclipseXml.JAVA_SDK_TYPE else ""}/${item.sdkName}"
|
||||
addClasspathEntry(EclipseXml.CON_KIND, jdkLink)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val compilerOutput = module.javaSettings?.compilerOutput
|
||||
val outputPath = if (compilerOutput != null) {
|
||||
val linkedPath = eclipseProperties?.getVariable(EclipseModuleManagerImpl.LINK_PREFIX, compilerOutput.url)
|
||||
linkedPath ?: convertToEclipsePath(compilerOutput, module, entitySource, pathShortener)
|
||||
}
|
||||
else {
|
||||
"bin"
|
||||
}
|
||||
eclipseProperties?.knownCons?.forEach {
|
||||
addClasspathEntry(EclipseXml.CON_KIND, it, eclipseProperties.srcPlace[it] ?: -1)
|
||||
}
|
||||
EclipseClasspathWriter.setAttributeIfAbsent(addClasspathEntry(EclipseXml.OUTPUT_KIND, outputPath), EclipseXml.PATH_ATTR,
|
||||
EclipseXml.BIN_DIR)
|
||||
|
||||
return classpathTag
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
// 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.idea.eclipse.config
|
||||
|
||||
import com.intellij.openapi.components.ExpandMacroToPathMap
|
||||
import com.intellij.openapi.roots.OrderRootType
|
||||
import com.intellij.openapi.util.JDOMUtil
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.workspaceModel.ide.impl.jps.serialization.ErrorReporter
|
||||
import com.intellij.workspaceModel.storage.VirtualFileUrlManager
|
||||
import com.intellij.workspaceModel.storage.WorkspaceEntityStorageBuilder
|
||||
import com.intellij.workspaceModel.storage.bridgeEntities.*
|
||||
import org.jdom.Element
|
||||
import org.jetbrains.idea.eclipse.IdeaXml
|
||||
import org.jetbrains.idea.eclipse.conversion.EPathUtil
|
||||
import org.jetbrains.idea.eclipse.conversion.IdeaSpecificSettings
|
||||
import org.jetbrains.jps.model.serialization.java.JpsJavaModelSerializerExtension
|
||||
import org.jetbrains.jps.model.serialization.module.JpsModuleRootModelSerializer
|
||||
import org.jetbrains.jps.util.JpsPathUtil
|
||||
import java.lang.IllegalArgumentException
|
||||
|
||||
/**
|
||||
* Loads additional module configuration from *.eml file to [ModuleEntity]
|
||||
*/
|
||||
internal class EmlFileLoader(
|
||||
private val module: ModuleEntity, private val builder: WorkspaceEntityStorageBuilder,
|
||||
private val expandMacroToPathMap: ExpandMacroToPathMap, private val errorReporter: ErrorReporter,
|
||||
private val virtualFileManager: VirtualFileUrlManager
|
||||
) {
|
||||
fun loadEml(emlTag: Element, contentRoot: ContentRootEntity) {
|
||||
loadLanguageLevel(emlTag)
|
||||
loadCompilerSettings(emlTag)
|
||||
loadContentEntries(emlTag, contentRoot)
|
||||
loadJdkSettings(emlTag)
|
||||
|
||||
loadDependencies(emlTag)
|
||||
}
|
||||
|
||||
private fun loadDependencies(emlTag: Element) {
|
||||
val moduleLibraries = module.dependencies.asSequence().filterIsInstance<ModuleDependencyItem.Exportable.LibraryDependency>()
|
||||
.mapNotNull { it.library.resolve(builder) }
|
||||
.filter { it.tableId is LibraryTableId.ModuleLibraryTableId }
|
||||
.associateBy { it.name }
|
||||
val libraryScopes = HashMap<String, ModuleDependencyItem.DependencyScope>()
|
||||
emlTag.getChildren("lib").forEach { libTag ->
|
||||
val name = libTag.getAttributeValue("name")!!
|
||||
libraryScopes[name] = libTag.getScope()
|
||||
val moduleLibrary = moduleLibraries[name]
|
||||
if (moduleLibrary != null) {
|
||||
loadModuleLibrary(libTag, moduleLibrary)
|
||||
}
|
||||
}
|
||||
val moduleScopes = emlTag.getChildren("module").associateBy(
|
||||
{ it.getAttributeValue("name") },
|
||||
{ it.getScope() }
|
||||
)
|
||||
builder.modifyEntity(ModifiableModuleEntity::class.java, module) {
|
||||
dependencies = dependencies.map { dep ->
|
||||
when (dep) {
|
||||
is ModuleDependencyItem.Exportable.LibraryDependency ->
|
||||
libraryScopes[dep.library.name]?.let { dep.copy(scope = it) } ?: dep
|
||||
is ModuleDependencyItem.Exportable.ModuleDependency ->
|
||||
moduleScopes[dep.module.name]?.let { dep.copy(scope = it) } ?: dep
|
||||
else -> dep
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Element.getScope(): ModuleDependencyItem.DependencyScope {
|
||||
return getAttributeValue("scope")?.let {
|
||||
try {
|
||||
ModuleDependencyItem.DependencyScope.valueOf(it)
|
||||
}
|
||||
catch (e: IllegalArgumentException) {
|
||||
null
|
||||
}
|
||||
} ?: ModuleDependencyItem.DependencyScope.COMPILE
|
||||
}
|
||||
|
||||
private fun loadModuleLibrary(libTag: Element, library: LibraryEntity) {
|
||||
val eclipseSrcRoot = library.roots.firstOrNull { it.type.name == OrderRootType.SOURCES.name() }
|
||||
val rootsToRemove = HashSet<LibraryRoot>()
|
||||
if (eclipseSrcRoot != null && libTag.getChildren(IdeaSpecificSettings.SRCROOT_ATTR).any { rootTag ->
|
||||
val url = rootTag.getAttributeValue("url")
|
||||
val bindAttribute = rootTag.getAttributeValue(IdeaSpecificSettings.SRCROOT_BIND_ATTR)
|
||||
(bindAttribute == null || bindAttribute.toBoolean()) && url != eclipseSrcRoot.url.url && EPathUtil.areUrlsPointTheSame(url, eclipseSrcRoot.url.url)
|
||||
}) {
|
||||
rootsToRemove.add(eclipseSrcRoot)
|
||||
}
|
||||
|
||||
val rootsToAdd = ArrayList<LibraryRoot>()
|
||||
libTag.getChildren(IdeaSpecificSettings.SRCROOT_ATTR).mapTo(rootsToAdd) {
|
||||
LibraryRoot(virtualFileManager.fromUrl(it.getAttributeValue("url")!!),
|
||||
LibraryRootTypeId(OrderRootType.SOURCES.name()), LibraryRoot.InclusionOptions.ROOT_ITSELF)
|
||||
}
|
||||
libTag.getChildren(IdeaSpecificSettings.JAVADOCROOT_ATTR).mapTo(rootsToAdd) {
|
||||
LibraryRoot(virtualFileManager.fromUrl(it.getAttributeValue("url")!!),
|
||||
LibraryRootTypeId("JAVADOC"), LibraryRoot.InclusionOptions.ROOT_ITSELF)
|
||||
}
|
||||
|
||||
fun updateRoots(tagName: String, rootType: String) {
|
||||
libTag.getChildren(tagName).forEach { rootTag ->
|
||||
val root = expandMacroToPathMap.substitute(rootTag.getAttributeValue(IdeaSpecificSettings.PROJECT_RELATED)!!, SystemInfo.isFileSystemCaseSensitive)
|
||||
library.roots.forEach { libRoot ->
|
||||
if (libRoot.type.name == rootType && EPathUtil.areUrlsPointTheSame(root, libRoot.url.url)) {
|
||||
rootsToRemove.add(libRoot)
|
||||
rootsToAdd.add(LibraryRoot(virtualFileManager.fromUrl(root), LibraryRootTypeId(rootType), LibraryRoot.InclusionOptions.ROOT_ITSELF))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateRoots(IdeaSpecificSettings.RELATIVE_MODULE_SRC, OrderRootType.SOURCES.name())
|
||||
updateRoots(IdeaSpecificSettings.RELATIVE_MODULE_CLS, OrderRootType.CLASSES.name())
|
||||
updateRoots(IdeaSpecificSettings.RELATIVE_MODULE_JAVADOC, "JAVADOC")
|
||||
if (rootsToAdd.isNotEmpty() || rootsToRemove.isNotEmpty()) {
|
||||
builder.modifyEntity(ModifiableLibraryEntity::class.java, library) {
|
||||
roots = roots - rootsToRemove + rootsToAdd
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadJdkSettings(emlTag: Element) {
|
||||
val sdkItem = if (emlTag.getAttributeValue(IdeaSpecificSettings.INHERIT_JDK).toBoolean()) {
|
||||
ModuleDependencyItem.InheritedSdkDependency
|
||||
}
|
||||
else {
|
||||
emlTag.getAttributeValue("jdk")
|
||||
?.let { ModuleDependencyItem.SdkDependency(it, "JavaSDK") }
|
||||
}
|
||||
|
||||
if (sdkItem != null) {
|
||||
builder.modifyEntity(ModifiableModuleEntity::class.java, module) {
|
||||
val newDependencies = dependencies.map {
|
||||
when (it) {
|
||||
is ModuleDependencyItem.SdkDependency -> sdkItem
|
||||
ModuleDependencyItem.InheritedSdkDependency -> sdkItem
|
||||
else -> it
|
||||
}
|
||||
}
|
||||
dependencies = if (newDependencies.size < dependencies.size) listOf(ModuleDependencyItem.InheritedSdkDependency) + newDependencies
|
||||
else newDependencies
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadCompilerSettings(emlTag: Element) {
|
||||
val javaSettings = module.javaSettings ?: builder.addJavaModuleSettingsEntity(true, true, null, null, module, module.entitySource)
|
||||
builder.modifyEntity(ModifiableJavaModuleSettingsEntity::class.java, javaSettings) {
|
||||
val testOutputElement = emlTag.getChild(IdeaXml.OUTPUT_TEST_TAG)
|
||||
if (testOutputElement != null) {
|
||||
compilerOutputForTests = testOutputElement.getAttributeValue(IdeaXml.URL_ATTR)?.let { virtualFileManager.fromUrl(it) }
|
||||
}
|
||||
|
||||
val inheritedOutput = emlTag.getAttributeValue(JpsJavaModelSerializerExtension.INHERIT_COMPILER_OUTPUT_ATTRIBUTE)
|
||||
if (inheritedOutput.toBoolean()) {
|
||||
inheritedCompilerOutput = true
|
||||
}
|
||||
|
||||
excludeOutput = emlTag.getChild(IdeaXml.EXCLUDE_OUTPUT_TAG) != null
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadLanguageLevel(emlTag: Element) {
|
||||
val languageLevelAttribute = emlTag.getAttributeValue("LANGUAGE_LEVEL")
|
||||
if (languageLevelAttribute != null) {
|
||||
val languageLevelTag = JDOMUtil.write(Element("component").setAttribute("LANGUAGE_LEVEL", languageLevelAttribute))
|
||||
val customImlData = module.customImlData
|
||||
if (customImlData != null) {
|
||||
builder.modifyEntity(ModifiableModuleCustomImlDataEntity::class.java, customImlData) {
|
||||
rootManagerTagCustomData = languageLevelTag
|
||||
}
|
||||
}
|
||||
else {
|
||||
builder.addModuleCustomImlDataEntity(languageLevelTag, emptyMap(), module, module.entitySource)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadContentEntries(emlTag: Element, contentRoot: ContentRootEntity) {
|
||||
val entriesElements = emlTag.getChildren(IdeaXml.CONTENT_ENTRY_TAG)
|
||||
if (entriesElements.isNotEmpty()) {
|
||||
entriesElements.forEach {
|
||||
val url = virtualFileManager.fromUrl(it.getAttributeValue(IdeaXml.URL_ATTR)!!)
|
||||
val contentRootEntity = contentRoot.module.contentRoots.firstOrNull { it.url == url }
|
||||
?: builder.addContentRootEntity(url, emptyList(), emptyList(), module)
|
||||
loadContentEntry(it, contentRootEntity)
|
||||
}
|
||||
}
|
||||
else {
|
||||
loadContentEntry(emlTag, contentRoot)
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadContentEntry(contentEntryTag: Element, entity: ContentRootEntity) {
|
||||
val testSourceFolders = contentEntryTag.getChildren(IdeaXml.TEST_FOLDER_TAG).mapTo(HashSet()) {
|
||||
it.getAttributeValue(IdeaXml.URL_ATTR)
|
||||
}
|
||||
val packagePrefixes = contentEntryTag.getChildren(IdeaXml.PACKAGE_PREFIX_TAG).associateBy(
|
||||
{ it.getAttributeValue(IdeaXml.URL_ATTR)!! },
|
||||
{ it.getAttributeValue(IdeaXml.PACKAGE_PREFIX_VALUE_ATTR)!! }
|
||||
)
|
||||
for (sourceRoot in entity.sourceRoots) {
|
||||
val url = sourceRoot.url.url
|
||||
val isForTests = url in testSourceFolders
|
||||
if (isForTests != sourceRoot.tests) {
|
||||
builder.modifyEntity(ModifiableSourceRootEntity::class.java, sourceRoot) {
|
||||
tests = isForTests
|
||||
rootType = if (isForTests) JpsModuleRootModelSerializer.JAVA_TEST_ROOT_TYPE_ID else JpsModuleRootModelSerializer.JAVA_SOURCE_ROOT_TYPE_ID
|
||||
}
|
||||
}
|
||||
|
||||
val packagePrefix = packagePrefixes[url]
|
||||
if (packagePrefix != null) {
|
||||
val javaRootProperties = sourceRoot.asJavaSourceRoot()
|
||||
if (javaRootProperties != null) {
|
||||
builder.modifyEntity(ModifiableJavaSourceRootEntity::class.java, javaRootProperties) {
|
||||
this.packagePrefix = packagePrefix
|
||||
}
|
||||
}
|
||||
else {
|
||||
builder.addJavaSourceRootEntity(sourceRoot, false, packagePrefix)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val excludedUrls = contentEntryTag.getChildren(IdeaXml.EXCLUDE_FOLDER_TAG)
|
||||
.mapNotNull { it.getAttributeValue(IdeaXml.URL_ATTR) }
|
||||
.filter { FileUtil.isAncestor(entity.url.file!!, JpsPathUtil.urlToFile(it), false) }
|
||||
.map { virtualFileManager.fromPath(it) }
|
||||
if (excludedUrls.isNotEmpty()) {
|
||||
builder.modifyEntity(ModifiableContentRootEntity::class.java, entity) {
|
||||
this.excludedUrls = this.excludedUrls + excludedUrls
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
// 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.idea.eclipse.config
|
||||
|
||||
import com.intellij.openapi.components.PathMacroMap
|
||||
import com.intellij.openapi.roots.JavadocOrderRootType
|
||||
import com.intellij.openapi.roots.OrderRootType
|
||||
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar
|
||||
import com.intellij.openapi.util.JDOMUtil
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
import com.intellij.openapi.vfs.JarFileSystem
|
||||
import com.intellij.openapi.vfs.VfsUtilCore
|
||||
import com.intellij.workspaceModel.ide.impl.jps.serialization.getLegacyLibraryName
|
||||
import com.intellij.workspaceModel.ide.impl.virtualFile
|
||||
import com.intellij.workspaceModel.storage.WorkspaceEntity
|
||||
import com.intellij.workspaceModel.storage.bridgeEntities.*
|
||||
import org.jdom.Element
|
||||
import org.jetbrains.annotations.NonNls
|
||||
import org.jetbrains.idea.eclipse.IdeaXml.*
|
||||
import org.jetbrains.idea.eclipse.conversion.EPathUtil
|
||||
import org.jetbrains.idea.eclipse.conversion.IdeaSpecificSettings
|
||||
import org.jetbrains.jps.model.serialization.java.JpsJavaModelSerializerExtension
|
||||
|
||||
/**
|
||||
* Saves additional module configuration from [ModuleEntity] to *.eml file
|
||||
*/
|
||||
internal class EmlFileSaver(private val module: ModuleEntity,
|
||||
private val entities: Map<Class<out WorkspaceEntity>, List<WorkspaceEntity>>,
|
||||
private val pathShortener: ModulePathShortener,
|
||||
private val replacePathMacroMap: PathMacroMap) {
|
||||
fun saveEml(): Element? {
|
||||
val root = Element(COMPONENT_TAG)
|
||||
saveCustomJavaSettings(root)
|
||||
saveContentRoots(root)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val moduleLibraries = (entities[LibraryEntity::class.java] as List<LibraryEntity>? ?: emptyList()).associateBy { it.name }
|
||||
val libLevels = LinkedHashMap<String, String>()
|
||||
module.dependencies.forEach { dep ->
|
||||
when (dep) {
|
||||
is ModuleDependencyItem.Exportable.ModuleDependency -> {
|
||||
if (dep.scope != ModuleDependencyItem.DependencyScope.COMPILE) {
|
||||
root.addContent(Element("module").setAttribute("name", dep.module.name).setAttribute("scope", dep.scope.name))
|
||||
}
|
||||
}
|
||||
is ModuleDependencyItem.InheritedSdkDependency -> {
|
||||
//todo don't set if sdk is unresolved
|
||||
root.setAttribute(IdeaSpecificSettings.INHERIT_JDK, true.toString())
|
||||
}
|
||||
is ModuleDependencyItem.SdkDependency -> {
|
||||
//todo don't set if sdk is unresolved
|
||||
root.setAttribute("jdk", dep.sdkName)
|
||||
root.setAttribute("jdk_type", dep.sdkType)
|
||||
}
|
||||
is ModuleDependencyItem.Exportable.LibraryDependency -> {
|
||||
val libTag = Element("lib")
|
||||
val library = moduleLibraries[dep.library.name]
|
||||
val libName = getLegacyLibraryName(dep.library) ?: generateLibName(library)
|
||||
libTag.setAttribute("name", libName)
|
||||
libTag.setAttribute("scope", dep.scope.name)
|
||||
when (val tableId = dep.library.tableId) {
|
||||
is LibraryTableId.ModuleLibraryTableId -> {
|
||||
if (library != null) {
|
||||
val srcRoots = library.roots.filter { it.type.name == OrderRootType.SOURCES.name() }
|
||||
val eclipseUrl = srcRoots.firstOrNull()?.url?.url?.substringBefore(JarFileSystem.JAR_SEPARATOR)
|
||||
srcRoots.forEach {
|
||||
val url = it.url.url
|
||||
val srcTag = Element(IdeaSpecificSettings.SRCROOT_ATTR).setAttribute("url", url)
|
||||
if (!EPathUtil.areUrlsPointTheSame(url, eclipseUrl)) {
|
||||
srcTag.setAttribute(IdeaSpecificSettings.SRCROOT_BIND_ATTR, false.toString())
|
||||
}
|
||||
libTag.addContent(srcTag)
|
||||
}
|
||||
library.roots.filter { it.type.name == "JAVADOC" }.forEach {
|
||||
libTag.addContent(Element(IdeaSpecificSettings.JAVADOCROOT_ATTR).setAttribute("url", it.url.url))
|
||||
}
|
||||
saveModuleRelatedRoots(libTag, library, OrderRootType.SOURCES, IdeaSpecificSettings.RELATIVE_MODULE_SRC)
|
||||
saveModuleRelatedRoots(libTag, library, OrderRootType.CLASSES, IdeaSpecificSettings.RELATIVE_MODULE_CLS)
|
||||
saveModuleRelatedRoots(libTag, library, JavadocOrderRootType.getInstance(), IdeaSpecificSettings.RELATIVE_MODULE_JAVADOC)
|
||||
}
|
||||
}
|
||||
is LibraryTableId.ProjectLibraryTableId -> libLevels[dep.library.name] = LibraryTablesRegistrar.PROJECT_LEVEL
|
||||
is LibraryTableId.GlobalLibraryTableId -> {
|
||||
if (tableId.level != LibraryTablesRegistrar.APPLICATION_LEVEL) {
|
||||
libLevels[dep.library.name] = tableId.level
|
||||
}
|
||||
}
|
||||
}
|
||||
if (libTag.children.isNotEmpty() || dep.scope != ModuleDependencyItem.DependencyScope.COMPILE) {
|
||||
root.addContent(libTag)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (libLevels.isNotEmpty()) {
|
||||
val levelsTag = Element("levels")
|
||||
for ((name, level) in libLevels) {
|
||||
levelsTag.addContent(Element("level").setAttribute("name", name).setAttribute("value", level))
|
||||
}
|
||||
root.addContent(levelsTag)
|
||||
}
|
||||
|
||||
replacePathMacroMap.substitute(root, SystemInfo.isFileSystemCaseSensitive)
|
||||
return if (JDOMUtil.isEmpty(root)) null else root
|
||||
}
|
||||
|
||||
private fun saveModuleRelatedRoots(libTag: Element, library: LibraryEntity, type: OrderRootType, tagName: @NonNls String) {
|
||||
library.roots.filter { it.type.name == type.name() }.forEach {
|
||||
if (pathShortener.isUnderContentRoots(it.url)) {
|
||||
libTag.addContent(Element(tagName).setAttribute(IdeaSpecificSettings.PROJECT_RELATED, it.url.url))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateLibName(library: LibraryEntity?): String {
|
||||
val firstRoot = library?.roots?.firstOrNull { it.type.name == OrderRootType.CLASSES.name() }?.url
|
||||
val file = firstRoot?.virtualFile
|
||||
val fileForJar = JarFileSystem.getInstance().getVirtualFileForJar(file)
|
||||
if (fileForJar != null) return fileForJar.name
|
||||
return file?.name ?: "Empty Library"
|
||||
}
|
||||
|
||||
private fun saveContentRoots(root: Element) {
|
||||
module.contentRoots.forEach { contentRoot ->
|
||||
val contentRootTag = Element(CONTENT_ENTRY_TAG).setAttribute(URL_ATTR, contentRoot.url.url)
|
||||
contentRoot.sourceRoots.forEach { sourceRoot ->
|
||||
if (sourceRoot.tests) {
|
||||
contentRootTag.addContent(Element(TEST_FOLDER_TAG).setAttribute(URL_ATTR, sourceRoot.url.url))
|
||||
}
|
||||
val packagePrefix = sourceRoot.asJavaSourceRoot()?.packagePrefix
|
||||
if (!packagePrefix.isNullOrEmpty()) {
|
||||
contentRootTag.addContent(Element(PACKAGE_PREFIX_TAG).setAttribute(URL_ATTR, sourceRoot.url.url)
|
||||
.setAttribute(PACKAGE_PREFIX_VALUE_ATTR, packagePrefix))
|
||||
}
|
||||
}
|
||||
val rootFile = contentRoot.url.virtualFile
|
||||
contentRoot.excludedUrls.forEach { excluded ->
|
||||
val excludedFile = excluded.virtualFile
|
||||
if (rootFile == null || excludedFile == null || VfsUtilCore.isAncestor(rootFile, excludedFile, false)) {
|
||||
contentRootTag.addContent(Element(EXCLUDE_FOLDER_TAG).setAttribute(URL_ATTR, excluded.url))
|
||||
}
|
||||
}
|
||||
if (!JDOMUtil.isEmpty(contentRootTag)) {
|
||||
root.addContent(contentRootTag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveCustomJavaSettings(root: Element) {
|
||||
module.javaSettings?.let { javaSettings ->
|
||||
javaSettings.compilerOutputForTests?.let { testOutput ->
|
||||
root.addContent(Element(OUTPUT_TEST_TAG).setAttribute(URL_ATTR, testOutput.url))
|
||||
}
|
||||
if (javaSettings.inheritedCompilerOutput) {
|
||||
root.setAttribute(JpsJavaModelSerializerExtension.INHERIT_COMPILER_OUTPUT_ATTRIBUTE, true.toString())
|
||||
}
|
||||
if (javaSettings.excludeOutput) {
|
||||
root.addContent(Element(EXCLUDE_OUTPUT_TAG))
|
||||
}
|
||||
}
|
||||
|
||||
module.customImlData?.rootManagerTagCustomData?.let { languageLevelTagString ->
|
||||
val tag = JDOMUtil.load(languageLevelTagString)
|
||||
tag.getAttributeValue("LANGUAGE_LEVEL")?.let {
|
||||
root.setAttribute("LANGUAGE_LEVEL", it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
// 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.idea.eclipse.config
|
||||
|
||||
import com.intellij.workspaceModel.ide.JpsFileDependentEntitySource
|
||||
import com.intellij.workspaceModel.ide.JpsFileEntitySource
|
||||
import com.intellij.workspaceModel.storage.EntitySource
|
||||
import com.intellij.workspaceModel.storage.VirtualFileUrl
|
||||
import com.intellij.workspaceModel.storage.WorkspaceEntityStorage
|
||||
import com.intellij.workspaceModel.storage.WorkspaceEntityStorageDiffBuilder
|
||||
import com.intellij.workspaceModel.storage.bridgeEntities.ModuleEntity
|
||||
import com.intellij.workspaceModel.storage.impl.EntityDataDelegation
|
||||
import com.intellij.workspaceModel.storage.impl.ModifiableWorkspaceEntityBase
|
||||
import com.intellij.workspaceModel.storage.impl.WorkspaceEntityBase
|
||||
import com.intellij.workspaceModel.storage.impl.WorkspaceEntityData
|
||||
import com.intellij.workspaceModel.storage.impl.references.ManyToOne
|
||||
import com.intellij.workspaceModel.storage.impl.references.MutableOneToOneChild
|
||||
import com.intellij.workspaceModel.storage.impl.references.OneToOneParent
|
||||
|
||||
data class EclipseProjectFile(
|
||||
val classpathFile: VirtualFileUrl,
|
||||
val internalSource: JpsFileEntitySource
|
||||
) : EntitySource, JpsFileDependentEntitySource {
|
||||
override val originalSource: JpsFileEntitySource
|
||||
get() = internalSource
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores data from [EclipseModuleManagerImpl] in workspace model
|
||||
*/
|
||||
class EclipseProjectPropertiesEntity(
|
||||
val variablePaths: Map<String, String>,
|
||||
val eclipseUrls: Set<VirtualFileUrl>,
|
||||
val unknownCons: Set<String>,
|
||||
val knownCons: Set<String>,
|
||||
val forceConfigureJdk: Boolean,
|
||||
val expectedModuleSourcePlace: Int,
|
||||
val srcPlace: Map<String, Int>,
|
||||
val invalidJdk: String?
|
||||
|
||||
) : WorkspaceEntityBase() {
|
||||
val module: ModuleEntity by moduleDelegate
|
||||
|
||||
companion object {
|
||||
val moduleDelegate = ManyToOne.NotNull<ModuleEntity, EclipseProjectPropertiesEntity>(ModuleEntity::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused") //created via reflection in ClassConversion.entityToEntityData
|
||||
class EclipseProjectPropertiesEntityData : WorkspaceEntityData<EclipseProjectPropertiesEntity>() {
|
||||
lateinit var variablePaths: Map<String, String>
|
||||
lateinit var eclipseUrls: Set<VirtualFileUrl>
|
||||
lateinit var unknownCons: Set<String>
|
||||
lateinit var knownCons: Set<String>
|
||||
var forceConfigureJdk = false
|
||||
var expectedModuleSourcePlace = 0
|
||||
lateinit var srcPlace: Map<String, Int>
|
||||
var invalidJdk: String? = null
|
||||
|
||||
override fun createEntity(snapshot: WorkspaceEntityStorage): EclipseProjectPropertiesEntity {
|
||||
return EclipseProjectPropertiesEntity(variablePaths, eclipseUrls, unknownCons, knownCons, forceConfigureJdk, expectedModuleSourcePlace, srcPlace, invalidJdk).also { addMetaData(it, snapshot) }
|
||||
}
|
||||
}
|
||||
|
||||
class ModifiableEclipseProjectPropertiesEntity : ModifiableWorkspaceEntityBase<EclipseProjectPropertiesEntity>() {
|
||||
var variablePaths: MutableMap<String, String> by EntityDataDelegation()
|
||||
var eclipseUrls: MutableSet<VirtualFileUrl> by EntityDataDelegation()
|
||||
var unknownCons: MutableSet<String> by EntityDataDelegation()
|
||||
var knownCons: MutableSet<String> by EntityDataDelegation()
|
||||
var forceConfigureJdk: Boolean by EntityDataDelegation()
|
||||
var expectedModuleSourcePlace: Int by EntityDataDelegation()
|
||||
var srcPlace: MutableMap<String, Int> by EntityDataDelegation()
|
||||
var invalidJdk: String? by EntityDataDelegation()
|
||||
var module: ModuleEntity by MutableOneToOneChild.NotNull(EclipseProjectPropertiesEntity::class.java, ModuleEntity::class.java, true)
|
||||
}
|
||||
|
||||
fun WorkspaceEntityStorageDiffBuilder.addEclipseProjectPropertiesEntity(module: ModuleEntity, source: EntitySource)
|
||||
= addEntity(ModifiableEclipseProjectPropertiesEntity::class.java, source) {
|
||||
this.module = module
|
||||
variablePaths = LinkedHashMap()
|
||||
eclipseUrls = LinkedHashSet()
|
||||
unknownCons = LinkedHashSet()
|
||||
knownCons = LinkedHashSet()
|
||||
srcPlace = LinkedHashMap()
|
||||
}
|
||||
|
||||
private val eclipsePropertiesDelegate = OneToOneParent.Nullable<ModuleEntity, EclipseProjectPropertiesEntity>(EclipseProjectPropertiesEntity::class.java, false)
|
||||
val ModuleEntity.eclipseProperties: EclipseProjectPropertiesEntity? by eclipsePropertiesDelegate
|
||||
|
||||
fun ModifiableEclipseProjectPropertiesEntity.setVariable(kind: String, name: String, path: String) {
|
||||
variablePaths[kind + path] = name
|
||||
}
|
||||
|
||||
fun EclipseProjectPropertiesEntity.getVariable(kind: String, path: String): String? = variablePaths[kind + path]
|
||||
@@ -0,0 +1,275 @@
|
||||
// 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.idea.eclipse.config
|
||||
|
||||
import com.intellij.openapi.application.PathMacros
|
||||
import com.intellij.openapi.components.ExpandMacroToPathMap
|
||||
import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.openapi.roots.impl.ProjectRootManagerImpl
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.util.io.OSAgnosticPathUtil
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.openapi.vfs.*
|
||||
import com.intellij.openapi.vfs.ex.http.HttpFileSystem
|
||||
import com.intellij.workspaceModel.ide.JpsProjectConfigLocation
|
||||
import com.intellij.workspaceModel.ide.impl.virtualFile
|
||||
import com.intellij.workspaceModel.storage.VirtualFileUrl
|
||||
import com.intellij.workspaceModel.storage.VirtualFileUrlManager
|
||||
import com.intellij.workspaceModel.storage.append
|
||||
import com.intellij.workspaceModel.storage.bridgeEntities.ContentRootEntity
|
||||
import com.intellij.workspaceModel.storage.bridgeEntities.LibraryRoot
|
||||
import com.intellij.workspaceModel.storage.bridgeEntities.ModuleEntity
|
||||
import org.jetbrains.idea.eclipse.AbstractEclipseClasspathReader
|
||||
import org.jetbrains.idea.eclipse.EPathCommonUtil
|
||||
import org.jetbrains.idea.eclipse.EclipseXml
|
||||
import org.jetbrains.idea.eclipse.conversion.EJavadocUtil
|
||||
import org.jetbrains.jps.util.JpsPathUtil
|
||||
import java.io.File
|
||||
|
||||
private val LOG = logger<EclipseModuleRootsSerializer>()
|
||||
|
||||
internal fun convertToJavadocUrl(originalPath: String,
|
||||
moduleEntity: ModuleEntity,
|
||||
relativePathResolver: ModuleRelativePathResolver,
|
||||
virtualUrlManager: VirtualFileUrlManager): VirtualFileUrl {
|
||||
val javadocPath = if (!SystemInfo.isWindows) {
|
||||
originalPath.replaceFirst(EclipseXml.FILE_PROTOCOL, EclipseXml.FILE_PROTOCOL + "/")
|
||||
}
|
||||
else {
|
||||
originalPath
|
||||
}
|
||||
|
||||
if (javadocPath.startsWith(EclipseXml.FILE_PROTOCOL)) {
|
||||
val path = javadocPath.removePrefix(EclipseXml.FILE_PROTOCOL)
|
||||
if (File(path).exists()) {
|
||||
return virtualUrlManager.fromUrl(pathToUrl(path))
|
||||
}
|
||||
}
|
||||
else {
|
||||
val protocol = VirtualFileManager.extractProtocol(javadocPath)
|
||||
if (protocol == HttpFileSystem.getInstance().protocol) {
|
||||
return virtualUrlManager.fromUrl(javadocPath)
|
||||
}
|
||||
else if (javadocPath.startsWith(EclipseXml.JAR_PREFIX)) {
|
||||
val jarJavadocPath = javadocPath.removePrefix(EclipseXml.JAR_PREFIX)
|
||||
if (jarJavadocPath.startsWith(EclipseXml.PLATFORM_PROTOCOL)) {
|
||||
val relativeToPlatform = jarJavadocPath.substring(EclipseXml.PLATFORM_PROTOCOL.length + "resource".length) // starts with leading /
|
||||
val currentRoot = moduleEntity.mainContentRoot?.url?.virtualFile
|
||||
val basePath = currentRoot?.parent?.path ?:
|
||||
JpsPathUtil.urlToPath((moduleEntity.entitySource as EclipseProjectFile).internalSource.projectLocation.baseDirectoryUrl.url)
|
||||
val currentModulePath = basePath + relativeToPlatform
|
||||
if (EJavadocUtil.isJarFileExist(currentModulePath)) {
|
||||
return virtualUrlManager.fromUrl(VirtualFileManager.constructUrl(JarFileSystem.PROTOCOL, currentModulePath))
|
||||
}
|
||||
else {
|
||||
val moduleName = EPathCommonUtil.getRelativeModuleName(relativeToPlatform)
|
||||
val relativeToModulePathWithJarSuffix = EPathCommonUtil.getRelativeToModulePath(relativeToPlatform)
|
||||
val relativeToModulePath = EJavadocUtil.stripPathInsideJar(relativeToModulePathWithJarSuffix)
|
||||
var url: String? = null
|
||||
if (moduleName != moduleEntity.name) {
|
||||
url = relativePathResolver.resolve(moduleName, relativeToModulePath)
|
||||
}
|
||||
if (url != null) {
|
||||
assert(relativeToModulePathWithJarSuffix != null)
|
||||
assert(relativeToModulePath != null)
|
||||
if (relativeToModulePath!!.length < relativeToModulePathWithJarSuffix!!.length) {
|
||||
url += relativeToModulePathWithJarSuffix.substring(relativeToModulePath.length)
|
||||
}
|
||||
return virtualUrlManager.fromUrl(VirtualFileManager.constructUrl(JarFileSystem.PROTOCOL, VfsUtil.urlToPath(url)))
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (jarJavadocPath.startsWith(EclipseXml.FILE_PROTOCOL)) {
|
||||
val localFile = jarJavadocPath.substring(EclipseXml.FILE_PROTOCOL.length)
|
||||
if (EJavadocUtil.isJarFileExist(localFile)) {
|
||||
return virtualUrlManager.fromUrl(VirtualFileManager.constructUrl(JarFileSystem.PROTOCOL, localFile))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return virtualUrlManager.fromUrl(javadocPath)
|
||||
}
|
||||
|
||||
internal fun convertToEclipseJavadocPath(javadocRoot: VirtualFileUrl,
|
||||
module: ModuleEntity,
|
||||
projectLocation: JpsProjectConfigLocation,
|
||||
pathShortener: ModulePathShortener): String? {
|
||||
val javadocUrl = javadocRoot.url
|
||||
val protocol = VirtualFileManager.extractProtocol(javadocUrl)
|
||||
if (protocol != HttpFileSystem.getInstance().protocol) {
|
||||
val path = VfsUtil.urlToPath(javadocUrl)
|
||||
val contentRoot = module.mainContentRoot?.url?.virtualFile
|
||||
val baseDir = if (contentRoot != null) contentRoot.parent else projectLocation.baseDirectoryUrl.virtualFile
|
||||
if (protocol == JarFileSystem.getInstance().protocol) {
|
||||
val javadocFile = JarFileSystem.getInstance().getVirtualFileForJar(javadocRoot.virtualFile)
|
||||
if (javadocFile != null) {
|
||||
val relativeUrl: String? = if (contentRoot != null && baseDir != null && VfsUtilCore.isAncestor(contentRoot, javadocFile, false)) {
|
||||
"/" + VfsUtilCore.getRelativePath(javadocFile, baseDir, '/')
|
||||
}
|
||||
else {
|
||||
pathShortener.shortenPath(javadocRoot)
|
||||
}
|
||||
if (relativeUrl != null) {
|
||||
var javadocPath = javadocUrl
|
||||
if (!javadocPath.contains(JarFileSystem.JAR_SEPARATOR)) {
|
||||
javadocPath = StringUtil.trimEnd(javadocPath, "/") + JarFileSystem.JAR_SEPARATOR
|
||||
}
|
||||
return EclipseXml.JAR_PREFIX + EclipseXml.PLATFORM_PROTOCOL + "resource" + relativeUrl +
|
||||
javadocPath.substring(javadocFile.url.length - 1)
|
||||
}
|
||||
else {
|
||||
return EclipseXml.JAR_PREFIX + EclipseXml.FILE_PROTOCOL + path.removePrefix("/")
|
||||
}
|
||||
}
|
||||
else {
|
||||
return EclipseXml.JAR_PREFIX + EclipseXml.FILE_PROTOCOL + path.removePrefix("/")
|
||||
}
|
||||
}
|
||||
else if (File(path).exists()) {
|
||||
return EclipseXml.FILE_PROTOCOL + path.removePrefix("/")
|
||||
}
|
||||
}
|
||||
return javadocUrl
|
||||
}
|
||||
|
||||
|
||||
internal fun convertToRootUrl(path: String, virtualUrlManager: VirtualFileUrlManager): VirtualFileUrl {
|
||||
val url = pathToUrl(path)
|
||||
val localFile = VirtualFileManager.getInstance().findFileByUrl(path)
|
||||
if (localFile != null) {
|
||||
val jarFile = JarFileSystem.getInstance().getJarRootForLocalFile(localFile)
|
||||
if (jarFile != null) {
|
||||
return virtualUrlManager.fromUrl(jarFile.url)
|
||||
}
|
||||
}
|
||||
|
||||
return virtualUrlManager.fromUrl(url)
|
||||
}
|
||||
|
||||
internal fun pathToUrl(path: String): String = JpsPathUtil.pathToUrl(FileUtil.toSystemIndependentName(path))
|
||||
|
||||
internal fun convertVariablePathToUrl(pathMap: ExpandMacroToPathMap,
|
||||
path: String?,
|
||||
varStart: Int,
|
||||
virtualUrlManager: VirtualFileUrlManager): VirtualFileUrl {
|
||||
val variable = AbstractEclipseClasspathReader.createEPathVariable(path, varStart)
|
||||
val url = pathToUrl(AbstractEclipseClasspathReader.getVariableRelatedPath(variable.variable, variable.relatedPath))
|
||||
return convertToRootUrl(pathMap.substitute(url, SystemInfo.isFileSystemCaseSensitive), virtualUrlManager)
|
||||
}
|
||||
|
||||
internal fun convertRelativePathToUrl(path: String,
|
||||
contentRootEntity: ContentRootEntity,
|
||||
pathResolver: ModuleRelativePathResolver,
|
||||
virtualUrlManager: VirtualFileUrlManager): VirtualFileUrl {
|
||||
if (!File(path).exists()) {
|
||||
if (path.startsWith("/")) {
|
||||
//relative to other project
|
||||
val moduleName = EPathCommonUtil.getRelativeModuleName(path)
|
||||
val relativeToRootPath = EPathCommonUtil.getRelativeToModulePath(path)
|
||||
if (moduleName != contentRootEntity.module.name) {
|
||||
val url = pathResolver.resolve(moduleName, relativeToRootPath)
|
||||
if (url != null) {
|
||||
return virtualUrlManager.fromUrl(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
val url = findFileUnderContentRoot(path, contentRootEntity, virtualUrlManager)
|
||||
if (url != null) {
|
||||
return url
|
||||
}
|
||||
}
|
||||
}
|
||||
return convertToRootUrl(path, virtualUrlManager)
|
||||
}
|
||||
|
||||
private fun findFileUnderContentRoot(path: String,
|
||||
contentRootEntity: ContentRootEntity,
|
||||
virtualUrlManager: VirtualFileUrlManager): VirtualFileUrl? {
|
||||
val root = contentRootEntity.url.file
|
||||
val mainRoot = if (root?.exists() == true) root
|
||||
else contentRootEntity.module.mainContentRoot?.url?.file
|
||||
val file = File(mainRoot, path)
|
||||
return if (file.exists()) convertToRootUrl(file.absolutePath, virtualUrlManager) else null
|
||||
}
|
||||
|
||||
internal val ModuleEntity.mainContentRoot: ContentRootEntity?
|
||||
get() = contentRoots.firstOrNull {
|
||||
VirtualFileManager.getInstance().findFileByUrl(it.url.url)?.findChild(EclipseXml.PROJECT_FILE) != null
|
||||
}
|
||||
|
||||
internal fun getStorageRoot(imlFileUrl: VirtualFileUrl, customDir: String?, virtualFileManager: VirtualFileUrlManager): VirtualFileUrl {
|
||||
val moduleRoot = imlFileUrl.parent!!
|
||||
if (customDir == null) return moduleRoot
|
||||
if (OSAgnosticPathUtil.isAbsolute(customDir)) {
|
||||
return virtualFileManager.fromPath(customDir)
|
||||
}
|
||||
return moduleRoot.append(customDir)
|
||||
}
|
||||
|
||||
internal fun convertToEclipsePath(fileUrl: VirtualFileUrl,
|
||||
moduleEntity: ModuleEntity,
|
||||
entitySource: EclipseProjectFile,
|
||||
pathShortener: ModulePathShortener): String? {
|
||||
val contentRoot = moduleEntity.mainContentRoot?.let { VirtualFileManager.getInstance().findFileByUrl(it.url.url) }
|
||||
var file = fileUrl.virtualFile
|
||||
val url = fileUrl.url
|
||||
if (file != null) {
|
||||
LOG.assertTrue(file.isValid)
|
||||
if (file.fileSystem is JarFileSystem) {
|
||||
val jarFile = JarFileSystem.getInstance().getVirtualFileForJar(file)
|
||||
if (jarFile == null) {
|
||||
LOG.error("Url: '$url'; file: $file")
|
||||
return ProjectRootManagerImpl.extractLocalPath(url)
|
||||
}
|
||||
file = jarFile
|
||||
}
|
||||
if (contentRoot != null && VfsUtilCore.isAncestor(contentRoot, file, false)) { //inside current project
|
||||
return VfsUtilCore.getRelativePath(file, contentRoot, '/')
|
||||
}
|
||||
else {
|
||||
val path = pathShortener.shortenPath(fileUrl)
|
||||
if (path != null) {
|
||||
return path
|
||||
}
|
||||
}
|
||||
}
|
||||
else { //try to avoid absolute path for deleted file
|
||||
if (contentRoot != null) {
|
||||
val rootUrl = contentRoot.url
|
||||
if (url.startsWith(rootUrl) && url.length > rootUrl.length) {
|
||||
return url.substring(rootUrl.length + 1) //without leading /
|
||||
}
|
||||
}
|
||||
val projectBaseDir = if (contentRoot != null) contentRoot.parent else entitySource.internalSource.projectLocation.baseDirectoryUrl.virtualFile!!
|
||||
val projectUrl = projectBaseDir.url
|
||||
if (url.startsWith(projectUrl)) {
|
||||
return url.substring(projectUrl.length) //leading /
|
||||
}
|
||||
val path = VfsUtilCore.urlToPath(url)
|
||||
val projectPath = projectBaseDir.path
|
||||
if (path.startsWith(projectPath)) {
|
||||
return ProjectRootManagerImpl.extractLocalPath(path.substring(projectPath.length))
|
||||
}
|
||||
}
|
||||
return ProjectRootManagerImpl.extractLocalPath(url) //absolute path
|
||||
}
|
||||
|
||||
fun convertToEclipsePathWithVariable(roots: List<LibraryRoot>): String? {
|
||||
roots.forEach { root ->
|
||||
var filePath = VirtualFileManager.extractPath(root.url.url)
|
||||
val jarSeparatorIdx = filePath.indexOf(JarFileSystem.JAR_SEPARATOR)
|
||||
if (jarSeparatorIdx > -1) {
|
||||
filePath = filePath.substring(0, jarSeparatorIdx)
|
||||
}
|
||||
val pathMacros = PathMacros.getInstance().userMacros
|
||||
for (name in pathMacros.keys) {
|
||||
val path = FileUtil.toSystemIndependentName(pathMacros[name]!!)
|
||||
if (filePath.startsWith("$path/")) {
|
||||
val substr = filePath.substring(path.length)
|
||||
return name + if (substr.startsWith("/") || substr.isEmpty()) substr else "/$substr"
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
// 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.idea.eclipse.config
|
||||
|
||||
import com.intellij.openapi.module.impl.getModuleNameByFilePath
|
||||
import com.intellij.workspaceModel.ide.impl.jps.serialization.JpsFileContentReader
|
||||
import com.intellij.workspaceModel.ide.impl.jps.serialization.JpsModuleListSerializer
|
||||
import com.intellij.workspaceModel.storage.VirtualFileUrl
|
||||
import com.intellij.workspaceModel.storage.VirtualFileUrlManager
|
||||
import com.intellij.workspaceModel.storage.WorkspaceEntityStorage
|
||||
import com.intellij.workspaceModel.storage.bridgeEntities.ContentRootEntity
|
||||
import org.jetbrains.jps.model.serialization.JpsProjectLoader
|
||||
import org.jetbrains.jps.util.JpsPathUtil
|
||||
|
||||
class ModuleRelativePathResolver(private val moduleListSerializer: JpsModuleListSerializer?,
|
||||
private val reader: JpsFileContentReader,
|
||||
private val virtualFileManager: VirtualFileUrlManager) {
|
||||
private val moduleFileUrls by lazy {
|
||||
(moduleListSerializer?.loadFileList(reader, virtualFileManager) ?: emptyList()).associateBy(
|
||||
{ getModuleNameByFilePath(JpsPathUtil.urlToPath(it.first.url)) },
|
||||
{ it.first }
|
||||
)
|
||||
}
|
||||
|
||||
fun resolve(moduleName: String, relativePath: String?): String? {
|
||||
val moduleFile = moduleFileUrls[moduleName] ?: return null
|
||||
val component = reader.loadComponent(moduleFile.url, "DeprecatedModuleOptionManager", null)
|
||||
val baseDir = component?.getChildren("option")
|
||||
?.firstOrNull { it.getAttributeValue("key") == JpsProjectLoader.CLASSPATH_DIR_ATTRIBUTE }
|
||||
?.getAttributeValue("value")
|
||||
val storageRoot = getStorageRoot(moduleFile, baseDir, virtualFileManager)
|
||||
if (relativePath.isNullOrEmpty()) return storageRoot.url
|
||||
return "${storageRoot.url}/${relativePath.removePrefix("/")}"
|
||||
}
|
||||
}
|
||||
|
||||
class ModulePathShortener(private val storage: WorkspaceEntityStorage) {
|
||||
private val contentRootsToModule by lazy {
|
||||
storage.entities(ContentRootEntity::class.java).associateBy({ it.url }, { it.module.name })
|
||||
}
|
||||
|
||||
fun shortenPath(url: VirtualFileUrl): String? {
|
||||
var current: VirtualFileUrl? = url
|
||||
val map = contentRootsToModule
|
||||
while (current != null) {
|
||||
val moduleName = map[current]
|
||||
if (moduleName != null) {
|
||||
return "/$moduleName${url.url.substring(current.url.length)}"
|
||||
}
|
||||
current = current.parent
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun isUnderContentRoots(url: VirtualFileUrl): Boolean {
|
||||
val map = contentRootsToModule
|
||||
return generateSequence(url, {it.parent}).any { it in map }
|
||||
}
|
||||
}
|
||||
@@ -117,7 +117,7 @@ public final class EJavadocUtil {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String stripPathInsideJar(@Nullable String relativeToModulePathWithJarSuffix) {
|
||||
public static String stripPathInsideJar(@Nullable String relativeToModulePathWithJarSuffix) {
|
||||
String relativeToModulePath = relativeToModulePathWithJarSuffix;
|
||||
if (relativeToModulePath != null) {
|
||||
int jarSufIdx = relativeToModulePathWithJarSuffix.indexOf(JarFileSystem.JAR_SEPARATOR);
|
||||
@@ -128,7 +128,7 @@ public final class EJavadocUtil {
|
||||
return relativeToModulePath;
|
||||
}
|
||||
|
||||
static boolean isJarFileExist(String path) {
|
||||
public static boolean isJarFileExist(String path) {
|
||||
final int jarSufIdx = path.indexOf(JarFileSystem.JAR_SEPARATOR);
|
||||
if (jarSufIdx != -1) {
|
||||
path = path.substring(0, jarSufIdx);
|
||||
@@ -188,10 +188,10 @@ public final class EJavadocUtil {
|
||||
setupAttributes(orderEntry, s -> toEclipseJavadocPath(model, s), JAVADOC_LOCATION, libraryOrderEntry.getRootUrls(JavadocOrderRootType.getInstance()));
|
||||
}
|
||||
|
||||
static void setupAttributes(Element orderEntry,
|
||||
Function<? super String, String> fun,
|
||||
String attributeName,
|
||||
String[] roots) {
|
||||
public static <T> void setupAttributes(Element orderEntry,
|
||||
Function<? super T, String> fun,
|
||||
String attributeName,
|
||||
T[] roots) {
|
||||
final List<String> eclipseUrls = new ArrayList<>();
|
||||
if (roots.length > 0) {
|
||||
eclipseUrls.add(fun.fun(roots[0]));
|
||||
|
||||
+1
-1
@@ -271,7 +271,7 @@ public class EclipseClasspathReader extends AbstractEclipseClasspathReader<Modif
|
||||
return lib;
|
||||
}
|
||||
|
||||
static String getJunitClsUrl(final boolean version4) {
|
||||
public static String getJunitClsUrl(final boolean version4) {
|
||||
String url = version4 ? JavaSdkUtil.getJunit4JarPath() : JavaSdkUtil.getJunit3JarPath();
|
||||
final VirtualFile localFile = VirtualFileManager.getInstance().findFileByUrl(pathToUrl(url));
|
||||
if (localFile != null) {
|
||||
|
||||
+20
-12
@@ -61,7 +61,7 @@ public class EclipseClasspathWriter {
|
||||
}
|
||||
}
|
||||
for (String support : eclipseModuleManager.getUsedCons()) {
|
||||
addOrderEntry(EclipseXml.CON_KIND, support, classpathElement, eclipseModuleManager.getSrcPlace(support));
|
||||
addOrderEntry(EclipseXml.CON_KIND, support, classpathElement, eclipseModuleManager.getSrcPlace(support), myOldEntries);
|
||||
}
|
||||
setAttributeIfAbsent(addOrderEntry(EclipseXml.OUTPUT_KIND, outputPath, classpathElement), EclipseXml.PATH_ATTR, EclipseXml.BIN_DIR);
|
||||
|
||||
@@ -84,13 +84,13 @@ public class EclipseClasspathWriter {
|
||||
}
|
||||
}
|
||||
int index = eclipseModuleManager.getSrcPlace(srcUrl);
|
||||
addOrderEntry(EclipseXml.SRC_KIND, relativePath, classpathRoot, shouldPlaceSeparately && index != -1 ? index : -1);
|
||||
addOrderEntry(EclipseXml.SRC_KIND, relativePath, classpathRoot, shouldPlaceSeparately && index != -1 ? index : -1, myOldEntries);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (entry instanceof ModuleOrderEntry) {
|
||||
final String path = '/' + ((ModuleOrderEntry)entry).getModuleName();
|
||||
final Element oldElement = getOldElement(EclipseXml.SRC_KIND, path);
|
||||
final Element oldElement = getOldElement(EclipseXml.SRC_KIND, path, myOldEntries);
|
||||
Element orderEntry = addOrderEntry(EclipseXml.SRC_KIND, path, classpathRoot);
|
||||
if (oldElement == null) {
|
||||
setAttributeIfAbsent(orderEntry, EclipseXml.COMBINEACCESSRULES_ATTR, EclipseXml.FALSE_VALUE);
|
||||
@@ -222,11 +222,15 @@ public class EclipseClasspathWriter {
|
||||
}
|
||||
|
||||
private Element addOrderEntry(String kind, String path, Element classpathRoot) {
|
||||
return addOrderEntry(kind, path, classpathRoot, -1);
|
||||
return addOrderEntry(kind, path, classpathRoot, myOldEntries);
|
||||
}
|
||||
|
||||
private Element addOrderEntry(@NotNull String kind, String path, Element classpathRoot, int index) {
|
||||
Element element = getOldElement(kind, path);
|
||||
public static Element addOrderEntry(String kind, String path, Element classpathRoot, Map<String, Element> oldEntries) {
|
||||
return addOrderEntry(kind, path, classpathRoot, -1, oldEntries);
|
||||
}
|
||||
|
||||
public static Element addOrderEntry(@NotNull String kind, String path, Element classpathRoot, int index, Map<String, Element> oldEntries) {
|
||||
Element element = getOldElement(kind, path, oldEntries);
|
||||
if (element != null) {
|
||||
Element clonedElement = element.clone();
|
||||
if (index == -1 || index >= classpathRoot.getContentSize()) {
|
||||
@@ -252,19 +256,23 @@ public class EclipseClasspathWriter {
|
||||
return orderEntry;
|
||||
}
|
||||
|
||||
private Element getOldElement(@NotNull String kind, String path) {
|
||||
return myOldEntries.get(kind + getJREKey(path));
|
||||
public static Element getOldElement(@NotNull String kind, String path, Map<String, Element> entries) {
|
||||
return entries.get(kind + getJREKey(path));
|
||||
}
|
||||
|
||||
private static String getJREKey(String path) {
|
||||
public static String getJREKey(String path) {
|
||||
return path.startsWith(EclipseXml.JRE_CONTAINER) ? EclipseXml.JRE_CONTAINER : path;
|
||||
}
|
||||
|
||||
private static void setExported(Element orderEntry, ExportableOrderEntry dependency) {
|
||||
setOrRemoveAttribute(orderEntry, EclipseXml.EXPORTED_ATTR, dependency.isExported() ? EclipseXml.TRUE_VALUE : null);
|
||||
setExported(orderEntry, dependency.isExported());
|
||||
}
|
||||
|
||||
private static void setOrRemoveAttribute(@NotNull Element element, @NotNull String name, @Nullable String value) {
|
||||
public static void setExported(Element orderEntry, boolean exported) {
|
||||
setOrRemoveAttribute(orderEntry, EclipseXml.EXPORTED_ATTR, exported ? EclipseXml.TRUE_VALUE : null);
|
||||
}
|
||||
|
||||
public static void setOrRemoveAttribute(@NotNull Element element, @NotNull String name, @Nullable String value) {
|
||||
if (value == null) {
|
||||
element.removeAttribute(name);
|
||||
}
|
||||
@@ -273,7 +281,7 @@ public class EclipseClasspathWriter {
|
||||
}
|
||||
}
|
||||
|
||||
private static void setAttributeIfAbsent(@NotNull Element element, String name, String value) {
|
||||
public static void setAttributeIfAbsent(@NotNull Element element, String name, String value) {
|
||||
if (element.getAttribute(name) == null) {
|
||||
element.setAttribute(name, value);
|
||||
}
|
||||
|
||||
@@ -39,15 +39,15 @@ import static org.jetbrains.idea.eclipse.conversion.EPathUtil.areUrlsPointTheSam
|
||||
* Read/write .eml
|
||||
*/
|
||||
public class IdeaSpecificSettings extends AbstractIdeaSpecificSettings<ModifiableRootModel, ContentEntry, Sdk> {
|
||||
@NonNls private static final String RELATIVE_MODULE_SRC = "relative-module-src";
|
||||
@NonNls private static final String RELATIVE_MODULE_CLS = "relative-module-cls";
|
||||
@NonNls private static final String RELATIVE_MODULE_JAVADOC = "relative-module-javadoc";
|
||||
@NonNls private static final String PROJECT_RELATED = "project-related";
|
||||
@NonNls public static final String RELATIVE_MODULE_SRC = "relative-module-src";
|
||||
@NonNls public static final String RELATIVE_MODULE_CLS = "relative-module-cls";
|
||||
@NonNls public static final String RELATIVE_MODULE_JAVADOC = "relative-module-javadoc";
|
||||
@NonNls public static final String PROJECT_RELATED = "project-related";
|
||||
|
||||
@NonNls private static final String SRCROOT_ATTR = "srcroot";
|
||||
@NonNls private static final String SRCROOT_BIND_ATTR = "bind";
|
||||
@NonNls public static final String SRCROOT_ATTR = "srcroot";
|
||||
@NonNls public static final String SRCROOT_BIND_ATTR = "bind";
|
||||
private static final Logger LOG = Logger.getInstance(IdeaSpecificSettings.class);
|
||||
@NonNls private static final String JAVADOCROOT_ATTR = "javadocroot_attr";
|
||||
@NonNls public static final String JAVADOCROOT_ATTR = "javadocroot_attr";
|
||||
public static final String INHERIT_JDK = "inheritJdk";
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,13 +23,13 @@ import com.intellij.testFramework.PlatformTestUtil
|
||||
import com.intellij.testFramework.TemporaryDirectory
|
||||
import com.intellij.testFramework.assertions.Assertions
|
||||
import com.intellij.testFramework.loadProjectAndCheckResults
|
||||
import com.intellij.testFramework.rules.ProjectModelRule
|
||||
import com.intellij.util.io.assertMatches
|
||||
import com.intellij.util.io.directoryContentOf
|
||||
import com.intellij.workspaceModel.ide.WorkspaceModel
|
||||
import com.intellij.workspaceModel.ide.impl.jps.serialization.JpsProjectModelSynchronizer
|
||||
import org.jetbrains.idea.eclipse.config.EclipseClasspathStorageProvider
|
||||
import org.jetbrains.idea.eclipse.conversion.EclipseClasspathReader
|
||||
import org.jetbrains.idea.eclipse.conversion.EclipseClasspathWriter
|
||||
import org.junit.Assume
|
||||
import org.junit.ClassRule
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
@@ -164,8 +164,6 @@ class EclipseClasspathTest {
|
||||
}
|
||||
|
||||
fun doTest(relativePath: String) {
|
||||
//todo loading and saving in Eclipse format isn't implemented in workspace model yet (IDEA-246236)
|
||||
Assume.assumeFalse(ProjectModelRule.isWorkspaceModelEnabled)
|
||||
val testDataRoot = PluginPathManager.getPluginHome("eclipse").toPath().resolve("testData/round")
|
||||
val testRoot = testDataRoot.resolve(testName.methodName.removePrefix("test").decapitalize()).resolve(relativePath)
|
||||
val commonRoot = testDataRoot.resolve("common")
|
||||
@@ -175,6 +173,9 @@ class EclipseClasspathTest {
|
||||
it.moduleFile!!.delete(this)
|
||||
it.stateStore.clearCaches()
|
||||
}
|
||||
if (WorkspaceModel.isEnabled) {
|
||||
JpsProjectModelSynchronizer.getInstance(project)!!.markAllEntitiesAsDirty()
|
||||
}
|
||||
}
|
||||
project.stateStore.save(true)
|
||||
val baseDir = Paths.get(project.basePath!!)
|
||||
|
||||
Reference in New Issue
Block a user