public void register(Description<?> description) {
   Preconditions.checkNotNull(description);
   BuildRuleType type = description.getBuildRuleType();
   types.put(type.getName(), type);
   factories.put(type, new DescribedRuleFactory<>(description));
   descriptions.put(type, description);
 }
Example #2
0
  @Test
  public void shouldConvertCamelCaseFieldNameToSnakeCaseParameter() {
    class Dto {
      public String someField;

      @Hint(name = "all_this_was_fields")
      public String hintedField;
    }

    String definition = buckPyFunction.toPythonFunction(BuildRuleType.of("case"), new Dto());

    assertEquals(
        Joiner.on("\n")
            .join(
                "@provide_for_build",
                "def case(name, all_this_was_fields, some_field, visibility=[], build_env=None):",
                "  add_rule({",
                "    'buck.type' : 'case',",
                "    'name' : name,",
                "    'hintedField' : all_this_was_fields,",
                "    'someField' : some_field,",
                "    'visibility' : visibility,",
                "  }, build_env)",
                "",
                ""),
        definition);
  }
/**
 * Description for an apple_asset_catalog rule, which identifies an asset catalog for an iOS or Mac
 * OS X library or binary.
 */
public class AppleAssetCatalogDescription implements Description<AppleAssetCatalogDescription.Arg> {
  public static final BuildRuleType TYPE = BuildRuleType.of("apple_asset_catalog");

  @Override
  public BuildRuleType getBuildRuleType() {
    return TYPE;
  }

  @Override
  public Arg createUnpopulatedConstructorArg() {
    return new Arg();
  }

  @Override
  public <A extends Arg> NoopBuildRule createBuildRule(
      BuildRuleParams params, BuildRuleResolver resolver, A args) {
    return new NoopBuildRule(params, new SourcePathResolver(resolver));
  }

  @SuppressFieldNotInitialized
  public static class Arg {
    public SortedSet<Path> dirs;
    public Optional<Boolean> copyToBundles;

    public boolean getCopyToBundles() {
      return copyToBundles.or(false);
    }
  }
}
/** Description for an apple_resource rule which copies resource files to the built bundle. */
public class AppleResourceDescription
    implements Description<AppleResourceDescription.Arg>, Flavored {
  public static final BuildRuleType TYPE = BuildRuleType.of("apple_resource");

  @Override
  public BuildRuleType getBuildRuleType() {
    return TYPE;
  }

  @Override
  public Arg createUnpopulatedConstructorArg() {
    return new Arg();
  }

  @Override
  public <A extends Arg> BuildRule createBuildRule(
      TargetGraph targetGraph, BuildRuleParams params, BuildRuleResolver resolver, A args) {
    return new NoopBuildRule(params, new SourcePathResolver(resolver));
  }

  @Override
  public boolean hasFlavors(ImmutableSet<Flavor> flavors) {
    return true;
  }

  @SuppressFieldNotInitialized
  public static class Arg extends AbstractDescriptionArg {
    public Set<SourcePath> dirs;
    public Set<SourcePath> files;
    public Optional<Set<SourcePath>> variants;
  }
}
Example #5
0
  @Test
  public void optionalFieldsAreListedAfterMandatoryOnes() {
    class Either {
      // Alphabetical ordering is deliberate.
      public Optional<String> cat;
      public String dog;
      public Optional<String> egg;
      public String fake;
    }

    String definition = buckPyFunction.toPythonFunction(BuildRuleType.of("either"), new Either());

    assertEquals(
        Joiner.on("\n")
            .join(
                "@provide_for_build",
                "def either(name, dog, fake, cat=None, egg=None, visibility=[], build_env=None):",
                "  add_rule({",
                "    'buck.type' : 'either',",
                "    'name' : name,",
                "    'dog' : dog,",
                "    'fake' : fake,",
                "    'cat' : cat,",
                "    'egg' : egg,",
                "    'visibility' : visibility,",
                "  }, build_env)",
                "",
                ""),
        definition);
  }
Example #6
0
  @Test(expected = HumanReadableException.class)
  public void visibilityOptionsMustNotBeSetAsTheyArePassedInBuildRuleParamsLater() {
    class Visible {
      public Set<BuildTargetPattern> visibility;
    }

    buckPyFunction.toPythonFunction(BuildRuleType.of("nope"), new Visible());
  }
Example #7
0
  @Test(expected = HumanReadableException.class)
  public void theNameFieldMustBeAString() {
    class BadName {
      public int name;
    }

    buckPyFunction.toPythonFunction(BuildRuleType.of("nope"), new BadName());
  }
Example #8
0
  @Test
  public void visibilityWillBeAddedIfMissing() {
    class NoVis {
      public String random;
    }

    String definition = buckPyFunction.toPythonFunction(BuildRuleType.of("bad"), new NoVis());

    assertTrue(definition.contains("visibility=[]"));
  }
Example #9
0
  @Test
  public void nameWillBeAddedIfMissing() {
    class NoName {
      public String random;
    }

    String definition = buckPyFunction.toPythonFunction(BuildRuleType.of("bad"), new NoName());

    assertTrue(definition.contains("name"));
  }
Example #10
0
  @Test
  public void optionalBooleanValuesShouldBeRepresentedByNone() {
    class Dto {
      public Optional<Boolean> field;
    }

    String definition = buckPyFunction.toPythonFunction(BuildRuleType.of("boolean"), new Dto());

    assertTrue(definition, definition.contains(", field=None,"));
  }
Example #11
0
  @Test
  public void optionalFieldsAreGivenSensibleDefaultValues() {
    class LotsOfOptions {
      public Optional<String> thing;
      public Optional<List<BuildTarget>> targets;
      public Optional<Integer> version;
    }

    String definition =
        buckPyFunction.toPythonFunction(BuildRuleType.of("optional"), new LotsOfOptions());

    assertTrue(definition, definition.contains("targets=[], thing=None, version=None"));
  }
/**
 * Description for a core_data_model rule, which identifies a model file for use with Apple's Core
 * Data.
 */
public class CoreDataModelDescription
    implements Description<CoreDataModelDescription.Arg>, Flavored {
  public static final BuildRuleType TYPE = BuildRuleType.of("core_data_model");
  private static final String CORE_DATA_MODEL_EXTENSION = "xcdatamodel";
  private static final String VERSIONED_CORE_DATA_MODEL_EXTENSION = "xcdatamodeld";

  @Override
  public BuildRuleType getBuildRuleType() {
    return TYPE;
  }

  @Override
  public Arg createUnpopulatedConstructorArg() {
    return new Arg();
  }

  @Override
  public <A extends Arg> CoreDataModel createBuildRule(
      TargetGraph targetGraph, BuildRuleParams params, BuildRuleResolver resolver, A args) {
    ProjectFilesystem projectFilesystem = params.getProjectFilesystem();
    Supplier<ImmutableCollection<Path>> inputPathsSupplier =
        RuleUtils.subpathsOfPathsSupplier(projectFilesystem, ImmutableSet.of(args.path));
    String extension = Files.getFileExtension(args.path.getFileName().toString());
    Preconditions.checkArgument(
        CORE_DATA_MODEL_EXTENSION.equals(extension)
            || VERSIONED_CORE_DATA_MODEL_EXTENSION.equals(extension));

    return new CoreDataModel(
        params, new SourcePathResolver(resolver), inputPathsSupplier, args.path);
  }

  public static boolean isVersionedDataModel(Arg arg) {
    return VERSIONED_CORE_DATA_MODEL_EXTENSION.equals(
        Files.getFileExtension(arg.path.getFileName().toString()));
  }

  @SuppressFieldNotInitialized
  public static class Arg extends AbstractDescriptionArg {
    public Path path;
  }

  @Override
  public boolean hasFlavors(ImmutableSet<Flavor> flavors) {
    return true;
  }
}
Example #13
0
public class GoBinaryDescription implements Description<GoBinaryDescription.Arg> {

  private static final BuildRuleType TYPE = BuildRuleType.of("go_binary");

  private final GoBuckConfig goBuckConfig;

  private final CxxPlatform cxxPlatform;

  public GoBinaryDescription(GoBuckConfig goBuckConfig, CxxPlatform cxxPlatform) {
    this.goBuckConfig = goBuckConfig;
    this.cxxPlatform = cxxPlatform;
  }

  @Override
  public BuildRuleType getBuildRuleType() {
    return TYPE;
  }

  @Override
  public Arg createUnpopulatedConstructorArg() {
    return new Arg();
  }

  @Override
  public <A extends Arg> BuildRule createBuildRule(
      TargetGraph targetGraph, BuildRuleParams params, BuildRuleResolver resolver, A args) {
    return GoDescriptors.createGoBinaryRule(
        params,
        resolver,
        goBuckConfig,
        cxxPlatform,
        args.srcs,
        args.compilerFlags.or(ImmutableList.<String>of()),
        args.linkerFlags.or(ImmutableList.<String>of()));
  }

  @SuppressFieldNotInitialized
  public static class Arg {
    public ImmutableSet<SourcePath> srcs;
    public Optional<List<String>> compilerFlags;
    public Optional<List<String>> linkerFlags;
    public Optional<ImmutableSortedSet<BuildTarget>> deps;
  }
}
Example #14
0
  @Test
  public void shouldOnlyIncludeTheNameFieldOnce() {
    class Named {
      public String name;
    }

    String definition = buckPyFunction.toPythonFunction(BuildRuleType.of("named"), new Named());

    assertEquals(
        Joiner.on("\n")
            .join(
                "@provide_for_build",
                "def named(name, visibility=[], build_env=None):",
                "  add_rule({",
                "    'buck.type' : 'named',",
                "    'name' : name,",
                "    'visibility' : visibility,",
                "  }, build_env)",
                "",
                ""),
        definition);
  }
Example #15
0
  @Test
  public void testHasDefaultName() {
    @TargetName(name = "lollerskates")
    class NoName {
      public String foobar;
    }

    String definition = buckPyFunction.toPythonFunction(BuildRuleType.of("noname"), new NoName());

    assertEquals(
        Joiner.on("\n")
            .join(
                "@provide_for_build",
                "def noname(foobar, visibility=[], build_env=None):",
                "  add_rule({",
                "    'buck.type' : 'noname',",
                "    'name' : 'lollerskates',",
                "    'foobar' : foobar,",
                "    'visibility' : visibility,",
                "  }, build_env)",
                "",
                ""),
        definition);
  }
