| /* |
| * 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.model; |
| |
| import com.facebook.buck.util.BuckConstant; |
| import com.facebook.buck.util.HumanReadableException; |
| import com.google.common.base.Optional; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.common.collect.ImmutableSortedSet; |
| import com.google.common.collect.Sets; |
| |
| import java.nio.file.Path; |
| import java.nio.file.Paths; |
| import java.util.Set; |
| |
| /** |
| * Static helpers for working with build targets. |
| */ |
| public class BuildTargets { |
| |
| /** Utility class: do not instantiate. */ |
| private BuildTargets() {} |
| |
| /** |
| * Return a path to a file in the buck-out/bin/ directory. {@code format} will be prepended with |
| * the {@link com.facebook.buck.util.BuckConstant#BIN_DIR} and the target base path, then |
| * formatted with the target short name. |
| * |
| * @param target The {@link BuildTarget} to scope this path to. |
| * @param format {@link String#format} string for the path name. It should contain one "%s", |
| * which will be filled in with the rule's short name. It should not start with a slash. |
| * @return A {@link java.nio.file.Path} under buck-out/bin, scoped to the base path of |
| * {@code target}. |
| */ |
| |
| public static Path getBinPath(BuildTarget target, String format) { |
| return Paths.get( |
| String.format( |
| "%s/%s" + format, |
| BuckConstant.BIN_DIR, |
| target.getBasePathWithSlash(), |
| target.getShortNameAndFlavorPostfix())); |
| } |
| |
| /** |
| * Return a path to a file in the buck-out/bin/ directory. {@code format} will be prepended with |
| * the {@link com.facebook.buck.util.BuckConstant#BIN_DIR} and the target base path, then |
| * formatted with the target short name. |
| * |
| * @param target The {@link UnflavoredBuildTarget} to scope this path to. |
| * @param format {@link String#format} string for the path name. It should contain one "%s", |
| * which will be filled in with the rule's short name. It should not start with a slash. |
| * @return A {@link java.nio.file.Path} under buck-out/bin, scoped to the base path of |
| * {@code target}. |
| */ |
| public static Path getBinPath(UnflavoredBuildTarget target, String format) { |
| return Paths.get( |
| String.format( |
| "%s/%s" + format, |
| BuckConstant.BIN_DIR, |
| target.getBasePathWithSlash(), |
| target.getShortName())); |
| } |
| |
| /** |
| * Return a path to a file in the buck-out/gen/ directory. {@code format} will be prepended with |
| * the {@link com.facebook.buck.util.BuckConstant#GEN_DIR} and the target base path, then |
| * formatted with the target short name. |
| * |
| * @param target The {@link BuildTarget} to scope this path to. |
| * @param format {@link String#format} string for the path name. It should contain one "%s", |
| * which will be filled in with the rule's short name. It should not start with a slash. |
| * @return A {@link java.nio.file.Path} under buck-out/gen, scoped to the base path of |
| * {@code target}. |
| */ |
| public static Path getGenPath(BuildTarget target, String format) { |
| return Paths.get(String.format("%s/%s" + format, |
| BuckConstant.GEN_DIR, |
| target.getBasePathWithSlash(), |
| target.getShortNameAndFlavorPostfix())); |
| } |
| |
| /** |
| * Return a path to a file in the buck-out/gen/ directory. {@code format} will be prepended with |
| * the {@link com.facebook.buck.util.BuckConstant#GEN_DIR} and the target base path, then |
| * formatted with the target short name. |
| * |
| * @param target The {@link UnflavoredBuildTarget} to scope this path to. |
| * @param format {@link String#format} string for the path name. It should contain one "%s", |
| * which will be filled in with the rule's short name. It should not start with a slash. |
| * @return A {@link java.nio.file.Path} under buck-out/gen, scoped to the base path of |
| * {@code target}. |
| */ |
| public static Path getGenPath(UnflavoredBuildTarget target, String format) { |
| return Paths.get(String.format("%s/%s" + format, |
| BuckConstant.GEN_DIR, |
| target.getBasePathWithSlash(), |
| target.getShortName())); |
| } |
| |
| /** |
| * Takes the {@link BuildTarget} for {@code hasBuildTarget} and derives a new {@link BuildTarget} |
| * from it with the specified flavor. |
| * @throws IllegalArgumentException if the original {@link BuildTarget} already has a flavor. |
| */ |
| public static BuildTarget createFlavoredBuildTarget( |
| UnflavoredBuildTarget buildTarget, |
| Flavor flavor) { |
| return BuildTarget.builder(buildTarget) |
| .addFlavors(flavor) |
| .build(); |
| } |
| |
| /** |
| * Returns whether the {@link BuildTarget} `target` is visible to the {@link BuildTarget} `other` |
| * using the given visibility patterns. |
| */ |
| public static boolean isVisibleTo( |
| BuildTarget target, |
| ImmutableSet<BuildTargetPattern> visibilityPatterns, |
| BuildTarget other) { |
| |
| // Targets in the same build file are always visible to each other. |
| if (target.getBaseName().equals(other.getBaseName())) { |
| return true; |
| } |
| |
| for (BuildTargetPattern pattern : visibilityPatterns) { |
| if (pattern.apply(other)) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Propagate flavors represented by the given {@link FlavorDomain} objects from a parent |
| * target to it's dependencies. |
| */ |
| public static ImmutableSortedSet<BuildTarget> propagateFlavorDomains( |
| BuildTarget target, |
| Iterable<FlavorDomain<?>> domains, |
| Iterable<BuildTarget> deps) { |
| |
| Set<Flavor> flavors = Sets.newHashSet(); |
| |
| // For each flavor domain, extract the corresponding flavor from the parent target and |
| // verify that each dependency hasn't already set this flavor. |
| for (FlavorDomain<?> domain : domains) { |
| |
| // Now extract all relevant domain flavors from our parent target. |
| Optional<Flavor> flavor; |
| try { |
| flavor = domain.getFlavor(ImmutableSet.copyOf(target.getFlavors())); |
| } catch (FlavorDomainException e) { |
| throw new HumanReadableException("%s: %s", target, e.getMessage()); |
| } |
| if (!flavor.isPresent()) { |
| throw new HumanReadableException( |
| "%s: no flavor for \"%s\"", |
| target, |
| domain.getName()); |
| } |
| flavors.add(flavor.get()); |
| |
| // First verify that our deps are not already flavored for our given domains. |
| for (BuildTarget dep : deps) { |
| Optional<Flavor> depFlavor; |
| try { |
| depFlavor = domain.getFlavor(ImmutableSet.copyOf(dep.getFlavors())); |
| } catch (FlavorDomainException e) { |
| throw new HumanReadableException("%s: dep %s: %s", target, dep, e.getMessage()); |
| } |
| if (depFlavor.isPresent()) { |
| throw new HumanReadableException( |
| "%s: dep %s already has flavor for \"%s\" : %s", |
| target, |
| dep, |
| domain.getName(), |
| flavor.get()); |
| } |
| } |
| } |
| |
| ImmutableSortedSet.Builder<BuildTarget> flavoredDeps = ImmutableSortedSet.naturalOrder(); |
| |
| // Now flavor each dependency with the relevant flavors. |
| for (BuildTarget dep : deps) { |
| flavoredDeps.add(BuildTarget.builder(dep).addAllFlavors(flavors).build()); |
| } |
| |
| return flavoredDeps.build(); |
| } |
| |
| } |