Skip to content

Commit

Permalink
[#6664] Resolve a workspace label across external repositories - 4/n
Browse files Browse the repository at this point in the history
  • Loading branch information
mtoader committed Aug 30, 2024
1 parent 5884f07 commit 4cdfa88
Show file tree
Hide file tree
Showing 6 changed files with 189 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,12 @@
import com.intellij.openapi.vfs.VirtualFileFilter;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiReference;
import com.intellij.psi.PsiReferenceBase;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;

import javax.annotation.Nullable;

/** Converts a blaze label into an absolute path, then resolves that path to a PsiElements */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
import com.google.common.base.Functions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.devtools.intellij.model.ProjectData;
import com.google.idea.blaze.base.ideinfo.ProtoWrapper;
import com.google.idea.blaze.base.model.primitives.ExternalWorkspace;

import javax.annotation.Nullable;

public final class ExternalWorkspaceData implements ProtoWrapper<ProjectData.ExternalWorkspaceData> {
public ImmutableMap<String, ExternalWorkspace> workspaces;

Expand All @@ -22,7 +25,7 @@ public static ExternalWorkspaceData create(ImmutableList<ExternalWorkspace> work
.stream()
.collect(
ImmutableMap.toImmutableMap(
ExternalWorkspace::name,
ExternalWorkspace::repoName,
Functions.identity()))
);
}
Expand All @@ -43,4 +46,9 @@ public ProjectData.ExternalWorkspaceData toProto() {
public static ExternalWorkspaceData fromProto(ProjectData.ExternalWorkspaceData proto) {
return new ExternalWorkspaceData(proto.getWorkspacesList().stream().map(ExternalWorkspace::fromProto).collect(ImmutableList.toImmutableList()));
}

@Nullable
public ExternalWorkspace getByRepoName(String name) {
return Maps.filterValues(workspaces, w -> w.repoName() != null && w.repoName().equals(name)).values().stream().findFirst().orElse(null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import com.google.common.annotations.VisibleForTesting;
import com.google.idea.blaze.base.bazel.BuildSystemProvider;
import com.google.idea.blaze.base.model.BlazeProjectData;
import com.google.idea.blaze.base.model.ExternalWorkspaceData;
import com.google.idea.blaze.base.model.primitives.ExternalWorkspace;
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;
Expand Down Expand Up @@ -169,8 +171,8 @@ private static Label deriveLabel(
TargetName.createIfValid(
FileUtil.getRelativePath(workspace.root.fileForPath(packagePath), file));
return targetName != null
? Label.create(workspace.externalWorkspaceName, packagePath, targetName)
: null;
? Label.create(workspace.externalWorkspaceName, packagePath, targetName)
: null;
}

private static WorkspacePath getPackagePath(
Expand All @@ -193,33 +195,41 @@ public static File getExternalSourceRoot(BlazeProjectData projectData) {

@Nullable
private static synchronized WorkspaceRoot getExternalWorkspaceRootsFile(String workspaceName,
Project project) {
Project project) {
if (Blaze.getBuildSystemName(project) == BuildSystemName.Blaze) {
return null;
}
logger.debug("getExternalWorkspaceRootsFile for " + workspaceName);
Map<String, WorkspaceRoot> workspaceRootCache = SyncCache.getInstance(project)
.get(WorkspaceHelper.class, (p, data) -> new ConcurrentHashMap<String, WorkspaceRoot>());
Map<String, WorkspaceRoot> workspaceRootCache =
SyncCache.getInstance(project)
.get(WorkspaceHelper.class, (p, data) -> new ConcurrentHashMap<>());

//the null cache value case could happen when the blazeProjectData is null.
if(workspaceRootCache == null) {
if (workspaceRootCache == null) {
return null;
}

WorkspaceRoot root = null;
if (workspaceRootCache.containsKey(workspaceName)) {
root = workspaceRootCache.get(workspaceName);
} else if (getBlazeProjectData(project) != null) {
File externalDir = new File(getBlazeProjectData(project).getBlazeInfo().getOutputBase(),
"external/" + workspaceName);
return workspaceRootCache.get(workspaceName);
}

BlazeProjectData blazeProjectData = getBlazeProjectData(project);
if (blazeProjectData != null) {
File workspaceDir = new File(blazeProjectData.getBlazeInfo().getOutputBase(), "external/" + workspaceName);

if (externalDir.exists() || isInTestMode()) {
root = new WorkspaceRoot(externalDir);
ExternalWorkspace workspace = blazeProjectData.getExternalWorkspaceData().getByRepoName(workspaceName);
if (workspace != null) {
workspaceDir = new File(blazeProjectData.getBlazeInfo().getOutputBase(), "external/" + workspace.name());
}

if (workspaceDir.exists() || isInTestMode()) {
WorkspaceRoot root = new WorkspaceRoot(workspaceDir);
workspaceRootCache.put(workspaceName, root);
return root;
}
}

return root;
return null;
}

//The unit test use the TempFileSystem to create VirtualFile which does not exist on disk.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.google.idea.blaze.base.lang.buildfile.language.semantics.RuleDefinition;
import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
import com.google.idea.blaze.base.model.primitives.WorkspacePath;
import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.openapi.editor.Editor;
import javax.annotation.Nullable;
Expand Down Expand Up @@ -188,6 +189,11 @@ public void testLocalPathIgnoredForNonLocalLabels() throws Throwable {
assertThat(completionItems).asList().doesNotContain("'//java/com/google:other_rule'");
}

@Test
public void testExternalRepoCompletion() throws Throwable {

}

private static void setBuildLanguageSpecRules(
MockBuildLanguageSpecProvider specProvider, String... ruleNames) {
ImmutableMap.Builder<String, RuleDefinition> rules = ImmutableMap.builder();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package com.google.idea.blaze.base.lang.buildfile.references;

import com.google.common.collect.ImmutableList;
import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
import com.google.idea.blaze.base.model.ExternalWorkspaceData;
import com.google.idea.blaze.base.model.primitives.ExternalWorkspace;
import com.google.idea.blaze.base.model.primitives.WorkspacePath;
import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
import com.intellij.codeInsight.navigation.actions.GotoDeclarationAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiElement;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertNotNull;

@RunWith(JUnit4.class)
public class ModuleRepositoryCompletionTest extends BuildFileIntegrationTestCase {

final ExternalWorkspaceFixture unmappedWorkspace =
new ExternalWorkspaceFixture(ExternalWorkspace.create("workspace_one", "workspace_one"));

final ExternalWorkspaceFixture remappedWorkspace =
new ExternalWorkspaceFixture(ExternalWorkspace.create("workspace_one", "com_workspace_one"));

@Override
protected ExternalWorkspaceData mockExternalWorkspaceData() {
return ExternalWorkspaceData.create(ImmutableList.of(unmappedWorkspace.workspace, remappedWorkspace.workspace));
}

@Test
public void testUnmappedExternalWorkspaceCompletion() throws Throwable {
WorkspaceRoot externalWorkspaceRoot = unmappedWorkspace.getWorkspaceRoot();
assertNotNull(externalWorkspaceRoot);

BuildFile otherPackage =
unmappedWorkspace.createBuildFile(new WorkspacePath( "p1/p2/BUILD"), "java_library(name = 'rule1')");

String targetRule = "@" + unmappedWorkspace.workspace.repoName() + "//p1/p2:rule1";

BuildFile file = createBuildFile(
new WorkspacePath("java/BUILD"),
"java_library(",
" name = 'lib',",
" deps = ['" + targetRule + "']");

Editor editor = editorTest.openFileInEditor(file);
editorTest.setCaretPosition(editor, 2, (" deps = ['" + targetRule).length());

PsiElement target =
GotoDeclarationAction.findTargetElement(
getProject(), editor, editor.getCaretModel().getOffset());

assertThat(target).isNotNull();
}

@Test
public void testRemappedExternalWorkspaceCompletion() throws Throwable {
WorkspaceRoot externalWorkspaceRoot = remappedWorkspace.getWorkspaceRoot();
assertNotNull(externalWorkspaceRoot);

BuildFile otherPackage =
remappedWorkspace.createBuildFile(new WorkspacePath("p1/p2/BUILD"), "java_library(name = 'rule1')");

String targetRule = "@" + remappedWorkspace.workspace.repoName() + "//p1/p2:rule1";

BuildFile file = createBuildFile(
new WorkspacePath("java/BUILD"),
"java_library(",
" name = 'lib',",
" deps = ['" + targetRule + "']");

Editor editor = editorTest.openFileInEditor(file);
editorTest.setCaretPosition(editor, 2, (" deps = ['" + targetRule).length());

PsiElement target =
GotoDeclarationAction.findTargetElement(
getProject(), editor, editor.getCaretModel().getOffset());

assertThat(target).isNotNull();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,29 @@
package com.google.idea.blaze.base.lang.buildfile;

import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertNotNull;

import com.google.common.base.Joiner;
import com.google.idea.blaze.base.BlazeIntegrationTestCase;
import com.google.idea.blaze.base.EditorTestHelper;
import com.google.idea.blaze.base.WorkspaceFileSystem;
import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
import com.google.idea.blaze.base.model.BlazeProjectData;
import com.google.idea.blaze.base.model.ExternalWorkspaceData;
import com.google.idea.blaze.base.model.MockBlazeProjectDataBuilder;
import com.google.idea.blaze.base.model.MockBlazeProjectDataManager;
import com.google.idea.blaze.base.model.primitives.ExternalWorkspace;
import com.google.idea.blaze.base.model.primitives.WorkspacePath;
import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;

import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;

import org.junit.Before;

/** BUILD file specific integration test base */
Expand All @@ -40,11 +51,16 @@ public final void doSetup() {
new MockBlazeProjectDataManager(
MockBlazeProjectDataBuilder.builder(workspaceRoot)
.setOutputBase(fileSystem.getRootDir() + "/output_base")
.setExternalWorkspaceData(mockExternalWorkspaceData())
.build());
registerProjectService(BlazeProjectDataManager.class, mockProjectDataManager);
editorTest = new EditorTestHelper(getProject(), testFixture);
}

protected ExternalWorkspaceData mockExternalWorkspaceData() {
return ExternalWorkspaceData.EMPTY;
}

/**
* Creates a file with the specified contents and file path in the test project, and asserts that
* it's parsed as a BuildFile
Expand All @@ -68,4 +84,50 @@ protected void assertFileContents(PsiFile file, List<String> contentLines) {
String contents = Joiner.on('\n').join(contentLines);
assertThat(file.getText()).isEqualTo(contents);
}

protected final class ExternalWorkspaceFixture {
public final ExternalWorkspace workspace;
WorkspaceFileSystem workspaceFileSystem;

public ExternalWorkspaceFixture(ExternalWorkspace workspace) {
this.workspace = workspace;
}

WorkspaceFileSystem getWorkspaceFileSystem() {
if (workspaceFileSystem == null) {
BlazeProjectData blazeProjectData = BlazeProjectDataManager.getInstance(getProject()).getBlazeProjectData();
assertNotNull(blazeProjectData);

File outputBase = blazeProjectData.getBlazeInfo().getOutputBase();
WorkspaceRoot workspaceRoot = new WorkspaceRoot(Paths.get(
blazeProjectData.getBlazeInfo().getOutputBase().getAbsolutePath(),
"external", workspace.name()).normalize().toFile());

File workspaceRootFile = workspaceRoot.directory();
assertThat(workspaceRootFile).isNotNull();
workspaceFileSystem = new WorkspaceFileSystem(workspaceRoot, BuildFileIntegrationTestCase.this.fileSystem);
}

return workspaceFileSystem;
}

public WorkspaceRoot getWorkspaceRoot() {
BlazeProjectData blazeProjectData = BlazeProjectDataManager.getInstance(getProject()).getBlazeProjectData();
assertThat(blazeProjectData).isNotNull();

File outputBase = blazeProjectData.getBlazeInfo().getOutputBase();

Path workspaceRootPath = Paths.get(
blazeProjectData.getBlazeInfo().getOutputBase().getAbsolutePath(),
"external", workspace.name());

return new WorkspaceRoot(workspaceRootPath.normalize().toFile());
}

public BuildFile createBuildFile(WorkspacePath workspacePath, String... contentLines) {
PsiFile file = getWorkspaceFileSystem().createPsiFile(workspacePath, contentLines);
assertThat(file).isInstanceOf(BuildFile.class);
return (BuildFile) file;
}
}
}

0 comments on commit 4cdfa88

Please sign in to comment.