diff --git a/base/src/META-INF/blaze-base.xml b/base/src/META-INF/blaze-base.xml index b37d79ac279..69bce8f2321 100644 --- a/base/src/META-INF/blaze-base.xml +++ b/base/src/META-INF/blaze-base.xml @@ -342,6 +342,9 @@ + diff --git a/base/src/com/google/idea/blaze/base/model/LibraryFilesProvider.java b/base/src/com/google/idea/blaze/base/model/LibraryFilesProvider.java index c71ba17a8ed..32e60156675 100644 --- a/base/src/com/google/idea/blaze/base/model/LibraryFilesProvider.java +++ b/base/src/com/google/idea/blaze/base/model/LibraryFilesProvider.java @@ -16,9 +16,12 @@ package com.google.idea.blaze.base.model; import com.google.common.collect.ImmutableList; +import com.google.idea.blaze.base.sync.libraries.LibraryModifier; import com.intellij.openapi.roots.libraries.Library; import java.io.File; +import static com.google.common.collect.ImmutableList.toImmutableList; + /** Provides files to be updated in {@link Library.ModifiableModel}. */ public interface LibraryFilesProvider { /** Returns the name of library that the modifier will update. */ @@ -30,12 +33,32 @@ public interface LibraryFilesProvider { */ ImmutableList getClassFiles(BlazeProjectData blazeProjectData); + /** + * Returns a list of files' urls that should be added to {@link Library.ModifiableModel} as + * OrderRootType.CLASSES. + */ + default ImmutableList getClassFilesUrls(BlazeProjectData blazeProjectData) { + return getClassFiles(blazeProjectData).stream() + .map(LibraryModifier::pathToUrl) + .collect(toImmutableList()); + }; + /** * Returns a list of files that should be added to {@link Library.ModifiableModel} as * OrderRootType.SOURCES. */ ImmutableList getSourceFiles(BlazeProjectData blazeProjectData); + /** + * Returns a list of files' urls that should be added to {@link Library.ModifiableModel} as + * OrderRootType.SOURCES. + */ + default ImmutableList getSourceFilesUrls(BlazeProjectData blazeProjectData) { + return getSourceFiles(blazeProjectData).stream() + .map(LibraryModifier::pathToUrl) + .collect(toImmutableList()); + } + default boolean supportAnchors() { return false; } diff --git a/base/src/com/google/idea/blaze/base/sync/libraries/LibraryModifier.java b/base/src/com/google/idea/blaze/base/sync/libraries/LibraryModifier.java index 1597cb7dd40..539d79b6a45 100644 --- a/base/src/com/google/idea/blaze/base/sync/libraries/LibraryModifier.java +++ b/base/src/com/google/idea/blaze/base/sync/libraries/LibraryModifier.java @@ -26,6 +26,7 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.io.FileUtilRt; import com.intellij.openapi.vfs.StandardFileSystems; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.util.io.URLUtil; import java.io.File; @@ -49,12 +50,12 @@ public Library.ModifiableModel getModifiableModel() { /** Writes the library content to its {@link Library.ModifiableModel}. */ public void updateModifiableModel(BlazeProjectData blazeProjectData) { removeAllContents(); - for (File classFile : libraryFilesProvider.getClassFiles(blazeProjectData)) { - addRoot(classFile, OrderRootType.CLASSES); + for (String classFileUrl : libraryFilesProvider.getClassFilesUrls(blazeProjectData)) { + addRoot(classFileUrl, OrderRootType.CLASSES); } - for (File sourceFile : libraryFilesProvider.getSourceFiles(blazeProjectData)) { - addRoot(sourceFile, OrderRootType.SOURCES); + for (String sourceFileUrl : libraryFilesProvider.getSourceFilesUrls(blazeProjectData)) { + addRoot(sourceFileUrl, OrderRootType.SOURCES); } } @@ -68,15 +69,16 @@ private ModifiableModel getLibraryModifiableModel( return modelsProvider.getModifiableLibraryModel(library); } - private void addRoot(File file, OrderRootType orderRootType) { - if (!file.exists()) { - logger.warn("No local file found for " + file); + private void addRoot(String fileUrl, OrderRootType orderRootType) { + VirtualFile virtualFile = VirtualFileManager.getInstance().findFileByUrl(fileUrl); + if (virtualFile == null || !virtualFile.exists()) { + logger.warn("No local file found for " + fileUrl); return; } - modifiableModel.addRoot(pathToUrl(file), orderRootType); + modifiableModel.addRoot(fileUrl, orderRootType); } - private String pathToUrl(File path) { + public static String pathToUrl(File path) { String name = path.getName(); boolean isJarFile = FileUtilRt.extensionEquals(name, "jar") diff --git a/java/src/com/google/idea/blaze/java/sync/model/BlazeJarLibrary.java b/java/src/com/google/idea/blaze/java/sync/model/BlazeJarLibrary.java index eeda2c03bf8..76f3918f72d 100644 --- a/java/src/com/google/idea/blaze/java/sync/model/BlazeJarLibrary.java +++ b/java/src/com/google/idea/blaze/java/sync/model/BlazeJarLibrary.java @@ -19,6 +19,7 @@ import com.google.common.collect.ImmutableList; import com.google.devtools.intellij.model.ProjectData; +import com.google.idea.blaze.base.async.executor.ProgressiveTaskWithProgressIndicator; import com.google.idea.blaze.base.ideinfo.LibraryArtifact; import com.google.idea.blaze.base.ideinfo.ProtoWrapper; import com.google.idea.blaze.base.ideinfo.TargetKey; @@ -26,12 +27,22 @@ import com.google.idea.blaze.base.model.BlazeProjectData; import com.google.idea.blaze.base.model.LibraryFilesProvider; import com.google.idea.blaze.base.model.LibraryKey; +import com.google.idea.blaze.base.sync.libraries.LibraryModifier; import com.google.idea.blaze.java.libraries.AttachedSourceJarManager; import com.google.idea.blaze.java.libraries.JarCache; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ui.configuration.JavaVfsSourceRootDetectionUtil; +import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileManager; + import java.io.File; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; import java.util.Objects; +import java.util.concurrent.ExecutionException; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; @@ -140,6 +151,36 @@ public ImmutableList getSourceFiles(BlazeProjectData blazeProjectData) { .collect(toImmutableList()); } + @Override + public ImmutableList getSourceFilesUrls(BlazeProjectData blazeProjectData) { + final ImmutableList sourceFiles = getSourceFiles(blazeProjectData); + ImmutableList jarFilesAsSourceRoots = sourceFiles.stream().map(LibraryModifier::pathToUrl).collect(toImmutableList()); + if (!Registry.is("bazel.sync.detect.source.roots")) { + return jarFilesAsSourceRoots; + } else { + try { + return ProgressiveTaskWithProgressIndicator.builder(project, "Locating source roots in source path entry") + .setModality(ProgressiveTaskWithProgressIndicator.Modality.MODAL) + .submitTaskWithResult(indicator -> { + List sourceFilesUrls = new LinkedList<>(); + for (File sourceFile : sourceFiles) { + VirtualFile jarFile = VirtualFileManager.getInstance().findFileByUrl(LibraryModifier.pathToUrl(sourceFile)); + List candidates = Collections.emptyList(); + if (jarFile != null && jarFile.exists()) { + candidates = JavaVfsSourceRootDetectionUtil.suggestRoots(jarFile, indicator); + } + if (!candidates.isEmpty()) { + candidates.forEach(sourceVirtualFile -> sourceFilesUrls.add(sourceVirtualFile.getUrl())); + } + } + return ImmutableList.copyOf(sourceFilesUrls); + }).get(); + } catch (InterruptedException | ExecutionException e) { + return jarFilesAsSourceRoots; + } + } + } + @Override public boolean equals(Object other) { if (this == other) {