1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package vogar; 18 19 import com.google.common.annotations.VisibleForTesting; 20 import com.google.common.collect.ImmutableList; 21 import com.google.common.collect.Lists; 22 23 import java.io.File; 24 import java.io.IOException; 25 import java.util.ArrayList; 26 import java.util.List; 27 import java.util.Set; 28 import java.util.LinkedHashSet; 29 30 import vogar.android.AdbTarget; 31 import vogar.android.AndroidSdk; 32 import vogar.android.DeviceFileCache; 33 import vogar.android.DeviceFilesystem; 34 import vogar.commands.Mkdir; 35 import vogar.commands.Rm; 36 import vogar.util.Strings; 37 38 /** 39 * Command line interface for running benchmarks and tests on dalvik. 40 */ 41 public final class Vogar { 42 static final int LARGE_TIMEOUT_MULTIPLIER = 10; 43 public static final int NUM_PROCESSORS = Runtime.getRuntime().availableProcessors(); 44 45 private final List<File> actionFiles = new ArrayList<File>(); 46 private final List<String> actionClassesAndPackages = new ArrayList<String>(); 47 final List<String> targetArgs = new ArrayList<String>(); 48 private final OptionParser optionParser = new OptionParser(this); 49 private File configFile = Vogar.dotFile(".vogarconfig"); 50 private String[] configArgs; 51 public final static Console console = new Console.StreamingConsole(); 52 dotFile(String name)53 public static File dotFile (String name) { 54 return new File(System.getProperty("user.home", "."), name); 55 } 56 57 @Option(names = { "--expectations" }) 58 Set<File> expectationFiles = new LinkedHashSet<File>(); 59 { AndroidSdk.defaultExpectations()60 expectationFiles.addAll(AndroidSdk.defaultExpectations()); 61 } 62 63 @Option(names = { "--mode" }) 64 ModeId modeId = ModeId.DEVICE; 65 66 @Option(names = { "--variant" }) 67 Variant variant = Variant.X32; 68 69 @Option(names = { "--ssh" }) 70 private String sshHost; 71 72 @Option(names = { "--timeout" }) 73 int timeoutSeconds = 60; // default is one minute; 74 75 @Option(names = { "--first-monitor-port" }) 76 int firstMonitorPort = -1; 77 78 @Option(names = { "--clean-before" }) 79 boolean cleanBefore = true; 80 81 @Option(names = { "--clean-after" }) 82 boolean cleanAfter = true; 83 84 @Option(names = { "--clean" }) 85 private boolean clean = true; 86 87 @Option(names = { "--xml-reports-directory" }) 88 File xmlReportsDirectory; 89 90 @Option(names = { "--indent" }) 91 private String indent = " "; 92 93 @Option(names = { "--verbose" }) 94 private boolean verbose; 95 96 @Option(names = { "--stream" }) 97 boolean stream = true; 98 99 @Option(names = { "--color" }) 100 private boolean color = true; 101 102 @Option(names = { "--pass-color" }) 103 private int passColor = 32; // green 104 105 @Option(names = { "--skip-color" }) 106 private int skipColor = 33; // yellow 107 108 @Option(names = { "--fail-color" }) 109 private int failColor = 31; // red 110 111 @Option(names = { "--warn-color" }) 112 private int warnColor = 35; // purple 113 114 @Option(names = { "--ansi" }) 115 private boolean ansi = !"dumb".equals(System.getenv("TERM")); 116 117 @Option(names = { "--debug" }) 118 Integer debugPort; 119 120 @Option(names = { "--debug-app" }) 121 boolean debugApp; 122 123 @Option(names = { "--device-dir" }) 124 private File deviceDir; 125 126 @Option(names = { "--vm-arg" }) 127 List<String> vmArgs = new ArrayList<String>(); 128 129 @Option(names = { "--vm-command" }) 130 String vmCommand; 131 132 @Option(names = { "--dalvik-cache" }) 133 String dalvikCache = "dalvik-cache"; 134 135 @Option(names = { "--java-home" }) 136 File javaHome; 137 138 @Option(names = { "--javac-arg" }) 139 List<String> javacArgs = new ArrayList<String>(); 140 141 @Option(names = { "--multidex" }) 142 boolean multidex = true; 143 144 @Option(names = { "--use-bootclasspath" }) 145 boolean useBootClasspath = false; 146 147 @Option(names = { "--build-classpath" }) 148 List<File> buildClasspath = new ArrayList<File>(); 149 150 @Option(names = { "--classpath", "-cp" }) 151 List<File> classpath = new ArrayList<File>(); 152 153 @Option(names = { "--resource-classpath" }) 154 List<File> resourceClasspath = new ArrayList<File>(); 155 156 @Option(names = { "--sourcepath" }) 157 List<File> sourcepath = new ArrayList<File>(); 158 { AndroidSdk.defaultSourcePath()159 sourcepath.addAll(AndroidSdk.defaultSourcePath()); 160 } 161 162 @Option(names = { "--jar-search-dir" }) 163 List<File> jarSearchDirs = Lists.newArrayList(); 164 165 @Option(names = { "--vogar-dir" }) 166 File vogarDir = Vogar.dotFile(".vogar"); 167 168 @Option(names = { "--record-results" }) 169 boolean recordResults = false; 170 171 @Option(names = { "--results-dir" }) 172 File resultsDir = null; 173 174 @Option(names = { "--suggest-classpaths" }) 175 boolean suggestClasspaths = false; 176 177 @Option(names = { "--invoke-with" }) 178 String invokeWith = null; 179 180 @Option(names = { "--benchmark" }) 181 boolean benchmark = false; 182 183 @Option(names = { "--open-bugs-command" }) 184 String openBugsCommand; 185 186 @Option(names = { "--test-only" }) 187 boolean testOnly = false; 188 189 @Option(names = { "--toolchain" }) 190 Toolchain toolchain = null; 191 192 @Option(names = { "--language" }) 193 Language language = Language.CUR; 194 195 @Option(names = { "--check-jni" }) 196 boolean checkJni = true; 197 198 @Option(names = {"--runner-type"}) 199 RunnerType runnerType; 200 Vogar()201 @VisibleForTesting public Vogar() {} 202 printUsage()203 private void printUsage() { 204 // have to reset fields so that "Default is: FOO" lines are accurate 205 optionParser.reset(); 206 207 System.out.println("Usage: Vogar [options]... <actions>... [-- target args]..."); 208 System.out.println(); 209 System.out.println(" <actions>: .java files, directories, or class names."); 210 System.out.println(" These should be JUnit tests, jtreg tests, Caliper benchmarks"); 211 System.out.println(" or executable Java classes."); 212 System.out.println(); 213 System.out.println(" When passing in a JUnit test class, it may have \"#method_name\""); 214 System.out.println(" appended to it, to specify a single test method."); 215 System.out.println(); 216 System.out.println(" [target args]: arguments passed to the target process. This is only useful when"); 217 System.out.println(" the target process is a Caliper benchmark or main method."); 218 System.out.println(); 219 System.out.println("GENERAL OPTIONS"); 220 System.out.println(); 221 System.out.println(" --mode <ACTIVITY|APP_PROCESS|DEVICE|HOST|JVM>: specify which environment to run in."); 222 System.out.println(" ACTIVITY: runs in an Android application on a device or emulator"); 223 System.out.println(" APP_PROCESS: runs in an app_process runtime on a device or emulator"); 224 System.out.println(" DEVICE: runs in an ART runtime on a device or emulator"); 225 System.out.println(" HOST: runs in an ART runtime on the local desktop built with any lunch combo."); 226 System.out.println(" JVM: runs in a Java VM on the local desktop"); 227 System.out.println(" Default is: " + modeId); 228 System.out.println(); 229 System.out.println(" --variant <X32|X64>: specify which dalvikvm variant to execute with"); 230 System.out.println(" Used with --mode <host|device> only, not applicable for all devices."); 231 System.out.println(" x32: 32-bit, x64: 64-bit"); 232 System.out.println(" Default is: " + variant); 233 System.out.println(); 234 System.out.println(" --toolchain <DX|D8|JAVAC>: Which toolchain to use."); 235 System.out.println(" Default depends on --mode value (currently " 236 + modeId.defaultToolchain() + " for --mode=" + modeId + ")"); 237 System.out.println(); 238 System.out.println(" --language <J17|JN|JO|CUR>: Which language level to use."); 239 System.out.println(" Default is: " + language); 240 System.out.println(); 241 System.out.println(" --ssh <host:port>: target a remote machine via SSH."); 242 System.out.println(); 243 System.out.println(" --clean: synonym for --clean-before and --clean-after (default)."); 244 System.out.println(" Disable with --no-clean if you want no files removed."); 245 System.out.println(); 246 System.out.println(" --stream: stream output as it is emitted."); 247 System.out.println(); 248 System.out.println(" --benchmark: for use with dalvikvm, this dexes all files together,"); 249 System.out.println(" and is mandatory for running Caliper benchmarks, and a good idea"); 250 System.out.println(" for other performance sensitive code."); 251 System.out.println(" If you specify this without specifying --runner-type then it"); 252 System.out.println(" assumes --runner-type=" 253 + RunnerType.CALIPER.name().toLowerCase()); 254 System.out.println(); 255 System.out.println(" --invoke-with: provide a command to invoke the VM with. Examples:"); 256 System.out.println(" --mode host --invoke-with \"valgrind --leak-check=full\""); 257 System.out.println(" --mode device --invoke-with \"strace -f -o/sdcard/strace.txt\""); 258 System.out.println(); 259 System.out.println(" --timeout <seconds>: maximum execution time of each action before the"); 260 System.out.println(" runner aborts it. Specifying zero seconds or using --debug will"); 261 System.out.println(" disable the execution timeout. Tests tagged with 'large' will time"); 262 System.out.println(" out in " + LARGE_TIMEOUT_MULTIPLIER + "x this timeout."); 263 System.out.println(" Default is: " + timeoutSeconds); 264 System.out.println(); 265 System.out.println(" --xml-reports-directory <path>: directory to emit JUnit-style"); 266 System.out.println(" XML test results."); 267 System.out.println(); 268 System.out.println(" --classpath <jar file>: add the .jar to both build and execute classpaths."); 269 System.out.println(); 270 System.out.println(" --use-bootclasspath: use the classpath as search path for bootstrap classes."); 271 System.out.println(); 272 System.out.println(" --build-classpath <element>: add the directory or .jar to the build"); 273 System.out.println(" classpath. Such classes are available as build dependencies, but"); 274 System.out.println(" not at runtime."); 275 System.out.println(); 276 System.out.println(" --sourcepath <directory>: add the directory to the build sourcepath."); 277 System.out.println(); 278 System.out.println(" --vogar-dir <directory>: directory in which to find Vogar"); 279 System.out.println(" configuration information, caches, saved and results"); 280 System.out.println(" unless they've been put explicitly elsewhere."); 281 System.out.println(" Default is: " + vogarDir); 282 System.out.println(); 283 System.out.println(" --record-results: record test results for future comparison."); 284 System.out.println(); 285 System.out.println(" --results-dir <directory>: read and write (if --record-results used)"); 286 System.out.println(" results from and to this directory."); 287 System.out.println(); 288 System.out.println(" --runner-type <default|caliper|main|junit>: specify which runner to use."); 289 System.out.println(" default: runs both JUnit tests and main() classes"); 290 System.out.println(" caliper: runs Caliper benchmarks only"); 291 System.out.println(" main: runs main() classes only"); 292 System.out.println(" junit: runs JUnit tests only"); 293 System.out.println(" Default is determined by --benchmark and --testonly, if they are"); 294 System.out.println(" not specified then defaults to: default"); 295 System.out.println(); 296 System.out.println(" --test-only: only run JUnit tests."); 297 System.out.println(" Default is: " + testOnly); 298 System.out.println(" DEPRECATED: Use --runner-type=" 299 + RunnerType.JUNIT.name().toLowerCase()); 300 System.out.println(); 301 System.out.println(" --verbose: turn on persistent verbose output."); 302 System.out.println(); 303 System.out.println(" --check-jni: enable CheckJNI mode."); 304 System.out.println(" See http://developer.android.com/training/articles/perf-jni.html."); 305 System.out.println(" Default is: " + checkJni + ", but disabled for --benchmark."); 306 System.out.println(""); 307 System.out.println("TARGET OPTIONS"); 308 System.out.println(); 309 System.out.println(" --debug <port>: enable Java debugging on the specified port."); 310 System.out.println(" This port must be free both on the device and on the local"); 311 System.out.println(" system. Disables the timeout specified by --timeout-seconds."); 312 System.out.println(); 313 System.out.println(" --debug-app: enable debugging while running in an activity."); 314 System.out.println(" This will require the use of DDMS to connect to the activity"); 315 System.out.println(" on the device, and expose the debugger on an appropriate port."); 316 System.out.println(); 317 System.out.println(" --device-dir <directory>: use the specified directory for"); 318 System.out.println(" on-device temporary files and code."); 319 System.out.println(); 320 System.out.println(" --vm-arg <argument>: include the specified argument when spawning a"); 321 System.out.println(" virtual machine. Examples: -Xint:fast, -ea, -Xmx16M"); 322 System.out.println(); 323 System.out.println(" --vm-command <argument>: override default vm executable name."); 324 System.out.println(" Default is 'java' for the JVM and a version of dalvikvm for the host and target."); 325 System.out.println(); 326 System.out.println(" --java-home <java_home>: execute the actions on the local workstation"); 327 System.out.println(" using the specified java home directory. This does not impact"); 328 System.out.println(" which javac gets used. When unset, java is used from the PATH."); 329 System.out.println(); 330 System.out.println("EXOTIC OPTIONS"); 331 System.out.println(); 332 System.out.println(" --suggest-classpaths: build an index of jar files under the"); 333 System.out.println(" directories given by --jar-search-dir arguments. If Vogar then "); 334 System.out.println(" fails due to missing classes or packages, it will use the index to"); 335 System.out.println(" diagnose the problem and suggest a fix."); 336 System.out.println(); 337 System.out.println(" Currently only looks for jars called exactly \"classes.jar\"."); 338 System.out.println(); 339 System.out.println(" --jar-search-dir <directory>: a directory that should be searched for"); 340 System.out.println(" jar files to add to the class file index for use with"); 341 System.out.println(" --suggest-classpaths."); 342 System.out.println(); 343 System.out.println(" --clean-before: remove working directories before building and"); 344 System.out.println(" running (default). Disable with --no-clean-before if you are"); 345 System.out.println(" using interactively with your own temporary input files."); 346 System.out.println(); 347 System.out.println(" --clean-after: remove temporary files after running (default)."); 348 System.out.println(" Disable with --no-clean-after and use with --verbose if"); 349 System.out.println(" you'd like to manually re-run commands afterwards."); 350 System.out.println(); 351 System.out.println(" --color: format output in technicolor."); 352 System.out.println(); 353 System.out.println(" --pass-color: ANSI color code to use for passes."); 354 System.out.println(" Default: 32 (green)"); 355 System.out.println(); 356 System.out.println(" --skip-color: ANSI color code to use for skips."); 357 System.out.println(" Default: 33 (yellow)"); 358 System.out.println(); 359 System.out.println(" --warn-color: ANSI color code to use for warnings."); 360 System.out.println(" Default: 35 (purple)"); 361 System.out.println(); 362 System.out.println(" --fail-color: ANSI color code to use for failures."); 363 System.out.println(" Default: 31 (red)"); 364 System.out.println(); 365 System.out.println(" --ansi: use ANSI escape sequences to remove intermediate output."); 366 System.out.println(); 367 System.out.println(" --expectations <file>: include the specified file when looking for"); 368 System.out.println(" action expectations. The file should include qualified action names"); 369 System.out.println(" and the corresponding expected output."); 370 System.out.println(" Default is: " + expectationFiles); 371 System.out.println(); 372 System.out.println(" --indent: amount to indent action result output. Can be set to ''"); 373 System.out.println(" (aka empty string) to simplify output parsing."); 374 System.out.println(" Default is: '" + indent + "'"); 375 System.out.println(); 376 System.out.println(" --javac-arg <argument>: include the specified argument when invoking"); 377 System.out.println(" javac. Examples: --javac-arg -Xmaxerrs --javac-arg 1"); 378 System.out.println(); 379 System.out.println(" --multidex: whether to use native multidex support"); 380 System.out.println(" Disable with --no-multidex."); 381 System.out.println(" Default is: " + multidex); 382 System.out.println(); 383 System.out.println(" --dalvik-cache <argument>: override default dalvik-cache location."); 384 System.out.println(" Default is: " + dalvikCache); 385 System.out.println(); 386 System.out.println(" --first-monitor-port <port>: the port on the host (and possibly target)"); 387 System.out.println(" used to traffic control messages between vogar and forked processes."); 388 System.out.println(" Use this to avoid port conflicts when running multiple vogar instances"); 389 System.out.println(" concurrently. Vogar will use up to N ports starting with this one,"); 390 System.out.println(" where N is the number of processors on the host (" + NUM_PROCESSORS + "). "); 391 System.out.println(); 392 System.out.println(" --open-bugs-command <command>: a command that will take bug IDs as parameters"); 393 System.out.println(" and return those bugs that are still open. For example, if bugs 123 and"); 394 System.out.println(" 789 are both open, the command should echo those values:"); 395 System.out.println(" $ ~/bin/bug-command 123 456 789"); 396 System.out.println(" 123"); 397 System.out.println(" 789"); 398 System.out.println(); 399 System.out.println("CONFIG FILE"); 400 System.out.println(); 401 System.out.println(" User-defined default arguments can be specified in ~/.vogarconfig. See"); 402 System.out.println(" .vogarconfig.example for an example."); 403 System.out.println(); 404 } 405 406 @VisibleForTesting parseArgs(String[] args)407 public boolean parseArgs(String[] args) { 408 // extract arguments from config file 409 configArgs = OptionParser.readFile(configFile); 410 411 // config file args are added first so that in a conflict, the currently supplied 412 // arguments win. 413 List<String> actionsAndTargetArgs = optionParser.parse(configArgs); 414 if (!actionsAndTargetArgs.isEmpty()) { 415 throw new RuntimeException( 416 "actions or targets given in .vogarconfig: " + actionsAndTargetArgs); 417 } 418 419 try { 420 actionsAndTargetArgs.addAll(optionParser.parse(args)); 421 } catch (RuntimeException e) { 422 System.out.println(e.getMessage()); 423 return false; 424 } 425 426 // 427 // Semantic error validation 428 // 429 430 if (javaHome != null && !new File(javaHome, "/bin/java").exists()) { 431 System.out.println("Invalid java home: " + javaHome); 432 return false; 433 } 434 435 // check vm option consistency 436 if (!modeId.acceptsVmArgs() && !vmArgs.isEmpty()) { 437 System.out.println("VM args " + vmArgs + " should not be specified for mode " + modeId); 438 return false; 439 } 440 441 // Check variant / mode compatibility. 442 if (!modeId.supportsVariant(variant)) { 443 System.out.println("Variant " + variant + " not supported for mode " + modeId); 444 return false; 445 } 446 447 if (toolchain == null) { 448 toolchain = modeId.defaultToolchain(); 449 System.out.println("Defaulting --toolchain to " + toolchain); 450 } else if (!modeId.supportsToolchain(toolchain)) { 451 System.out.println("Toolchain " + toolchain + " not supported for mode " + modeId); 452 return false; 453 } 454 455 if (xmlReportsDirectory != null && !xmlReportsDirectory.isDirectory()) { 456 System.out.println("Invalid XML reports directory: " + xmlReportsDirectory); 457 return false; 458 } 459 460 if (!clean) { 461 cleanBefore = false; 462 cleanAfter = false; 463 } 464 465 // 466 // Post-processing arguments 467 // 468 469 if (vmCommand == null) { 470 vmCommand = modeId.defaultVmCommand(variant); 471 } 472 473 // disable timeout when benchmarking or debugging 474 if (benchmark || debugPort != null) { 475 timeoutSeconds = 0; 476 } 477 478 if (firstMonitorPort == -1) { 479 firstMonitorPort = modeId.isLocal() ? 8788 : 8787; 480 } 481 482 // separate the actions and the target args 483 int index = 0; 484 for (; index < actionsAndTargetArgs.size(); index++) { 485 String arg = actionsAndTargetArgs.get(index); 486 if (arg.equals("--")) { 487 index++; 488 break; 489 } 490 491 File file = new File(arg); 492 if (file.exists()) { 493 if (arg.endsWith(".java") || file.isDirectory()) { 494 actionFiles.add(file.getAbsoluteFile()); 495 } else { 496 System.out.println("Expected a .jar file, .java file, directory, " 497 + "package name or classname, but was: " + arg); 498 return false; 499 } 500 } else { 501 actionClassesAndPackages.add(arg); 502 } 503 } 504 505 targetArgs.addAll(actionsAndTargetArgs.subList(index, actionsAndTargetArgs.size())); 506 507 if (actionFiles.isEmpty() && actionClassesAndPackages.isEmpty()) { 508 System.out.println("No actions provided."); 509 return false; 510 } 511 512 if (!modeId.acceptsVmArgs() && !targetArgs.isEmpty()) { 513 System.out.println("Target args " + targetArgs + " should not be specified for mode " + modeId); 514 return false; 515 } 516 517 if (modeId == ModeId.ACTIVITY && debugPort != null) { 518 System.out.println("Activity debugging requires the use of --debug-app and DDMS."); 519 return false; 520 } 521 522 if (debugApp && modeId != ModeId.ACTIVITY) { 523 System.out.println("--debug-app can only be used in combination with --mode activity."); 524 return false; 525 } 526 527 // When using --benchmark, 528 // caliper will spawn each benchmark as a new process (default dalvikvm). 529 // 530 // When using also --mode app_process, we want that new process to be app_process. 531 // 532 // Pass --vm app_process to it so that it knows not to use dalvikvm. 533 if ("app_process".equals(vmCommand) && benchmark) { 534 targetArgs.add("--vm"); 535 targetArgs.add("app_process"); 536 } 537 538 return true; 539 } 540 541 /** 542 * The type of the target. 543 */ 544 private enum TargetType { 545 ADB(AdbTarget.defaultDeviceDir()), 546 LOCAL(LocalTarget.defaultDeviceDir()), 547 SSH(SshTarget.defaultDeviceDir()); 548 549 /** 550 * The default device dir. 551 */ 552 private final File defaultDeviceDir; 553 TargetType(File defaultDeviceDir)554 TargetType(File defaultDeviceDir) { 555 this.defaultDeviceDir = defaultDeviceDir; 556 } 557 defaultDeviceDir()558 public File defaultDeviceDir() { 559 return defaultDeviceDir; 560 } 561 } 562 run()563 private boolean run() throws IOException { 564 // Create a new Console for use by Run. 565 Console console = this.stream 566 ? new Console.StreamingConsole() 567 : new Console.MultiplexingConsole(); 568 console.setUseColor(color, passColor, skipColor, failColor, warnColor); 569 console.setAnsi(ansi); 570 console.setIndent(indent); 571 console.setVerbose(verbose); 572 573 Mkdir mkdir = new Mkdir(console); 574 Rm rm = new Rm(console); 575 576 // Select the target type, this is needed in order to calculate the runnerDir, which is in 577 // turn needed for creating the AdbTarget below. 578 TargetType targetType; 579 if (sshHost != null) { 580 targetType = TargetType.SSH; 581 } else if (modeId.isLocal()) { 582 targetType = TargetType.LOCAL; 583 } else { 584 targetType = TargetType.ADB; 585 } 586 587 File runnerDir = deviceDir != null 588 ? new File(deviceDir, "run") 589 : new File(targetType.defaultDeviceDir(), "run"); 590 591 // Create the target. 592 Target target; 593 switch (targetType) { 594 case ADB: 595 DeviceFilesystem deviceFilesystem = 596 new DeviceFilesystem(console, ImmutableList.of("adb", "shell")); 597 DeviceFileCache deviceFileCache = 598 new DeviceFileCache(console, runnerDir, deviceFilesystem); 599 target = new AdbTarget(console, deviceFilesystem, deviceFileCache); 600 break; 601 case SSH: 602 target = new SshTarget(console, sshHost); 603 break; 604 case LOCAL: 605 target = new LocalTarget(console, mkdir, rm); 606 break; 607 default: 608 throw new IllegalStateException("Unknown target type: " + targetType); 609 } 610 611 AndroidSdk androidSdk = null; 612 if (modeId.requiresAndroidSdk()) { 613 androidSdk = AndroidSdk.createAndroidSdk(console, mkdir, modeId, language); 614 } 615 616 if (runnerType == null) { 617 if (benchmark) { 618 if (testOnly) { 619 throw new IllegalStateException( 620 "--benchmark and --testOnly are mutually exclusive and deprecated," 621 + " use --runner-type"); 622 } 623 if (modeId == ModeId.ACTIVITY) { 624 throw new IllegalStateException( 625 "--benchmark and --mode activity are mutually exclusive"); 626 } 627 runnerType = RunnerType.CALIPER; 628 } else if (testOnly) { 629 runnerType = RunnerType.JUNIT; 630 } else { 631 runnerType = RunnerType.DEFAULT; 632 } 633 } else { 634 if (testOnly) { 635 throw new IllegalStateException( 636 "--runnerType and --testOnly are mutually exclusive"); 637 } 638 639 if (runnerType.supportsCaliper()) { 640 if (modeId == ModeId.ACTIVITY) { 641 throw new IllegalStateException( 642 "--runnerType caliper and --mode activity are mutually exclusive"); 643 } 644 645 // Assume --benchmark 646 benchmark = true; 647 } 648 } 649 650 Run run = new Run(this, toolchain, console, mkdir, androidSdk, rm, 651 target, runnerDir); 652 if (configArgs.length > 0) { 653 run.console.verbose("loaded arguments from .vogarconfig: " + 654 Strings.join(" ", (Object)configArgs)); 655 } 656 return run.driver.buildAndRun(actionFiles, actionClassesAndPackages); 657 } 658 main(String[] args)659 public static void main(String[] args) throws IOException { 660 Vogar vogar = new Vogar(); 661 if (!vogar.parseArgs(args)) { 662 vogar.printUsage(); 663 System.exit(1); 664 } 665 boolean allSuccess = vogar.run(); 666 System.exit(allSuccess ? 0 : 1); 667 } 668 } 669