public class AndroidBuildConfigDescription
    implements Description<AndroidBuildConfigDescription.Arg> {

  public static final BuildRuleType TYPE = new BuildRuleType("android_build_config");

  private static final BuildRuleType GEN_JAVA_TYPE =
      new BuildRuleType("gen_java_android_build_config");
  private static final Flavor GEN_JAVA_FLAVOR = new Flavor(GEN_JAVA_TYPE.getName());

  @Override
  public BuildRuleType getBuildRuleType() {
    return TYPE;
  }

  @Override
  public Arg createUnpopulatedConstructorArg() {
    return new Arg();
  }

  @Override
  public <A extends Arg> BuildRule createBuildRule(
      BuildRuleParams params, BuildRuleResolver resolver, A args) {
    return createBuildRule(
        params,
        args.javaPackage,
        args.values.get(),
        args.valuesFile,
        /* useConstantExpressions */ false);
  }

  /**
   * @param values Collection whose entries identify fields for the generated {@code BuildConfig}
   *     class. The values for fields can be overridden by values from the {@code valuesFile} file,
   *     if present.
   * @param valuesFile Path to a file with values to override those in {@code values}.
   */
  static AndroidBuildConfigJavaLibrary createBuildRule(
      BuildRuleParams params,
      String javaPackage,
      BuildConfigFields values,
      Optional<SourcePath> valuesFile,
      boolean useConstantExpressions) {
    // Create one build rule to generate BuildConfig.java.
    BuildRuleParams buildConfigParams =
        params.copyWithChanges(
            GEN_JAVA_TYPE,
            BuildTarget.builder(params.getBuildTarget()).setFlavor(GEN_JAVA_FLAVOR).build(),
            params.getDeclaredDeps(),
            params.getExtraDeps());
    AndroidBuildConfig androidBuildConfig =
        new AndroidBuildConfig(
            buildConfigParams, javaPackage, values, valuesFile, useConstantExpressions);

    // Create a second build rule to compile BuildConfig.java and expose it as a JavaLibrary.
    BuildRuleParams javaLibraryParams =
        params.copyWithChanges(
            TYPE,
            params.getBuildTarget(),
            /* declaredDeps */ ImmutableSortedSet.<BuildRule>of(androidBuildConfig),
            /* extraDeps */ ImmutableSortedSet.<BuildRule>of());
    return new AndroidBuildConfigJavaLibrary(javaLibraryParams, androidBuildConfig);
  }

  public static class Arg implements ConstructorArg {
    @Hint(name = "package")
    public String javaPackage;

    /** This will never be absent after this Arg is populated. */
    public Optional<BuildConfigFields> values;

    /** If present, contents of file can override those of {@link #values}. */
    public Optional<SourcePath> valuesFile;
  }
}
Example #17
0
public class GoBinaryDescription implements Description<GoBinaryDescription.Arg> {

  private static final BuildRuleType TYPE = BuildRuleType.of("go_binary");

  private final GoBuckConfig goBuckConfig;

  private final CxxPlatform cxxPlatform;

  public GoBinaryDescription(GoBuckConfig goBuckConfig, CxxPlatform cxxPlatform) {
    this.goBuckConfig = goBuckConfig;
    this.cxxPlatform = cxxPlatform;
  }

  @Override
  public BuildRuleType getBuildRuleType() {
    return TYPE;
  }

  @Override
  public Arg createUnpopulatedConstructorArg() {
    return new Arg();
  }

