/*
* Copyright 2015-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.cxx;
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.BuildRuleParams;
import com.facebook.buck.rules.BuildableContext;
import com.facebook.buck.rules.ExplicitBuildTargetSourcePath;
import com.facebook.buck.rules.SourcePath;
import com.facebook.buck.shell.DefaultShellStep;
import com.facebook.buck.step.AbstractExecutionStep;
import com.facebook.buck.step.ExecutionContext;
import com.facebook.buck.step.Step;
import com.facebook.buck.step.StepExecutionResult;
import com.facebook.buck.step.fs.MkdirStep;
import com.facebook.buck.step.fs.SymCopyStep;
import com.facebook.buck.util.MoreCollectors;
import com.google.common.base.Function;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Ordering;
import java.io.IOException;
import java.nio.file.Path;
public class CxxInferAnalyze extends AbstractBuildRule {
private CxxInferCaptureAndAggregatingRules<CxxInferAnalyze> captureAndAnalyzeRules;
private final Path resultsDir;
private final Path reportFile;
private final Path specsDir;
private final Path specsPathList;
@AddToRuleKey private final InferBuckConfig inferConfig;
CxxInferAnalyze(
BuildRuleParams buildRuleParams,
InferBuckConfig inferConfig,
CxxInferCaptureAndAggregatingRules<CxxInferAnalyze> captureAndAnalyzeRules) {
super(buildRuleParams);
this.captureAndAnalyzeRules = captureAndAnalyzeRules;
this.resultsDir =
BuildTargets.getGenPath(getProjectFilesystem(), this.getBuildTarget(), "infer-analysis-%s");
this.reportFile = this.resultsDir.resolve("report.json");
this.specsDir = this.resultsDir.resolve("specs");
this.specsPathList = this.resultsDir.resolve("specs_path_list.txt");
this.inferConfig = inferConfig;
}
private ImmutableSortedSet<SourcePath> getSpecsOfAllDeps() {
return FluentIterable.from(captureAndAnalyzeRules.aggregatingRules)
.transform(
(Function<CxxInferAnalyze, SourcePath>)
input ->
new ExplicitBuildTargetSourcePath(input.getBuildTarget(), input.getSpecsDir()))
.toSortedSet(Ordering.natural());
}
public Path getSpecsDir() {
return specsDir;
}
public Path getAbsolutePathToResultsDir() {
return getProjectFilesystem().resolve(resultsDir);
}
public ImmutableSet<CxxInferCapture> getCaptureRules() {
return captureAndAnalyzeRules.captureRules;
}
public ImmutableSet<CxxInferAnalyze> getTransitiveAnalyzeRules() {
return captureAndAnalyzeRules.aggregatingRules;
}
private ImmutableList<String> getAnalyzeCommand() {
ImmutableList.Builder<String> commandBuilder = ImmutableList.builder();
commandBuilder
.add(inferConfig.getInferTopLevel().toString())
.add("--project_root", getProjectFilesystem().getRootPath().toString())
.add("--out", resultsDir.toString())
.add("--specs-dir-list-file", getProjectFilesystem().resolve(specsPathList).toString());
commandBuilder.add("--", "analyze");
return commandBuilder.build();
}
@Override
public ImmutableList<Step> getBuildSteps(
BuildContext context, BuildableContext buildableContext) {
buildableContext.recordArtifact(specsDir);
buildableContext.recordArtifact(
context.getSourcePathResolver().getRelativePath(getSourcePathToOutput()));
return ImmutableList.<Step>builder()
.add(MkdirStep.of(getProjectFilesystem(), specsDir))
.add(
new SymCopyStep(
getProjectFilesystem(),
captureAndAnalyzeRules
.captureRules
.stream()
.map(CxxInferCapture::getSourcePathToOutput)
.map(context.getSourcePathResolver()::getRelativePath)
.collect(MoreCollectors.toImmutableList()),
resultsDir))
.add(
new AbstractExecutionStep("write_specs_path_list") {
@Override
public StepExecutionResult execute(ExecutionContext executionContext)
throws IOException {
try {
ImmutableList<String> specsDirsWithAbsolutePath =
getSpecsOfAllDeps()
.stream()
.map(
input ->
context.getSourcePathResolver().getAbsolutePath(input).toString())
.collect(MoreCollectors.toImmutableList());
getProjectFilesystem().writeLinesToPath(specsDirsWithAbsolutePath, specsPathList);
} catch (IOException e) {
executionContext.logError(
e, "Error while writing specs path list file for the analyzer");
return StepExecutionResult.ERROR;
}
return StepExecutionResult.SUCCESS;
}
})
.add(
new DefaultShellStep(
getProjectFilesystem().getRootPath(), getAnalyzeCommand(), ImmutableMap.of()))
.build();
}
@Override
public SourcePath getSourcePathToOutput() {
return new ExplicitBuildTargetSourcePath(getBuildTarget(), reportFile);
}
}