From 412de3750c019ae86589412807a4a3b376983794 Mon Sep 17 00:00:00 2001 From: Tomasz Pasternak Date: Thu, 21 Nov 2024 01:01:15 +0100 Subject: [PATCH] fix(qsync): External modules navigation in starlark files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Błażej Kardyś --- base/src/META-INF/blaze-base.xml | 2 + .../ExternalWorkspaceReferenceFragment.java | 8 +- .../base/model/AspectSyncProjectData.java | 5 - .../blaze/base/model/BlazeProjectData.java | 2 - .../model/ExternalWorkspaceDataManager.java | 35 +++++ .../model/ExternalWorkspaceSyncListener.java | 122 ++++++++++++++++++ .../blaze/base/qsync/BazelInfoHandler.java | 38 ++++++ .../idea/blaze/base/qsync/ProjectLoader.java | 14 +- .../blaze/base/qsync/ProjectQuerierImpl.java | 30 +++-- .../base/qsync/QuerySyncProjectData.java | 5 - .../blaze/base/sync/ProjectStateSyncTask.java | 3 + .../strategy/SyncAspectTemplateProvider.java | 15 +-- .../base/sync/workspace/WorkspaceHelper.java | 42 ++++-- .../BuildFileIntegrationTestCase.java | 6 +- .../cpp/BlazeConfigurationResolverTest.java | 2 +- .../idea/blaze/qsync/FullProjectUpdate.java | 4 + .../idea/blaze/qsync/ProjectRefresher.java | 18 ++- .../idea/blaze/qsync/RefreshParameters.java | 3 + .../qsync/project/PostQuerySyncData.java | 6 + .../blaze/qsync/ProjectRefresherTest.java | 11 ++ 20 files changed, 311 insertions(+), 60 deletions(-) create mode 100644 base/src/com/google/idea/blaze/base/model/ExternalWorkspaceDataManager.java create mode 100644 base/src/com/google/idea/blaze/base/model/ExternalWorkspaceSyncListener.java create mode 100644 base/src/com/google/idea/blaze/base/qsync/BazelInfoHandler.java diff --git a/base/src/META-INF/blaze-base.xml b/base/src/META-INF/blaze-base.xml index 55f26730761..2bb4762215b 100644 --- a/base/src/META-INF/blaze-base.xml +++ b/base/src/META-INF/blaze-base.xml @@ -260,6 +260,7 @@ + @@ -630,6 +631,7 @@ + diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/references/ExternalWorkspaceReferenceFragment.java b/base/src/com/google/idea/blaze/base/lang/buildfile/references/ExternalWorkspaceReferenceFragment.java index 9cf4fd88492..13bbf32731f 100644 --- a/base/src/com/google/idea/blaze/base/lang/buildfile/references/ExternalWorkspaceReferenceFragment.java +++ b/base/src/com/google/idea/blaze/base/lang/buildfile/references/ExternalWorkspaceReferenceFragment.java @@ -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; @@ -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); } diff --git a/base/src/com/google/idea/blaze/base/model/AspectSyncProjectData.java b/base/src/com/google/idea/blaze/base/model/AspectSyncProjectData.java index e03d237d7ef..e3256def077 100644 --- a/base/src/com/google/idea/blaze/base/model/AspectSyncProjectData.java +++ b/base/src/com/google/idea/blaze/base/model/AspectSyncProjectData.java @@ -192,11 +192,6 @@ public RemoteOutputArtifacts getRemoteOutputs() { return targetData.remoteOutputs; } - @Override - public ExternalWorkspaceData getExternalWorkspaceData() { - return externalWorkspaceData; - } - @Override public SyncState getSyncState() { return syncState; diff --git a/base/src/com/google/idea/blaze/base/model/BlazeProjectData.java b/base/src/com/google/idea/blaze/base/model/BlazeProjectData.java index 399bc669991..0a2271bb6e0 100644 --- a/base/src/com/google/idea/blaze/base/model/BlazeProjectData.java +++ b/base/src/com/google/idea/blaze/base/model/BlazeProjectData.java @@ -51,8 +51,6 @@ public interface BlazeProjectData { RemoteOutputArtifacts getRemoteOutputs(); - ExternalWorkspaceData getExternalWorkspaceData(); - SyncState getSyncState(); boolean isQuerySync(); diff --git a/base/src/com/google/idea/blaze/base/model/ExternalWorkspaceDataManager.java b/base/src/com/google/idea/blaze/base/model/ExternalWorkspaceDataManager.java new file mode 100644 index 00000000000..5c2e566ffec --- /dev/null +++ b/base/src/com/google/idea/blaze/base/model/ExternalWorkspaceDataManager.java @@ -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; + } +} diff --git a/base/src/com/google/idea/blaze/base/model/ExternalWorkspaceSyncListener.java b/base/src/com/google/idea/blaze/base/model/ExternalWorkspaceSyncListener.java new file mode 100644 index 00000000000..a3320828429 --- /dev/null +++ b/base/src/com/google/idea/blaze/base/model/ExternalWorkspaceSyncListener.java @@ -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 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 blazeModFlags = + BlazeFlags.blazeFlags( + project, + projectViewSet, + BlazeCommandName.MOD, + context, + BlazeInvocationContext.SYNC_CONTEXT); + + ListenableFuture externalWorkspaceDataFuture = + ExternalWorkspaceDataProvider.getInstance(project) + .getExternalWorkspaceData(context, blazeModFlags, blazeVersionData, blazeInfo); + + FutureResult 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; + } + +} diff --git a/base/src/com/google/idea/blaze/base/qsync/BazelInfoHandler.java b/base/src/com/google/idea/blaze/base/qsync/BazelInfoHandler.java new file mode 100644 index 00000000000..75421c2a450 --- /dev/null +++ b/base/src/com/google/idea/blaze/base/qsync/BazelInfoHandler.java @@ -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); + } + } +} diff --git a/base/src/com/google/idea/blaze/base/qsync/ProjectLoader.java b/base/src/com/google/idea/blaze/base/qsync/ProjectLoader.java index e50813fa3c1..23fa321bd0a 100644 --- a/base/src/com/google/idea/blaze/base/qsync/ProjectLoader.java +++ b/base/src/com/google/idea/blaze/base/qsync/ProjectLoader.java @@ -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()); @@ -257,11 +259,11 @@ private ParallelPackageReader createWorkspaceRelativePackageReader() { } private ProjectQuerierImpl createProjectQuerier( - ProjectRefresher projectRefresher, - QueryRunner queryRunner, - Optional vcsHandler, - BazelVersionHandler bazelVersionProvider) { - return new ProjectQuerierImpl(queryRunner, projectRefresher, vcsHandler, bazelVersionProvider); + ProjectRefresher projectRefresher, + QueryRunner queryRunner, + Optional vcsHandler, + BazelVersionHandler bazelVersionProvider, BazelInfoHandler bazelInfoHandler) { + return new ProjectQuerierImpl(queryRunner, projectRefresher, vcsHandler, bazelVersionProvider, bazelInfoHandler); } protected QueryRunner createQueryRunner(BuildSystem buildSystem) { diff --git a/base/src/com/google/idea/blaze/base/qsync/ProjectQuerierImpl.java b/base/src/com/google/idea/blaze/base/qsync/ProjectQuerierImpl.java index 04e6a203165..4fe20140644 100644 --- a/base/src/com/google/idea/blaze/base/qsync/ProjectQuerierImpl.java +++ b/base/src/com/google/idea/blaze/base/qsync/ProjectQuerierImpl.java @@ -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; @@ -46,18 +47,21 @@ public class ProjectQuerierImpl implements ProjectQuerier { private final ProjectRefresher projectRefresher; private final Optional vcsHandler; private final BazelVersionHandler bazelVersionProvider; + private final BazelInfoHandler bazelInfoHandler; - @VisibleForTesting + @VisibleForTesting public ProjectQuerierImpl( - QueryRunner queryRunner, - ProjectRefresher projectRefresher, - Optional vcsHandler, - BazelVersionHandler bazelVersionProvider) { + QueryRunner queryRunner, + ProjectRefresher projectRefresher, + Optional 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. @@ -78,9 +82,13 @@ public PostQuerySyncData fullQuery(ProjectDefinition projectDef, BlazeContext co vcsState.map(s -> s.upstreamRevision).orElse(""), vcsState.flatMap(s -> s.workspaceSnapshotPath).map(Object::toString).orElse(""))); + 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)); @@ -133,15 +141,19 @@ public PostQuerySyncData update( } Optional bazelVersion = Optional.empty(); + Optional 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 spec = refresh.getQuerySpec(); QuerySummary querySummary; diff --git a/base/src/com/google/idea/blaze/base/qsync/QuerySyncProjectData.java b/base/src/com/google/idea/blaze/base/qsync/QuerySyncProjectData.java index d967b41c5aa..c72c14a33bd 100644 --- a/base/src/com/google/idea/blaze/base/qsync/QuerySyncProjectData.java +++ b/base/src/com/google/idea/blaze/base/qsync/QuerySyncProjectData.java @@ -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"); diff --git a/base/src/com/google/idea/blaze/base/sync/ProjectStateSyncTask.java b/base/src/com/google/idea/blaze/base/sync/ProjectStateSyncTask.java index 9afaa93f087..068e6895e74 100644 --- a/base/src/com/google/idea/blaze/base/sync/ProjectStateSyncTask.java +++ b/base/src/com/google/idea/blaze/base/sync/ProjectStateSyncTask.java @@ -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; @@ -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 = diff --git a/base/src/com/google/idea/blaze/base/sync/aspects/strategy/SyncAspectTemplateProvider.java b/base/src/com/google/idea/blaze/base/sync/aspects/strategy/SyncAspectTemplateProvider.java index 49154a64c78..c67103f3167 100644 --- a/base/src/com/google/idea/blaze/base/sync/aspects/strategy/SyncAspectTemplateProvider.java +++ b/base/src/com/google/idea/blaze/base/sync/aspects/strategy/SyncAspectTemplateProvider.java @@ -18,6 +18,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.idea.blaze.base.model.BlazeProjectData; +import com.google.idea.blaze.base.model.ExternalWorkspaceDataManager; import com.google.idea.blaze.base.model.primitives.LanguageClass; import com.google.idea.blaze.base.projectview.ProjectViewManager; import com.google.idea.blaze.base.projectview.ProjectViewSet; @@ -121,7 +122,7 @@ private void writeLanguageInfos( Path realizedAspectsPath, File templateAspects, Project project) throws SyncFailedException { - var templateLanguageStringMap = getLanguageStringMap(manager); + var templateLanguageStringMap = getLanguageStringMap(manager, project); writeLanguageInfo(manager, realizedAspectsPath, templateAspects, TEMPLATE_JAVA, REALIZED_JAVA, templateLanguageStringMap); writeLanguageInfo(manager, realizedAspectsPath, templateAspects, TEMPLATE_PYTHON, REALIZED_PYTHON, templateLanguageStringMap); } @@ -140,17 +141,15 @@ private void writeLanguageInfo( } } - private static @NotNull Map getLanguageStringMap(BlazeProjectDataManager manager) { + private static @NotNull Map getLanguageStringMap(BlazeProjectDataManager manager, Project project) { var projectData = Optional.ofNullable(manager.getBlazeProjectData()); // It can be empty on intial sync. Fall back to no language support var activeLanguages = projectData.map(it -> it.getWorkspaceLanguageSettings().getActiveLanguages()).orElse(ImmutableSet.of()); - // TODO: adapt the logic to query sync - boolean isQuerySync = projectData.map(BlazeProjectData::isQuerySync).orElse(false); - var externalWorkspaceData = isQuerySync ? null : projectData.map(BlazeProjectData::getExternalWorkspaceData).orElse(null); + var externalWorkspaceData = ExternalWorkspaceDataManager.getInstance(project).getData(); var isAtLeastBazel8 = projectData.map(it -> it.getBlazeVersionData().bazelIsAtLeastVersion(8, 0, 0)).orElse(false); var isJavaEnabled = activeLanguages.contains(LanguageClass.JAVA) && - (isQuerySync || (externalWorkspaceData != null && (!isAtLeastBazel8 || externalWorkspaceData.getByRepoName("rules_java") != null))); + ((externalWorkspaceData != null && (!isAtLeastBazel8 || externalWorkspaceData.getByRepoName("rules_java") != null))); var isPythonEnabled = activeLanguages.contains(LanguageClass.PYTHON) && - (isQuerySync || (externalWorkspaceData != null && (!isAtLeastBazel8 || externalWorkspaceData.getByRepoName("rules_python") != null))); + ((externalWorkspaceData != null && (!isAtLeastBazel8 || externalWorkspaceData.getByRepoName("rules_python") != null))); return Map.of( "bazel8OrAbove", isAtLeastBazel8 ? "true" : "false", "isJavaEnabled", isJavaEnabled ? "true" : "false", @@ -202,4 +201,4 @@ public String toString() { } -} \ No newline at end of file +} diff --git a/base/src/com/google/idea/blaze/base/sync/workspace/WorkspaceHelper.java b/base/src/com/google/idea/blaze/base/sync/workspace/WorkspaceHelper.java index 81549609a0f..3620af92dac 100644 --- a/base/src/com/google/idea/blaze/base/sync/workspace/WorkspaceHelper.java +++ b/base/src/com/google/idea/blaze/base/sync/workspace/WorkspaceHelper.java @@ -17,19 +17,21 @@ import com.google.common.annotations.VisibleForTesting; import com.google.idea.blaze.base.bazel.BuildSystemProvider; +import com.google.idea.blaze.base.command.info.BlazeInfo; 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.ExternalWorkspaceDataManager; 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; import com.google.idea.blaze.base.model.primitives.WorkspaceRoot; +import com.google.idea.blaze.base.qsync.QuerySyncManager; import com.google.idea.blaze.base.settings.Blaze; -import com.google.idea.blaze.base.settings.BlazeImportSettings.ProjectType; -import com.google.idea.blaze.base.settings.BlazeImportSettings; import com.google.idea.blaze.base.settings.BuildSystemName; import com.google.idea.blaze.base.sync.SyncCache; import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager; +import com.google.idea.blaze.qsync.QuerySyncProjectSnapshot; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.diagnostic.Logger; @@ -127,7 +129,7 @@ private static Workspace resolveWorkspace(Project project, File absoluteFile) { if (blazeProjectData == null) { return null; // Project not imported yet } - Path bazelRootPath = getExternalSourceRoot(blazeProjectData); + Path bazelRootPath = getExternalSourceRoot(project, blazeProjectData); logger.debug("the bazelRootPath is " + bazelRootPath); Path path = Paths.get(absoluteFile.getAbsolutePath()).normalize(); @@ -185,18 +187,15 @@ private static WorkspacePath getPackagePath( } @VisibleForTesting - public static Path getExternalSourceRoot(BlazeProjectData projectData) { - return Paths.get(projectData.getBlazeInfo().getOutputBase().getAbsolutePath(), "external").normalize(); + public static Path getExternalSourceRoot(Project project, BlazeProjectData projectData) { + return getExternalBase(project, projectData).toPath().normalize(); } /** resolve workspace root for a named external repository. needs context since the same name can mean something different in different workspaces. */ @Nullable private static synchronized WorkspaceRoot resolveExternalWorkspaceRoot( Project project, String workspaceName, @Nullable BuildFile buildFile) { - if (Blaze.getBuildSystemName(project) == BuildSystemName.Blaze || Blaze.getProjectType(project) == BlazeImportSettings.ProjectType.QUERY_SYNC) { - return null; - } - if (Blaze.getProjectType(project) == ProjectType.QUERY_SYNC) { + if (Blaze.getBuildSystemName(project) != BuildSystemName.Bazel) { return null; } @@ -220,10 +219,14 @@ private static synchronized WorkspaceRoot resolveExternalWorkspaceRoot( BlazeProjectData blazeProjectData = BlazeProjectDataManager.getInstance(project).getBlazeProjectData(); if (blazeProjectData != null) { - File externalBase = new File(blazeProjectData.getBlazeInfo().getOutputBase(), "external"); + + + File externalBase = null; + externalBase = getExternalBase(project, blazeProjectData); + if (externalBase == null) return null; File workspaceDir = new File(externalBase, workspaceName); - ExternalWorkspace workspace = blazeProjectData.getExternalWorkspaceData().getByRepoName(workspaceName); + ExternalWorkspace workspace = ExternalWorkspaceDataManager.getInstance(project).getData().getByRepoName(workspaceName); if (workspace != null) { workspaceDir = new File(externalBase, workspace.name()); } @@ -238,8 +241,23 @@ private static synchronized WorkspaceRoot resolveExternalWorkspaceRoot( return null; } + private static @Nullable File getExternalBase(Project project, BlazeProjectData blazeProjectData) { + File externalBase; + if(blazeProjectData.isQuerySync()) { + QuerySyncProjectSnapshot snapshot = + QuerySyncManager.getInstance(project).getCurrentSnapshot().orElse(null); + if(snapshot == null) return null; + externalBase = snapshot.queryData().outputBase() + .map(pathname -> new File(pathname, "external")).orElse(null); + } else { + BlazeInfo blazeInfo = blazeProjectData.getBlazeInfo(); + externalBase = new File(blazeInfo.getOutputBase(), "external"); + } + return externalBase; + } + //The unit test use the TempFileSystem to create VirtualFile which does not exist on disk. private static boolean isInTestMode() { return ApplicationManager.getApplication().isUnitTestMode(); } -} \ No newline at end of file +} diff --git a/base/tests/utils/integration/com/google/idea/blaze/base/lang/buildfile/BuildFileIntegrationTestCase.java b/base/tests/utils/integration/com/google/idea/blaze/base/lang/buildfile/BuildFileIntegrationTestCase.java index 2cc202f6099..a4549910dad 100644 --- a/base/tests/utils/integration/com/google/idea/blaze/base/lang/buildfile/BuildFileIntegrationTestCase.java +++ b/base/tests/utils/integration/com/google/idea/blaze/base/lang/buildfile/BuildFileIntegrationTestCase.java @@ -23,6 +23,7 @@ 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.ExternalWorkspaceDataManager; 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; @@ -50,8 +51,9 @@ public final void doSetup() { new MockBlazeProjectDataManager( MockBlazeProjectDataBuilder.builder(workspaceRoot) .setOutputBase(fileSystem.getRootDir() + "/output_base") - .setExternalWorkspaceData(mockExternalWorkspaceData()) +// .setExternalWorkspaceData(mockExternalWorkspaceData()) .build()); + ExternalWorkspaceDataManager.getInstance(getProject()).setData(mockExternalWorkspaceData()); registerProjectService(BlazeProjectDataManager.class, mockProjectDataManager); registerProjectService(ProjectViewManager.class, new MockProjectViewManager()); editorTest = new EditorTestHelper(getProject(), testFixture); @@ -103,7 +105,7 @@ protected File getExternalSourceRoot() { BlazeProjectData blazeProjectData = BlazeProjectDataManager.getInstance(getProject()).getBlazeProjectData(); assertThat(blazeProjectData).isNotNull(); - return WorkspaceHelper.getExternalSourceRoot(blazeProjectData).toFile(); + return WorkspaceHelper.getExternalSourceRoot(getProject(), blazeProjectData).toFile(); } protected ExternalWorkspaceFixture createExternalWorkspaceFixture(ExternalWorkspace workspace) { diff --git a/cpp/tests/unittests/com/google/idea/blaze/cpp/BlazeConfigurationResolverTest.java b/cpp/tests/unittests/com/google/idea/blaze/cpp/BlazeConfigurationResolverTest.java index fc479a858c6..18d35440897 100644 --- a/cpp/tests/unittests/com/google/idea/blaze/cpp/BlazeConfigurationResolverTest.java +++ b/cpp/tests/unittests/com/google/idea/blaze/cpp/BlazeConfigurationResolverTest.java @@ -825,7 +825,7 @@ public void testExternalDependencyResolvedWhenIsPartOfProject() throws IOExcepti "//:toolchain")) .build(); - File externalRoot = WorkspaceHelper.getExternalSourceRoot( + File externalRoot = WorkspaceHelper.getExternalSourceRoot(project, BlazeProjectDataManager.getInstance(project).getBlazeProjectData()).toFile(); File spyExternalDependencyRoot = spy(new File(externalRoot, "external_dependency")); diff --git a/querysync/java/com/google/idea/blaze/qsync/FullProjectUpdate.java b/querysync/java/com/google/idea/blaze/qsync/FullProjectUpdate.java index 93413def19b..ce1f21a5d0f 100644 --- a/querysync/java/com/google/idea/blaze/qsync/FullProjectUpdate.java +++ b/querysync/java/com/google/idea/blaze/qsync/FullProjectUpdate.java @@ -38,6 +38,7 @@ public class FullProjectUpdate implements RefreshOperation { private final ProjectDefinition projectDefinition; private final Optional vcsState; private final Optional bazelVersion; + private final Optional outputBase; private final QuerySpec.QueryStrategy queryStrategy; public FullProjectUpdate( @@ -46,12 +47,14 @@ public FullProjectUpdate( ProjectDefinition definition, Optional vcsState, Optional bazelVersion, + Optional outputBase, QuerySpec.QueryStrategy queryStrategy) { this.context = context; this.effectiveWorkspaceRoot = effectiveWorkspaceRoot; this.projectDefinition = definition; this.vcsState = vcsState; this.bazelVersion = bazelVersion; + this.outputBase = outputBase; this.queryStrategy = queryStrategy; } @@ -71,6 +74,7 @@ public PostQuerySyncData createPostQuerySyncData(QuerySummary output) { .setVcsState(vcsState) .setBazelVersion(bazelVersion) .setQuerySummary(output) + .setOutputBase(outputBase) .build(); } } diff --git a/querysync/java/com/google/idea/blaze/qsync/ProjectRefresher.java b/querysync/java/com/google/idea/blaze/qsync/ProjectRefresher.java index 62546b8da15..7c755f5f998 100644 --- a/querysync/java/com/google/idea/blaze/qsync/ProjectRefresher.java +++ b/querysync/java/com/google/idea/blaze/qsync/ProjectRefresher.java @@ -22,6 +22,7 @@ import com.google.idea.blaze.qsync.project.PostQuerySyncData; import com.google.idea.blaze.qsync.project.ProjectDefinition; import com.google.idea.blaze.qsync.query.QuerySpec; + import java.nio.file.Path; import java.util.Optional; import java.util.function.Supplier; @@ -52,14 +53,15 @@ public ProjectRefresher( } public RefreshOperation startFullUpdate( - Context context, - ProjectDefinition spec, - Optional vcsState, - Optional bazelVersion) { + Context context, + ProjectDefinition spec, + Optional vcsState, + Optional bazelVersion, + Optional outputBase) { Path effectiveWorkspaceRoot = runQueryInWorkspaceExperiment.get() ? workspaceRoot : ( vcsState.flatMap(s -> s.workspaceSnapshotPath).orElse(workspaceRoot)); - return new FullProjectUpdate(context, effectiveWorkspaceRoot, spec, vcsState, bazelVersion, queryStrategy); + return new FullProjectUpdate(context, effectiveWorkspaceRoot, spec, vcsState, bazelVersion, outputBase, queryStrategy); } public RefreshOperation startPartialRefresh( @@ -67,11 +69,12 @@ public RefreshOperation startPartialRefresh( PostQuerySyncData currentProject, Optional latestVcsState, Optional latestBazelVersion, + Optional latestOutputBase, ProjectDefinition latestProjectDefinition) throws BuildException { return startPartialRefresh( new RefreshParameters( - currentProject, latestVcsState, latestBazelVersion, latestProjectDefinition, vcsDiffer), + currentProject, latestVcsState, latestBazelVersion, latestOutputBase, latestProjectDefinition, vcsDiffer), context); } @@ -82,7 +85,8 @@ public RefreshOperation startPartialRefresh(RefreshParameters params, Context context, params.latestProjectDefinition, params.latestVcsState, - params.latestBazelVersion); + params.latestBazelVersion, + params.latestOutputBase); } AffectedPackages affected = params.calculateAffectedPackages(context); diff --git a/querysync/java/com/google/idea/blaze/qsync/RefreshParameters.java b/querysync/java/com/google/idea/blaze/qsync/RefreshParameters.java index 23985f17b9b..331bdda09d5 100644 --- a/querysync/java/com/google/idea/blaze/qsync/RefreshParameters.java +++ b/querysync/java/com/google/idea/blaze/qsync/RefreshParameters.java @@ -39,6 +39,7 @@ public class RefreshParameters { final PostQuerySyncData currentProject; final Optional latestVcsState; final Optional latestBazelVersion; + final Optional latestOutputBase; final ProjectDefinition latestProjectDefinition; final VcsStateDiffer vcsDiffer; @@ -46,11 +47,13 @@ public class RefreshParameters { PostQuerySyncData currentProject, Optional latestVcsState, Optional latestBazelVersion, + Optional latestOutputBase, ProjectDefinition latestProjectDefinition, VcsStateDiffer vcsDiffer) { this.currentProject = currentProject; this.latestVcsState = latestVcsState; this.latestBazelVersion = latestBazelVersion; + this.latestOutputBase = latestOutputBase; this.latestProjectDefinition = latestProjectDefinition; this.vcsDiffer = vcsDiffer; } diff --git a/querysync/java/com/google/idea/blaze/qsync/project/PostQuerySyncData.java b/querysync/java/com/google/idea/blaze/qsync/project/PostQuerySyncData.java index 9f9e3fb08e7..d515f288e7b 100644 --- a/querysync/java/com/google/idea/blaze/qsync/project/PostQuerySyncData.java +++ b/querysync/java/com/google/idea/blaze/qsync/project/PostQuerySyncData.java @@ -46,6 +46,7 @@ public abstract class PostQuerySyncData { /* systemExcludes= */ ImmutableSet.of())) .setVcsState(Optional.empty()) .setBazelVersion(Optional.empty()) + .setOutputBase(Optional.empty()) .setQuerySummary(QuerySummary.EMPTY) .build(); @@ -58,6 +59,9 @@ public abstract class PostQuerySyncData { /** The version of bazel that the query was run. */ public abstract Optional bazelVersion(); + /** result of bazel info output_base */ + public abstract Optional outputBase(); + /** The summarised output from the query. */ public abstract QuerySummary querySummary(); @@ -78,6 +82,8 @@ public abstract static class Builder { public abstract Builder setBazelVersion(Optional value); + public abstract Builder setOutputBase(Optional value); + public abstract Builder setQuerySummary(QuerySummary value); @CanIgnoreReturnValue diff --git a/querysync/javatests/com/google/idea/blaze/qsync/ProjectRefresherTest.java b/querysync/javatests/com/google/idea/blaze/qsync/ProjectRefresherTest.java index be4b37699cd..ef55a40fec1 100644 --- a/querysync/javatests/com/google/idea/blaze/qsync/ProjectRefresherTest.java +++ b/querysync/javatests/com/google/idea/blaze/qsync/ProjectRefresherTest.java @@ -73,6 +73,7 @@ public void testStartPartialRefresh_pluginVersionChanged() throws Exception { project, project.vcsState(), project.bazelVersion(), + project.outputBase(), project.projectDefinition()); assertThat(update).isInstanceOf(FullProjectUpdate.class); } @@ -99,6 +100,7 @@ public void testStartPartialRefresh_vcsSnapshotUnchanged_existingProjectSnapshot project, project.vcsState(), project.bazelVersion(), + project.outputBase(), project.projectDefinition()); assertThat(update).isInstanceOf(NoopProjectRefresh.class); assertThat(update.createPostQuerySyncData(QuerySummary.EMPTY)) @@ -127,6 +129,7 @@ public void testStartPartialRefresh_vcsSnapshotUnchanged_noExistingProjectSnapsh project, project.vcsState(), project.bazelVersion(), + project.outputBase(), project.projectDefinition()); assertThat(update).isInstanceOf(PartialProjectRefresh.class); } @@ -146,6 +149,7 @@ public void testStartPartialRefresh_workspaceChange() throws Exception { project, Optional.of(new VcsState("workspace2", "1", ImmutableSet.of(), Optional.empty())), project.bazelVersion(), + project.outputBase(), project.projectDefinition()); assertThat(update).isInstanceOf(FullProjectUpdate.class); } @@ -165,6 +169,7 @@ public void testStartPartialRefresh_upstreamRevisionChange() throws Exception { project, Optional.of(new VcsState("workspaceId", "2", ImmutableSet.of(), Optional.empty())), project.bazelVersion(), + project.outputBase(), project.projectDefinition()); assertThat(update).isInstanceOf(FullProjectUpdate.class); } @@ -200,6 +205,7 @@ public void testStartPartialRefresh_bazelVersionChanged() throws Exception { project, project.vcsState(), Optional.of("2.0.0"), + project.outputBase(), project.projectDefinition()); assertThat(update).isInstanceOf(FullProjectUpdate.class); @@ -234,6 +240,7 @@ public void testStartPartialRefresh_buildFileAddedThenReverted() throws Exceptio project, Optional.of(new VcsState("workspaceId", "1", ImmutableSet.of(), Optional.empty())), project.bazelVersion(), + project.outputBase(), project.projectDefinition()); assertThat(update).isInstanceOf(PartialProjectRefresh.class); @@ -271,6 +278,7 @@ public void testStartPartialRefresh_buildFileDeletedThenReverted() throws Except project, Optional.of(new VcsState("workspaceId", "1", ImmutableSet.of(), Optional.empty())), project.bazelVersion(), + project.outputBase(), project.projectDefinition()); assertThat(update).isInstanceOf(PartialProjectRefresh.class); @@ -304,6 +312,7 @@ public void testStartPartialRefresh_buildFileModified() throws Exception { project, Optional.of(new VcsState("workspaceId", "1", workingSet, Optional.empty())), project.bazelVersion(), + project.outputBase(), project.projectDefinition()); assertThat(update).isInstanceOf(PartialProjectRefresh.class); @@ -339,6 +348,7 @@ public void testStartPartialRefresh_buildFileInWorkingSet_unmodified() throws Ex project, Optional.of(new VcsState("workspaceId", "1", workingSet, Optional.empty())), project.bazelVersion(), + project.outputBase(), project.projectDefinition()); assertThat(update).isInstanceOf(NoopProjectRefresh.class); @@ -374,6 +384,7 @@ public void testStartPartialRefresh_buildFileModifiedThenReverted() throws Excep project, Optional.of(new VcsState("workspaceId", "1", ImmutableSet.of(), Optional.empty())), project.bazelVersion(), + project.outputBase(), project.projectDefinition()); assertThat(update).isInstanceOf(PartialProjectRefresh.class);