  @Override
  public <A extends Arg> BuildRule createBuildRule(
      TargetGraph targetGraph, BuildRuleParams params, BuildRuleResolver resolver, A args) {
    BuildTarget libraryTarget =
        BuildTarget.builder(params.getBuildTarget())
            .addFlavors(ImmutableFlavor.of("compile"))
            .build();
    GoLibrary library =
        GoDescriptors.createGoLibraryRule(
            params.copyWithBuildTarget(libraryTarget),
            resolver,
            goBuckConfig,
            Paths.get("main"),
            args.srcs,
            args.compilerFlags.or(ImmutableList.<String>of()));
    resolver.addToIndex(library);

    BuildRuleParams binaryParams =
        params.copyWithDeps(
            Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of(library)),
            Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of()));

    GoSymlinkTree symlinkTree =
        GoDescriptors.requireTransitiveSymlinkTreeRule(binaryParams, resolver);

    return new GoBinary(
        params.copyWithDeps(
            Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of(symlinkTree, library)),
            Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of())),
        new SourcePathResolver(resolver),
        cxxPlatform.getLd(),
        symlinkTree,
        library,
        goBuckConfig.getGoLinker().get(),
        ImmutableList.<String>builder()
            .addAll(goBuckConfig.getLinkerFlags())
            .addAll(args.linkerFlags.or(ImmutableList.<String>of()))
            .build());
  }

  @SuppressFieldNotInitialized
  public static class Arg {
    public ImmutableSet<SourcePath> srcs;
    public Optional<List<String>> compilerFlags;
    public Optional<List<String>> linkerFlags;
    public Optional<ImmutableSortedSet<BuildTarget>> deps;
  }
}
public class JavaTestDescription
    implements Description<JavaTestDescription.Arg>,
        ImplicitDepsInferringDescription<JavaTestDescription.Arg> {

  public static final BuildRuleType TYPE = BuildRuleType.of("java_test");

  private final JavaOptions javaOptions;
  private final JavacOptions templateJavacOptions;
  private final Optional<Long> defaultTestRuleTimeoutMs;
  private final CxxPlatform cxxPlatform;

  public JavaTestDescription(
      JavaOptions javaOptions,
      JavacOptions templateOptions,
      Optional<Long> defaultTestRuleTimeoutMs,
      CxxPlatform cxxPlatform) {
    this.javaOptions = javaOptions;
    this.templateJavacOptions = templateOptions;
    this.defaultTestRuleTimeoutMs = defaultTestRuleTimeoutMs;
    this.cxxPlatform = cxxPlatform;
  }

  @Override
  public BuildRuleType getBuildRuleType() {
    return TYPE;
  }

  @Override
  public Arg createUnpopulatedConstructorArg() {
    return new Arg();
  }

  @Override
  public <A extends Arg> JavaTest createBuildRule(
      TargetGraph targetGraph, BuildRuleParams params, BuildRuleResolver resolver, A args)
      throws NoSuchBuildTargetException {
    SourcePathResolver pathResolver = new SourcePathResolver(resolver);

    JavacOptions javacOptions =
        JavacOptionsFactory.create(templateJavacOptions, params, resolver, pathResolver, args);

    CxxLibraryEnhancement cxxLibraryEnhancement =
        new CxxLibraryEnhancement(
            params, args.useCxxLibraries, resolver, pathResolver, cxxPlatform);
    params = cxxLibraryEnhancement.updatedParams;

    BuildTarget abiJarTarget = params.getBuildTarget().withAppendedFlavors(CalculateAbi.FLAVOR);

    JavaTest test =
        resolver.addToIndex(
            new JavaTest(
                params.appendExtraDeps(
                    Iterables.concat(
                        BuildRules.getExportedRules(
                            Iterables.concat(
                                params.getDeclaredDeps().get(),
                                resolver.getAllRules(args.providedDeps.get()))),
                        pathResolver.filterBuildRuleInputs(javacOptions.getInputs(pathResolver)))),
                pathResolver,
                args.srcs.get(),
                ResourceValidator.validateResources(
                    pathResolver, params.getProjectFilesystem(), args.resources.get()),
                javacOptions.getGeneratedSourceFolderName(),
                args.labels.get(),
                args.contacts.get(),
                args.proguardConfig.transform(
                    SourcePaths.toSourcePath(params.getProjectFilesystem())),
                new BuildTargetSourcePath(abiJarTarget),
                javacOptions.trackClassUsage(),
                /* additionalClasspathEntries */ ImmutableSet.<Path>of(),
                args.testType.or(TestType.JUNIT),
                new JavacToJarStepFactory(javacOptions, JavacOptionsAmender.IDENTITY),
                javaOptions.getJavaRuntimeLauncher(),
                args.vmArgs.get(),
                cxxLibraryEnhancement.nativeLibsEnvironment,
                validateAndGetSourcesUnderTest(
                    args.sourceUnderTest.get(), params.getBuildTarget(), resolver),
                args.resourcesRoot,
                args.mavenCoords,
                args.testRuleTimeoutMs.or(defaultTestRuleTimeoutMs),
                args.env.get(),
                args.getRunTestSeparately(),
                args.stdOutLogLevel,
                args.stdErrLogLevel));

    resolver.addToIndex(
        CalculateAbi.of(
            abiJarTarget, pathResolver, params, new BuildTargetSourcePath(test.getBuildTarget())));

    return test;
  }

  public static ImmutableSet<BuildRule> validateAndGetSourcesUnderTest(
      ImmutableSet<BuildTarget> sourceUnderTestTargets,
      BuildTarget owner,
      BuildRuleResolver resolver) {
    ImmutableSet.Builder<BuildRule> sourceUnderTest = ImmutableSet.builder();
    for (BuildTarget target : sourceUnderTestTargets) {
      BuildRule rule = resolver.getRule(target);
      if (!(rule instanceof JavaLibrary)) {
        // In this case, the source under test specified in the build file was not a Java library
        // rule. Since EMMA requires the sources to be in Java, we will throw this exception and
        // not continue with the tests.
        throw new HumanReadableException(
            "Specified source under test for %s is not a Java library: %s (%s).",
            owner, rule.getFullyQualifiedName(), rule.getType());
      }
      sourceUnderTest.add(rule);
    }
    return sourceUnderTest.build();
  }

  @Override
  public Iterable<BuildTarget> findDepsForTargetFromConstructorArgs(
      BuildTarget buildTarget, CellPathResolver cellRoots, Arg constructorArg) {
    ImmutableSet.Builder<BuildTarget> deps = ImmutableSet.builder();
    if (constructorArg.useCxxLibraries.or(false)) {
      deps.addAll(CxxPlatforms.getParseTimeDeps(cxxPlatform));
    }
    return deps.build();
  }

  @SuppressFieldNotInitialized
  public static class Arg extends JavaLibraryDescription.Arg implements HasSourceUnderTest {
    public Optional<ImmutableSortedSet<String>> contacts;
    public Optional<ImmutableSortedSet<Label>> labels;

    @Hint(isDep = false)
    public Optional<ImmutableSortedSet<BuildTarget>> sourceUnderTest;

    public Optional<ImmutableList<String>> vmArgs;
    public Optional<TestType> testType;
    public Optional<Boolean> runTestSeparately;
    public Optional<Level> stdErrLogLevel;
    public Optional<Level> stdOutLogLevel;
    public Optional<Boolean> useCxxLibraries;
    public Optional<Long> testRuleTimeoutMs;
    public Optional<ImmutableMap<String, String>> env;

    @Override
    public ImmutableSortedSet<BuildTarget> getSourceUnderTest() {
      return sourceUnderTest.get();
    }

    public boolean getRunTestSeparately() {
      return runTestSeparately.or(false);
    }
  }

  public static class CxxLibraryEnhancement {
    public final BuildRuleParams updatedParams;
    public final ImmutableMap<String, String> nativeLibsEnvironment;

    public CxxLibraryEnhancement(
        BuildRuleParams params,
        Optional<Boolean> useCxxLibraries,
        BuildRuleResolver resolver,
        SourcePathResolver pathResolver,
        CxxPlatform cxxPlatform)
        throws NoSuchBuildTargetException {
      if (useCxxLibraries.or(false)) {
        SymlinkTree nativeLibsSymlinkTree =
            buildNativeLibsSymlinkTreeRule(params, pathResolver, cxxPlatform);
        updatedParams =
            params.appendExtraDeps(
                ImmutableList.<BuildRule>builder()
                    .add(nativeLibsSymlinkTree)
                    // Add all the native libraries as first-order dependencies.
                    // This has two effects:
                    // (1) They become runtime deps because JavaTest adds all first-order deps.
                    // (2) They affect the JavaTest's RuleKey, so changing them will invalidate
                    // the test results cache.
                    .addAll(
                        pathResolver.filterBuildRuleInputs(
                            nativeLibsSymlinkTree.getLinks().values()))
                    .build());
        nativeLibsEnvironment =
            ImmutableMap.of(
                cxxPlatform.getLd().resolve(resolver).searchPathEnvVar(),
                nativeLibsSymlinkTree.getRoot().toString());
      } else {
        updatedParams = params;
        nativeLibsEnvironment = ImmutableMap.of();
      }
    }

    public static SymlinkTree buildNativeLibsSymlinkTreeRule(
        BuildRuleParams buildRuleParams, SourcePathResolver pathResolver, CxxPlatform cxxPlatform)
        throws NoSuchBuildTargetException {
      return CxxDescriptionEnhancer.createSharedLibrarySymlinkTree(
          buildRuleParams,
          pathResolver,
          cxxPlatform,
          buildRuleParams.getDeps(),
          Predicates.or(
              Predicates.instanceOf(NativeLinkable.class),
              Predicates.instanceOf(JavaLibrary.class)));
    }
  }
}
public class AndroidInstrumentationApkDescription
    implements Description<AndroidInstrumentationApkDescription.Arg> {

  public static final BuildRuleType TYPE = BuildRuleType.of("android_instrumentation_apk");

  private final ProGuardConfig proGuardConfig;
  private final JavacOptions javacOptions;
  private final ImmutableMap<NdkCxxPlatforms.TargetCpuType, NdkCxxPlatform> nativePlatforms;
  private final ListeningExecutorService dxExecutorService;

  public AndroidInstrumentationApkDescription(
      ProGuardConfig proGuardConfig,
      JavacOptions androidJavacOptions,
      ImmutableMap<NdkCxxPlatforms.TargetCpuType, NdkCxxPlatform> nativePlatforms,
      ListeningExecutorService dxExecutorService) {
    this.proGuardConfig = proGuardConfig;
    this.javacOptions = androidJavacOptions;
    this.nativePlatforms = nativePlatforms;
    this.dxExecutorService = dxExecutorService;
  }

  @Override
  public BuildRuleType getBuildRuleType() {
    return TYPE;
  }

  @Override
  public Arg createUnpopulatedConstructorArg() {
    return new Arg();
  }

  @Override
  public <A extends Arg> BuildRule createBuildRule(
      TargetGraph targetGraph, BuildRuleParams params, BuildRuleResolver resolver, A args) {
    BuildRule installableApk = resolver.getRule(args.apk);
    if (!(installableApk instanceof InstallableApk)) {
      throw new HumanReadableException(
          "In %s, apk='%s' must be an android_binary() or apk_genrule() but was %s().",
          params.getBuildTarget(),
          installableApk.getFullyQualifiedName(),
          installableApk.getType());
    }
    AndroidBinary apkUnderTest = getUnderlyingApk((InstallableApk) installableApk);

    ImmutableSortedSet<JavaLibrary> rulesToExcludeFromDex =
        FluentIterable.from(
                ImmutableSet.<JavaLibrary>builder()
                    .addAll(apkUnderTest.getRulesToExcludeFromDex())
                    .addAll(
                        Classpaths.getClasspathEntries(apkUnderTest.getClasspathDeps()).keySet())
                    .build())
            .toSortedSet(HasBuildTarget.BUILD_TARGET_COMPARATOR);

    // TODO(natthu): Instrumentation APKs should also exclude native libraries and assets from the
    // apk under test.
    AndroidPackageableCollection.ResourceDetails resourceDetails =
        apkUnderTest.getAndroidPackageableCollection().getResourceDetails();
    ImmutableSet<BuildTarget> resourcesToExclude =
        ImmutableSet.copyOf(
            Iterables.concat(
                resourceDetails.getResourcesWithNonEmptyResDir(),
                resourceDetails.getResourcesWithEmptyResButNonEmptyAssetsDir()));

    Path primaryDexPath = AndroidBinary.getPrimaryDexPath(params.getBuildTarget());
    AndroidBinaryGraphEnhancer graphEnhancer =
        new AndroidBinaryGraphEnhancer(
            targetGraph,
            params,
            resolver,
            ResourceCompressionMode.DISABLED,
            FilterResourcesStep.ResourceFilter.EMPTY_FILTER,
            /* resourceUnionPackage */ Optional.<String>absent(),
            /* locales */ ImmutableSet.<String>of(),
            args.manifest,
            PackageType.INSTRUMENTED,
            apkUnderTest.getCpuFilters(),
            /* shouldBuildStringSourceMap */ false,
            /* shouldPreDex */ false,
            primaryDexPath,
            DexSplitMode.NO_SPLIT,
            FluentIterable.from(rulesToExcludeFromDex).transform(TO_TARGET).toSet(),
            resourcesToExclude,
            /* skipCrunchPngs */ false,
            javacOptions,
            EnumSet.noneOf(ExopackageMode.class),
            apkUnderTest.getKeystore(),
            /* buildConfigValues */ BuildConfigFields.empty(),
            /* buildConfigValuesFile */ Optional.<SourcePath>absent(),
            /* xzCompressionLevel */ Optional.<Integer>absent(),
            nativePlatforms,
            dxExecutorService);

    AndroidGraphEnhancementResult enhancementResult = graphEnhancer.createAdditionalBuildables();

    return new AndroidInstrumentationApk(
        params
            .copyWithExtraDeps(Suppliers.ofInstance(enhancementResult.getFinalDeps()))
            .appendExtraDeps(rulesToExcludeFromDex),
        new SourcePathResolver(resolver),
        proGuardConfig.getProguardJarOverride(),
        proGuardConfig.getProguardMaxHeapSize(),
        apkUnderTest,
        rulesToExcludeFromDex,
        enhancementResult,
        dxExecutorService);
  }

  private static AndroidBinary getUnderlyingApk(InstallableApk installable) {
    if (installable instanceof AndroidBinary) {
      return (AndroidBinary) installable;
    } else if (installable instanceof ApkGenrule) {
      return getUnderlyingApk(((ApkGenrule) installable).getInstallableApk());
    } else {
      throw new IllegalStateException(
          installable.getBuildTarget().getFullyQualifiedName()
              + " must be backed by either an android_binary() or an apk_genrule()");
    }
  }

  @SuppressFieldNotInitialized
  public static class Arg {
    public SourcePath manifest;
    public BuildTarget apk;
    public Optional<ImmutableSortedSet<BuildTarget>> deps;
  }
}
public class CxxPythonExtensionDescription
    implements Description<CxxPythonExtensionDescription.Arg>,
        ImplicitDepsInferringDescription<CxxPythonExtensionDescription.Arg> {

  private enum Type {
    EXTENSION,
  }

  private static final FlavorDomain<Type> LIBRARY_TYPE =
      new FlavorDomain<>(
          "C/C++ Library Type",
          ImmutableMap.of(CxxDescriptionEnhancer.SHARED_FLAVOR, Type.EXTENSION));

  public static final BuildRuleType TYPE = BuildRuleType.of("cxx_python_extension");

  private final CxxBuckConfig cxxBuckConfig;
  private final FlavorDomain<CxxPlatform> cxxPlatforms;

  public CxxPythonExtensionDescription(
      CxxBuckConfig cxxBuckConfig, FlavorDomain<CxxPlatform> cxxPlatforms) {
    this.cxxBuckConfig = cxxBuckConfig;
    this.cxxPlatforms = cxxPlatforms;
  }

  @Override
  public Arg createUnpopulatedConstructorArg() {
    return new Arg();
  }

  @VisibleForTesting
  protected BuildTarget getExtensionTarget(BuildTarget target, Flavor platform) {
    return CxxDescriptionEnhancer.createSharedLibraryBuildTarget(target, platform);
  }

  @VisibleForTesting
  protected String getExtensionName(BuildTarget target) {
    // .so is used on OS X too (as opposed to dylib).
    return String.format("%s.so", target.getShortName());
  }

  @VisibleForTesting
  protected Path getExtensionPath(BuildTarget target, Flavor platform) {
    return BuildTargets.getGenPath(getExtensionTarget(target, platform), "%s")
        .resolve(getExtensionName(target));
  }

  private <A extends Arg> BuildRule createExtensionBuildRule(
      TargetGraph targetGraph,
      BuildRuleParams params,
      BuildRuleResolver ruleResolver,
      CxxPlatform cxxPlatform,
      A args) {
    SourcePathResolver pathResolver = new SourcePathResolver(ruleResolver);

    // Extract all C/C++ sources from the constructor arg.
    ImmutableMap<String, CxxSource> srcs =
        CxxDescriptionEnhancer.parseCxxSources(params, ruleResolver, cxxPlatform, args);
    ImmutableMap<Path, SourcePath> headers =
        CxxDescriptionEnhancer.parseHeaders(params, ruleResolver, cxxPlatform, args);
    ImmutableMap<String, SourcePath> lexSrcs =
        CxxDescriptionEnhancer.parseLexSources(params, ruleResolver, args);
    ImmutableMap<String, SourcePath> yaccSrcs =
        CxxDescriptionEnhancer.parseYaccSources(params, ruleResolver, args);

    CxxHeaderSourceSpec lexYaccSources =
        CxxDescriptionEnhancer.createLexYaccBuildRules(
            params,
            ruleResolver,
            cxxPlatform,
            ImmutableList.<String>of(),
            lexSrcs,
            ImmutableList.<String>of(),
            yaccSrcs);

    // Setup the header symlink tree and combine all the preprocessor input from this rule
    // and all dependencies.
    HeaderSymlinkTree headerSymlinkTree =
        CxxDescriptionEnhancer.requireHeaderSymlinkTree(
            params,
            ruleResolver,
            new SourcePathResolver(ruleResolver),
            cxxPlatform,
            /* includeLexYaccHeaders */ true,
            lexSrcs,
            yaccSrcs,
            headers,
            HeaderVisibility.PRIVATE);
    ImmutableList<CxxPreprocessorInput> cxxPreprocessorInput =
        CxxDescriptionEnhancer.collectCxxPreprocessorInput(
            targetGraph,
            params,
            cxxPlatform,
            CxxFlags.getLanguageFlags(
                args.preprocessorFlags,
                args.platformPreprocessorFlags,
                args.langPreprocessorFlags,
                cxxPlatform),
            args.prefixHeaders.get(),
            ImmutableList.of(headerSymlinkTree),
            ImmutableSet.<Path>of(),
            CxxPreprocessables.getTransitiveCxxPreprocessorInput(
                targetGraph, cxxPlatform, params.getDeps()));

    ImmutableMap<String, CxxSource> allSources =
        ImmutableMap.<String, CxxSource>builder()
            .putAll(srcs)
            .putAll(lexYaccSources.getCxxSources())
            .build();

    // Generate rule to build the object files.
    ImmutableMap<CxxPreprocessAndCompile, SourcePath> picObjects =
        CxxSourceRuleFactory.requirePreprocessAndCompileRules(
            params,
            ruleResolver,
            pathResolver,
            cxxPlatform,
            cxxPreprocessorInput,
            CxxFlags.getFlags(args.compilerFlags, args.platformCompilerFlags, cxxPlatform),
            cxxBuckConfig.getPreprocessMode(),
            allSources,
            CxxSourceRuleFactory.PicType.PIC);

    // Setup the rules to link the shared library.
    String extensionName = getExtensionName(params.getBuildTarget());
    Path extensionPath = getExtensionPath(params.getBuildTarget(), cxxPlatform.getFlavor());
    return CxxLinkableEnhancer.createCxxLinkableBuildRule(
        targetGraph,
        cxxPlatform,
        params,
        pathResolver,
        /* extraLdFlags */ CxxFlags.getFlags(
            args.linkerFlags, args.platformLinkerFlags, cxxPlatform),
        getExtensionTarget(params.getBuildTarget(), cxxPlatform.getFlavor()),
        Linker.LinkType.SHARED,
        Optional.of(extensionName),
        extensionPath,
        picObjects.values(),
        Linker.LinkableDepType.SHARED,
        params.getDeps(),
        args.cxxRuntimeType,
        Optional.<SourcePath>absent());
  }

  @Override
  public <A extends Arg> BuildRule createBuildRule(
      TargetGraph targetGraph, BuildRuleParams params, BuildRuleResolver ruleResolver, A args) {

    // See if we're building a particular "type" of this library, and if so, extract
    // it as an enum.
    Optional<Map.Entry<Flavor, Type>> type;
    Optional<Map.Entry<Flavor, CxxPlatform>> platform;
    try {
      type =
          LIBRARY_TYPE.getFlavorAndValue(ImmutableSet.copyOf(params.getBuildTarget().getFlavors()));
      platform =
          cxxPlatforms.getFlavorAndValue(ImmutableSet.copyOf(params.getBuildTarget().getFlavors()));
    } catch (FlavorDomainException e) {
      throw new HumanReadableException("%s: %s", params.getBuildTarget(), e.getMessage());
    }

    // If we *are* building a specific type of this lib, call into the type specific
    // rule builder methods.  Currently, we only support building a shared lib from the
    // pre-existing static lib, which we do here.
    if (type.isPresent()) {
      Preconditions.checkState(type.get().getValue() == Type.EXTENSION);
      Preconditions.checkState(platform.isPresent());
      return createExtensionBuildRule(
          targetGraph, params, ruleResolver, platform.get().getValue(), args);
    }

    // Otherwise, we return the generic placeholder of this library, that dependents can use
    // get the real build rules via querying the action graph.
    SourcePathResolver pathResolver = new SourcePathResolver(ruleResolver);
    Path baseModule = PythonUtil.getBasePath(params.getBuildTarget(), args.baseModule);
    return new CxxPythonExtension(
        params,
        ruleResolver,
        pathResolver,
        baseModule.resolve(getExtensionName(params.getBuildTarget())));
  }

  @Override
  public BuildRuleType getBuildRuleType() {
    return TYPE;
  }

  @Override
  public Iterable<BuildTarget> findDepsForTargetFromConstructorArgs(
      BuildTarget buildTarget, Arg constructorArg) {
    ImmutableSet.Builder<BuildTarget> deps = ImmutableSet.builder();

    deps.add(cxxBuckConfig.getPythonDep());

    if (constructorArg.lexSrcs.isPresent() && !constructorArg.lexSrcs.get().isEmpty()) {
      deps.add(cxxBuckConfig.getLexDep());
    }

    return deps.build();
  }

  @SuppressFieldNotInitialized
  public static class Arg extends CxxConstructorArg {
    public Optional<String> baseModule;
  }
}
/**
 * Description for a {@link BuildRule} that generates an {@code .aar} file.
 *
 * <p>This represents an Android Library Project packaged as an {@code .aar} bundle as specified by:
 * <a> http://tools.android.com/tech-docs/new-build-system/aar-format</a>.
 *
 * <p>Note that the {@code aar} may be specified as a {@link SourcePath}, so it could be either a
 * binary {@code .aar} file checked into version control, or a zip file that conforms to the {@code
 * .aar} specification that is generated by another build rule.
 */
