Path remapping when reading JPS projects inside WSL

GitOrigin-RevId: cfcd6059b38cf12c885dbc229468bdfd63ec7414
This commit is contained in:
Dmitry Jemerov
2020-11-20 18:33:33 +01:00
committed by intellij-monorepo-bot
parent 697acd6687
commit fdffd34bf1
9 changed files with 107 additions and 34 deletions

View File

@@ -1,12 +1,14 @@
// 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.jps.model.serialization;
import org.jetbrains.annotations.Nullable;
public interface JpsPathMapper {
String mapUrl(String url);
@Nullable String mapUrl(@Nullable String url);
JpsPathMapper IDENTITY = new JpsPathMapper() {
@Override
public String mapUrl(String url) {
public @Nullable String mapUrl(@Nullable String url) {
return url;
}
};

View File

@@ -19,6 +19,10 @@ import java.util.stream.Stream;
public final class JpsPathUtil {
public static final String FILE_URL_PREFIX = "file://";
public static final String JAR_URL_PREFIX = "jar://";
public static final String JAR_SEPARATOR = "!/";
public static boolean isUnder(Set<File> ancestors, File file) {
if (ancestors.isEmpty()) {
return false; // optimization
@@ -47,12 +51,13 @@ public final class JpsPathUtil {
if (url == null) {
return null;
}
if (url.startsWith("file://")) {
return url.substring("file://".length());
if (url.startsWith(FILE_URL_PREFIX)) {
return url.substring(FILE_URL_PREFIX.length());
}
else if (url.startsWith("jar://")) {
url = url.substring("jar://".length());
url = Strings.trimEnd(url, "!/");
else if (url.startsWith(JAR_URL_PREFIX)) {
url = url.substring(JAR_URL_PREFIX
.length());
url = Strings.trimEnd(url, JAR_SEPARATOR);
}
return url;
}
@@ -76,12 +81,13 @@ public final class JpsPathUtil {
}
public static String pathToUrl(String path) {
return "file://" + path;
return FILE_URL_PREFIX + path;
}
public static String getLibraryRootUrl(File file) {
String path = FileUtilRt.toSystemIndependentName(file.getAbsolutePath());
return file.isDirectory() ? "file://" + path : "jar://" + path + "!/";
return file.isDirectory() ? FILE_URL_PREFIX + path : JAR_URL_PREFIX
+ path + "!/";
}
public static boolean isJrtUrl(@NotNull String url) {

View File

@@ -113,7 +113,7 @@ public final class JpsGlobalLoader extends JpsLoaderBase {
@Override
public void loadExtension(@NotNull JpsGlobal global, @NotNull Element componentTag) {
JpsLibraryTableSerializer.loadLibraries(componentTag, global.getLibraryCollection());
JpsLibraryTableSerializer.loadLibraries(componentTag, global.getPathMapper(), global.getLibraryCollection());
}
}

View File

@@ -63,12 +63,18 @@ public final class JpsProjectLoader extends JpsLoaderBase {
private final JpsProject myProject;
private final Map<String, String> myPathVariables;
private final JpsPathMapper myPathMapper;
private final boolean myLoadUnloadedModules;
private JpsProjectLoader(JpsProject project, Map<String, String> pathVariables, Path baseDir, boolean loadUnloadedModules) {
private JpsProjectLoader(JpsProject project,
Map<String, String> pathVariables,
@NotNull JpsPathMapper pathMapper,
Path baseDir,
boolean loadUnloadedModules) {
super(createProjectMacroExpander(pathVariables, baseDir));
myProject = project;
myPathVariables = pathVariables;
myPathMapper = pathMapper;
myProject.getContainer().setChild(JpsProjectSerializationDataExtensionImpl.ROLE, new JpsProjectSerializationDataExtensionImpl(baseDir));
myLoadUnloadedModules = loadUnloadedModules;
}
@@ -80,13 +86,13 @@ public final class JpsProjectLoader extends JpsLoaderBase {
}
public static void loadProject(JpsProject project, Map<String, String> pathVariables, String projectPath) throws IOException {
loadProject(project, pathVariables, projectPath, false);
loadProject(project, pathVariables, JpsPathMapper.IDENTITY, projectPath, false);
}
public static void loadProject(JpsProject project, Map<String, String> pathVariables, String projectPath, boolean loadUnloadedModules) throws IOException {
public static void loadProject(JpsProject project, Map<String, String> pathVariables, @NotNull JpsPathMapper pathMapper, String projectPath, boolean loadUnloadedModules) throws IOException {
Path file = Paths.get(FileUtil.toCanonicalPath(projectPath));
if (Files.isRegularFile(file) && projectPath.endsWith(".ipr")) {
new JpsProjectLoader(project, pathVariables, file.getParent(), loadUnloadedModules).loadFromIpr(file);
new JpsProjectLoader(project, pathVariables, pathMapper, file.getParent(), loadUnloadedModules).loadFromIpr(file);
}
else {
Path dotIdea = file.resolve(PathMacroUtil.DIRECTORY_STORE_NAME);
@@ -100,7 +106,7 @@ public final class JpsProjectLoader extends JpsLoaderBase {
else {
throw new IOException("Cannot find IntelliJ IDEA project files at " + projectPath);
}
new JpsProjectLoader(project, pathVariables, directory.getParent(), loadUnloadedModules).loadFromDirectory(directory);
new JpsProjectLoader(project, pathVariables, pathMapper, directory.getParent(), loadUnloadedModules).loadFromDirectory(directory);
}
}
@@ -293,7 +299,7 @@ public final class JpsProjectLoader extends JpsLoaderBase {
}
private void loadProjectLibraries(@Nullable Element libraryTableElement) {
JpsLibraryTableSerializer.loadLibraries(libraryTableElement, myProject.getLibraryCollection());
JpsLibraryTableSerializer.loadLibraries(libraryTableElement, myPathMapper, myProject.getLibraryCollection());
}
private void loadModules(@Nullable Element componentElement, final @Nullable JpsSdkType<?> projectSdkType, @NotNull Path workspaceFile) {
@@ -322,7 +328,7 @@ public final class JpsProjectLoader extends JpsLoaderBase {
}
}
List<JpsModule> modules = loadModules(moduleFiles, projectSdkType, myPathVariables);
List<JpsModule> modules = loadModules(moduleFiles, projectSdkType, myPathVariables, myPathMapper);
for (JpsModule module : modules) {
myProject.addModule(module);
}
@@ -338,7 +344,8 @@ public final class JpsProjectLoader extends JpsLoaderBase {
@NotNull
public static List<JpsModule> loadModules(@NotNull List<? extends Path> moduleFiles,
@Nullable JpsSdkType<?> projectSdkType,
@NotNull Map<String, String> pathVariables) {
@NotNull Map<String, String> pathVariables,
@NotNull JpsPathMapper pathMapper) {
List<JpsModule> modules = new ArrayList<>();
List<Future<Pair<Path, Element>>> futureModuleFilesContents = new ArrayList<>();
Path externalModuleDir = resolveExternalProjectConfig("modules");
@@ -389,7 +396,7 @@ public final class JpsProjectLoader extends JpsLoaderBase {
final Pair<Path, Element> moduleFile = futureModuleFile.get();
if (moduleFile.getSecond() != null) {
futures.add(ourThreadPool.submit(
() -> loadModule(moduleFile.getFirst(), moduleFile.getSecond(), classpathDirs, projectSdkType, pathVariables)));
() -> loadModule(moduleFile.getFirst(), moduleFile.getSecond(), classpathDirs, projectSdkType, pathVariables, pathMapper)));
}
}
for (Future<JpsModule> future : futures) {
@@ -407,7 +414,7 @@ public final class JpsProjectLoader extends JpsLoaderBase {
@NotNull
private static JpsModule loadModule(@NotNull Path file, @NotNull Element moduleRoot, List<String> paths,
@Nullable JpsSdkType<?> projectSdkType, Map<String, String> pathVariables) {
@Nullable JpsSdkType<?> projectSdkType, Map<String, String> pathVariables, @NotNull JpsPathMapper pathMapper) {
String name = getModuleName(file);
final String typeId = moduleRoot.getAttributeValue("type");
final JpsModulePropertiesSerializer<?> serializer = getModulePropertiesSerializer(typeId);
@@ -424,7 +431,7 @@ public final class JpsProjectLoader extends JpsLoaderBase {
if (classpath == null) {
try {
JpsModuleRootModelSerializer.loadRootModel(module, JDomSerializationUtil.findComponent(moduleRoot, "NewModuleRootManager"),
projectSdkType);
projectSdkType, pathMapper);
}
catch (JpsSerializationFormatException e) {
LOG.warn("Failed to load module configuration from " + file.toString() + ": " + e.getMessage(), e);

View File

@@ -1,11 +1,23 @@
// 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.jps.model.serialization;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.io.StreamUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.util.JpsPathUtil;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
public class JpsWslPathMapper implements JpsPathMapper {
private static final String WSL_PREFIX = "//wsl$/";
private @Nullable String myWslRootPrefix;
@Override
public String mapUrl(String url) {
public @Nullable String mapUrl(@Nullable String url) {
if (url == null) return null;
if (url.contains(WSL_PREFIX)) {
int startPos = url.indexOf(WSL_PREFIX);
int endPos = url.indexOf('/', startPos + WSL_PREFIX.length());
@@ -13,6 +25,43 @@ public class JpsWslPathMapper implements JpsPathMapper {
return url.substring(0, startPos) + url.substring(endPos);
}
}
if (url.startsWith(JpsPathUtil.FILE_URL_PREFIX)) {
return JpsPathUtil.FILE_URL_PREFIX + mapPath(url.substring(JpsPathUtil.FILE_URL_PREFIX.length()));
}
if (url.startsWith(JpsPathUtil.JAR_URL_PREFIX)) {
int index = url.indexOf(JpsPathUtil.JAR_SEPARATOR);
if (index >= 0) {
return JpsPathUtil.JAR_URL_PREFIX + mapPath(url.substring(JpsPathUtil.JAR_URL_PREFIX.length(), index)) + url.substring(index);
}
}
return url;
}
@NotNull
private String mapPath(@NotNull String path) {
if (myWslRootPrefix == null || path.indexOf(':') != 1) {
String wslPath;
try {
wslPath = runWslPath(path);
}
catch (IOException | InterruptedException e) {
return path;
}
if (path.indexOf(':') == 1) {
int pathLengthAfterDriveLetter = path.length() - 2;
myWslRootPrefix = wslPath.substring(0, wslPath.length() - pathLengthAfterDriveLetter - 2 /* slash and drive letter */);
}
return wslPath;
}
return myWslRootPrefix + Character.toLowerCase(path.charAt(0)) + FileUtil.toSystemIndependentName(path.substring(2));
}
private static String runWslPath(String path) throws IOException, InterruptedException {
ProcessBuilder processBuilder = new ProcessBuilder("/usr/bin/wslpath", path);
Process process = processBuilder.start();
process.waitFor();
return StreamUtil.readText(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8));
}
}

View File

@@ -21,7 +21,7 @@ public final class JpsSerializationManagerImpl extends JpsSerializationManager {
JpsGlobalLoader.loadGlobalSettings(model.getGlobal(), optionsPath);
}
Map<String, String> pathVariables = JpsModelSerializationDataService.computeAllPathVariables(model.getGlobal());
JpsProjectLoader.loadProject(model.getProject(), pathVariables, projectPath, loadUnloadedModules);
JpsProjectLoader.loadProject(model.getProject(), pathVariables, model.getGlobal().getPathMapper(), projectPath, loadUnloadedModules);
return model;
}

View File

@@ -4,12 +4,17 @@ package org.jetbrains.jps.model.serialization.library;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.util.containers.MultiMap;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.model.*;
import org.jetbrains.jps.model.java.JpsJavaLibraryType;
import org.jetbrains.jps.model.library.*;
import org.jetbrains.jps.model.library.JpsLibrary;
import org.jetbrains.jps.model.library.JpsLibraryCollection;
import org.jetbrains.jps.model.library.JpsLibraryRoot;
import org.jetbrains.jps.model.library.JpsOrderRootType;
import org.jetbrains.jps.model.module.JpsModuleReference;
import org.jetbrains.jps.model.serialization.JpsModelSerializerExtension;
import org.jetbrains.jps.model.serialization.JpsPathMapper;
public final class JpsLibraryTableSerializer {
private static final JpsLibraryRootTypeSerializer[] PREDEFINED_ROOT_TYPES_SERIALIZERS = {
@@ -36,17 +41,19 @@ public final class JpsLibraryTableSerializer {
public static final String PROJECT_LEVEL = "project";
public static final String APPLICATION_LEVEL = "application";
public static void loadLibraries(@Nullable Element libraryTableElement, JpsLibraryCollection result) {
public static void loadLibraries(@Nullable Element libraryTableElement,
@NotNull JpsPathMapper pathMapper,
JpsLibraryCollection result) {
for (Element libraryElement : JDOMUtil.getChildren(libraryTableElement, LIBRARY_TAG)) {
result.addLibrary(loadLibrary(libraryElement));
result.addLibrary(loadLibrary(libraryElement, pathMapper));
}
}
public static JpsLibrary loadLibrary(Element libraryElement) {
return loadLibrary(libraryElement, libraryElement.getAttributeValue(NAME_ATTRIBUTE));
public static JpsLibrary loadLibrary(Element libraryElement, @NotNull JpsPathMapper pathMapper) {
return loadLibrary(libraryElement, libraryElement.getAttributeValue(NAME_ATTRIBUTE), pathMapper);
}
public static JpsLibrary loadLibrary(Element libraryElement, String name) {
public static JpsLibrary loadLibrary(Element libraryElement, String name, @NotNull JpsPathMapper pathMapper) {
String typeId = libraryElement.getAttributeValue(TYPE_ATTRIBUTE);
final JpsLibraryPropertiesSerializer<?> loader = getLibraryPropertiesSerializer(typeId);
JpsLibrary library = createLibrary(name, loader, libraryElement.getChild(PROPERTIES_TAG));
@@ -54,7 +61,7 @@ public final class JpsLibraryTableSerializer {
MultiMap<JpsOrderRootType, String> jarDirectories = new MultiMap<>();
MultiMap<JpsOrderRootType, String> recursiveJarDirectories = new MultiMap<>();
for (Element jarDirectory : JDOMUtil.getChildren(libraryElement, JAR_DIRECTORY_TAG)) {
String url = jarDirectory.getAttributeValue(URL_ATTRIBUTE);
String url = pathMapper.mapUrl(jarDirectory.getAttributeValue(URL_ATTRIBUTE));
String rootTypeId = jarDirectory.getAttributeValue(TYPE_ATTRIBUTE);
final JpsOrderRootType rootType = rootTypeId != null ? getRootType(rootTypeId) : JpsOrderRootType.COMPILED;
boolean recursive = Boolean.parseBoolean(jarDirectory.getAttributeValue(RECURSIVE_ATTRIBUTE));
@@ -68,7 +75,7 @@ public final class JpsLibraryTableSerializer {
if (!rootTypeId.equals(JAR_DIRECTORY_TAG) && !rootTypeId.equals(PROPERTIES_TAG)) {
final JpsOrderRootType rootType = getRootType(rootTypeId);
for (Element rootElement : JDOMUtil.getChildren(rootsElement, ROOT_TAG)) {
String url = rootElement.getAttributeValue(URL_ATTRIBUTE);
String url = pathMapper.mapUrl(rootElement.getAttributeValue(URL_ATTRIBUTE));
JpsLibraryRoot.InclusionOptions options;
if (jarDirectories.get(rootType).contains(url)) {
final boolean recursive = recursiveJarDirectories.get(rootType).contains(url);

View File

@@ -13,6 +13,7 @@ import org.jetbrains.jps.model.library.JpsLibrary;
import org.jetbrains.jps.model.library.sdk.JpsSdkType;
import org.jetbrains.jps.model.module.*;
import org.jetbrains.jps.model.serialization.JpsModelSerializerExtension;
import org.jetbrains.jps.model.serialization.JpsPathMapper;
import org.jetbrains.jps.model.serialization.impl.JpsSerializationFormatException;
import org.jetbrains.jps.model.serialization.library.JpsLibraryTableSerializer;
import org.jetbrains.jps.model.serialization.library.JpsSdkTableSerializer;
@@ -48,7 +49,7 @@ public final class JpsModuleRootModelSerializer {
public static final String JAVA_TEST_ROOT_TYPE_ID = "java-test";
private static final String GENERATED_LIBRARY_NAME_PREFIX = "#";
public static void loadRootModel(JpsModule module, @Nullable Element rootModelComponent, @Nullable JpsSdkType<?> projectSdkType) {
public static void loadRootModel(JpsModule module, @Nullable Element rootModelComponent, @Nullable JpsSdkType<?> projectSdkType, @NotNull JpsPathMapper pathMapper) {
if (rootModelComponent == null) return;
for (Element contentElement : getChildren(rootModelComponent, CONTENT_TAG)) {
@@ -108,7 +109,7 @@ public final class JpsModuleRootModelSerializer {
name = GENERATED_LIBRARY_NAME_PREFIX;
}
String uniqueName = nameGenerator.generateUniqueName(name);
final JpsLibrary library = JpsLibraryTableSerializer.loadLibrary(moduleLibraryElement, uniqueName);
final JpsLibrary library = JpsLibraryTableSerializer.loadLibrary(moduleLibraryElement, uniqueName, pathMapper);
module.addModuleLibrary(library);
final JpsLibraryDependency dependency = dependenciesList.addLibraryDependency(library);

View File

@@ -23,6 +23,7 @@ import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager
import org.jetbrains.jps.model.module.JpsModule
import org.jetbrains.jps.model.module.JpsModuleDependency
import org.jetbrains.jps.model.serialization.JpsGlobalLoader
import org.jetbrains.jps.model.serialization.JpsPathMapper
import org.jetbrains.jps.model.serialization.JpsProjectLoader
import java.nio.file.Paths
@@ -45,7 +46,7 @@ class UnloadedModuleDescriptionImpl(val modulePath: ModulePath,
@JvmStatic
fun createFromPaths(paths: Collection<ModulePath>, parentDisposable: Disposable): List<UnloadedModuleDescriptionImpl> {
val pathVariables = JpsGlobalLoader.computeAllPathVariables(PathManager.getOptionsPath())
val modules = JpsProjectLoader.loadModules(paths.map { Paths.get(it.path) }, null, pathVariables)
val modules = JpsProjectLoader.loadModules(paths.map { Paths.get(it.path) }, null, pathVariables, JpsPathMapper.IDENTITY)
val pathsByName = paths.associateBy { it.moduleName }
return modules.map { create(pathsByName[it.name]!!, it, parentDisposable) }
}