Skip to content

Commit

Permalink
fix(qsync): External modules navigation in starlark files
Browse files Browse the repository at this point in the history
Co-authored-by: Błażej Kardyś <blazej.kardys@jetbrains.com>
  • Loading branch information
Tomasz Pasternak and sellophane committed Jan 7, 2025
1 parent 1578ce8 commit 412de37
Show file tree
Hide file tree
Showing 20 changed files with 311 additions and 60 deletions.
2 changes: 2 additions & 0 deletions base/src/META-INF/blaze-base.xml
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@
<projectService serviceInterface="com.google.idea.blaze.base.sync.data.BlazeProjectDataManager"
serviceImplementation="com.google.idea.blaze.base.sync.data.DelegatingBlazeProjectDataManager"/>
<projectService serviceImplementation="com.google.idea.blaze.base.sync.BlazeSyncManager"/>
<projectService serviceImplementation="com.google.idea.blaze.base.model.ExternalWorkspaceDataManager"/>
<applicationConfigurable provider="com.google.idea.blaze.base.qsync.settings.QuerySyncConfigurableProvider" id ="query.sync" displayName="Query Sync"/>
<applicationService serviceImplementation="com.google.idea.blaze.base.qsync.settings.QuerySyncSettings" id="QuerySyncSettings"/>
<psi.referenceContributor language="BUILD" implementation="com.google.idea.blaze.base.lang.buildfile.references.VisibilityReferenceContributor"/>
Expand Down Expand Up @@ -630,6 +631,7 @@
<SyncListener implementation="com.google.idea.blaze.base.model.ExternalWorkspaceDataProvider$Invalidator"/>
<SyncListener implementation="com.google.idea.blaze.base.qsync.QuerySyncAsyncFileListener$QuerySyncListener"/>
<SyncListener implementation="com.google.idea.blaze.base.sync.aspects.strategy.SyncAspectTemplateProvider"/>
<SyncListener implementation="com.google.idea.blaze.base.model.ExternalWorkspaceSyncListener"/>
<SyncPlugin implementation="com.google.idea.blaze.base.lang.buildfile.sync.BuildLangSyncPlugin"/>
<SyncPlugin implementation="com.google.idea.blaze.base.sync.libraries.ExternalLibraryManager$SyncPlugin"/>
<BuildFlagsProvider implementation="com.google.idea.blaze.base.command.BuildFlagsProviderImpl"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
import com.google.idea.blaze.base.model.BlazeProjectData;
import com.google.idea.blaze.base.model.ExternalWorkspaceDataManager;
import com.google.idea.blaze.base.model.primitives.WorkspacePath;
import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
import com.google.idea.blaze.base.settings.Blaze;
Expand Down Expand Up @@ -112,12 +113,13 @@ private static BuildFile resolveProjectWorkspaceFile(Project project) {
@Override
@Nonnull
public BuildLookupElement[] getVariants() {
BlazeProjectData blazeProjectData = BlazeProjectDataManager.getInstance(myElement.getProject()).getBlazeProjectData();
if (blazeProjectData == null) {

var externalWorkspaceData = ExternalWorkspaceDataManager.getInstance(myElement.getProject()).getData();
if(externalWorkspaceData == null) {
return BuildLookupElement.EMPTY_ARRAY;
}

return blazeProjectData.getExternalWorkspaceData().workspaces.values().stream()
return externalWorkspaceData.workspaces.values().stream()
.map(ExternalWorkspaceLookupElement::new)
.toArray(BuildLookupElement[]::new);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,11 +192,6 @@ public RemoteOutputArtifacts getRemoteOutputs() {
return targetData.remoteOutputs;
}

@Override
public ExternalWorkspaceData getExternalWorkspaceData() {
return externalWorkspaceData;
}

@Override
public SyncState getSyncState() {
return syncState;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,6 @@ public interface BlazeProjectData {

RemoteOutputArtifacts getRemoteOutputs();

ExternalWorkspaceData getExternalWorkspaceData();

SyncState getSyncState();

boolean isQuerySync();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2024 The Bazel Authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.idea.blaze.base.model;

import com.intellij.openapi.project.Project;


public class ExternalWorkspaceDataManager {
private ExternalWorkspaceData data;

public static ExternalWorkspaceDataManager getInstance(Project project) {
return project.getService(ExternalWorkspaceDataManager.class);
}

public ExternalWorkspaceData getData(){
return data;
}

public void setData(ExternalWorkspaceData data) {
this.data = data;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* Copyright 2016 The Bazel Authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.idea.blaze.base.model;

import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.idea.blaze.base.bazel.BuildSystem;
import com.google.idea.blaze.base.command.info.BlazeInfo;
import com.google.idea.blaze.base.projectview.ProjectViewSet;
import com.google.idea.blaze.base.scope.BlazeContext;
import com.google.idea.blaze.base.settings.Blaze;
import com.google.idea.blaze.base.settings.BlazeImportSettings;
import com.google.idea.blaze.base.sync.SyncListener;
import com.google.idea.blaze.base.sync.SyncMode;
import com.google.idea.blaze.base.sync.SyncResult;
import com.google.idea.blaze.base.sync.SyncScope;
import com.intellij.openapi.project.Project;

import com.google.idea.blaze.base.async.FutureUtil;
import com.google.idea.blaze.base.async.FutureUtil.FutureResult;
import com.google.idea.blaze.base.command.BlazeCommandName;
import com.google.idea.blaze.base.command.BlazeFlags;
import com.google.idea.blaze.base.command.BlazeInvocationContext;
import com.google.idea.blaze.base.execution.ExecutionDeniedException;
import com.google.idea.blaze.base.projectview.ProjectViewManager;
import com.google.idea.blaze.base.scope.scopes.TimingScope.EventType;
import com.google.idea.blaze.base.sync.SyncScope.SyncCanceledException;
import com.google.idea.blaze.base.sync.SyncScope.SyncFailedException;
import com.google.idea.blaze.exception.BuildException;

import java.util.List;

public class ExternalWorkspaceSyncListener implements SyncListener {
@Override
public void onSyncComplete(Project project, BlazeContext context, BlazeImportSettings importSettings, ProjectViewSet projectViewSet, ImmutableSet<Integer> buildIds, BlazeProjectData blazeProjectData, SyncMode syncMode, SyncResult syncResult) {
if(Blaze.getProjectType(project) != BlazeImportSettings.ProjectType.QUERY_SYNC) {
return;
}

if(syncMode != SyncMode.STARTUP && syncMode != SyncMode.FULL){
return ;
}

ProjectViewSet projectView = ProjectViewManager.getInstance(project).getProjectViewSet();
BuildSystem.BuildInvoker invoker =
Blaze.getBuildSystemProvider(project).getBuildSystem().getBuildInvoker(project, context);
try {
var data = getExternalWorkspaceData(
project,
context,
projectView,
blazeProjectData.getBlazeVersionData(),
invoker.getBlazeInfo(),
syncMode
);
ExternalWorkspaceDataManager.getInstance(project).setData(data);
} catch (SyncCanceledException | SyncFailedException e) {
throw new RuntimeException(e);
}

}



private ExternalWorkspaceData getExternalWorkspaceData(
Project project,
BlazeContext context,
ProjectViewSet projectViewSet,
BlazeVersionData blazeVersionData,
BlazeInfo blazeInfo,
SyncMode syncMode)
throws SyncScope.SyncCanceledException, SyncScope.SyncFailedException {

List<String> blazeModFlags =
BlazeFlags.blazeFlags(
project,
projectViewSet,
BlazeCommandName.MOD,
context,
BlazeInvocationContext.SYNC_CONTEXT);

ListenableFuture<ExternalWorkspaceData> externalWorkspaceDataFuture =
ExternalWorkspaceDataProvider.getInstance(project)
.getExternalWorkspaceData(context, blazeModFlags, blazeVersionData, blazeInfo);

FutureResult<ExternalWorkspaceData> externalWorkspaceDataResult =
FutureUtil.waitForFuture(context, externalWorkspaceDataFuture)
.timed(Blaze.buildSystemName(project) + "Mod", EventType.BlazeInvocation)
.withProgressMessage("Resolving module repository mapping...")
.onError(String.format("Could not run %s mod dump_repo_mapping", Blaze.buildSystemName(project)))
.run();

ExternalWorkspaceData externalWorkspaceData = externalWorkspaceDataResult.result();
if (externalWorkspaceData == null) {
Exception exception = externalWorkspaceDataResult.exception();
if (exception != null) {
Throwable cause = exception.getCause();
if (cause instanceof BuildException
&& cause.getCause() instanceof ExecutionDeniedException) {
throw new SyncCanceledException();
}
}
throw new SyncFailedException();
}

return externalWorkspaceData;
}

}
38 changes: 38 additions & 0 deletions base/src/com/google/idea/blaze/base/qsync/BazelInfoHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2024 The Bazel Authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.idea.blaze.base.qsync;

import com.google.idea.blaze.base.bazel.BuildSystem;
import com.google.idea.blaze.base.command.info.BlazeInfo;
import com.google.idea.blaze.base.sync.SyncScope;
import com.google.idea.blaze.exception.BuildException;

public class BazelInfoHandler {
private final BuildSystem.BuildInvoker buildInvoker;

BazelInfoHandler(BuildSystem.BuildInvoker buildInvoker) {
this.buildInvoker = buildInvoker;
}

BlazeInfo getBazelInfo() throws BuildException {
try {
return buildInvoker.getBlazeInfo();
} catch (SyncScope.SyncFailedException e) {
throw new BuildException(e);
}
}
}
14 changes: 8 additions & 6 deletions base/src/com/google/idea/blaze/base/qsync/ProjectLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -211,12 +211,14 @@ public QuerySyncProject loadProject(BlazeContext context) throws BuildException
QuerySync.USE_NEW_RES_DIR_LOGIC::getValue,
() -> !QuerySync.EXTRACT_RES_PACKAGES_AT_BUILD_TIME.getValue());
QueryRunner queryRunner = createQueryRunner(buildSystem);
BuildSystem.BuildInvoker buildInvoker = buildSystem.getBuildInvoker(project, context);
ProjectQuerier projectQuerier =
createProjectQuerier(
projectRefresher,
queryRunner,
vcsHandler,
new BazelVersionHandler(buildSystem, buildSystem.getBuildInvoker(project, context)));
new BazelVersionHandler(buildSystem, buildInvoker),
new BazelInfoHandler(buildInvoker));
QuerySyncSourceToTargetMap sourceToTargetMap =
new QuerySyncSourceToTargetMap(graph, workspaceRoot.path());

Expand Down Expand Up @@ -257,11 +259,11 @@ private ParallelPackageReader createWorkspaceRelativePackageReader() {
}

private ProjectQuerierImpl createProjectQuerier(
ProjectRefresher projectRefresher,
QueryRunner queryRunner,
Optional<BlazeVcsHandler> vcsHandler,
BazelVersionHandler bazelVersionProvider) {
return new ProjectQuerierImpl(queryRunner, projectRefresher, vcsHandler, bazelVersionProvider);
ProjectRefresher projectRefresher,
QueryRunner queryRunner,
Optional<BlazeVcsHandler> vcsHandler,
BazelVersionHandler bazelVersionProvider, BazelInfoHandler bazelInfoHandler) {
return new ProjectQuerierImpl(queryRunner, projectRefresher, vcsHandler, bazelVersionProvider, bazelInfoHandler);
}

protected QueryRunner createQueryRunner(BuildSystem buildSystem) {
Expand Down
30 changes: 21 additions & 9 deletions base/src/com/google/idea/blaze/base/qsync/ProjectQuerierImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.Uninterruptibles;
import com.google.idea.blaze.base.async.executor.BlazeExecutor;
import com.google.idea.blaze.base.bazel.BazelVersion;
import com.google.idea.blaze.base.logging.utils.querysync.SyncQueryStats;
import com.google.idea.blaze.base.logging.utils.querysync.SyncQueryStatsScope;
import com.google.idea.blaze.base.scope.BlazeContext;
Expand Down Expand Up @@ -46,18 +47,21 @@ public class ProjectQuerierImpl implements ProjectQuerier {
private final ProjectRefresher projectRefresher;
private final Optional<BlazeVcsHandler> vcsHandler;
private final BazelVersionHandler bazelVersionProvider;
private final BazelInfoHandler bazelInfoHandler;

@VisibleForTesting
@VisibleForTesting
public ProjectQuerierImpl(
QueryRunner queryRunner,
ProjectRefresher projectRefresher,
Optional<BlazeVcsHandler> vcsHandler,
BazelVersionHandler bazelVersionProvider) {
QueryRunner queryRunner,
ProjectRefresher projectRefresher,
Optional<BlazeVcsHandler> vcsHandler,
BazelVersionHandler bazelVersionProvider,
BazelInfoHandler bazelInfoHandler) {
this.queryRunner = queryRunner;
this.projectRefresher = projectRefresher;
this.vcsHandler = vcsHandler;
this.bazelVersionProvider = bazelVersionProvider;
}
this.bazelInfoHandler = bazelInfoHandler;
}

/**
* Performs a full query for the project, starting from scratch.
Expand All @@ -78,9 +82,13 @@ public PostQuerySyncData fullQuery(ProjectDefinition projectDef, BlazeContext co
vcsState.map(s -> s.upstreamRevision).orElse("<unknown>"),
vcsState.flatMap(s -> s.workspaceSnapshotPath).map(Object::toString).orElse("<none>")));

var bazelInfo = bazelInfoHandler.getBazelInfo();
var bazelVersion = Optional.of(BazelVersion.parseVersion(bazelInfo.getRelease()).toString());
var outputBase = Optional.of(bazelInfo.getOutputBase().toString());

RefreshOperation fullQuery =
projectRefresher.startFullUpdate(
context, projectDef, vcsState, bazelVersionProvider.getBazelVersion());
context, projectDef, vcsState, bazelVersion, outputBase);

QuerySpec querySpec = fullQuery.getQuerySpec().get();
return fullQuery.createPostQuerySyncData(queryRunner.runQuery(querySpec, context));
Expand Down Expand Up @@ -133,15 +141,19 @@ public PostQuerySyncData update(
}

Optional<String> bazelVersion = Optional.empty();
Optional<String> outputBase = Optional.empty();

try {
bazelVersion = bazelVersionProvider.getBazelVersion();
var bazelInfo = bazelInfoHandler.getBazelInfo();
bazelVersion = Optional.of(BazelVersion.parseVersion(bazelInfo.getRelease()).toString());
outputBase = Optional.of(bazelInfo.getOutputBase().toString());
} catch (BuildException e) {
context.handleExceptionAsWarning("Could not get bazel version", e);
}

RefreshOperation refresh =
projectRefresher.startPartialRefresh(
context, previousState, vcsState, bazelVersion, currentProjectDef);
context, previousState, vcsState, bazelVersion, outputBase, currentProjectDef);

Optional<QuerySpec> spec = refresh.getQuerySpec();
QuerySummary querySummary;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,11 +175,6 @@ public RemoteOutputArtifacts getRemoteOutputs() {
throw new NotSupportedWithQuerySyncException("getRemoteOutputs");
}

@Override
public ExternalWorkspaceData getExternalWorkspaceData() {
throw new NotSupportedWithQuerySyncException("getExternalWorkspaceData");
}

@Override
public SyncState getSyncState() {
throw new NotSupportedWithQuerySyncException("getSyncState");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.google.idea.blaze.base.command.info.BlazeInfo;
import com.google.idea.blaze.base.command.info.BlazeInfoProvider;
import com.google.idea.blaze.base.command.info.BlazeInfoRunner;
import com.google.idea.blaze.base.model.ExternalWorkspaceDataManager;
import com.google.idea.blaze.base.model.ExternalWorkspaceDataProvider;
import com.google.idea.blaze.base.execution.ExecutionDeniedException;
import com.google.idea.blaze.base.io.FileOperationProvider;
Expand Down Expand Up @@ -164,6 +165,8 @@ private SyncProjectState getProjectState(BlazeContext context, BlazeSyncParams p
ExternalWorkspaceData externalWorkspaceData =
getExternalWorkspaceData(context, projectViewSet, blazeVersionData, blazeInfo, params.syncMode());

ExternalWorkspaceDataManager.getInstance(project).setData(externalWorkspaceData);

WorkspacePathResolver workspacePathResolver =
workspacePathResolverAndProjectView.workspacePathResolver;
WorkspaceLanguageSettings workspaceLanguageSettings =
Expand Down
Loading

0 comments on commit 412de37

Please sign in to comment.