blob: 19de92abdfb19158ea5f9ebe1e3eab7d76c2b1d1 [file]
// Copyright (c) 2024, 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;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.keepanno.annotations.KeepForApi;
import com.android.tools.r8.origin.CommandLineOrigin;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.CliParserUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.internal.CliParser;
import com.android.tools.r8.utils.internal.SemanticVersion;
import java.nio.file.Path;
import java.nio.file.Paths;
@KeepForApi
/** Experimental API to extract embedded rules from libraries. */
public class ExtractR8RulesCommand extends BaseCommand {
private final StringConsumer rulesConsumer;
private final boolean includeOriginComments;
private final SemanticVersion compilerVersion;
private final DexItemFactory factory;
private final Reporter reporter;
@KeepForApi
public static class Builder extends BaseCommand.Builder<ExtractR8RulesCommand, Builder> {
private final DexItemFactory factory = new DexItemFactory();
private StringConsumer rulesConsumer = null;
private boolean includeOriginComments = false;
private SemanticVersion compilerVersion = null;
private Builder() {}
private Builder(DiagnosticsHandler diagnosticsHandler) {
super(diagnosticsHandler);
}
@Override
ExtractR8RulesCommand.Builder self() {
return this;
}
/** TBD */
public ExtractR8RulesCommand.Builder setRulesOutputPath(Path rulesOutputPath) {
rulesConsumer = new StringConsumer.FileConsumer(rulesOutputPath);
return self();
}
/** TBD */
public ExtractR8RulesCommand.Builder setRulesConsumer(StringConsumer rulesConsumer) {
this.rulesConsumer = rulesConsumer;
return self();
}
/** TBD */
public ExtractR8RulesCommand.Builder setIncludeOriginComments(boolean include) {
this.includeOriginComments = include;
return self();
}
/** TBD */
public Builder setCompilerVersion(SemanticVersion version) {
compilerVersion = version;
return self();
}
@Override
protected ExtractR8RulesCommand makeCommand() {
// If printing versions ignore everything else.
if (isPrintHelp() || isPrintVersion()) {
return new ExtractR8RulesCommand(isPrintHelp(), isPrintVersion());
}
return new ExtractR8RulesCommand(
factory,
getAppBuilder().build(),
rulesConsumer,
includeOriginComments,
compilerVersion,
getReporter());
}
}
static String usageMessage() {
return CliParserUtils.getUsageMessage(createParser());
}
public static ExtractR8RulesCommand.Builder builder() {
return new ExtractR8RulesCommand.Builder();
}
public static ExtractR8RulesCommand.Builder builder(DiagnosticsHandler diagnosticsHandler) {
return new ExtractR8RulesCommand.Builder(diagnosticsHandler);
}
public static ExtractR8RulesCommand.Builder parse(String[] args) {
var builder = builder();
createParser()
.parse(
args,
builder,
err ->
builder
.getReporter()
.fatalError(new StringDiagnostic(err, CommandLineOrigin.INSTANCE)));
return builder;
}
public StringConsumer getRulesConsumer() {
return rulesConsumer;
}
public boolean getIncludeOriginComments() {
return includeOriginComments;
}
public SemanticVersion getCompilerVersion() {
return compilerVersion;
}
Reporter getReporter() {
return reporter;
}
private static CliParser<ExtractR8RulesCommand.Builder> createParser() {
var header = "Usage: TBD";
var parser = new CliParser<ExtractR8RulesCommand.Builder>(header);
return parser
.option1(
"--rules-output",
"<file>",
"Output the extracted keep rules.",
(b, arg) -> b.setRulesOutputPath(Paths.get(arg)))
.option1(
"--compiler-version",
"<version>",
"Output the proguard rules extracted.",
(b, arg) -> b.setCompilerVersion(SemanticVersion.parse(arg)))
.option0(
"--include-origin-comments",
"Include comments with origin for extracted rules.",
b -> b.setIncludeOriginComments(true))
.option0("--version", "Print the version.", b -> b.setPrintVersion(true))
.option0("--help", "Print this message.", b -> b.setPrintHelp(true), "-h")
.positional((b, arg) -> b.addProgramFiles(Paths.get(arg)));
}
private ExtractR8RulesCommand(
DexItemFactory factory,
AndroidApp inputApp,
StringConsumer rulesConsumer,
boolean includeOriginComments,
SemanticVersion compilerVersion,
Reporter reporter) {
super(inputApp);
this.factory = factory;
this.rulesConsumer = rulesConsumer;
this.includeOriginComments = includeOriginComments;
this.compilerVersion = compilerVersion;
this.reporter = reporter;
}
private ExtractR8RulesCommand(boolean printHelp, boolean printVersion) {
super(printHelp, printVersion);
this.factory = new DexItemFactory();
this.rulesConsumer = null;
this.includeOriginComments = false;
this.compilerVersion = null;
this.reporter = new Reporter();
}
@Override
InternalOptions getInternalOptions() {
InternalOptions internal = new InternalOptions(factory, reporter);
internal.programConsumer = DexIndexedConsumer.emptyConsumer();
assert internal.retainCompileTimeAnnotations;
internal.retainCompileTimeAnnotations = false;
return internal;
}
}