public class AndroidAarDescription implements Description<AndroidAarDescription.Arg> {

  public static final BuildRuleType TYPE = BuildRuleType.of("android_aar");

  private static final Flavor AAR_ANDROID_MANIFEST_FLAVOR =
      ImmutableFlavor.of("aar_android_manifest");
  private static final Flavor AAR_ASSEMBLE_RESOURCE_FLAVOR =
      ImmutableFlavor.of("aar_assemble_resource");
  private static final Flavor AAR_ASSEMBLE_ASSETS_FLAVOR =
      ImmutableFlavor.of("aar_assemble_assets");
  private static final Flavor AAR_ANDROID_RESOURCE_FLAVOR =
      ImmutableFlavor.of("aar_android_resource");

  private final AndroidManifestDescription androidManifestDescription;
  private final ImmutableMap<NdkCxxPlatforms.TargetCpuType, NdkCxxPlatform> nativePlatforms;

  public AndroidAarDescription(
      AndroidManifestDescription androidManifestDescription,
      ImmutableMap<NdkCxxPlatforms.TargetCpuType, NdkCxxPlatform> nativePlatforms) {
    this.androidManifestDescription = androidManifestDescription;
    this.nativePlatforms = nativePlatforms;
  }

  @Override
  public BuildRuleType getBuildRuleType() {
    return TYPE;
  }

  @Override
  public Arg createUnpopulatedConstructorArg() {
    return new Arg();
  }

