// 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.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.Iterables; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.actions.ParameterFile.ParameterFileType; import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext; import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; import com.google.devtools.build.lib.analysis.actions.SpawnAction; import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.vfs.PathFragment; import java.util.ArrayList; import java.util.List; /** Builder for creating $android_resource_parser action. */ public class AndroidResourceParsingActionBuilder { private static final ResourceContainerToArtifacts RESOURCE_CONTAINER_TO_ARTIFACTS = new ResourceContainerToArtifacts(); private static final ResourceContainerToArg RESOURCE_CONTAINER_TO_ARG = new ResourceContainerToArg(); private final RuleContext ruleContext; private LocalResourceContainer primary; private Artifact output; private ResourceContainer resourceContainer; /** * @param ruleContext The RuleContext that was used to create the SpawnAction.Builder. */ public AndroidResourceParsingActionBuilder(RuleContext ruleContext) { this.ruleContext = ruleContext; } /** * Set the resource container to parse. */ public AndroidResourceParsingActionBuilder setParse(LocalResourceContainer primary) { this.primary = primary; return this; } /** * Set the artifact location for the output protobuf. */ public AndroidResourceParsingActionBuilder setOutput(Artifact output) { this.output = output; return this; } /** Set the primary resources. */ public AndroidResourceParsingActionBuilder withPrimary(ResourceContainer resourceContainer) { this.resourceContainer = resourceContainer; return this; } private static class ResourceContainerToArg implements Function<LocalResourceContainer, String> { public ResourceContainerToArg() { } @Override public String apply(LocalResourceContainer container) { return new StringBuilder() .append(convertRoots(container.getResourceRoots())) .append(":") .append(convertRoots(container.getAssetRoots())) .toString(); } } private static class ResourceContainerToArtifacts implements Function<LocalResourceContainer, NestedSet<Artifact>> { public ResourceContainerToArtifacts() { } @Override public NestedSet<Artifact> apply(LocalResourceContainer container) { NestedSetBuilder<Artifact> artifacts = NestedSetBuilder.naiveLinkOrder(); artifacts.addAll(container.getAssets()); artifacts.addAll(container.getResources()); return artifacts.build(); } } private static String convertRoots(Iterable<PathFragment> roots) { return Joiner.on("#").join(Iterables.transform(roots, Functions.toStringFunction())); } public ResourceContainer build(ActionConstructionContext context) { CustomCommandLine.Builder builder = new CustomCommandLine.Builder(); // Set the busybox tool. builder.add("--tool").add("PARSE").add("--"); NestedSetBuilder<Artifact> inputs = NestedSetBuilder.naiveLinkOrder(); inputs.addAll( ruleContext .getExecutablePrerequisite("$android_resources_busybox", Mode.HOST) .getRunfilesSupport() .getRunfilesArtifactsWithoutMiddlemen()); Preconditions.checkNotNull(primary); builder.add("--primaryData").add(RESOURCE_CONTAINER_TO_ARG.apply(primary)); inputs.addTransitive(RESOURCE_CONTAINER_TO_ARTIFACTS.apply(primary)); List<Artifact> outs = new ArrayList<>(); Preconditions.checkNotNull(output); builder.addExecPath("--output", output); outs.add(output); SpawnAction.Builder spawnActionBuilder = new SpawnAction.Builder(); // Create the spawn action. ruleContext.registerAction( spawnActionBuilder .useParameterFile(ParameterFileType.UNQUOTED) .addTransitiveInputs(inputs.build()) .addOutputs(ImmutableList.copyOf(outs)) .setCommandLine(builder.build()) .setExecutable( ruleContext.getExecutablePrerequisite("$android_resources_busybox", Mode.HOST)) .setProgressMessage("Parsing Android resources for " + ruleContext.getLabel()) .setMnemonic("AndroidResourceParser") .build(context)); return resourceContainer.toBuilder().setSymbols(output).build(); } }