blob: 0b38e3a45e877369f4c97a72d883e3790d449809 [file] [log] [blame]
// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.bisect;
import com.android.tools.r8.errors.CompilationError;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class BisectOptions {
private static final String HELP_FLAG = "--help";
public static final String BUILD_GOOD_FLAG = "--good";
public static final String BUILD_BAD_FLAG = "--bad";
public static final String RESULT_GOOD_FLAG = "--result-good";
public static final String RESULT_BAD_FLAG = "--result-bad";
public static final String STATE_FLAG = "--state";
public static final String OUTPUT_FLAG = "--output";
public static final String COMMAND_FLAG = "--command";
public final Path goodBuild;
public final Path badBuild;
public final Path stateFile;
public final Path command;
public final Path output;
public final Result result;
public enum Result {
UNKNOWN,
GOOD,
BAD
}
private BisectOptions(
Path goodBuild, Path badBuild, Path stateFile, Path command, Path output, Result result) {
this.goodBuild = goodBuild;
this.badBuild = badBuild;
this.stateFile = stateFile;
this.command = command;
this.output = output;
this.result = result;
}
public static BisectOptions parse(String[] args) throws IOException {
Path badBuild = null;
Path goodBuild = null;
Path stateFile = null;
Path command = null;
Path output = null;
Result result = Result.UNKNOWN;
for (int i = 0; i < args.length; i++) {
String arg = args[i].trim();
if (arg.equals(HELP_FLAG)) {
printHelp();
return null;
} else if (arg.equals(BUILD_BAD_FLAG)) {
i = nextArg(i, args, BUILD_BAD_FLAG);
badBuild = Paths.get(args[i]);
} else if (arg.equals(BUILD_GOOD_FLAG)) {
i = nextArg(i, args, BUILD_GOOD_FLAG);
goodBuild = Paths.get(args[i]);
} else if (arg.equals(COMMAND_FLAG)) {
i = nextArg(i, args, COMMAND_FLAG);
command = Paths.get(args[i]);
} else if (arg.equals(OUTPUT_FLAG)) {
i = nextArg(i, args, OUTPUT_FLAG);
output = Paths.get(args[i]);
} else if (arg.equals(RESULT_BAD_FLAG)) {
result = checkSingleResult(result, Result.BAD);
} else if (arg.equals(RESULT_GOOD_FLAG)) {
result = checkSingleResult(result, Result.GOOD);
} else if (arg.equals(STATE_FLAG)) {
i = nextArg(i, args, STATE_FLAG);
stateFile = Paths.get(args[i]);
}
}
exists(require(badBuild, BUILD_BAD_FLAG), BUILD_BAD_FLAG);
exists(require(goodBuild, BUILD_GOOD_FLAG), BUILD_GOOD_FLAG);
if (stateFile != null) {
exists(stateFile, STATE_FLAG);
}
if (command != null) {
exists(command, COMMAND_FLAG);
}
if (output != null) {
directoryExists(output, OUTPUT_FLAG);
}
return new BisectOptions(goodBuild, badBuild, stateFile, command, output, result);
}
private static int nextArg(int index, String[] args, String flag) {
if (args.length == index + 1) {
throw new CompilationError("Missing argument for: " + flag);
}
return index + 1;
}
private static Path require(Path value, String flag) {
if (value == null) {
throw new CompilationError("Missing required option: " + flag);
}
return value;
}
private static Path exists(Path path, String flag) {
if (Files.exists(path)) {
return path;
}
throw new CompilationError("File " + flag + ": " + path + " does not exist");
}
private static Path directoryExists(Path path, String flag) {
if (Files.exists(path) && Files.isDirectory(path)) {
return path;
}
throw new CompilationError("File " + flag + ": " + path + " is not a valid directory");
}
private static Result checkSingleResult(Result current, Result result) {
if (current != Result.UNKNOWN) {
throw new CompilationError(
"Cannot specify " + RESULT_GOOD_FLAG + " and " + RESULT_BAD_FLAG + " simultaneously");
}
return result;
}
public static void printHelp() throws IOException {
System.out.println("--bad <apk> Known bad APK.");
System.out.println("--command <file> Command to run after each bisection.");
System.out.println("--good <apk> Known good APK.");
System.out.println("--help");
System.out.println("--output <dir> Output directory.");
System.out.println(
"--result-bad Bisect again assuming previous run was\n" + " bad.");
System.out.println(
"--result-good Bisect again assuming previous run was\n" + " good.");
System.out.println("--state <file> Bisection state.");
}
}