Java tutorial
/* * 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.python; import com.facebook.buck.cxx.CxxPlatform; import com.facebook.buck.cxx.Linker; import com.facebook.buck.model.HasBuildTarget; import com.facebook.buck.rules.AddToRuleKey; import com.facebook.buck.rules.BuildContext; import com.facebook.buck.rules.BuildRuleParams; import com.facebook.buck.rules.BuildRuleResolver; import com.facebook.buck.rules.BuildTargetSourcePath; import com.facebook.buck.rules.BuildableContext; import com.facebook.buck.rules.CommandTool; import com.facebook.buck.rules.HasRuntimeDeps; import com.facebook.buck.rules.SourcePath; import com.facebook.buck.rules.SourcePathResolver; import com.facebook.buck.rules.SymlinkTree; import com.facebook.buck.rules.Tool; import com.facebook.buck.rules.args.SourcePathArg; import com.facebook.buck.step.Step; import com.facebook.buck.step.fs.MkdirStep; import com.facebook.buck.step.fs.WriteFileStep; import com.facebook.buck.util.Escaper; import com.google.common.base.Charsets; import com.google.common.base.Joiner; import com.google.common.base.Supplier; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.io.Resources; import org.stringtemplate.v4.ST; import java.io.IOException; import java.nio.file.Path; import java.util.stream.Stream; public class PythonInPlaceBinary extends PythonBinary implements HasRuntimeDeps { private static final String RUN_INPLACE_RESOURCE = "com/facebook/buck/python/run_inplace.py.in"; // TODO(andrewjcg): Task #8098647: This rule has no steps, so it // really doesn't need a rule key. // // However, Python tests will never be re-run if the rule key // doesn't change, so we use the rule key to force the test runner // to re-run the tests if the input changes. // // We should upate the Python test rule to account for this. @AddToRuleKey private final Supplier<String> script; private final SymlinkTree linkTree; @AddToRuleKey private final PythonPackageComponents components; @AddToRuleKey private final Tool python; public PythonInPlaceBinary(BuildRuleParams params, SourcePathResolver resolver, BuildRuleResolver ruleResolver, PythonPlatform pythonPlatform, CxxPlatform cxxPlatform, SymlinkTree linkTree, String mainModule, PythonPackageComponents components, Tool python, String pexExtension, ImmutableSet<String> preloadLibraries, boolean legacyOutputPath) { super(params, resolver, pythonPlatform, mainModule, components, preloadLibraries, pexExtension, legacyOutputPath); this.script = getScript(ruleResolver, pythonPlatform, cxxPlatform, mainModule, components, getProjectFilesystem().resolve(getBinPath()).getParent().relativize(linkTree.getRoot()), preloadLibraries); this.linkTree = linkTree; this.components = components; this.python = python; } @Override public boolean outputFileCanBeCopied() { return true; } private static String getRunInplaceResource() { try { return Resources.toString(Resources.getResource(RUN_INPLACE_RESOURCE), Charsets.UTF_8); } catch (IOException e) { throw new RuntimeException(e); } } private static Supplier<String> getScript(final BuildRuleResolver resolver, final PythonPlatform pythonPlatform, final CxxPlatform cxxPlatform, final String mainModule, final PythonPackageComponents components, final Path relativeLinkTreeRoot, final ImmutableSet<String> preloadLibraries) { final String relativeLinkTreeRootStr = Escaper.escapeAsPythonString(relativeLinkTreeRoot.toString()); final Linker ld = cxxPlatform.getLd().resolve(resolver); return () -> { ST st = new ST(getRunInplaceResource()).add("PYTHON", pythonPlatform.getEnvironment().getPythonPath()) .add("MAIN_MODULE", Escaper.escapeAsPythonString(mainModule)) .add("MODULES_DIR", relativeLinkTreeRootStr); // Only add platform-specific values when the binary includes native libraries. if (components.getNativeLibraries().isEmpty()) { st.add("NATIVE_LIBS_ENV_VAR", "None"); st.add("NATIVE_LIBS_DIR", "None"); } else { st.add("NATIVE_LIBS_ENV_VAR", Escaper.escapeAsPythonString(ld.searchPathEnvVar())); st.add("NATIVE_LIBS_DIR", relativeLinkTreeRootStr); } if (preloadLibraries.isEmpty()) { st.add("NATIVE_LIBS_PRELOAD_ENV_VAR", "None"); st.add("NATIVE_LIBS_PRELOAD", "None"); } else { st.add("NATIVE_LIBS_PRELOAD_ENV_VAR", Escaper.escapeAsPythonString(ld.preloadEnvVar())); st.add("NATIVE_LIBS_PRELOAD", Escaper.escapeAsPythonString(Joiner.on(':').join(preloadLibraries))); } return st.render(); }; } @Override public ImmutableList<Step> getBuildSteps(BuildContext context, BuildableContext buildableContext) { Path binPath = getBinPath(); buildableContext.recordArtifact(binPath); return ImmutableList.of(new MkdirStep(getProjectFilesystem(), binPath.getParent()), new WriteFileStep(getProjectFilesystem(), script, binPath, /* executable */ true)); } @Override public Tool getExecutableCommand() { return new CommandTool.Builder(python) .addArg(new SourcePathArg(getResolver(), new BuildTargetSourcePath(getBuildTarget()))) .addDep(linkTree).addInputs(components.getModules().values()) .addInputs(components.getResources().values()).addInputs(components.getNativeLibraries().values()) .build(); } @Override public Stream<SourcePath> getRuntimeDeps() { return Stream.of( Stream.concat(Stream.of(linkTree), getDeclaredDeps().stream()).map(HasBuildTarget::getBuildTarget) .<SourcePath>map(BuildTargetSourcePath::new), components.getModules().values().stream(), components.getResources().values().stream(), components.getNativeLibraries().values().stream()).reduce(Stream.empty(), Stream::concat); } }