  @Override
  public <A extends Arg> BuildRule createBuildRule(
      TargetGraph targetGraph,
      BuildRuleParams originalBuildRuleParams,
      BuildRuleResolver resolver,
      A args) {

    UnflavoredBuildTarget originalBuildTarget =
        originalBuildRuleParams.getBuildTarget().checkUnflavored();
    SourcePathResolver pathResolver = new SourcePathResolver(resolver);
    ImmutableList.Builder<BuildRule> aarExtraDepsBuilder =
        ImmutableList.<BuildRule>builder().addAll(originalBuildRuleParams.getExtraDeps().get());

    /* android_manifest */
    AndroidManifestDescription.Arg androidManifestArgs =
        androidManifestDescription.createUnpopulatedConstructorArg();
    androidManifestArgs.skeleton = args.manifestSkeleton;
    androidManifestArgs.deps = args.deps;

    BuildRuleParams androidManifestParams =
        originalBuildRuleParams.copyWithChanges(
            BuildTargets.createFlavoredBuildTarget(
                originalBuildTarget, AAR_ANDROID_MANIFEST_FLAVOR),
            originalBuildRuleParams.getDeclaredDeps(),
            originalBuildRuleParams.getExtraDeps());

    AndroidManifest manifest =
        androidManifestDescription.createBuildRule(
            targetGraph, androidManifestParams, resolver, androidManifestArgs);
    aarExtraDepsBuilder.add(resolver.addToIndex(manifest));

    /* assemble dirs */
    AndroidPackageableCollector collector =
        new AndroidPackageableCollector(
            originalBuildRuleParams.getBuildTarget(),
            /* buildTargetsToExcludeFromDex */ ImmutableSet.<BuildTarget>of(),
            /* resourcesToExclude */ ImmutableSet.<BuildTarget>of());
    collector.addPackageables(
        AndroidPackageableCollector.getPackageableRules(originalBuildRuleParams.getDeps()));
    AndroidPackageableCollection packageableCollection = collector.build();

    ImmutableSortedSet<BuildRule> androidResourceDeclaredDeps =
        AndroidResourceHelper.androidResOnly(originalBuildRuleParams.getDeclaredDeps().get());
    ImmutableSortedSet<BuildRule> androidResourceExtraDeps =
        AndroidResourceHelper.androidResOnly(originalBuildRuleParams.getExtraDeps().get());

    BuildRuleParams assembleAssetsParams =
        originalBuildRuleParams.copyWithChanges(
            BuildTargets.createFlavoredBuildTarget(originalBuildTarget, AAR_ASSEMBLE_ASSETS_FLAVOR),
            Suppliers.ofInstance(androidResourceDeclaredDeps),
            Suppliers.ofInstance(androidResourceExtraDeps));
    ImmutableCollection<SourcePath> assetsDirectories =
        packageableCollection.getAssetsDirectories();
    AssembleDirectories assembleAssetsDirectories =
        new AssembleDirectories(assembleAssetsParams, pathResolver, assetsDirectories);
    aarExtraDepsBuilder.add(resolver.addToIndex(assembleAssetsDirectories));

    BuildRuleParams assembleResourceParams =
        originalBuildRuleParams.copyWithChanges(
            BuildTargets.createFlavoredBuildTarget(
                originalBuildTarget, AAR_ASSEMBLE_RESOURCE_FLAVOR),
            Suppliers.ofInstance(androidResourceDeclaredDeps),
            Suppliers.ofInstance(androidResourceExtraDeps));
    ImmutableCollection<SourcePath> resDirectories =
        packageableCollection.getResourceDetails().getResourceDirectories();
    MergeAndroidResourceSources assembleResourceDirectories =
        new MergeAndroidResourceSources(assembleResourceParams, pathResolver, resDirectories);
    aarExtraDepsBuilder.add(resolver.addToIndex(assembleResourceDirectories));

    /* android_resource */
    BuildRuleParams androidResourceParams =
        originalBuildRuleParams.copyWithChanges(
            BuildTargets.createFlavoredBuildTarget(
                originalBuildTarget, AAR_ANDROID_RESOURCE_FLAVOR),
            Suppliers.ofInstance(
                ImmutableSortedSet.<BuildRule>of(
                    manifest, assembleAssetsDirectories, assembleResourceDirectories)),
            Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of()));

    AndroidResource androidResource =
        new AndroidResource(
            androidResourceParams,
            pathResolver,
            /* deps */ ImmutableSortedSet.<BuildRule>naturalOrder()
                .add(assembleAssetsDirectories)
                .add(assembleResourceDirectories)
                .addAll(originalBuildRuleParams.getDeclaredDeps().get())
                .build(),
            new BuildTargetSourcePath(assembleResourceDirectories.getBuildTarget()),
            /* resSrcs */ ImmutableSortedSet.<SourcePath>of(),
            Optional.<SourcePath>absent(),
            /* rDotJavaPackage */ null,
            new BuildTargetSourcePath(assembleAssetsDirectories.getBuildTarget()),
            /* assetsSrcs */ ImmutableSortedSet.<SourcePath>of(),
            Optional.<SourcePath>absent(),
            new BuildTargetSourcePath(manifest.getBuildTarget()),
            /* hasWhitelistedStrings */ false);
    aarExtraDepsBuilder.add(resolver.addToIndex(androidResource));

    /* native_libraries */
    AndroidNativeLibsPackageableGraphEnhancer packageableGraphEnhancer =
        new AndroidNativeLibsPackageableGraphEnhancer(
            resolver,
            originalBuildRuleParams,
            nativePlatforms,
            ImmutableSet.<NdkCxxPlatforms.TargetCpuType>of());
    Optional<CopyNativeLibraries> nativeLibrariesOptional =
        packageableGraphEnhancer.getCopyNativeLibraries(targetGraph, packageableCollection);
    if (nativeLibrariesOptional.isPresent()) {
      aarExtraDepsBuilder.add(resolver.addToIndex(nativeLibrariesOptional.get()));
    }

