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