aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/runtime
diff options
context:
space:
mode:
authorGravatar Googler <noreply@google.com>2017-06-09 04:20:23 +0200
committerGravatar Jakob Buchgraber <buchgr@google.com>2017-06-09 10:23:22 +0200
commit88677dbef8a9a1f88a35229f342fdf8523273456 (patch)
treeabc4e53ef19b6237c305771155367f7cc94547ab /src/main/java/com/google/devtools/build/lib/runtime
parent2730bae6223d611fbe5a45463cd788c4f4cc076f (diff)
Execute the launcher script from mobile-install command.
PiperOrigin-RevId: 158473075
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/runtime')
-rw-r--r--src/main/java/com/google/devtools/build/lib/runtime/mobileinstall/MobileInstallCommand.java216
1 files changed, 185 insertions, 31 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/mobileinstall/MobileInstallCommand.java b/src/main/java/com/google/devtools/build/lib/runtime/mobileinstall/MobileInstallCommand.java
index 15102ee80c..b424fd00ba 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/mobileinstall/MobileInstallCommand.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/mobileinstall/MobileInstallCommand.java
@@ -11,23 +11,33 @@
// 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.devtools.build.lib.runtime.mobileinstall;
import static com.google.devtools.build.lib.analysis.OutputGroupProvider.INTERNAL_SUFFIX;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.buildtool.BuildRequest;
+import com.google.devtools.build.lib.buildtool.BuildResult;
import com.google.devtools.build.lib.buildtool.BuildTool;
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.rules.android.WriteAdbArgsAction;
import com.google.devtools.build.lib.rules.android.WriteAdbArgsAction.StartType;
import com.google.devtools.build.lib.runtime.BlazeCommand;
-import com.google.devtools.build.lib.runtime.BlazeRuntime;
import com.google.devtools.build.lib.runtime.Command;
import com.google.devtools.build.lib.runtime.CommandEnvironment;
import com.google.devtools.build.lib.runtime.commands.BuildCommand;
import com.google.devtools.build.lib.runtime.commands.ProjectFileSupport;
+import com.google.devtools.build.lib.shell.AbnormalTerminationException;
+import com.google.devtools.build.lib.shell.BadExitStatusException;
+import com.google.devtools.build.lib.shell.CommandException;
+import com.google.devtools.build.lib.util.CommandBuilder;
import com.google.devtools.build.lib.util.ExitCode;
+import com.google.devtools.build.lib.util.io.OutErr;
+import com.google.devtools.build.lib.vfs.Path;
+import com.google.devtools.common.options.EnumConverter;
import com.google.devtools.common.options.Option;
import com.google.devtools.common.options.OptionPriority;
import com.google.devtools.common.options.OptionsBase;
@@ -35,6 +45,8 @@ import com.google.devtools.common.options.OptionsParser;
import com.google.devtools.common.options.OptionsParser.OptionUsageRestrictions;
import com.google.devtools.common.options.OptionsParsingException;
import com.google.devtools.common.options.OptionsProvider;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
/**
@@ -49,6 +61,43 @@ import java.util.List;
allowResidue = true,
help = "resource:mobile-install.txt")
public class MobileInstallCommand implements BlazeCommand {
+
+
+ /**
+ * An enumeration of all the modes that mobile-install supports.
+ */
+ public enum Mode {
+ CLASSIC("classic", null),
+ SKYLARK("skylark", "MIASPECT"),
+ SKYLARK_INCREMENTAL_RES("skylark_incremental_res", "MIRESASPECT");
+
+ private final String mode;
+ private final String aspectName;
+
+ private Mode(String mode, String aspectName) {
+ this.mode = mode;
+ this.aspectName = aspectName;
+ }
+
+ public String getAspectName() {
+ return aspectName;
+ }
+
+ @Override
+ public String toString() {
+ return mode;
+ }
+ }
+
+ /**
+ * Converter for the --mode option.
+ */
+ public static class ModeConverter extends EnumConverter<Mode> {
+ public ModeConverter() {
+ super(Mode.class, "mode");
+ }
+ }
+
/**
* Command line options for the 'mobile-install' command.
*/
@@ -71,65 +120,170 @@ public class MobileInstallCommand implements BlazeCommand {
public boolean incremental;
@Option(
- name = "v2",
+ name = "mode",
category = "mobile-install",
- defaultValue = "false",
- help = "Whether to use the v2 mobile-install. If true, rather than using the current "
- + "version of mobile-install, use version 2.",
+ defaultValue = "classic",
+ converter = ModeConverter.class,
+ help = "Select how to run mobile-install. \"classic\" runs the current version of "
+ + "mobile-install. \"skylark\" uses the new skylark version, which has support for "
+ + "android_test. \"skylark_incremental_res\" is the same as \"skylark\" plus incremental "
+ + "resource processing. \"skylark_incremental_res\" requires a device with root access.",
optionUsageRestrictions = OptionUsageRestrictions.UNDOCUMENTED
)
- public boolean v2;
+ public Mode mode;
@Option(
- name = "mobile_install_aspects",
+ name = "mobile_install_aspect",
category = "mobile-install",
- defaultValue =
- "@android_test_support//tools/android/mobile_install:mobile-install.bzl%MIASPECT",
+ defaultValue = "@android_test_support//tools/android/mobile_install:mobile-install.bzl",
help = "The aspect to use for mobile-install.",
optionUsageRestrictions = OptionUsageRestrictions.UNDOCUMENTED
)
- public String mobileInstallAspects;
+ public String mobileInstallAspect;
}
+ private static final String SINGLE_TARGET_MESSAGE =
+ "Can only run a single target. Do not use wildcards that match more than one target";
+ private static final String NO_TARGET_MESSAGE = "No targets found to run";
+
@Override
public ExitCode exec(CommandEnvironment env, OptionsProvider options) {
- BlazeRuntime runtime = env.getRuntime();
Options mobileInstallOptions = options.getOptions(Options.class);
- WriteAdbArgsAction.Options adbOptions = options.getOptions(WriteAdbArgsAction.Options.class);
- if (adbOptions.start == StartType.WARM && !mobileInstallOptions.incremental) {
- env.getReporter().handle(Event.warn(
- "Warm start is enabled, but will have no effect on a non-incremental build"));
+
+ if (mobileInstallOptions.mode == Mode.CLASSIC) {
+ WriteAdbArgsAction.Options adbOptions = options.getOptions(WriteAdbArgsAction.Options.class);
+ if (adbOptions.start == StartType.WARM && !mobileInstallOptions.incremental) {
+ env.getReporter().handle(Event.warn(
+ "Warm start is enabled, but will have no effect on a non-incremental build"));
+ }
+ List<String> targets = ProjectFileSupport.getTargets(env.getRuntime(), options);
+ BuildRequest request =
+ BuildRequest.create(
+ this.getClass().getAnnotation(Command.class).name(),
+ options,
+ env.getRuntime().getStartupOptionsProvider(),
+ targets,
+ env.getReporter().getOutErr(),
+ env.getCommandId(),
+ env.getCommandStartTime());
+ return new BuildTool(env).processRequest(request, null).getExitCondition();
}
- List<String> targets = ProjectFileSupport.getTargets(runtime, options);
- BuildRequest request = BuildRequest.create(
- this.getClass().getAnnotation(Command.class).name(), options,
- runtime.getStartupOptionsProvider(), targets,
- env.getReporter().getOutErr(), env.getCommandId(), env.getCommandStartTime());
- return new BuildTool(env).processRequest(request, null).getExitCondition();
+ // This list should look like: ["//executable:target", "arg1", "arg2"]
+ List<String> targetAndArgs = options.getResidue();
+
+ // The user must at least specify an executable target.
+ if (targetAndArgs.isEmpty()) {
+ env.getReporter().handle(Event.error("Must specify a target to run"));
+ return ExitCode.COMMAND_LINE_ERROR;
+ }
+
+ List<String> targets = ImmutableList.of(targetAndArgs.get(0));
+ List<String> runTargetArgs = targetAndArgs.subList(1, targetAndArgs.size());
+
+ OutErr outErr = env.getReporter().getOutErr();
+ BuildRequest request =
+ BuildRequest.create(
+ this.getClass().getAnnotation(Command.class).name(),
+ options,
+ env.getRuntime().getStartupOptionsProvider(),
+ targets,
+ outErr,
+ env.getCommandId(),
+ env.getCommandStartTime());
+ BuildResult result = new BuildTool(env).processRequest(request, null);
+
+ if (!result.getSuccess()) {
+ env.getReporter().handle(Event.error("Build failed. Not running target"));
+ return result.getExitCondition();
+ }
+
+ Collection<ConfiguredTarget> targetsBuilt = result.getSuccessfulTargets();
+ if (targetsBuilt == null) {
+ env.getReporter().handle(Event.error(NO_TARGET_MESSAGE));
+ return ExitCode.COMMAND_LINE_ERROR;
+ }
+ if (targetsBuilt.size() != 1) {
+ env.getReporter().handle(Event.error(SINGLE_TARGET_MESSAGE));
+ return ExitCode.COMMAND_LINE_ERROR;
+ }
+ ConfiguredTarget targetToRun = Iterables.getOnlyElement(targetsBuilt);
+
+ List<String> cmdLine = new ArrayList<>();
+ // TODO(bazel-team): Get the executable path from the filesToRun provider from the aspect.
+ cmdLine.add(
+ targetToRun.getConfiguration().getBinFragment().getPathString()
+ + "/"
+ + targetToRun.getLabel().toPathFragment().getPathString()
+ + "_launcher");
+ cmdLine.addAll(runTargetArgs);
+
+ Path workingDir = env.getBlazeWorkspace().getOutputPath().getParentDirectory();
+ com.google.devtools.build.lib.shell.Command command =
+ new CommandBuilder()
+ .addArgs(cmdLine)
+ .setEnv(env.getClientEnv())
+ .setWorkingDir(workingDir)
+ .build();
+
+ try {
+ // Restore a raw EventHandler if it is registered. This allows for blaze run to produce the
+ // actual output of the command being run even if --color=no is specified.
+ env.getReporter().switchToAnsiAllowingHandler();
+
+ // The command API is a little strange in that the following statement
+ // will return normally only if the program exits with exit code 0.
+ // If it ends with any other code, we have to catch BadExitStatusException.
+ command
+ .execute(
+ com.google.devtools.build.lib.shell.Command.NO_INPUT,
+ com.google.devtools.build.lib.shell.Command.NO_OBSERVER,
+ outErr.getOutputStream(),
+ outErr.getErrorStream(),
+ true /* interruptible */)
+ .getTerminationStatus()
+ .getExitCode();
+ return ExitCode.SUCCESS;
+ } catch (BadExitStatusException e) {
+ String message =
+ "Non-zero return code '"
+ + e.getResult().getTerminationStatus().getExitCode()
+ + "' from command: "
+ + e.getMessage();
+ env.getReporter().handle(Event.error(message));
+ return ExitCode.RUN_FAILURE;
+ } catch (AbnormalTerminationException e) {
+ // The process was likely terminated by a signal in this case.
+ return ExitCode.INTERRUPTED;
+ } catch (CommandException e) {
+ env.getReporter().handle(Event.error("Error running program: " + e.getMessage()));
+ return ExitCode.RUN_FAILURE;
+ }
}
@Override
public void editOptions(OptionsParser optionsParser) {
+ Options options = optionsParser.getOptions(Options.class);
try {
- if (optionsParser.getOptions(Options.class).v2) {
- optionsParser.parse(
- OptionPriority.COMMAND_LINE,
- "Options required by the mobile-install v2 command",
- ImmutableList.of(
- "--aspects=" + optionsParser.getOptions(Options.class).mobileInstallAspects,
- "--output_groups=mobile_install_v2" + INTERNAL_SUFFIX));
- } else {
+ if (options.mode == Mode.CLASSIC) {
String outputGroup =
- optionsParser.getOptions(Options.class).splitApks
+ options.splitApks
? "mobile_install_split" + INTERNAL_SUFFIX
- : optionsParser.getOptions(Options.class).incremental
+ : options.incremental
? "mobile_install_incremental" + INTERNAL_SUFFIX
: "mobile_install_full" + INTERNAL_SUFFIX;
optionsParser.parse(
OptionPriority.COMMAND_LINE,
"Options required by the mobile-install command",
ImmutableList.of("--output_groups=" + outputGroup));
+ } else {
+ optionsParser.parse(
+ OptionPriority.COMMAND_LINE,
+ "Options required by the skylark implementation of mobile-install command",
+ ImmutableList.of(
+ "--aspects=" + options.mobileInstallAspect + "%" + options.mode.getAspectName(),
+ "--output_groups=mobile_install" + INTERNAL_SUFFIX,
+ "--output_groups=mobile_install_launcher" + INTERNAL_SUFFIX));
}
} catch (OptionsParsingException e) {
throw new IllegalStateException(e);