/* * Copyright 2013-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.assertNotEquals; import com.facebook.buck.io.MorePaths; import com.facebook.buck.io.ProjectFilesystem; import com.facebook.buck.rules.BuildRuleResolver; import com.facebook.buck.rules.CommandTool; import com.facebook.buck.rules.DefaultTargetNodeToBuildRuleTransformer; import com.facebook.buck.rules.FakeBuildRuleParamsBuilder; import com.facebook.buck.rules.HashedFileTool; import com.facebook.buck.rules.PathSourcePath; import com.facebook.buck.rules.RuleKey; 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.testutil.FakeFileHashCache; import com.facebook.buck.testutil.FakeProjectFilesystem; import com.google.common.base.Charsets; import com.google.common.base.Strings; 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 java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Optional; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; public class PythonPackagedBinaryTest { private static final Tool PEX = new CommandTool.Builder().addArg("something").build(); @Rule public final TemporaryFolder tmpDir = new TemporaryFolder(); private RuleKey getRuleKeyForModuleLayout( DefaultRuleKeyFactory ruleKeyFactory, SourcePathRuleFinder ruleFinder, String main, Path mainSrc, String mod1, Path src1, String mod2, Path src2) throws IOException { ProjectFilesystem projectFilesystem = new FakeProjectFilesystem(); // The top-level python binary that lists the above libraries as deps. PythonBinary binary = PythonPackagedBinary.from( new FakeBuildRuleParamsBuilder("//:bin").build(), ruleFinder, PythonTestUtils.PYTHON_PLATFORM, PEX, ImmutableList.of(), new HashedFileTool(Paths.get("dummy_path_to_pex_runner")), ".pex", new PythonEnvironment(Paths.get("fake_python"), PythonVersion.of("CPython", "2.7")), "main", PythonPackageComponents.of( ImmutableMap.of( Paths.get(main), new PathSourcePath(projectFilesystem, mainSrc), Paths.get(mod1), new PathSourcePath(projectFilesystem, src1), Paths.get(mod2), new PathSourcePath(projectFilesystem, src2)), ImmutableMap.of(), ImmutableMap.of(), ImmutableSet.of(), Optional.empty()), ImmutableSortedSet.of(), /* cache */ true, /* legacyOutputPath */ false); // Calculate and return the rule key. return ruleKeyFactory.build(binary); } @Test public void testRuleKeysFromModuleLayouts() throws IOException { SourcePathRuleFinder ruleFinder = new SourcePathRuleFinder( new BuildRuleResolver( TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer())); SourcePathResolver resolver = new SourcePathResolver(ruleFinder); // Create two different sources, which we'll swap in as different modules. Path main = tmpDir.newFile().toPath(); Files.write(main, "main".getBytes(Charsets.UTF_8)); Path source1 = tmpDir.newFile().toPath(); Files.write(source1, "hello world".getBytes(Charsets.UTF_8)); Path source2 = tmpDir.newFile().toPath(); Files.write(source2, "goodbye world".getBytes(Charsets.UTF_8)); Path mainRelative = MorePaths.relativize(tmpDir.getRoot().toPath(), main); Path source1Relative = MorePaths.relativize(tmpDir.getRoot().toPath(), source1); Path source2Relative = MorePaths.relativize(tmpDir.getRoot().toPath(), source2); // Setup a rulekey builder factory. FakeFileHashCache hashCache = FakeFileHashCache.createFromStrings( ImmutableMap.of( mainRelative.toString(), Strings.repeat("a", 40), source1Relative.toString(), Strings.repeat("b", 40), source2Relative.toString(), Strings.repeat("c", 40))); // Calculate the rule keys for the various ways we can layout the source and modules // across different python libraries. RuleKey pair1 = getRuleKeyForModuleLayout( new DefaultRuleKeyFactory(0, hashCache, resolver, ruleFinder), ruleFinder, "main.py", mainRelative, "module/one.py", source1Relative, "module/two.py", source2Relative); RuleKey pair2 = getRuleKeyForModuleLayout( new DefaultRuleKeyFactory(0, hashCache, resolver, ruleFinder), ruleFinder, "main.py", mainRelative, "module/two.py", source2Relative, "module/one.py", source1Relative); RuleKey pair3 = getRuleKeyForModuleLayout( new DefaultRuleKeyFactory(0, hashCache, resolver, ruleFinder), ruleFinder, "main.py", mainRelative, "module/one.py", source2Relative, "module/two.py", source1Relative); RuleKey pair4 = getRuleKeyForModuleLayout( new DefaultRuleKeyFactory(0, hashCache, resolver, ruleFinder), ruleFinder, "main.py", mainRelative, "module/two.py", source1Relative, "module/one.py", source2Relative); // Make sure only cases where the actual module layouts are different result // in different rules keys. assertEquals(pair1, pair2); assertEquals(pair3, pair4); assertNotEquals(pair1, pair3); } }