forked from bazelbuild/intellij
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Resolve _virtual_includes to local or external workspace (bazelbuild#…
…5059) * Resolve _virtual_includes to local or external workspace Bazel generates _virtual_includes directory in the execution root for targets with strip_include_prefix attribute. However, the headers there are just linked to either external or local workspace. Unfortunately, CLion can not follow symbolic link and displays non-project file warning on a project file * bazelbuild#510 * https://youtrack.jetbrains.com/issue/CPP-17658 In some cases symbolic links in execroot could disappear after other target build resulting in non-resolved or incorrectly suggested include directive (bazelbuild#145). The proposal is to identify workspace and target from the include path and then apply strip_include_prefix attribute to point to the proper include directory. * fixup! Resolve _virtual_includes to local or external workspace Signed-off-by: Evgenii Novozhilov <[email protected]> * fixup! Resolve _virtual_includes to local or external workspace Signed-off-by: Evgenii Novozhilov <[email protected]> * fixup! Resolve _virtual_includes to local or external workspace Signed-off-by: Evgenii Novozhilov <[email protected]> * fixup! Resolve _virtual_includes to local or external workspace Signed-off-by: Evgenii Novozhilov <[email protected]> * fixup! Resolve _virtual_includes to local or external workspace Signed-off-by: Evgenii Novozhilov <[email protected]> --------- Signed-off-by: Evgenii Novozhilov <[email protected]>
- Loading branch information
Showing
12 changed files
with
391 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
156 changes: 156 additions & 0 deletions
156
base/src/com/google/idea/blaze/base/sync/workspace/VirtualIncludesHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
package com.google.idea.blaze.base.sync.workspace; | ||
|
||
import com.google.common.collect.ImmutableList; | ||
import com.google.common.collect.Lists; | ||
import com.google.idea.blaze.base.ideinfo.CIdeInfo; | ||
import com.google.idea.blaze.base.ideinfo.TargetIdeInfo; | ||
import com.google.idea.blaze.base.ideinfo.TargetKey; | ||
import com.google.idea.blaze.base.ideinfo.TargetMap; | ||
import com.google.idea.blaze.base.model.primitives.ExecutionRootPath; | ||
import com.google.idea.blaze.base.model.primitives.Label; | ||
import com.google.idea.blaze.base.model.primitives.TargetName; | ||
import com.google.idea.blaze.base.model.primitives.WorkspacePath; | ||
import com.intellij.openapi.diagnostic.Logger; | ||
import com.intellij.openapi.util.io.FileUtil; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.jetbrains.annotations.Nullable; | ||
|
||
import java.io.File; | ||
import java.nio.file.Path; | ||
import java.util.Collections; | ||
import java.util.List; | ||
|
||
/** | ||
* Utility class designed to convert execroot {@code _virtual_includes} references to | ||
* either external or local workspace. | ||
* <p> | ||
* Virtual includes are generated for targets with strip_include_prefix attribute | ||
* and are stored for external workspaces in | ||
* <p> | ||
* {@code bazel-out/.../bin/external/.../_virtual_includes/...} | ||
* <p> | ||
* or for local workspace in | ||
* <p> | ||
* {@code bazel-out/.../bin/.../_virtual_includes/...} | ||
*/ | ||
class VirtualIncludesHandler { | ||
private static final Logger LOG = Logger.getInstance(VirtualIncludesHandler.class); | ||
final static Path VIRTUAL_INCLUDES_DIRECTORY = Path.of("_virtual_includes"); | ||
private static final int EXTERNAL_DIRECTORY_IDX = 3; | ||
private static final int EXTERNAL_WORKSPACE_NAME_IDX = 4; | ||
private static final int WORKSPACE_PATH_START_FOR_EXTERNAL_WORKSPACE = 5; | ||
private static final int WORKSPACE_PATH_START_FOR_LOCAL_WORKSPACE = 3; | ||
|
||
private static List<Path> splitExecutionPath(ExecutionRootPath executionRootPath) { | ||
return Lists.newArrayList(executionRootPath.getAbsoluteOrRelativeFile().toPath().iterator()); | ||
} | ||
|
||
static boolean containsVirtualInclude(ExecutionRootPath executionRootPath) { | ||
return splitExecutionPath(executionRootPath).contains(VIRTUAL_INCLUDES_DIRECTORY); | ||
} | ||
|
||
/** | ||
* Resolves execution root path to {@code _virtual_includes} directory to the matching workspace location | ||
* | ||
* @return list of resolved paths if required information is obtained from execution root path and target data | ||
* or empty list if resolution has failed | ||
*/ | ||
@NotNull | ||
static ImmutableList<File> resolveVirtualInclude(ExecutionRootPath executionRootPath, | ||
File externalWorkspacePath, | ||
WorkspacePathResolver workspacePathResolver, | ||
TargetMap targetMap) | ||
{ | ||
TargetKey key = null; | ||
try { | ||
key = guessTargetKey(executionRootPath); | ||
} catch (IndexOutOfBoundsException exception) { | ||
// report to intellij EA | ||
LOG.error( | ||
"Failed to detect target from execution root path: " + executionRootPath, | ||
exception); | ||
} | ||
|
||
if (key == null) { | ||
return ImmutableList.of(); | ||
} | ||
|
||
TargetIdeInfo info = targetMap.get(key); | ||
if (info == null) { | ||
return ImmutableList.of(); | ||
} | ||
|
||
CIdeInfo cIdeInfo = info.getcIdeInfo(); | ||
if (cIdeInfo == null) { | ||
return ImmutableList.of(); | ||
} | ||
|
||
if (!info.getcIdeInfo().getIncludePrefix().isEmpty()) { | ||
LOG.debug( | ||
"_virtual_includes cannot be handled for targets with include_prefix attribute"); | ||
return ImmutableList.of(); | ||
} | ||
|
||
String stripPrefix = info.getcIdeInfo().getStripIncludePrefix(); | ||
if (!stripPrefix.isEmpty()) { | ||
String extrenalWorkspaceName = key.getLabel().externalWorkspaceName(); | ||
WorkspacePath workspacePath = key.getLabel().blazePackage(); | ||
if (key.getLabel().externalWorkspaceName() != null) { | ||
ExecutionRootPath external = new ExecutionRootPath( | ||
ExecutionRootPathResolver.externalPath.toPath() | ||
.resolve(extrenalWorkspaceName) | ||
.resolve(workspacePath.toString()) | ||
.resolve(stripPrefix).toString()); | ||
|
||
return ImmutableList.of(external.getFileRootedAt(externalWorkspacePath)); | ||
} else { | ||
return workspacePathResolver.resolveToIncludeDirectories( | ||
new WorkspacePath(workspacePath, stripPrefix)); | ||
} | ||
} else { | ||
return ImmutableList.of(); | ||
} | ||
|
||
} | ||
|
||
/** | ||
* @throws IndexOutOfBoundsException if executionRootPath has _virtual_includes but | ||
* its content is unexpected | ||
*/ | ||
@Nullable | ||
private static TargetKey guessTargetKey(ExecutionRootPath executionRootPath) { | ||
List<Path> split = splitExecutionPath(executionRootPath); | ||
int virtualIncludesIdx = split.indexOf(VIRTUAL_INCLUDES_DIRECTORY); | ||
|
||
if (virtualIncludesIdx > -1) { | ||
String externalWorkspaceName = | ||
split.get(EXTERNAL_DIRECTORY_IDX) | ||
.equals(ExecutionRootPathResolver.externalPath.toPath()) | ||
? split.get(EXTERNAL_WORKSPACE_NAME_IDX).toString() | ||
: null; | ||
|
||
int workspacePathStart = externalWorkspaceName != null | ||
? WORKSPACE_PATH_START_FOR_EXTERNAL_WORKSPACE | ||
: WORKSPACE_PATH_START_FOR_LOCAL_WORKSPACE; | ||
|
||
List<Path> workspacePaths = (workspacePathStart <= virtualIncludesIdx) | ||
? split.subList(workspacePathStart, virtualIncludesIdx) | ||
: Collections.emptyList(); | ||
|
||
String workspacePathString = | ||
FileUtil.toSystemIndependentName( | ||
workspacePaths.stream().reduce(Path.of(""), Path::resolve).toString()); | ||
|
||
TargetName target = TargetName.create(split.get(virtualIncludesIdx + 1).toString()); | ||
WorkspacePath workspacePath = WorkspacePath.createIfValid(workspacePathString); | ||
if (workspacePath == null) { | ||
return null; | ||
} | ||
|
||
return TargetKey.forPlainTarget( | ||
Label.create(externalWorkspaceName, workspacePath, target)); | ||
} else { | ||
return null; | ||
} | ||
} | ||
} |
Oops, something went wrong.