    Optional<Path> assembledNativeLibsDir =
        nativeLibrariesOptional.transform(
            new Function<CopyNativeLibraries, Path>() {
              @Override
              public Path apply(CopyNativeLibraries input) {
                return input.getPathToNativeLibsDir();
              }
            });
    BuildRuleParams androidAarParams =
        originalBuildRuleParams.copyWithExtraDeps(
            Suppliers.ofInstance(ImmutableSortedSet.copyOf(aarExtraDepsBuilder.build())));
    return new AndroidAar(
        androidAarParams,
        pathResolver,
        manifest,
        androidResource,
        assembleResourceDirectories.getPathToOutput(),
        assembleAssetsDirectories.getPathToOutput(),
        assembledNativeLibsDir,
        packageableCollection.getNativeLibAssetsDirectories());
  }

  @SuppressFieldNotInitialized
  public static class Arg extends AndroidLibraryDescription.Arg {
    public SourcePath manifestSkeleton;
  }
}
public class CxxPythonExtensionDescription
    implements Description<CxxPythonExtensionDescription.Arg>,
        ImplicitDepsInferringDescription<CxxPythonExtensionDescription.Arg> {

  private enum Type {
    EXTENSION,
  }

  private static final FlavorDomain<Type> LIBRARY_TYPE =
      new FlavorDomain<>(
          "C/C++ Library Type",
          ImmutableMap.of(CxxDescriptionEnhancer.SHARED_FLAVOR, Type.EXTENSION));

  public static final BuildRuleType TYPE = BuildRuleType.of("cxx_python_extension");

  private final FlavorDomain<PythonPlatform> pythonPlatforms;
  private final CxxBuckConfig cxxBuckConfig;
  private final FlavorDomain<CxxPlatform> cxxPlatforms;

  public CxxPythonExtensionDescription(
      FlavorDomain<PythonPlatform> pythonPlatforms,
      CxxBuckConfig cxxBuckConfig,
      FlavorDomain<CxxPlatform> cxxPlatforms) {
    this.pythonPlatforms = pythonPlatforms;
    this.cxxBuckConfig = cxxBuckConfig;
    this.cxxPlatforms = cxxPlatforms;
  }

  @Override
  public Arg createUnpopulatedConstructorArg() {
    return new Arg();
  }

  @VisibleForTesting
  protected static BuildTarget getExtensionTarget(
      BuildTarget target, Flavor pythonPlatform, Flavor platform) {
    return CxxDescriptionEnhancer.createSharedLibraryBuildTarget(
        BuildTarget.builder(target).addFlavors(pythonPlatform).build(), platform);
  }

  @VisibleForTesting
  protected static String getExtensionName(BuildTarget target) {
    // .so is used on OS X too (as opposed to dylib).
    return String.format("%s.so", target.getShortName());
  }

  @VisibleForTesting
  protected Path getExtensionPath(
      ProjectFilesystem filesystem, BuildTarget target, Flavor pythonPlatform, Flavor platform) {
    return BuildTargets.getGenPath(
            filesystem, getExtensionTarget(target, pythonPlatform, platform), "%s")
        .resolve(getExtensionName(target));
  }

  private ImmutableList<com.facebook.buck.rules.args.Arg> getExtensionArgs(
      BuildRuleParams params,
      BuildRuleResolver ruleResolver,
      SourcePathResolver pathResolver,
      CxxPlatform cxxPlatform,
      Arg args)
      throws NoSuchBuildTargetException {

    // Extract all C/C++ sources from the constructor arg.
    ImmutableMap<String, CxxSource> srcs =
        CxxDescriptionEnhancer.parseCxxSources(
            params.getBuildTarget(), pathResolver, cxxPlatform, args);
    ImmutableMap<Path, SourcePath> headers =
        CxxDescriptionEnhancer.parseHeaders(
            params.getBuildTarget(), pathResolver, Optional.of(cxxPlatform), args);

    // Setup the header symlink tree and combine all the preprocessor input from this rule
    // and all dependencies.
    HeaderSymlinkTree headerSymlinkTree =
        CxxDescriptionEnhancer.requireHeaderSymlinkTree(
            params,
            ruleResolver,
            new SourcePathResolver(ruleResolver),
            cxxPlatform,
            headers,
            HeaderVisibility.PRIVATE);
    ImmutableList<CxxPreprocessorInput> cxxPreprocessorInput =
        CxxDescriptionEnhancer.collectCxxPreprocessorInput(
            params,
            cxxPlatform,
            CxxFlags.getLanguageFlags(
                args.preprocessorFlags,
                args.platformPreprocessorFlags,
                args.langPreprocessorFlags,
                cxxPlatform),
            ImmutableList.of(headerSymlinkTree),
            ImmutableSet.<FrameworkPath>of(),
            CxxPreprocessables.getTransitiveCxxPreprocessorInput(cxxPlatform, params.getDeps()));

    // Generate rule to build the object files.
    ImmutableMap<CxxPreprocessAndCompile, SourcePath> picObjects =
        CxxSourceRuleFactory.requirePreprocessAndCompileRules(
            params,
            ruleResolver,
            pathResolver,
            cxxBuckConfig,
            cxxPlatform,
            cxxPreprocessorInput,
            CxxFlags.getLanguageFlags(
                args.compilerFlags,
                args.platformCompilerFlags,
                args.langCompilerFlags,
                cxxPlatform),
            args.prefixHeader,
            cxxBuckConfig.getPreprocessMode(),
            srcs,
            CxxSourceRuleFactory.PicType.PIC);

    ImmutableList.Builder<com.facebook.buck.rules.args.Arg> argsBuilder = ImmutableList.builder();
    argsBuilder.addAll(
        StringArg.from(CxxFlags.getFlags(args.linkerFlags, args.platformLinkerFlags, cxxPlatform)));

    // Embed a origin-relative library path into the binary so it can find the shared libraries.
    argsBuilder.addAll(
        StringArg.from(
            Linkers.iXlinker(
                "-rpath",
                String.format("%s/", cxxPlatform.getLd().resolve(ruleResolver).libOrigin()))));

    // Add object files into the args.
    argsBuilder.addAll(SourcePathArg.from(pathResolver, picObjects.values()));

    return argsBuilder.build();
  }

  private ImmutableList<BuildRule> getPlatformDeps(
      BuildRuleParams params,
      BuildRuleResolver ruleResolver,
      PythonPlatform pythonPlatform,
      Arg args) {

    ImmutableList.Builder<BuildRule> rules = ImmutableList.builder();

    // Add declared deps.
    rules.addAll(params.getDeclaredDeps().get());

    // Add platform specific deps.
    rules.addAll(
        ruleResolver.getAllRules(
            Iterables.concat(
                args.platformDeps
                    .or(PatternMatchedCollection.<ImmutableSortedSet<BuildTarget>>of())
                    .getMatchingValues(pythonPlatform.getFlavor().toString()))));

    // Add a dep on the python C/C++ library.
    rules.add(ruleResolver.getRule(pythonPlatform.getCxxLibrary().get().getBuildTarget()));

    return rules.build();
  }

  private <A extends Arg> BuildRule createExtensionBuildRule(
      BuildRuleParams params,
      BuildRuleResolver ruleResolver,
      PythonPlatform pythonPlatform,
      CxxPlatform cxxPlatform,
      A args)
      throws NoSuchBuildTargetException {
    SourcePathResolver pathResolver = new SourcePathResolver(ruleResolver);
    String extensionName = getExtensionName(params.getBuildTarget());
    Path extensionPath =
        getExtensionPath(
            params.getProjectFilesystem(),
            params.getBuildTarget(),
            pythonPlatform.getFlavor(),
            cxxPlatform.getFlavor());
    return CxxLinkableEnhancer.createCxxLinkableBuildRule(
        cxxBuckConfig,
        cxxPlatform,
        params,
        ruleResolver,
        pathResolver,
        getExtensionTarget(
            params.getBuildTarget(), pythonPlatform.getFlavor(), cxxPlatform.getFlavor()),
        Linker.LinkType.SHARED,
        Optional.of(extensionName),
        extensionPath,
        Linker.LinkableDepType.SHARED,
        FluentIterable.from(params.getDeps()).filter(NativeLinkable.class),
        args.cxxRuntimeType,
        Optional.<SourcePath>absent(),
        ImmutableSet.<BuildTarget>of(),
        NativeLinkableInput.builder()
            .setArgs(getExtensionArgs(params, ruleResolver, pathResolver, cxxPlatform, args))
            .setFrameworks(args.frameworks.or(ImmutableSortedSet.<FrameworkPath>of()))
            .setLibraries(args.libraries.or(ImmutableSortedSet.<FrameworkPath>of()))
            .build());
  }

  @Override
  public <A extends Arg> BuildRule createBuildRule(
      TargetGraph targetGraph,
      final BuildRuleParams params,
      final BuildRuleResolver ruleResolver,
      final A args)
      throws NoSuchBuildTargetException {

    // See if we're building a particular "type" of this library, and if so, extract
    // it as an enum.
    final Optional<Map.Entry<Flavor, Type>> type =
        LIBRARY_TYPE.getFlavorAndValue(params.getBuildTarget());
    Optional<Map.Entry<Flavor, CxxPlatform>> platform =
        cxxPlatforms.getFlavorAndValue(params.getBuildTarget());
    final Optional<Map.Entry<Flavor, PythonPlatform>> pythonPlatform =
        pythonPlatforms.getFlavorAndValue(params.getBuildTarget());

    // If we *are* building a specific type of this lib, call into the type specific
    // rule builder methods.  Currently, we only support building a shared lib from the
    // pre-existing static lib, which we do here.
    if (type.isPresent() && platform.isPresent() && pythonPlatform.isPresent()) {
      Preconditions.checkState(type.get().getValue() == Type.EXTENSION);
      return createExtensionBuildRule(
          params.copyWithDeps(
              Suppliers.ofInstance(
                  ImmutableSortedSet.copyOf(
                      getPlatformDeps(
                          params, ruleResolver, pythonPlatform.get().getValue(), args))),
              Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of())),
          ruleResolver,
          pythonPlatform.get().getValue(),
          platform.get().getValue(),
          args);
    }

    // Otherwise, we return the generic placeholder of this library, that dependents can use
    // get the real build rules via querying the action graph.
    final SourcePathResolver pathResolver = new SourcePathResolver(ruleResolver);
    Path baseModule = PythonUtil.getBasePath(params.getBuildTarget(), args.baseModule);
    final Path module = baseModule.resolve(getExtensionName(params.getBuildTarget()));
    return new CxxPythonExtension(params, pathResolver) {

      @Override
      protected BuildRule getExtension(PythonPlatform pythonPlatform, CxxPlatform cxxPlatform)
          throws NoSuchBuildTargetException {
        return ruleResolver.requireRule(
            getBuildTarget()
                .withFlavors(
                    pythonPlatform.getFlavor(),
                    cxxPlatform.getFlavor(),
                    CxxDescriptionEnhancer.SHARED_FLAVOR));
      }

      @Override
      public Path getModule() {
        return module;
      }

      @Override
      public PythonPackageComponents getPythonPackageComponents(
          PythonPlatform pythonPlatform, CxxPlatform cxxPlatform)
          throws NoSuchBuildTargetException {
        BuildRule extension = getExtension(pythonPlatform, cxxPlatform);
        SourcePath output = new BuildTargetSourcePath(extension.getBuildTarget());
        return PythonPackageComponents.of(
            ImmutableMap.of(module, output),
            ImmutableMap.<Path, SourcePath>of(),
            ImmutableMap.<Path, SourcePath>of(),
            ImmutableSet.<SourcePath>of(),
            Optional.of(false));
      }

      @Override
      public SharedNativeLinkTarget getNativeLinkTarget(final PythonPlatform pythonPlatform) {
        return new SharedNativeLinkTarget() {

          @Override
          public BuildTarget getBuildTarget() {
            return params.getBuildTarget().withAppendedFlavors(pythonPlatform.getFlavor());
          }

          @Override
          public Iterable<? extends NativeLinkable> getSharedNativeLinkTargetDeps(
              CxxPlatform cxxPlatform) {
            return FluentIterable.from(getPlatformDeps(params, ruleResolver, pythonPlatform, args))
                .filter(NativeLinkable.class);
          }

          @Override
          public Optional<String> getSharedNativeLinkTargetLibraryName(CxxPlatform cxxPlatform) {
            return Optional.absent();
          }

          @Override
          public NativeLinkableInput getSharedNativeLinkTargetInput(CxxPlatform cxxPlatform)
              throws NoSuchBuildTargetException {
            return NativeLinkableInput.builder()
                .addAllArgs(
                    getExtensionArgs(
                        params.copyWithChanges(
                            params
                                .getBuildTarget()
                                .withAppendedFlavors(
                                    pythonPlatform.getFlavor(),
                                    CxxDescriptionEnhancer.SHARED_FLAVOR),
                            Suppliers.ofInstance(
                                ImmutableSortedSet.copyOf(
                                    getPlatformDeps(params, ruleResolver, pythonPlatform, args))),
                            Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of())),
                        ruleResolver,
                        pathResolver,
                        cxxPlatform,
                        args))
                .addAllFrameworks(args.frameworks.or(ImmutableSortedSet.<FrameworkPath>of()))
                .build();
          }
        };
      }

      @Override
      public ImmutableSortedSet<BuildRule> getRuntimeDeps() {
        return getDeclaredDeps();
      }
    };
  }

  @Override
  public BuildRuleType getBuildRuleType() {
    return TYPE;
  }

  @Override
  public Iterable<BuildTarget> findDepsForTargetFromConstructorArgs(
      BuildTarget buildTarget, CellPathResolver cellRoots, Arg constructorArg) {
    ImmutableSet.Builder<BuildTarget> deps = ImmutableSet.builder();

    // Get any parse time deps from the C/C++ platforms.
    deps.addAll(CxxPlatforms.getParseTimeDeps(cxxPlatforms.getValues()));

    for (PythonPlatform pythonPlatform : pythonPlatforms.getValues()) {
      deps.addAll(pythonPlatform.getCxxLibrary().asSet());
    }

    return deps.build();
  }

  @SuppressFieldNotInitialized
  public static class Arg extends CxxConstructorArg {
    public Optional<PatternMatchedCollection<ImmutableSortedSet<BuildTarget>>> platformDeps;
    public Optional<String> baseModule;
  }
}
Example #23
0
 public Builder register(Description<?> description) {
   BuildRuleType type = description.getBuildRuleType();
   types.put(type.getName(), type);
   descriptions.put(type, description);
   return this;
 }
Example #24
0
public class JavaBinaryDescription implements Description<JavaBinaryDescription.Args> {

  public static final BuildRuleType TYPE = BuildRuleType.of("java_binary");

  private static final Flavor FAT_JAR_INNER_JAR_FLAVOR = ImmutableFlavor.of("inner-jar");

  private final JavacOptions javacOptions;
  private final CxxPlatform cxxPlatform;
  private final Optional<String> javaBinOverride;

  public JavaBinaryDescription(
      JavacOptions javacOptions, CxxPlatform cxxPlatform, Optional<String> javaBinOverride) {
    this.javacOptions = Preconditions.checkNotNull(javacOptions);
    this.cxxPlatform = Preconditions.checkNotNull(cxxPlatform);
    this.javaBinOverride = javaBinOverride;
  }

  @Override
  public BuildRuleType getBuildRuleType() {
    return TYPE;
  }

  @Override
  public Args createUnpopulatedConstructorArg() {
    return new Args();
  }

