/*
* Copyright 2014-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 static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThat;
import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.model.BuildTargetFactory;
import com.facebook.buck.rules.BuildContext;
import com.facebook.buck.rules.BuildRule;
import com.facebook.buck.rules.BuildRuleParams;
import com.facebook.buck.rules.BuildRuleResolver;
import com.facebook.buck.rules.DefaultTargetNodeToBuildRuleTransformer;
import com.facebook.buck.rules.FakeBuildContext;
import com.facebook.buck.rules.FakeBuildRule;
import com.facebook.buck.rules.FakeBuildRuleParamsBuilder;
import com.facebook.buck.rules.FakeBuildableContext;
import com.facebook.buck.rules.FakeSourcePath;
import com.facebook.buck.rules.HashedFileTool;
import com.facebook.buck.rules.RuleKey;
import com.facebook.buck.rules.SourcePath;
import com.facebook.buck.rules.SourcePathResolver;
import com.facebook.buck.rules.SourcePathRuleFinder;
import com.facebook.buck.rules.TargetGraph;
import com.facebook.buck.rules.Tool;
import com.facebook.buck.rules.keys.DefaultRuleKeyFactory;
import com.facebook.buck.shell.Genrule;
import com.facebook.buck.shell.GenruleBuilder;
import com.facebook.buck.step.Step;
import com.facebook.buck.step.TestExecutionContext;
import com.facebook.buck.testutil.FakeFileHashCache;
import com.google.common.base.Strings;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSortedSet;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.junit.Test;
public class ArchiveTest {
private static final Path AR = Paths.get("ar");
private static final Archiver DEFAULT_ARCHIVER = new GnuArchiver(new HashedFileTool(AR));
private static final Path RANLIB = Paths.get("ranlib");
private static final Tool DEFAULT_RANLIB = new HashedFileTool(RANLIB);
private static final Path DEFAULT_OUTPUT = Paths.get("foo/libblah.a");
private static final ImmutableList<SourcePath> DEFAULT_INPUTS =
ImmutableList.of(
new FakeSourcePath("a.o"), new FakeSourcePath("b.o"), new FakeSourcePath("c.o"));
@Test
public void testThatInputChangesCauseRuleKeyChanges() {
SourcePathRuleFinder ruleFinder =
new SourcePathRuleFinder(
new BuildRuleResolver(
TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer()));
SourcePathResolver pathResolver = new SourcePathResolver(ruleFinder);
BuildTarget target = BuildTargetFactory.newInstance("//foo:bar");
BuildRuleParams params = new FakeBuildRuleParamsBuilder(target).build();
FakeFileHashCache hashCache =
FakeFileHashCache.createFromStrings(
ImmutableMap.<String, String>builder()
.put(AR.toString(), Strings.repeat("0", 40))
.put(RANLIB.toString(), Strings.repeat("1", 40))
.put("a.o", Strings.repeat("a", 40))
.put("b.o", Strings.repeat("b", 40))
.put("c.o", Strings.repeat("c", 40))
.put(Paths.get("different").toString(), Strings.repeat("d", 40))
.build());
// Generate a rule key for the defaults.
RuleKey defaultRuleKey =
new DefaultRuleKeyFactory(0, hashCache, pathResolver, ruleFinder)
.build(
Archive.from(
target,
params,
ruleFinder,
DEFAULT_ARCHIVER,
ImmutableList.of(),
DEFAULT_RANLIB,
ImmutableList.of(),
Archive.Contents.NORMAL,
DEFAULT_OUTPUT,
DEFAULT_INPUTS));
// Verify that changing the archiver causes a rulekey change.
RuleKey archiverChange =
new DefaultRuleKeyFactory(0, hashCache, pathResolver, ruleFinder)
.build(
Archive.from(
target,
params,
ruleFinder,
new GnuArchiver(new HashedFileTool(Paths.get("different"))),
ImmutableList.of(),
DEFAULT_RANLIB,
ImmutableList.of(),
Archive.Contents.NORMAL,
DEFAULT_OUTPUT,
DEFAULT_INPUTS));
assertNotEquals(defaultRuleKey, archiverChange);
// Verify that changing the output path causes a rulekey change.
RuleKey outputChange =
new DefaultRuleKeyFactory(0, hashCache, pathResolver, ruleFinder)
.build(
Archive.from(
target,
params,
ruleFinder,
DEFAULT_ARCHIVER,
ImmutableList.of(),
DEFAULT_RANLIB,
ImmutableList.of(),
Archive.Contents.NORMAL,
Paths.get("different"),
DEFAULT_INPUTS));
assertNotEquals(defaultRuleKey, outputChange);
// Verify that changing the inputs causes a rulekey change.
RuleKey inputChange =
new DefaultRuleKeyFactory(0, hashCache, pathResolver, ruleFinder)
.build(
Archive.from(
target,
params,
ruleFinder,
DEFAULT_ARCHIVER,
ImmutableList.of(),
DEFAULT_RANLIB,
ImmutableList.of(),
Archive.Contents.NORMAL,
DEFAULT_OUTPUT,
ImmutableList.of(new FakeSourcePath("different"))));
assertNotEquals(defaultRuleKey, inputChange);
// Verify that changing the type of archiver causes a rulekey change.
RuleKey archiverTypeChange =
new DefaultRuleKeyFactory(0, hashCache, pathResolver, ruleFinder)
.build(
Archive.from(
target,
params,
ruleFinder,
new BsdArchiver(new HashedFileTool(AR)),
ImmutableList.of(),
DEFAULT_RANLIB,
ImmutableList.of(),
Archive.Contents.NORMAL,
DEFAULT_OUTPUT,
DEFAULT_INPUTS));
assertNotEquals(defaultRuleKey, archiverTypeChange);
}
@Test
public void flagsArePropagated() throws Exception {
BuildRuleResolver resolver =
new BuildRuleResolver(TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer());
BuildTarget target = BuildTargetFactory.newInstance("//foo:bar");
BuildRuleParams params = new FakeBuildRuleParamsBuilder(target).build();
SourcePathRuleFinder ruleFinder = new SourcePathRuleFinder(resolver);
SourcePathResolver pathResolver = new SourcePathResolver(ruleFinder);
Archive archive =
Archive.from(
target,
params,
ruleFinder,
DEFAULT_ARCHIVER,
ImmutableList.of("-foo"),
DEFAULT_RANLIB,
ImmutableList.of("-bar"),
Archive.Contents.NORMAL,
DEFAULT_OUTPUT,
ImmutableList.of(new FakeSourcePath("simple.o")));
BuildContext buildContext =
BuildContext.builder()
.from(FakeBuildContext.NOOP_CONTEXT)
.setSourcePathResolver(pathResolver)
.build();
ImmutableList<Step> steps = archive.getBuildSteps(buildContext, new FakeBuildableContext());
Step archiveStep = FluentIterable.from(steps).filter(ArchiveStep.class).first().get();
assertThat(
archiveStep.getDescription(TestExecutionContext.newInstance()), containsString("-foo"));
Step ranlibStep = FluentIterable.from(steps).filter(RanlibStep.class).first().get();
assertThat(
ranlibStep.getDescription(TestExecutionContext.newInstance()), containsString("-bar"));
}
@Test
public void testThatBuildTargetSourcePathDepsAndPathsArePropagated() throws Exception {
BuildRuleResolver resolver =
new BuildRuleResolver(TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer());
BuildTarget target = BuildTargetFactory.newInstance("//foo:bar");
BuildRuleParams params = new FakeBuildRuleParamsBuilder(target).build();
// Create a couple of genrules to generate inputs for an archive rule.
Genrule genrule1 =
GenruleBuilder.newGenruleBuilder(BuildTargetFactory.newInstance("//:genrule"))
.setOut("foo/bar.o")
.build(resolver);
Genrule genrule2 =
GenruleBuilder.newGenruleBuilder(BuildTargetFactory.newInstance("//:genrule2"))
.setOut("foo/test.o")
.build(resolver);
// Build the archive using a normal input the outputs of the genrules above.
SourcePathRuleFinder ruleFinder = new SourcePathRuleFinder(resolver);
Archive archive =
Archive.from(
target,
params,
ruleFinder,
DEFAULT_ARCHIVER,
ImmutableList.of(),
DEFAULT_RANLIB,
ImmutableList.of(),
Archive.Contents.NORMAL,
DEFAULT_OUTPUT,
ImmutableList.of(
new FakeSourcePath("simple.o"),
genrule1.getSourcePathToOutput(),
genrule2.getSourcePathToOutput()));
// Verify that the archive dependencies include the genrules providing the
// SourcePath inputs.
assertEquals(ImmutableSortedSet.<BuildRule>of(genrule1, genrule2), archive.getBuildDeps());
}
@Test
public void testThatOriginalBuildParamsDepsDoNotPropagateToArchive() {
SourcePathRuleFinder ruleFinder =
new SourcePathRuleFinder(
new BuildRuleResolver(
TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer()));
SourcePathResolver pathResolver = new SourcePathResolver(ruleFinder);
// Create an `Archive` rule using build params with an existing dependency,
// as if coming from a `TargetNode` which had declared deps. These should *not*
// propagate to the `Archive` rule, since it only cares about dependencies generating
// it's immediate inputs.
BuildRule dep =
new FakeBuildRule(new FakeBuildRuleParamsBuilder("//:fake").build(), pathResolver);
BuildTarget target = BuildTargetFactory.newInstance("//:archive");
BuildRuleParams params =
new FakeBuildRuleParamsBuilder(BuildTargetFactory.newInstance("//:dummy"))
.setDeclaredDeps(ImmutableSortedSet.of(dep))
.build();
Archive archive =
Archive.from(
target,
params,
ruleFinder,
DEFAULT_ARCHIVER,
ImmutableList.of(),
DEFAULT_RANLIB,
ImmutableList.of(),
Archive.Contents.NORMAL,
DEFAULT_OUTPUT,
DEFAULT_INPUTS);
// Verify that the archive rules dependencies are empty.
assertEquals(archive.getBuildDeps(), ImmutableSortedSet.<BuildRule>of());
}
}