/*
* 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.python;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import com.facebook.buck.cxx.CxxGenrule;
import com.facebook.buck.cxx.CxxGenruleBuilder;
import com.facebook.buck.cxx.CxxPlatformUtils;
import com.facebook.buck.io.ProjectFilesystem;
import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.model.BuildTargetFactory;
import com.facebook.buck.rules.BuildRule;
import com.facebook.buck.rules.BuildRuleResolver;
import com.facebook.buck.rules.DefaultBuildTargetSourcePath;
import com.facebook.buck.rules.DefaultTargetNodeToBuildRuleTransformer;
import com.facebook.buck.rules.FakeSourcePath;
import com.facebook.buck.rules.SourcePath;
import com.facebook.buck.rules.TargetGraph;
import com.facebook.buck.rules.TargetGraphAndBuildTargets;
import com.facebook.buck.rules.coercer.DefaultTypeCoercerFactory;
import com.facebook.buck.rules.coercer.PatternMatchedCollection;
import com.facebook.buck.rules.coercer.SourceList;
import com.facebook.buck.rules.coercer.VersionMatchedCollection;
import com.facebook.buck.shell.GenruleBuilder;
import com.facebook.buck.testutil.FakeProjectFilesystem;
import com.facebook.buck.testutil.TargetGraphFactory;
import com.facebook.buck.util.RichStream;
import com.facebook.buck.versions.FixedVersionSelector;
import com.facebook.buck.versions.Version;
import com.facebook.buck.versions.VersionedAliasBuilder;
import com.facebook.buck.versions.VersionedTargetGraphBuilder;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import java.nio.file.Paths;
import java.util.concurrent.ForkJoinPool;
import java.util.regex.Pattern;
import org.hamcrest.Matchers;
import org.junit.Test;
public class PythonLibraryDescriptionTest {
@Test
public void baseModule() throws Exception {
ProjectFilesystem filesystem = new FakeProjectFilesystem();
BuildTarget target = BuildTargetFactory.newInstance("//foo:lib");
String sourceName = "main.py";
SourcePath source = new FakeSourcePath("foo/" + sourceName);
// Run without a base module set and verify it defaults to using the build target
// base name.
PythonLibraryBuilder normalBuilder =
new PythonLibraryBuilder(target)
.setSrcs(SourceList.ofUnnamedSources(ImmutableSortedSet.of(source)));
TargetGraph normalTargetGraph = TargetGraphFactory.newInstance(normalBuilder.build());
PythonLibrary normal =
normalBuilder.build(
new BuildRuleResolver(normalTargetGraph, new DefaultTargetNodeToBuildRuleTransformer()),
filesystem,
normalTargetGraph);
assertEquals(
ImmutableMap.of(target.getBasePath().resolve(sourceName), source),
normal
.getPythonPackageComponents(
PythonTestUtils.PYTHON_PLATFORM, CxxPlatformUtils.DEFAULT_PLATFORM)
.getModules());
// Run *with* a base module set and verify it gets used to build the main module path.
String baseModule = "blah";
PythonLibraryBuilder withBaseModuleBuilder =
new PythonLibraryBuilder(target)
.setSrcs(SourceList.ofUnnamedSources(ImmutableSortedSet.of(source)))
.setBaseModule(baseModule);
TargetGraph withBaseModuleTargetGraph =
TargetGraphFactory.newInstance(withBaseModuleBuilder.build());
PythonLibrary withBaseModule =
withBaseModuleBuilder.build(
new BuildRuleResolver(
withBaseModuleTargetGraph, new DefaultTargetNodeToBuildRuleTransformer()),
filesystem,
withBaseModuleTargetGraph);
assertEquals(
ImmutableMap.of(Paths.get(baseModule).resolve(sourceName), source),
withBaseModule
.getPythonPackageComponents(
PythonTestUtils.PYTHON_PLATFORM, CxxPlatformUtils.DEFAULT_PLATFORM)
.getModules());
}
@Test
public void platformSrcs() throws Exception {
ProjectFilesystem filesystem = new FakeProjectFilesystem();
BuildTarget target = BuildTargetFactory.newInstance("//foo:lib");
SourcePath matchedSource = new FakeSourcePath("foo/a.py");
SourcePath unmatchedSource = new FakeSourcePath("foo/b.py");
PythonLibraryBuilder builder =
new PythonLibraryBuilder(target)
.setPlatformSrcs(
PatternMatchedCollection.<SourceList>builder()
.add(
Pattern.compile(PythonTestUtils.PYTHON_PLATFORM.getFlavor().toString()),
SourceList.ofUnnamedSources(ImmutableSortedSet.of(matchedSource)))
.add(
Pattern.compile("won't match anything"),
SourceList.ofUnnamedSources(ImmutableSortedSet.of(unmatchedSource)))
.build());
TargetGraph targetGraph = TargetGraphFactory.newInstance(builder.build());
PythonLibrary library =
builder.build(
new BuildRuleResolver(targetGraph, new DefaultTargetNodeToBuildRuleTransformer()),
filesystem,
targetGraph);
assertThat(
library
.getPythonPackageComponents(
PythonTestUtils.PYTHON_PLATFORM, CxxPlatformUtils.DEFAULT_PLATFORM)
.getModules()
.values(),
Matchers.contains(matchedSource));
}
@Test
public void platformResources() throws Exception {
ProjectFilesystem filesystem = new FakeProjectFilesystem();
BuildTarget target = BuildTargetFactory.newInstance("//foo:lib");
SourcePath matchedSource = new FakeSourcePath("foo/a.dat");
SourcePath unmatchedSource = new FakeSourcePath("foo/b.dat");
PythonLibraryBuilder builder =
new PythonLibraryBuilder(target)
.setPlatformResources(
PatternMatchedCollection.<SourceList>builder()
.add(
Pattern.compile(PythonTestUtils.PYTHON_PLATFORM.getFlavor().toString()),
SourceList.ofUnnamedSources(ImmutableSortedSet.of(matchedSource)))
.add(
Pattern.compile("won't match anything"),
SourceList.ofUnnamedSources(ImmutableSortedSet.of(unmatchedSource)))
.build());
TargetGraph targetGraph = TargetGraphFactory.newInstance(builder.build());
PythonLibrary library =
builder.build(
new BuildRuleResolver(targetGraph, new DefaultTargetNodeToBuildRuleTransformer()),
filesystem,
targetGraph);
assertThat(
library
.getPythonPackageComponents(
PythonTestUtils.PYTHON_PLATFORM, CxxPlatformUtils.DEFAULT_PLATFORM)
.getResources()
.values(),
Matchers.contains(matchedSource));
}
@Test
public void versionedSrcs() throws Exception {
BuildTarget target = BuildTargetFactory.newInstance("//foo:lib");
SourcePath matchedSource = new FakeSourcePath("foo/a.py");
SourcePath unmatchedSource = new FakeSourcePath("foo/b.py");
GenruleBuilder transitiveDepBuilder =
GenruleBuilder.newGenruleBuilder(BuildTargetFactory.newInstance("//:tdep")).setOut("out");
VersionedAliasBuilder depBuilder =
new VersionedAliasBuilder(BuildTargetFactory.newInstance("//:dep"))
.setVersions(
ImmutableMap.of(
Version.of("1.0"), transitiveDepBuilder.getTarget(),
Version.of("2.0"), transitiveDepBuilder.getTarget()));
PythonLibraryBuilder builder =
new PythonLibraryBuilder(target)
.setVersionedSrcs(
VersionMatchedCollection.<SourceList>builder()
.add(
ImmutableMap.of(depBuilder.getTarget(), Version.of("1.0")),
SourceList.ofUnnamedSources(ImmutableSortedSet.of(matchedSource)))
.add(
ImmutableMap.of(depBuilder.getTarget(), Version.of("2.0")),
SourceList.ofUnnamedSources(ImmutableSortedSet.of(unmatchedSource)))
.build());
TargetGraph targetGraph =
VersionedTargetGraphBuilder.transform(
new FixedVersionSelector(
ImmutableMap.of(
builder.getTarget(),
ImmutableMap.of(depBuilder.getTarget(), Version.of("1.0")))),
TargetGraphAndBuildTargets.of(
TargetGraphFactory.newInstance(
transitiveDepBuilder.build(), depBuilder.build(), builder.build()),
ImmutableSet.of(builder.getTarget())),
new ForkJoinPool(),
new DefaultTypeCoercerFactory())
.getTargetGraph();
BuildRuleResolver resolver =
new BuildRuleResolver(targetGraph, new DefaultTargetNodeToBuildRuleTransformer());
PythonLibrary library = (PythonLibrary) resolver.requireRule(builder.getTarget());
assertThat(
library
.getPythonPackageComponents(
PythonTestUtils.PYTHON_PLATFORM, CxxPlatformUtils.DEFAULT_PLATFORM)
.getModules()
.values(),
Matchers.contains(matchedSource));
}
@Test
public void versionedResources() throws Exception {
BuildTarget target = BuildTargetFactory.newInstance("//foo:lib");
SourcePath matchedSource = new FakeSourcePath("foo/a.py");
SourcePath unmatchedSource = new FakeSourcePath("foo/b.py");
GenruleBuilder transitiveDepBuilder =
GenruleBuilder.newGenruleBuilder(BuildTargetFactory.newInstance("//:tdep")).setOut("out");
VersionedAliasBuilder depBuilder =
new VersionedAliasBuilder(BuildTargetFactory.newInstance("//:dep"))
.setVersions(
ImmutableMap.of(
Version.of("1.0"), transitiveDepBuilder.getTarget(),
Version.of("2.0"), transitiveDepBuilder.getTarget()));
PythonLibraryBuilder builder =
new PythonLibraryBuilder(target)
.setVersionedResources(
VersionMatchedCollection.<SourceList>builder()
.add(
ImmutableMap.of(depBuilder.getTarget(), Version.of("1.0")),
SourceList.ofUnnamedSources(ImmutableSortedSet.of(matchedSource)))
.add(
ImmutableMap.of(depBuilder.getTarget(), Version.of("2.0")),
SourceList.ofUnnamedSources(ImmutableSortedSet.of(unmatchedSource)))
.build());
TargetGraph targetGraph =
VersionedTargetGraphBuilder.transform(
new FixedVersionSelector(
ImmutableMap.of(
builder.getTarget(),
ImmutableMap.of(depBuilder.getTarget(), Version.of("1.0")))),
TargetGraphAndBuildTargets.of(
TargetGraphFactory.newInstance(
transitiveDepBuilder.build(), depBuilder.build(), builder.build()),
ImmutableSet.of(builder.getTarget())),
new ForkJoinPool(),
new DefaultTypeCoercerFactory())
.getTargetGraph();
BuildRuleResolver resolver =
new BuildRuleResolver(targetGraph, new DefaultTargetNodeToBuildRuleTransformer());
PythonLibrary library = (PythonLibrary) resolver.requireRule(builder.getTarget());
assertThat(
library
.getPythonPackageComponents(
PythonTestUtils.PYTHON_PLATFORM, CxxPlatformUtils.DEFAULT_PLATFORM)
.getResources()
.values(),
Matchers.contains(matchedSource));
}
@Test
public void cxxGenruleSrcs() throws Exception {
CxxGenruleBuilder srcBuilder =
new CxxGenruleBuilder(BuildTargetFactory.newInstance("//:src")).setOut("out.py");
PythonLibraryBuilder libraryBuilder =
new PythonLibraryBuilder(BuildTargetFactory.newInstance("//:lib"))
.setSrcs(
SourceList.ofUnnamedSources(
ImmutableSortedSet.of(
new DefaultBuildTargetSourcePath(srcBuilder.getTarget()))));
TargetGraph targetGraph =
TargetGraphFactory.newInstance(srcBuilder.build(), libraryBuilder.build());
BuildRuleResolver resolver =
new BuildRuleResolver(targetGraph, new DefaultTargetNodeToBuildRuleTransformer());
CxxGenrule src = (CxxGenrule) resolver.requireRule(srcBuilder.getTarget());
PythonLibrary library = (PythonLibrary) resolver.requireRule(libraryBuilder.getTarget());
PythonPackageComponents components =
library.getPythonPackageComponents(
PythonTestUtils.PYTHON_PLATFORM, CxxPlatformUtils.DEFAULT_PLATFORM);
assertThat(
components.getModules().values(),
Matchers.contains(src.getGenrule(CxxPlatformUtils.DEFAULT_PLATFORM)));
}
@Test
public void platformDeps() throws Exception {
PythonLibraryBuilder libraryABuilder =
PythonLibraryBuilder.createBuilder(BuildTargetFactory.newInstance("//:libA"));
PythonLibraryBuilder libraryBBuilder =
PythonLibraryBuilder.createBuilder(BuildTargetFactory.newInstance("//:libB"));
PythonLibraryBuilder ruleBuilder =
PythonLibraryBuilder.createBuilder(BuildTargetFactory.newInstance("//:rule"))
.setPlatformDeps(
PatternMatchedCollection.<ImmutableSortedSet<BuildTarget>>builder()
.add(
Pattern.compile(
CxxPlatformUtils.DEFAULT_PLATFORM.getFlavor().toString(),
Pattern.LITERAL),
ImmutableSortedSet.of(libraryABuilder.getTarget()))
.add(
Pattern.compile("matches nothing", Pattern.LITERAL),
ImmutableSortedSet.of(libraryBBuilder.getTarget()))
.build());
TargetGraph targetGraph =
TargetGraphFactory.newInstance(
libraryABuilder.build(), libraryBBuilder.build(), ruleBuilder.build());
BuildRuleResolver resolver =
new BuildRuleResolver(targetGraph, new DefaultTargetNodeToBuildRuleTransformer());
PythonLibrary rule = (PythonLibrary) resolver.requireRule(ruleBuilder.getTarget());
assertThat(
RichStream.from(
rule.getPythonPackageDeps(
PythonTestUtils.PYTHON_PLATFORM, CxxPlatformUtils.DEFAULT_PLATFORM))
.map(BuildRule::getBuildTarget)
.toImmutableSet(),
Matchers.allOf(
Matchers.hasItem(libraryABuilder.getTarget()),
Matchers.not(Matchers.hasItem(libraryBBuilder.getTarget()))));
}
}