  @Override
  public <A extends Args> BuildRule createBuildRule(
      TargetGraph targetGraph, BuildRuleParams params, BuildRuleResolver resolver, A args) {

    SourcePathResolver pathResolver = new SourcePathResolver(resolver);
    ImmutableMap<String, SourcePath> nativeLibraries =
        JavaLibraryRules.getNativeLibraries(targetGraph, params.getDeps(), cxxPlatform);
    BuildRuleParams binaryParams = params;

    // If we're packaging native libraries, we'll build the binary JAR in a separate rule and
    // package it into the final fat JAR, so adjust it's params to use a flavored target.
    if (!nativeLibraries.isEmpty()) {
      binaryParams =
          params.copyWithChanges(
              BuildTarget.builder(params.getBuildTarget())
                  .addFlavors(FAT_JAR_INNER_JAR_FLAVOR)
                  .build(),
              params.getDeclaredDeps(),
              params.getExtraDeps());
    }

    // Construct the build rule to build the binary JAR.
    ImmutableSetMultimap<JavaLibrary, Path> transitiveClasspathEntries =
        Classpaths.getClasspathEntries(binaryParams.getDeps());
    BuildRule rule =
        new JavaBinary(
            binaryParams.appendExtraDeps(transitiveClasspathEntries.keys()),
            pathResolver,
            args.mainClass.orNull(),
            args.manifestFile.orNull(),
            args.mergeManifests.or(true),
            args.metaInfDirectory.orNull(),
            args.blacklist.or(ImmutableSortedSet.<String>of()),
            new DefaultDirectoryTraverser(),
            transitiveClasspathEntries,
            javaBinOverride);

    // If we're packaging native libraries, construct the rule to build the fat JAR, which packages
    // up the original binary JAR and any required native libraries.
    if (!nativeLibraries.isEmpty()) {
      BuildRule innerJarRule = rule;
      resolver.addToIndex(innerJarRule);
      SourcePath innerJar = new BuildTargetSourcePath(innerJarRule.getBuildTarget());
      rule =
          new JarFattener(
              params.appendExtraDeps(
                  Suppliers.<Iterable<BuildRule>>ofInstance(
                      pathResolver.filterBuildRuleInputs(
                          ImmutableList.<SourcePath>builder()
                              .add(innerJar)
                              .addAll(nativeLibraries.values())
                              .build()))),
              pathResolver,
              javacOptions,
              innerJar,
              nativeLibraries,
              javaBinOverride);
    }

    return rule;
  }

