blob: fd9ba71a945ce77ccd7508533d80b4a134193e12 [file] [log] [blame]
// Copyright 2016 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// 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.rules.android;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterators;
import com.google.devtools.build.lib.analysis.actions.CommandLineItem;
import com.google.devtools.build.lib.analysis.actions.CustomCommandLine;
import com.google.devtools.build.lib.analysis.actions.CustomCommandLine.VectorArg;
import com.google.devtools.build.lib.rules.android.ResourceContainer.ResourceType;
/**
* Factory for functions to convert a {@link ResourceContainer} to a commandline argument, or a
* collection of artifacts. Uses a certain convention for commandline arguments (e.g., separators,
* and ordering of container elements).
*/
@VisibleForTesting
public class ResourceContainerConverter {
static Builder builder() {
return new Builder();
}
interface ToArg extends CommandLineItem.MapFn<ResourceContainer> {
String listSeparator();
}
static class Builder {
private boolean includeResourceRoots;
private boolean includeLabel;
private boolean includeManifest;
private boolean includeRTxt;
private boolean includeSymbolsBin;
private boolean includeCompiledSymbols;
private boolean includeStaticLibrary;
private boolean includeAapt2RTxt;
private SeparatorType separatorType;
private Joiner argJoiner;
private Function<String, String> escaper = Functions.identity();
enum SeparatorType {
COLON_COMMA,
SEMICOLON_AMPERSAND
}
Builder() {}
Builder includeAapt2RTxt() {
includeAapt2RTxt = true;
return this;
}
Builder includeStaticLibrary() {
includeStaticLibrary = true;
return this;
}
Builder includeResourceRoots() {
includeResourceRoots = true;
return this;
}
Builder includeLabel() {
includeLabel = true;
return this;
}
Builder includeManifest() {
includeManifest = true;
return this;
}
Builder includeRTxt() {
includeRTxt = true;
return this;
}
Builder includeSymbolsBin() {
includeSymbolsBin = true;
return this;
}
Builder includeCompiledSymbols() {
includeCompiledSymbols = true;
return this;
}
Builder withSeparator(SeparatorType type) {
separatorType = type;
return this;
}
ToArg toArgConverter() {
switch (separatorType) {
case COLON_COMMA:
argJoiner = Joiner.on(":");
// We currently use ":" to separate components of an argument and "," to separate
// arguments in a list of arguments. Those characters require escaping if used in a label
// (part of the set of allowed characters in a label).
if (includeLabel) {
escaper = (String input) -> input.replace(":", "\\:").replace(",", "\\,");
}
break;
case SEMICOLON_AMPERSAND:
argJoiner = Joiner.on(";");
break;
default:
Preconditions.checkState(false, "Unknown separator type " + separatorType);
break;
}
return new ToArg() {
@Override
public String expandToCommandLine(ResourceContainer container) {
ImmutableList.Builder<String> cmdPieces = ImmutableList.builder();
if (includeResourceRoots) {
cmdPieces.add(convertRoots(container, ResourceType.RESOURCES));
cmdPieces.add(convertRoots(container, ResourceType.ASSETS));
}
if (includeLabel) {
cmdPieces.add(escaper.apply(container.getLabel().toString()));
}
if (includeManifest) {
cmdPieces.add(container.getManifest().getExecPathString());
}
if (includeRTxt) {
cmdPieces.add(
container.getRTxt() == null ? "" : container.getRTxt().getExecPathString());
}
if (includeAapt2RTxt) {
cmdPieces.add(
container.getAapt2RTxt() == null
? ""
: container.getAapt2RTxt().getExecPathString());
}
if (includeStaticLibrary) {
cmdPieces.add(
container.getStaticLibrary() == null
? ""
: container.getStaticLibrary().getExecPathString());
}
if (includeCompiledSymbols) {
cmdPieces.add(
container.getCompiledSymbols() == null
? ""
: container.getCompiledSymbols().getExecPathString());
}
if (includeSymbolsBin) {
cmdPieces.add(
container.getSymbols() == null ? "" : container.getSymbols().getExecPathString());
}
return argJoiner.join(cmdPieces.build());
}
@Override
public String listSeparator() {
switch (separatorType) {
case COLON_COMMA:
return ",";
case SEMICOLON_AMPERSAND:
return "&";
default:
Preconditions.checkState(false, "Unknown separator type " + separatorType);
return null;
}
}
};
}
}
@VisibleForTesting
public static String convertRoots(ResourceContainer container, ResourceType resourceType) {
return Joiner.on("#")
.join(
Iterators.transform(
container.getRoots(resourceType).iterator(), Functions.toStringFunction()));
}
/**
* Convert ResourceDependencies to commandline args and artifacts, assuming the commandline
* arguments should be split into direct deps and transitive deps.
*/
static void addToCommandLine(
ResourceDependencies dependencies, CustomCommandLine.Builder cmdBuilder, ToArg toArg) {
cmdBuilder.addAll(
"--data",
VectorArg.join(toArg.listSeparator())
.each(dependencies.getTransitiveResourceContainers())
.mapped(toArg));
cmdBuilder.addAll(
"--directData",
VectorArg.join(toArg.listSeparator())
.each(dependencies.getDirectResourceContainers())
.mapped(toArg));
}
}