Skip to content

Commit

Permalink
[bazelbuild#6664] Add blaze mod ... runner implementation - 2/n
Browse files Browse the repository at this point in the history
  • Loading branch information
mtoader committed Aug 28, 2024
1 parent a510e66 commit 992d231
Show file tree
Hide file tree
Showing 8 changed files with 275 additions and 64 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 @@ -281,6 +281,8 @@
serviceImplementation="com.google.idea.blaze.base.io.VirtualFileSystemProviderImpl"/>
<applicationService serviceInterface="com.google.idea.blaze.base.command.info.BlazeInfoRunner"
serviceImplementation="com.google.idea.blaze.base.command.info.BlazeInfoRunnerImpl"/>
<applicationService serviceInterface="com.google.idea.blaze.base.command.mod.BlazeModRunner"
serviceImplementation="com.google.idea.blaze.base.command.mod.BlazeModRunnerImpl"/>
<applicationService serviceImplementation="com.google.idea.blaze.base.model.primitives.Kind$ApplicationState"/>
<applicationService serviceInterface="com.google.idea.blaze.base.io.TempDirectoryProvider"
serviceImplementation="com.google.idea.blaze.base.io.TempDirectoryProviderImpl"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public final class BlazeCommandName {
public static final BlazeCommandName INFO = fromString("info");
public static final BlazeCommandName MOBILE_INSTALL = fromString("mobile-install");
public static final BlazeCommandName COVERAGE = fromString("coverage");
public static final BlazeCommandName MOD = fromString("mod");

public static BlazeCommandName fromString(String name) {
knownCommands.putIfAbsent(name, new BlazeCommandName(name));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@ InputStream runBlazeInfo(
BlazeContext context)
throws BuildException;

@MustBeClosed
InputStream runBlazeMod(
Project project,
BlazeCommand.Builder blazeCommandBuilder,
BuildResultHelper buildResultHelper,
BlazeContext context)
throws BuildException;

/** Allows enabling the use of command runner for restricted set of users. */
default boolean canUseCli() {
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,41 @@ public InputStream runBlazeInfo(
}
}

@Override
@MustBeClosed
public InputStream runBlazeMod(
Project project,
BlazeCommand.Builder blazeCommandBuilder,
BuildResultHelper buildResultHelper,
BlazeContext context)
throws BuildException {
performGuardCheckAsBuildException(project, context);

try (Closer closer = Closer.create()) {
Path tmpFile =
Files.createTempFile(
String.format("intellij-bazel-%s-", blazeCommandBuilder.build().getName()),
".stdout");
OutputStream out = closer.register(Files.newOutputStream(tmpFile));
OutputStream stderr =
closer.register(LineProcessingOutputStream.of(new PrintOutputLineProcessor(context)));
int exitCode =
ExternalTask.builder(WorkspaceRoot.fromProject(project))
.addBlazeCommand(blazeCommandBuilder.build())
.context(context)
.stdout(out)
.stderr(stderr)
.ignoreExitCode(true)
.build()
.run();
BazelExitCodeException.throwIfFailed(blazeCommandBuilder, exitCode);
return new BufferedInputStream(
Files.newInputStream(tmpFile, StandardOpenOption.DELETE_ON_CLOSE));
} catch (IOException e) {
throw new BuildException(e);
}
}

private BuildResult issueBuild(
BlazeCommand.Builder blazeCommandBuilder, WorkspaceRoot workspaceRoot, Map<String, String> envVars, BlazeContext context) {
blazeCommandBuilder.addBlazeFlags(getExtraBuildFlags(blazeCommandBuilder));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.google.idea.blaze.base.command.mod;

import com.google.idea.blaze.exception.BuildException;

import javax.annotation.concurrent.Immutable;

@Immutable
public final class BlazeModException extends BuildException {
public BlazeModException(String message) {
super(message);
}

public BlazeModException(String message, Throwable cause) {
super(message, cause);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* 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.command.mod;

import com.google.common.util.concurrent.ListenableFuture;
import com.google.idea.blaze.base.bazel.BuildSystem.BuildInvoker;
import com.google.idea.blaze.base.model.ExternalWorkspaceData;
import com.google.idea.blaze.base.scope.BlazeContext;
import com.google.idea.blaze.base.settings.BuildSystemName;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;

import java.util.List;

/** Runs the blaze info command. The results may be cached in the workspace. */
public abstract class BlazeModRunner {

public static BlazeModRunner getInstance() {
return ApplicationManager.getApplication().getService(BlazeModRunner.class);
}

/**
* This calls blaze info without any specific key so blaze info will return all keys and values
* that it has.
*
* @param blazeFlags The blaze flags that will be passed to Blaze.
* @return The blaze info data fields.
*/
public abstract ListenableFuture<ExternalWorkspaceData> dumpRepoMapping(
Project project,
BuildInvoker invoker,
BlazeContext context,
BuildSystemName buildSystemName,
List<String> blazeFlags);

/**
* @param modArgs The arguments passed into `blaze mod ...`
* @param blazeFlags The blaze flags that will be passed to Blaze.
* @return The blaze info value associated with the specified key
*/
protected abstract ListenableFuture<byte[]> runBlazeModGetBytes(
Project project,
BuildInvoker invoker,
BlazeContext context,
List<String> modArgs,
List<String> blazeFlags);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.google.idea.blaze.base.command.mod;

import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.idea.blaze.base.async.executor.BlazeExecutor;
import com.google.idea.blaze.base.bazel.BuildSystem;
import com.google.idea.blaze.base.command.BlazeCommand;
import com.google.idea.blaze.base.command.BlazeCommandName;
import com.google.idea.blaze.base.command.BlazeCommandRunner;
import com.google.idea.blaze.base.command.buildresult.BuildResultHelper;
import com.google.idea.blaze.base.model.ExternalWorkspaceData;
import com.google.idea.blaze.base.model.primitives.ExternalWorkspace;
import com.google.idea.blaze.base.scope.BlazeContext;
import com.google.idea.blaze.base.settings.BuildSystemName;
import com.intellij.openapi.project.Project;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.List;

public class BlazeModRunnerImpl extends BlazeModRunner {

@Override
public ListenableFuture<ExternalWorkspaceData> dumpRepoMapping(
Project project,
BuildSystem.BuildInvoker invoker,
BlazeContext context,
BuildSystemName buildSystemName,
List<String> blazeFlags) {
return Futures.transform(
runBlazeModGetBytes(project, invoker, context, ImmutableList.of( "dump_repo_mapping", "workspace"), blazeFlags),
bytes -> {
JsonObject json = JsonParser.parseString(new String(bytes, StandardCharsets.UTF_8).trim()).getAsJsonObject();

ImmutableList<ExternalWorkspace> externalWorkspaces =
json
.asMap().entrySet().stream()
.filter(e -> e.getValue().isJsonPrimitive())
.filter(e -> !e.getValue().getAsString().trim().isEmpty())
.map(e -> ExternalWorkspace.create(e.getValue().getAsString(), e.getKey()))
.collect(ImmutableList.toImmutableList());

return ExternalWorkspaceData.create(externalWorkspaces);
},
BlazeExecutor.getInstance().getExecutor());
}

@Override
public ListenableFuture<byte[]> runBlazeModGetBytes(
Project project,
BuildSystem.BuildInvoker invoker,
BlazeContext context,
List<String> modArgs,
List<String> blazeFlags) {
return BlazeExecutor.getInstance()
.submit(() -> {
BlazeCommand.Builder builder =
BlazeCommand.builder(invoker, BlazeCommandName.MOD)
.addBlazeFlags(blazeFlags);

if (modArgs != null) {
builder.addBlazeFlags(modArgs);
}

try (BuildResultHelper buildResultHelper = invoker.createBuildResultHelper()) {
BlazeCommandRunner runner = invoker.getCommandRunner();
try (InputStream stream = runner.runBlazeMod(project, builder, buildResultHelper, context)) {
return stream.readAllBytes();
}
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.google.idea.blaze.base.command.buildresult.BuildResultHelper;
import com.google.idea.blaze.base.command.buildresult.BuildResultHelper.GetArtifactsException;
import com.google.idea.blaze.base.command.info.BlazeInfoException;
import com.google.idea.blaze.base.command.mod.BlazeModException;
import com.google.idea.blaze.base.logging.utils.querysync.BuildDepsStatsScope;
import com.google.idea.blaze.base.logging.utils.querysync.SyncQueryStatsScope;
import com.google.idea.blaze.base.run.testlogs.BlazeTestResults;
Expand All @@ -29,6 +30,7 @@
import com.google.idea.blaze.base.sync.aspects.BuildResult;
import com.google.idea.blaze.exception.BuildException;
import com.intellij.openapi.project.Project;

import java.io.InputStream;
import java.util.Map;

Expand All @@ -38,77 +40,88 @@
*/
public class FakeBlazeCommandRunner implements BlazeCommandRunner {

@FunctionalInterface
public interface BuildFunction {
BlazeBuildOutputs runBuild(BuildResultHelper buildResultHelper) throws BuildException;
}
@FunctionalInterface
public interface BuildFunction {
BlazeBuildOutputs runBuild(BuildResultHelper buildResultHelper) throws BuildException;
}

private final BuildFunction resultsFunction;
private BlazeCommand command;
private final BuildFunction resultsFunction;
private BlazeCommand command;

public FakeBlazeCommandRunner() {
this(
buildResultHelper ->
BlazeBuildOutputs.fromParsedBepOutput(
BuildResult.SUCCESS, buildResultHelper.getBuildOutput()));
}
public FakeBlazeCommandRunner() {
this(
buildResultHelper ->
BlazeBuildOutputs.fromParsedBepOutput(
BuildResult.SUCCESS, buildResultHelper.getBuildOutput()));
}

public FakeBlazeCommandRunner(BuildFunction buildFunction) {
this.resultsFunction = buildFunction;
}

public FakeBlazeCommandRunner(BuildFunction buildFunction) {
this.resultsFunction = buildFunction;
}
@Override
public BlazeBuildOutputs run(
Project project,
BlazeCommand.Builder blazeCommandBuilder,
BuildResultHelper buildResultHelper,
BlazeContext context,
Map<String, String> envVars)
throws BuildException {
command = blazeCommandBuilder.build();
try {
BlazeBuildOutputs blazeBuildOutputs = resultsFunction.runBuild(buildResultHelper);
int exitCode = blazeBuildOutputs.buildResult.exitCode;
BuildDepsStatsScope.fromContext(context).ifPresent(stats -> stats.setBazelExitCode(exitCode));
return blazeBuildOutputs;
} catch (GetArtifactsException e) {
return BlazeBuildOutputs.noOutputs(BuildResult.FATAL_ERROR);
}
}

@Override
public BlazeBuildOutputs run(
Project project,
BlazeCommand.Builder blazeCommandBuilder,
BuildResultHelper buildResultHelper,
BlazeContext context,
Map<String, String> envVars)
throws BuildException {
command = blazeCommandBuilder.build();
try {
BlazeBuildOutputs blazeBuildOutputs = resultsFunction.runBuild(buildResultHelper);
int exitCode = blazeBuildOutputs.buildResult.exitCode;
BuildDepsStatsScope.fromContext(context).ifPresent(stats -> stats.setBazelExitCode(exitCode));
return blazeBuildOutputs;
} catch (GetArtifactsException e) {
return BlazeBuildOutputs.noOutputs(BuildResult.FATAL_ERROR);
@Override
public BlazeTestResults runTest(
Project project,
BlazeCommand.Builder blazeCommandBuilder,
BuildResultHelper buildResultHelper,
BlazeContext context,
Map<String, String> envVars) {
return BlazeTestResults.NO_RESULTS;
}
}

@Override
public BlazeTestResults runTest(
Project project,
BlazeCommand.Builder blazeCommandBuilder,
BuildResultHelper buildResultHelper,
BlazeContext context,
Map<String, String> envVars) {
return BlazeTestResults.NO_RESULTS;
}
@Override
public InputStream runQuery(
Project project,
BlazeCommand.Builder blazeCommandBuilder,
BuildResultHelper buildResultHelper,
BlazeContext context)
throws BuildException {
SyncQueryStatsScope.fromContext(context).ifPresent(stats -> stats.setBazelExitCode(0));
return InputStream.nullInputStream();
}

@Override
public InputStream runQuery(
Project project,
BlazeCommand.Builder blazeCommandBuilder,
BuildResultHelper buildResultHelper,
BlazeContext context)
throws BuildException {
SyncQueryStatsScope.fromContext(context).ifPresent(stats -> stats.setBazelExitCode(0));
return InputStream.nullInputStream();
}
@Override
@MustBeClosed
public InputStream runBlazeInfo(
Project project,
BlazeCommand.Builder blazeCommandBuilder,
BuildResultHelper buildResultHelper,
BlazeContext context)
throws BlazeInfoException {
return InputStream.nullInputStream();
}

@Override
@MustBeClosed
public InputStream runBlazeInfo(
Project project,
BlazeCommand.Builder blazeCommandBuilder,
BuildResultHelper buildResultHelper,
BlazeContext context)
throws BlazeInfoException {
return InputStream.nullInputStream();
}
@Override
@MustBeClosed
public InputStream runBlazeMod(
Project project,
BlazeCommand.Builder blazeCommandBuilder,
BuildResultHelper buildResultHelper,
BlazeContext context)
throws BlazeModException {
return InputStream.nullInputStream();
}

public BlazeCommand getIssuedCommand() {
return command;
}
public BlazeCommand getIssuedCommand() {
return command;
}
}

0 comments on commit 992d231

Please sign in to comment.