Skip to content

Commit

Permalink
[#6665] Add a ExternalWorkspaceDataProvider and wire inside the syn…
Browse files Browse the repository at this point in the history
…c - 3/n
  • Loading branch information
mtoader committed Aug 30, 2024
1 parent 2d713ca commit 2474a92
Show file tree
Hide file tree
Showing 9 changed files with 249 additions and 31 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 @@ -263,6 +263,7 @@
<editorNotificationProvider implementation="com.google.idea.blaze.base.qsync.UnsyncedFileEditorNotificationProvider" />

<projectService serviceImplementation="com.google.idea.blaze.base.command.info.BlazeInfoProvider"/>
<projectService serviceImplementation="com.google.idea.blaze.base.model.ExternalWorkspaceDataProvider"/>
<projectService serviceImplementation="com.google.idea.blaze.base.sync.SyncPhaseCoordinator"/>
<projectService serviceInterface="com.google.idea.blaze.base.sync.status.BlazeSyncStatus"
serviceImplementation="com.google.idea.blaze.base.sync.status.BlazeSyncStatusImpl"/>
Expand Down Expand Up @@ -604,6 +605,7 @@
<SyncListener implementation="com.google.idea.blaze.base.sync.autosync.ProjectTargetManagerImpl$TargetSyncListener"/>
<SyncListener implementation="com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpecProviderImpl$Listener"/>
<SyncListener implementation="com.google.idea.blaze.base.command.info.BlazeInfoProvider$Invalidator"/>
<SyncListener implementation="com.google.idea.blaze.base.model.ExternalWorkspaceDataProvider$Invalidator"/>
<SyncListener implementation="com.google.idea.blaze.base.qsync.QuerySyncAsyncFileListener$QuerySyncListener"/>
<SyncPlugin implementation="com.google.idea.blaze.base.lang.buildfile.sync.BuildLangSyncPlugin"/>
<SyncPlugin implementation="com.google.idea.blaze.base.sync.libraries.ExternalLibraryManager$SyncPlugin"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public ListenableFuture<ExternalWorkspaceData> dumpRepoMapping(
}

@Override
public ListenableFuture<byte[]> runBlazeModGetBytes(
protected ListenableFuture<byte[]> runBlazeModGetBytes(
Project project,
BuildSystem.BuildInvoker invoker,
BlazeContext context,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* 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.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.idea.blaze.base.async.executor.BlazeExecutor;
import com.google.idea.blaze.base.bazel.BazelVersion;
import com.google.idea.blaze.base.bazel.BuildSystem;
import com.google.idea.blaze.base.command.mod.BlazeModException;
import com.google.idea.blaze.base.command.mod.BlazeModRunner;
import com.google.idea.blaze.base.scope.BlazeContext;
import com.google.idea.blaze.base.scope.output.StatusOutput;
import com.google.idea.blaze.base.settings.Blaze;
import com.google.idea.blaze.base.settings.BlazeImportSettings;
import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
import com.google.idea.blaze.base.sync.SyncListener;
import com.google.idea.blaze.base.sync.SyncMode;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.Nullable;

import java.util.List;
import java.util.concurrent.ExecutionException;

public class ExternalWorkspaceDataProvider {

// bazel mod dump_repo_mapping was added in bazel 7.1.0
private static final BazelVersion MINIMUM_BLAZE_VERSION = new BazelVersion(7, 1, 0);

private static final Logger logger = Logger.getInstance(ExternalWorkspaceDataProvider.class);
private final Project project;

private volatile ExternalWorkspaceData externalWorkspaceData;

public ExternalWorkspaceDataProvider(Project project) {
this.project = project;
}

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

static Boolean isEnabled(BlazeVersionData blazeVersionData) {
return blazeVersionData.bazelIsAtLeastVersion(MINIMUM_BLAZE_VERSION);
}

public ListenableFuture<ExternalWorkspaceData> getExternalWorkspaceData(
BlazeContext context,
List<String> blazeFlags,
BlazeVersionData blazeVersionData) {
if (!isEnabled(blazeVersionData)) {
return Futures.immediateFuture(ExternalWorkspaceData.EMPTY);
}

return BlazeExecutor.getInstance().submit(() -> {
ExternalWorkspaceData mapping = getCachedExternalWorkspaceData(context, blazeFlags);
if (mapping == null) {
throw new BlazeModException("Unable to get module mapping");
}
return mapping;
});
}

private @Nullable ExternalWorkspaceData getCachedExternalWorkspaceData(
BlazeContext context,
List<String> blazeFlags) {
if (externalWorkspaceData != null) {
logger.info("Using cached External Repository Mapping");
return externalWorkspaceData;
}
try {
BlazeImportSettings importSettings = BlazeImportSettingsManager.getInstance(project).getImportSettings();
if (importSettings == null) {
return null;
}
BuildSystem.BuildInvoker buildInvoker =
Blaze.getBuildSystemProvider(project)
.getBuildSystem()
.getDefaultInvoker(project, context);

externalWorkspaceData = BlazeModRunner.getInstance()
.dumpRepoMapping(
project,
buildInvoker,
context,
importSettings.getBuildSystem(),
blazeFlags
).get();
return externalWorkspaceData;
} catch (InterruptedException | ExecutionException e) {
logger.warn("Unable to run blaze mod dump_repo_mapping", e);
return null;
}
}

public void invalidate(BlazeContext context, SyncMode syncMode) {
context.output(new StatusOutput(String.format("Invalidating External Repository Mapping info (%s)", syncMode)));
externalWorkspaceData = null;
}

public static final class Invalidator implements SyncListener {
@Override
public void onSyncStart(
Project project,
BlazeContext context,
SyncMode syncMode) {
if (syncMode == SyncMode.NO_BUILD || syncMode == SyncMode.FULL) {
ExternalWorkspaceDataProvider provider = ExternalWorkspaceDataProvider.getInstance(project);
if (provider != null) {
provider.invalidate(context, syncMode);
}
}
}
}
}
98 changes: 74 additions & 24 deletions base/src/com/google/idea/blaze/base/sync/ProjectStateSyncTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,11 @@
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.ExternalWorkspaceDataProvider;
import com.google.idea.blaze.base.execution.ExecutionDeniedException;
import com.google.idea.blaze.base.io.FileOperationProvider;
import com.google.idea.blaze.base.model.BlazeVersionData;
import com.google.idea.blaze.base.model.ExternalWorkspaceData;
import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
import com.google.idea.blaze.base.plugin.BuildSystemVersionChecker;
import com.google.idea.blaze.base.projectview.ProjectViewManager;
Expand All @@ -58,6 +60,7 @@
import com.google.idea.blaze.common.PrintOutput;
import com.google.idea.blaze.exception.BuildException;
import com.intellij.openapi.project.Project;

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -119,10 +122,10 @@ private SyncProjectState getProjectState(BlazeContext context, BlazeSyncParams p
BlazeInvocationContext.SYNC_CONTEXT);

ListenableFuture<BlazeInfo> blazeInfoFuture =
createBazelInfoFuture(context, syncFlags, params.syncMode());
createBazelInfoFuture(context, syncFlags, params.syncMode());

ListenableFuture<WorkingSet> workingSetFuture;
if(params.addWorkingSet() || params.syncMode() == SyncMode.FULL) {
if (params.addWorkingSet() || params.syncMode() == SyncMode.FULL) {
workingSetFuture = vcsHandler.getWorkingSet(context, executor);
} else {
workingSetFuture = Futures.immediateFuture(null);
Expand All @@ -142,12 +145,13 @@ private SyncProjectState getProjectState(BlazeContext context, BlazeSyncParams p
if (exception != null) {
Throwable cause = exception.getCause();
if (cause instanceof BuildException
&& cause.getCause() instanceof ExecutionDeniedException) {
&& cause.getCause() instanceof ExecutionDeniedException) {
throw new SyncCanceledException();
}
}
throw new SyncFailedException();
}

BlazeVersionData blazeVersionData =
BlazeVersionData.build(
Blaze.getBuildSystemProvider(project).getBuildSystem(), workspaceRoot, blazeInfo);
Expand All @@ -156,6 +160,9 @@ private SyncProjectState getProjectState(BlazeContext context, BlazeSyncParams p
throw new SyncFailedException();
}

ExternalWorkspaceData externalWorkspaceData =
getExternalWorkspaceData(context, projectViewSet, blazeVersionData, params.syncMode());

WorkspacePathResolver workspacePathResolver =
workspacePathResolverAndProjectView.workspacePathResolver;
WorkspaceLanguageSettings workspaceLanguageSettings =
Expand Down Expand Up @@ -186,35 +193,78 @@ private SyncProjectState getProjectState(BlazeContext context, BlazeSyncParams p
printWorkingSet(context, workingSet);
}
return SyncProjectState.builder()
.setProjectViewSet(projectViewSet)
.setLanguageSettings(workspaceLanguageSettings)
.setBlazeVersionData(blazeVersionData)
.setWorkingSet(workingSet)
.setWorkspacePathResolver(workspacePathResolver)
.build();
.setProjectViewSet(projectViewSet)
.setLanguageSettings(workspaceLanguageSettings)
.setBlazeVersionData(blazeVersionData)
.setWorkingSet(workingSet)
.setWorkspacePathResolver(workspacePathResolver)
.setExternalWorkspaceData(externalWorkspaceData)
.build();
}

private ListenableFuture<BlazeInfo> createBazelInfoFuture(
BlazeContext context,
List<String> syncFlags,
SyncMode syncMode) {
BlazeContext context,
List<String> syncFlags,
SyncMode syncMode) {
boolean useBazelInfoRunner = !BlazeInfoProvider.isEnabled() || syncMode == SyncMode.FULL;
if (useBazelInfoRunner) {
return BlazeInfoRunner.getInstance()
.runBlazeInfo(
project,
Blaze.getBuildSystemProvider(project)
.getBuildSystem()
.getDefaultInvoker(project,
context),
context,
importSettings.getBuildSystem(),
syncFlags);
.runBlazeInfo(
project,
Blaze.getBuildSystemProvider(project)
.getBuildSystem()
.getDefaultInvoker(project,
context),
context,
importSettings.getBuildSystem(),
syncFlags);
}
return BlazeInfoProvider.getInstance(project)
.getBlazeInfo(
context,
syncFlags);
.getBlazeInfo(
context,
syncFlags);
}

private ExternalWorkspaceData getExternalWorkspaceData(
BlazeContext context,
ProjectViewSet projectViewSet,
BlazeVersionData blazeVersionData,
SyncMode syncMode)
throws SyncCanceledException, SyncFailedException {

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

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

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;
}

private static class WorkspacePathResolverAndProjectView {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import com.google.idea.blaze.base.model.BlazeLibrary;
import com.google.idea.blaze.base.model.BlazeProjectData;
import com.google.idea.blaze.base.model.BlazeVersionData;
import com.google.idea.blaze.base.model.ExternalWorkspaceData;
import com.google.idea.blaze.base.model.ProjectTargetData;
import com.google.idea.blaze.base.model.RemoteOutputArtifacts;
import com.google.idea.blaze.base.model.SyncState;
Expand Down Expand Up @@ -228,7 +227,7 @@ private void run(BlazeContext context) throws SyncCanceledException, SyncFailedE
projectState.getWorkspacePathResolver(),
artifactLocationDecoder,
projectState.getLanguageSettings(),
ExternalWorkspaceData.EMPTY,
projectState.getExternalWorkspaceData(),
syncStateBuilder.build());

FileCaches.onSync(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import com.google.auto.value.AutoValue;
import com.google.idea.blaze.base.model.BlazeVersionData;
import com.google.idea.blaze.base.model.ExternalWorkspaceData;
import com.google.idea.blaze.base.projectview.ProjectViewSet;
import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
import com.google.idea.blaze.base.sync.workspace.WorkingSet;
Expand All @@ -38,6 +39,8 @@ public abstract class SyncProjectState {

public abstract WorkspacePathResolver getWorkspacePathResolver();

public abstract ExternalWorkspaceData getExternalWorkspaceData();

public static Builder builder() {
return new AutoValue_SyncProjectState.Builder();
}
Expand All @@ -55,6 +58,8 @@ public abstract static class Builder {

public abstract Builder setWorkspacePathResolver(WorkspacePathResolver pathResolver);

public abstract Builder setExternalWorkspaceData(ExternalWorkspaceData externalWorkspaceData);

public abstract SyncProjectState build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.google.idea.blaze.base.bazel.BuildSystemProvider;
import com.google.idea.blaze.base.model.BlazeProjectData;
import com.google.idea.blaze.base.model.BlazeVersionData;
import com.google.idea.blaze.base.model.ExternalWorkspaceData;
import com.google.idea.blaze.base.model.MockBlazeProjectDataBuilder;
import com.google.idea.blaze.base.model.primitives.LanguageClass;
import com.google.idea.blaze.base.model.primitives.TargetExpression;
Expand Down Expand Up @@ -192,6 +193,7 @@ private SyncProjectState getMockProjectStateWithLanguages(
.setBlazeVersionData(BlazeVersionData.builder().build())
.setWorkspacePathResolver(
new WorkspacePathResolverImpl(WorkspaceRoot.fromProjectSafe(project)))
.setExternalWorkspaceData(ExternalWorkspaceData.EMPTY)
.build();
}

Expand Down
Loading

0 comments on commit 2474a92

Please sign in to comment.