/*
* Copyright 2017-present Facebook, Inc.
*
* 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.facebook.buck.android;
import com.facebook.buck.android.aapt.RDotTxtEntry;
import com.facebook.buck.io.ProjectFilesystem;
import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.model.BuildTargets;
import com.facebook.buck.rules.AbstractBuildRule;
import com.facebook.buck.rules.AddToRuleKey;
import com.facebook.buck.rules.BuildContext;
import com.facebook.buck.rules.BuildRule;
import com.facebook.buck.rules.BuildRuleParams;
import com.facebook.buck.rules.BuildableContext;
import com.facebook.buck.rules.ExplicitBuildTargetSourcePath;
import com.facebook.buck.rules.SourcePath;
import com.facebook.buck.rules.SourcePathResolver;
import com.facebook.buck.rules.SourcePathRuleFinder;
import com.facebook.buck.step.Step;
import com.facebook.buck.step.fs.MakeCleanDirectoryStep;
import com.facebook.buck.util.MoreCollectors;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSortedSet;
import java.nio.file.Path;
import java.util.EnumSet;
import java.util.Optional;
import javax.annotation.Nullable;
public class GenerateRDotJava extends AbstractBuildRule {
@AddToRuleKey private final EnumSet<RDotTxtEntry.RType> bannedDuplicateResourceTypes;
@AddToRuleKey private final SourcePath pathToRDotTxtFile;
@AddToRuleKey private Optional<String> resourceUnionPackage;
@AddToRuleKey private boolean shouldBuildStringSourceMap;
private final ImmutableList<HasAndroidResourceDeps> resourceDeps;
private FilteredResourcesProvider resourcesProvider;
GenerateRDotJava(
BuildRuleParams buildRuleParams,
SourcePathRuleFinder ruleFinder,
EnumSet<RDotTxtEntry.RType> bannedDuplicateResourceTypes,
SourcePath pathToRDotTxtFile,
Optional<String> resourceUnionPackage,
boolean shouldBuildStringSourceMap,
ImmutableSortedSet<BuildRule> resourceDeps,
FilteredResourcesProvider resourcesProvider) {
super(
buildRuleParams.copyAppendingExtraDeps(
getAllDeps(ruleFinder, pathToRDotTxtFile, resourceDeps, resourcesProvider)));
this.bannedDuplicateResourceTypes = bannedDuplicateResourceTypes;
this.pathToRDotTxtFile = pathToRDotTxtFile;
this.resourceUnionPackage = resourceUnionPackage;
this.shouldBuildStringSourceMap = shouldBuildStringSourceMap;
this.resourceDeps =
resourceDeps
.stream()
.map(HasAndroidResourceDeps.class::cast)
.collect(MoreCollectors.toImmutableList());
this.resourcesProvider = resourcesProvider;
}
private static ImmutableSortedSet<BuildRule> getAllDeps(
SourcePathRuleFinder ruleFinder,
SourcePath pathToRDotTxtFile,
ImmutableSortedSet<BuildRule> resourceDeps,
FilteredResourcesProvider resourcesProvider) {
ImmutableSortedSet.Builder<BuildRule> builder = ImmutableSortedSet.naturalOrder();
builder.addAll(ruleFinder.filterBuildRuleInputs(pathToRDotTxtFile)).addAll(resourceDeps);
resourcesProvider.getResourceFilterRule().ifPresent(builder::add);
return builder.build();
}
@Override
public ImmutableList<Step> getBuildSteps(
BuildContext buildContext, BuildableContext buildableContext) {
SourcePathResolver pathResolver = buildContext.getSourcePathResolver();
ImmutableList.Builder<Step> steps = ImmutableList.builder();
// Merge R.txt of HasAndroidRes and generate the resulting R.java files per package.
Path rDotJavaSrc = getPathToGeneratedRDotJavaSrcFiles();
steps.addAll(MakeCleanDirectoryStep.of(getProjectFilesystem(), rDotJavaSrc));
Path rDotTxtPath = pathResolver.getAbsolutePath(pathToRDotTxtFile);
MergeAndroidResourcesStep mergeStep =
MergeAndroidResourcesStep.createStepForUberRDotJava(
getProjectFilesystem(),
buildContext.getSourcePathResolver(),
resourceDeps,
rDotTxtPath,
rDotJavaSrc,
bannedDuplicateResourceTypes,
resourceUnionPackage);
steps.add(mergeStep);
if (shouldBuildStringSourceMap) {
// Make sure we have an output directory
Path outputDirPath = getPathForNativeStringInfoDirectory();
steps.addAll(MakeCleanDirectoryStep.of(getProjectFilesystem(), outputDirPath));
// Add the step that parses R.txt and all the strings.xml files, and
// produces a JSON with android resource id's and xml paths for each string resource.
GenStringSourceMapStep genNativeStringInfo =
new GenStringSourceMapStep(
getProjectFilesystem(),
rDotTxtPath.getParent(),
resourcesProvider.getResDirectories(),
outputDirPath);
steps.add(genNativeStringInfo);
// Cache the generated strings.json file, it will be stored inside outputDirPath
buildableContext.recordArtifact(outputDirPath);
}
// Ensure the generated R.txt and R.java files are also recorded.
buildableContext.recordArtifact(rDotJavaSrc);
return steps.build();
}
private Path getPathToGeneratedRDotJavaSrcFiles() {
return getPathToGeneratedRDotJavaSrcFiles(getBuildTarget(), getProjectFilesystem());
}
@VisibleForTesting
static Path getPathToGeneratedRDotJavaSrcFiles(
BuildTarget buildTarget, ProjectFilesystem filesystem) {
return BuildTargets.getScratchPath(filesystem, buildTarget, "__%s_rdotjava_src__");
}
private Path getPathForNativeStringInfoDirectory() {
return BuildTargets.getScratchPath(
getProjectFilesystem(), getBuildTarget(), "__%s_string_source_map__");
}
public SourcePath getSourcePathToGeneratedRDotJavaSrcFiles() {
return new ExplicitBuildTargetSourcePath(
getBuildTarget(), getPathToGeneratedRDotJavaSrcFiles());
}
@Nullable
@Override
public SourcePath getSourcePathToOutput() {
return null;
}
}