/* * Copyright 2012-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 com.facebook.buck.rules.BuildableProperties.Kind.PACKAGING; import com.facebook.buck.model.BuildTarget; import com.facebook.buck.model.BuildTargets; import com.facebook.buck.rules.AddToRuleKey; import com.facebook.buck.rules.BuildContext; import com.facebook.buck.rules.BuildRule; import com.facebook.buck.rules.BuildRuleParams; import com.facebook.buck.rules.BuildableContext; import com.facebook.buck.rules.BuildableProperties; import com.facebook.buck.rules.CommandTool; import com.facebook.buck.rules.HasRuntimeDeps; import com.facebook.buck.rules.SourcePathResolver; import com.facebook.buck.rules.SourcePathRuleFinder; 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.MakeCleanDirectoryStep; import com.facebook.buck.step.fs.MkdirStep; import com.facebook.buck.step.fs.RmStep; import com.facebook.buck.util.RichStream; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedSet; import java.nio.file.Path; import java.util.stream.Stream; public class PythonPackagedBinary extends PythonBinary implements HasRuntimeDeps { private static final BuildableProperties OUTPUT_TYPE = new BuildableProperties(PACKAGING); private final SourcePathRuleFinder ruleFinder; @AddToRuleKey private final Tool builder; @AddToRuleKey private final ImmutableList<String> buildArgs; private final Tool pathToPexExecuter; @AddToRuleKey private final String mainModule; @AddToRuleKey private final PythonEnvironment pythonEnvironment; @AddToRuleKey private final ImmutableSet<String> preloadLibraries; private final boolean cache; private PythonPackagedBinary( BuildRuleParams params, Supplier<ImmutableSortedSet<BuildRule>> originalDeclareDeps, SourcePathRuleFinder ruleFinder, PythonPlatform pythonPlatform, Tool builder, ImmutableList<String> buildArgs, Tool pathToPexExecuter, String pexExtension, PythonEnvironment pythonEnvironment, String mainModule, PythonPackageComponents components, ImmutableSet<String> preloadLibraries, boolean cache, boolean legacyOutputPath) { super( params, originalDeclareDeps, pythonPlatform, mainModule, components, preloadLibraries, pexExtension, legacyOutputPath); this.ruleFinder = ruleFinder; this.builder = builder; this.buildArgs = buildArgs; this.pathToPexExecuter = pathToPexExecuter; this.pythonEnvironment = pythonEnvironment; this.mainModule = mainModule; this.preloadLibraries = preloadLibraries; this.cache = cache; } static PythonPackagedBinary from( BuildRuleParams params, SourcePathRuleFinder ruleFinder, PythonPlatform pythonPlatform, Tool builder, ImmutableList<String> buildArgs, Tool pathToPexExecuter, String pexExtension, PythonEnvironment pythonEnvironment, String mainModule, PythonPackageComponents components, ImmutableSet<String> preloadLibraries, boolean cache, boolean legacyOutputPath) { return new PythonPackagedBinary( params.copyReplacingDeclaredAndExtraDeps( Suppliers.ofInstance( ImmutableSortedSet.<BuildRule>naturalOrder() .addAll(components.getDeps(ruleFinder)) .addAll(builder.getDeps(ruleFinder)) .build()), Suppliers.ofInstance(ImmutableSortedSet.of())), params.getDeclaredDeps(), ruleFinder, pythonPlatform, builder, buildArgs, pathToPexExecuter, pexExtension, pythonEnvironment, mainModule, components, preloadLibraries, cache, legacyOutputPath); } @Override public BuildableProperties getProperties() { return OUTPUT_TYPE; } @Override public Tool getExecutableCommand() { return new CommandTool.Builder(pathToPexExecuter) .addArg(SourcePathArg.of(getSourcePathToOutput())) .build(); } @Override public ImmutableList<Step> getBuildSteps( BuildContext context, BuildableContext buildableContext) { ImmutableList.Builder<Step> steps = ImmutableList.builder(); Path binPath = context.getSourcePathResolver().getRelativePath(getSourcePathToOutput()); // Make sure the parent directory exists. steps.add(MkdirStep.of(getProjectFilesystem(), binPath.getParent())); // Delete any other pex that was there (when switching between pex styles). steps.add(RmStep.of(getProjectFilesystem(), binPath).withRecursive(true)); Path workingDirectory = BuildTargets.getGenPath( getProjectFilesystem(), getBuildTarget(), "__%s__working_directory"); steps.addAll(MakeCleanDirectoryStep.of(getProjectFilesystem(), workingDirectory)); SourcePathResolver resolver = context.getSourcePathResolver(); // Generate and return the PEX build step. steps.add( new PexStep( getProjectFilesystem(), builder.getEnvironment(resolver), ImmutableList.<String>builder() .addAll(builder.getCommandPrefix(resolver)) .addAll(buildArgs) .build(), pythonEnvironment.getPythonPath(), pythonEnvironment.getPythonVersion(), workingDirectory, binPath, mainModule, resolver.getMappedPaths(getComponents().getModules()), resolver.getMappedPaths(getComponents().getResources()), resolver.getMappedPaths(getComponents().getNativeLibraries()), ImmutableSet.copyOf( resolver.getAllAbsolutePaths(getComponents().getPrebuiltLibraries())), preloadLibraries, getComponents().isZipSafe().orElse(true))); // Record the executable package for caching. buildableContext.recordArtifact(binPath); return steps.build(); } @Override public Stream<BuildTarget> getRuntimeDeps() { return RichStream.<BuildTarget>empty() .concat(super.getRuntimeDeps()) .concat(pathToPexExecuter.getDeps(ruleFinder).stream().map(BuildRule::getBuildTarget)); } @Override public boolean isCacheable() { return cache; } }