  @SuppressFieldNotInitialized
  public static class Args {
    public Optional<ImmutableSortedSet<BuildTarget>> deps;
    public Optional<String> mainClass;
    public Optional<SourcePath> manifestFile;
    public Optional<Boolean> mergeManifests;
    @Beta public Optional<Path> metaInfDirectory;
    @Beta public Optional<ImmutableSortedSet<String>> blacklist;
  }
}
public class AppleBundleDescription
    implements Description<AppleBundleDescription.Arg>,
        Flavored,
        ImplicitDepsInferringDescription<AppleBundleDescription.Arg> {
  public static final BuildRuleType TYPE = BuildRuleType.of("apple_bundle");

  private static final Flavor WATCH = ImmutableFlavor.of("watch");

  private static final ImmutableSet<Flavor> SUPPORTED_LIBRARY_FLAVORS =
      ImmutableSet.of(CxxDescriptionEnhancer.STATIC_FLAVOR, CxxDescriptionEnhancer.SHARED_FLAVOR);

  private final AppleBinaryDescription appleBinaryDescription;
  private final AppleLibraryDescription appleLibraryDescription;
  private final FlavorDomain<CxxPlatform> cxxPlatformFlavorDomain;
  private final ImmutableMap<Flavor, AppleCxxPlatform> platformFlavorsToAppleCxxPlatforms;
  private final CxxPlatform defaultCxxPlatform;
  private final CodeSignIdentityStore codeSignIdentityStore;
  private final ProvisioningProfileStore provisioningProfileStore;

  public AppleBundleDescription(
      AppleBinaryDescription appleBinaryDescription,
      AppleLibraryDescription appleLibraryDescription,
      FlavorDomain<CxxPlatform> cxxPlatformFlavorDomain,
      Map<Flavor, AppleCxxPlatform> platformFlavorsToAppleCxxPlatforms,
      CxxPlatform defaultCxxPlatform,
      CodeSignIdentityStore codeSignIdentityStore,
      ProvisioningProfileStore provisioningProfileStore) {
    this.appleBinaryDescription = appleBinaryDescription;
    this.appleLibraryDescription = appleLibraryDescription;
    this.cxxPlatformFlavorDomain = cxxPlatformFlavorDomain;
    this.platformFlavorsToAppleCxxPlatforms =
        ImmutableMap.copyOf(platformFlavorsToAppleCxxPlatforms);
    this.defaultCxxPlatform = defaultCxxPlatform;
    this.codeSignIdentityStore = codeSignIdentityStore;
    this.provisioningProfileStore = provisioningProfileStore;
  }

  @Override
  public BuildRuleType getBuildRuleType() {
    return TYPE;
  }

  @Override
  public Arg createUnpopulatedConstructorArg() {
    return new Arg();
  }

  @Override
  public boolean hasFlavors(final ImmutableSet<Flavor> flavors) {
    if (appleLibraryDescription.hasFlavors(flavors)) {
      return true;
    }
    ImmutableSet.Builder<Flavor> flavorBuilder = ImmutableSet.builder();
    for (Flavor flavor : flavors) {
      if (flavor.equals(ReactNativeFlavors.DO_NOT_BUNDLE)) {
        continue;
      }
      flavorBuilder.add(flavor);
    }
    return appleBinaryDescription.hasFlavors(flavorBuilder.build());
  }

  /** Only works with thin binaries. */
  private CxxPlatform getCxxPlatformForBuildTarget(BuildTarget target) {
    CxxPlatform cxxPlatform;
    try {
      cxxPlatform = cxxPlatformFlavorDomain.getValue(target.getFlavors()).or(defaultCxxPlatform);
    } catch (FlavorDomainException e) {
      throw new HumanReadableException(e, "%s: %s", target, e.getMessage());
    }

    return cxxPlatform;
  }

  private AppleCxxPlatform getAppleCxxPlatformForBuildTarget(BuildTarget target) {
    Optional<FatBinaryInfo> fatBinaryInfo =
        FatBinaryInfo.create(platformFlavorsToAppleCxxPlatforms, target);
    AppleCxxPlatform appleCxxPlatform;
    if (fatBinaryInfo.isPresent()) {
      appleCxxPlatform = fatBinaryInfo.get().getRepresentativePlatform();
    } else {
      CxxPlatform cxxPlatform = getCxxPlatformForBuildTarget(target);
      appleCxxPlatform = platformFlavorsToAppleCxxPlatforms.get(cxxPlatform.getFlavor());
      if (appleCxxPlatform == null) {
        throw new HumanReadableException(
            "%s: Apple bundle requires an Apple platform, found '%s'",
            target, cxxPlatform.getFlavor().getName());
      }
    }

    return appleCxxPlatform;
  }

  @Override
  public <A extends Arg> AppleBundle createBuildRule(
      TargetGraph targetGraph, BuildRuleParams params, BuildRuleResolver resolver, A args) {
    AppleCxxPlatform appleCxxPlatform = getAppleCxxPlatformForBuildTarget(params.getBuildTarget());
    AppleBundleDestinations destinations =
        AppleBundleDestinations.platformDestinations(
            appleCxxPlatform.getAppleSdk().getApplePlatform());

    ImmutableSet.Builder<SourcePath> bundleDirsBuilder = ImmutableSet.builder();
    ImmutableSet.Builder<SourcePath> dirsContainingResourceDirsBuilder = ImmutableSet.builder();
    ImmutableSet.Builder<SourcePath> bundleFilesBuilder = ImmutableSet.builder();
    ImmutableSet.Builder<SourcePath> bundleVariantFilesBuilder = ImmutableSet.builder();
    AppleResources.collectResourceDirsAndFiles(
        targetGraph,
        Preconditions.checkNotNull(targetGraph.get(params.getBuildTarget())),
        bundleDirsBuilder,
        dirsContainingResourceDirsBuilder,
        bundleFilesBuilder,
        bundleVariantFilesBuilder);
    ImmutableSet<SourcePath> bundleDirs = bundleDirsBuilder.build();
    ImmutableSet<SourcePath> dirsContainingResourceDirs = dirsContainingResourceDirsBuilder.build();
    ImmutableSet<SourcePath> bundleFiles = bundleFilesBuilder.build();
    ImmutableSet<SourcePath> bundleVariantFiles = bundleVariantFilesBuilder.build();

    SourcePathResolver sourcePathResolver = new SourcePathResolver(resolver);

    Optional<AppleAssetCatalog> assetCatalog =
        AppleDescriptions.createBuildRuleForTransitiveAssetCatalogDependencies(
            targetGraph,
            params,
            sourcePathResolver,
            appleCxxPlatform.getAppleSdk().getApplePlatform(),
            appleCxxPlatform.getActool());

    // TODO(user): Sort through the changes needed to make project generation work with
    // binary being optional.
    BuildRule flavoredBinaryRule = getFlavoredBinaryRule(targetGraph, params, resolver, args);
    BuildRuleParams bundleParamsWithFlavoredBinaryDep =
        getBundleParamsWithUpdatedDeps(
            params,
            args.binary,
            ImmutableSet.<BuildRule>builder()
                .add(flavoredBinaryRule)
                .addAll(assetCatalog.asSet())
                .addAll(
                    BuildRules.toBuildRulesFor(
                        params.getBuildTarget(),
                        resolver,
                        SourcePaths.filterBuildTargetSourcePaths(
                            Iterables.concat(
                                bundleFiles,
                                bundleDirs,
                                dirsContainingResourceDirs,
                                bundleVariantFiles))))
                .build());

    ImmutableMap<SourcePath, String> extensionBundlePaths =
        collectFirstLevelAppleDependencyBundles(params.getDeps(), destinations);

    return new AppleBundle(
        bundleParamsWithFlavoredBinaryDep,
        sourcePathResolver,
        args.extension,
        args.productName,
        args.infoPlist,
        args.infoPlistSubstitutions.get(),
        Optional.of(flavoredBinaryRule),
        destinations,
        bundleDirs,
        bundleFiles,
        dirsContainingResourceDirs,
        extensionBundlePaths,
        Optional.of(bundleVariantFiles),
        appleCxxPlatform.getIbtool(),
        appleCxxPlatform.getDsymutil(),
        appleCxxPlatform.getCxxPlatform().getStrip(),
        assetCatalog,
        args.getTests(),
        appleCxxPlatform.getAppleSdk(),
        codeSignIdentityStore,
        provisioningProfileStore,
        AppleBundle.DebugInfoFormat.DSYM);
  }

  private <A extends Arg> BuildRule getFlavoredBinaryRule(
      TargetGraph targetGraph,
      final BuildRuleParams params,
      final BuildRuleResolver resolver,
      A args) {
    // Cxx targets must have one Platform Flavor set otherwise nothing gets compiled.
    ImmutableSet<Flavor> flavors =
        params
            .getBuildTarget()
            .withoutFlavors(ImmutableSet.of(ReactNativeFlavors.DO_NOT_BUNDLE))
            .getFlavors();
    if (!cxxPlatformFlavorDomain.containsAnyOf(flavors)) {
      flavors =
          new ImmutableSet.Builder<Flavor>()
              .addAll(flavors)
              .add(defaultCxxPlatform.getFlavor())
              .build();
    }

    final TargetNode<?> binaryTargetNode = Preconditions.checkNotNull(targetGraph.get(args.binary));
    // If the binary target of the AppleBundle is an AppleLibrary then the build flavor
    // must be specified.
    if (binaryTargetNode.getDescription() instanceof AppleLibraryDescription
        && (Sets.intersection(
                    SUPPORTED_LIBRARY_FLAVORS, binaryTargetNode.getBuildTarget().getFlavors())
                .size()
            != 1)) {
      throw new HumanReadableException(
          "AppleExtension bundle [%s] must have exactly one of these flavors: [%s].",
          binaryTargetNode.getBuildTarget().toString(),
          Joiner.on(", ").join(SUPPORTED_LIBRARY_FLAVORS));
    }

    BuildRuleParams binaryRuleParams =
        new BuildRuleParams(
            args.binary,
            Suppliers.ofInstance(
                BuildRules.toBuildRulesFor(
                    params.getBuildTarget(), resolver, binaryTargetNode.getDeclaredDeps())),
            Suppliers.ofInstance(
                BuildRules.toBuildRulesFor(
                    params.getBuildTarget(), resolver, binaryTargetNode.getExtraDeps())),
            params.getProjectFilesystem(),
            params.getCellRoots(),
            params.getRuleKeyBuilderFactory());

    return CxxDescriptionEnhancer.requireBuildRule(
        targetGraph, binaryRuleParams, resolver, flavors.toArray(new Flavor[0]));
  }

  private static BuildRuleParams getBundleParamsWithUpdatedDeps(
      final BuildRuleParams params,
      final BuildTarget originalBinaryTarget,
      final Set<BuildRule> newDeps) {
    // Remove the unflavored binary rule and add the flavored one instead.
    final Predicate<BuildRule> notOriginalBinaryRule =
        Predicates.not(BuildRules.isBuildRuleWithTarget(originalBinaryTarget));
    return params.copyWithDeps(
        Suppliers.ofInstance(
            FluentIterable.from(params.getDeclaredDeps().get())
                .filter(notOriginalBinaryRule)
                .append(newDeps)
                .toSortedSet(Ordering.natural())),
        Suppliers.ofInstance(
            FluentIterable.from(params.getExtraDeps().get())
                .filter(notOriginalBinaryRule)
                .toSortedSet(Ordering.natural())));
  }

  private ImmutableMap<SourcePath, String> collectFirstLevelAppleDependencyBundles(
      ImmutableSortedSet<BuildRule> deps, AppleBundleDestinations destinations) {
    ImmutableMap.Builder<SourcePath, String> extensionBundlePaths = ImmutableMap.builder();
    // We only care about the direct layer of dependencies. ExtensionBundles inside ExtensionBundles
    // do not get pulled in to the top-level Bundle.
    for (BuildRule rule : deps) {
      if (rule instanceof AppleBundle) {
        AppleBundle appleBundle = (AppleBundle) rule;
        if (AppleBundleExtension.APPEX.toFileExtension().equals(appleBundle.getExtension())
            || AppleBundleExtension.APP.toFileExtension().equals(appleBundle.getExtension())) {
          Path outputPath =
              Preconditions.checkNotNull(
                  appleBundle.getPathToOutput(),
                  "Path cannot be null for AppleBundle [%s].",
                  appleBundle);
          SourcePath sourcePath =
              new BuildTargetSourcePath(appleBundle.getBuildTarget(), outputPath);

          Path destinationPath;

          String platformName = appleBundle.getPlatformName();

          if ((platformName.equals(ApplePlatform.Name.WATCHOS)
                  || platformName.equals(ApplePlatform.Name.WATCHSIMULATOR))
              && appleBundle.getExtension().equals(AppleBundleExtension.APP.toFileExtension())) {
            destinationPath = destinations.getWatchAppPath();
          } else {
            destinationPath = destinations.getPlugInsPath();
          }

          extensionBundlePaths.put(sourcePath, destinationPath.toString());
        }
      }
    }

    return extensionBundlePaths.build();
  }

  /** Propagate the bundle's platform flavors to its dependents. */
  @Override
  public ImmutableSet<BuildTarget> findDepsForTargetFromConstructorArgs(
      BuildTarget buildTarget,
      Function<Optional<String>, Path> cellRoots,
      AppleBundleDescription.Arg constructorArg) {
    if (!constructorArg.deps.isPresent()) {
      return ImmutableSet.of();
    }

    if (!cxxPlatformFlavorDomain.containsAnyOf(buildTarget.getFlavors())) {
      buildTarget =
          BuildTarget.builder(buildTarget)
              .addAllFlavors(ImmutableSet.of(defaultCxxPlatform.getFlavor()))
              .build();
    }

    Optional<FatBinaryInfo> fatBinaryInfo =
        FatBinaryInfo.create(platformFlavorsToAppleCxxPlatforms, buildTarget);
    CxxPlatform cxxPlatform;
    if (fatBinaryInfo.isPresent()) {
      AppleCxxPlatform appleCxxPlatform = fatBinaryInfo.get().getRepresentativePlatform();
      cxxPlatform = appleCxxPlatform.getCxxPlatform();
    } else {
      cxxPlatform = getCxxPlatformForBuildTarget(buildTarget);
    }

    String platformName = cxxPlatform.getFlavor().getName();
    final Flavor actualWatchFlavor;
    if (ApplePlatform.isSimulator(platformName)) {
      actualWatchFlavor = ImmutableFlavor.builder().name("watchsimulator-i386").build();
    } else if (platformName.startsWith(ApplePlatform.Name.IPHONEOS)
        || platformName.startsWith(ApplePlatform.Name.WATCHOS)) {
      actualWatchFlavor = ImmutableFlavor.builder().name("watchos-armv7k").build();
    } else {
      actualWatchFlavor = ImmutableFlavor.builder().name(platformName).build();
    }

    FluentIterable<BuildTarget> depsExcludingBinary =
        FluentIterable.from(constructorArg.deps.get())
            .filter(Predicates.not(Predicates.equalTo(constructorArg.binary)));

    FluentIterable<BuildTarget> targetsWithPlatformFlavors =
        depsExcludingBinary.filter(BuildTargets.containsFlavors(cxxPlatformFlavorDomain));

    FluentIterable<BuildTarget> targetsWithoutPlatformFlavors =
        depsExcludingBinary.filter(
            Predicates.not(BuildTargets.containsFlavors(cxxPlatformFlavorDomain)));

    FluentIterable<BuildTarget> watchTargets =
        targetsWithoutPlatformFlavors
            .filter(BuildTargets.containsFlavor(WATCH))
            .transform(
                new Function<BuildTarget, BuildTarget>() {
                  @Override
                  public BuildTarget apply(BuildTarget input) {
                    return BuildTarget.builder(input.withoutFlavors(ImmutableSet.of(WATCH)))
                        .addFlavors(actualWatchFlavor)
                        .build();
                  }
                });

    targetsWithoutPlatformFlavors =
        targetsWithoutPlatformFlavors.filter(Predicates.not(BuildTargets.containsFlavor(WATCH)));

    return ImmutableSet.<BuildTarget>builder()
        .addAll(targetsWithPlatformFlavors)
        .addAll(watchTargets)
        .addAll(
            BuildTargets.propagateFlavorDomains(
                buildTarget,
                ImmutableSet.<FlavorDomain<?>>of(cxxPlatformFlavorDomain),
                targetsWithoutPlatformFlavors))
        .build();
  }

  @SuppressFieldNotInitialized
  public static class Arg implements HasAppleBundleFields, HasTests {
    public Either<AppleBundleExtension, String> extension;
    public BuildTarget binary;
    public SourcePath infoPlist;
    public Optional<ImmutableMap<String, String>> infoPlistSubstitutions;

    @Hint(isDep = false)
    public Optional<ImmutableSortedSet<BuildTarget>> deps;

    @Hint(isDep = false)
    public Optional<ImmutableSortedSet<BuildTarget>> tests;

    public Optional<String> xcodeProductType;
    public Optional<String> productName;

    @Override
    public Either<AppleBundleExtension, String> getExtension() {
      return extension;
    }

    @Override
    public SourcePath getInfoPlist() {
      return infoPlist;
    }

    @Override
    public ImmutableSortedSet<BuildTarget> getTests() {
      return tests.get();
    }

    @Override
    public Optional<String> getXcodeProductType() {
      return xcodeProductType;
    }
  }
}
Example #26
0
 @Override
 public BuildRuleType getBuildRuleType() {
   return BuildRuleType.of("fake_rule");
 }