Example usage for com.google.common.collect ImmutableMultimap keySet

List of usage examples for com.google.common.collect ImmutableMultimap keySet

Introduction

In this page you can find the example usage for com.google.common.collect ImmutableMultimap keySet.

Prototype

@Override
public ImmutableSet<K> keySet() 

Source Link

Document

Returns an immutable set of the distinct keys in this multimap, in the same order as they appear in this multimap.

Usage

From source file:com.facebook.buck.apple.project_generator.WorkspaceAndProjectGenerator.java

private void generateProject(final Map<Path, ProjectGenerator> projectGenerators,
        ListeningExecutorService listeningExecutorService, WorkspaceGenerator workspaceGenerator,
        ImmutableSet<BuildTarget> targetsInRequiredProjects,
        ImmutableMultimap.Builder<BuildTarget, PBXTarget> buildTargetToPbxTargetMapBuilder,
        ImmutableMap.Builder<PBXTarget, Path> targetToProjectPathMapBuilder,
        final Optional<BuildTarget> targetToBuildWithBuck) throws IOException, InterruptedException {
    ImmutableMultimap.Builder<Cell, BuildTarget> projectCellToBuildTargetsBuilder = ImmutableMultimap.builder();
    for (TargetNode<?, ?> targetNode : projectGraph.getNodes()) {
        BuildTarget buildTarget = targetNode.getBuildTarget();
        projectCellToBuildTargetsBuilder.put(rootCell.getCell(buildTarget), buildTarget);
    }//w w  w  .j a  va2  s . c  o m
    ImmutableMultimap<Cell, BuildTarget> projectCellToBuildTargets = projectCellToBuildTargetsBuilder.build();
    List<ListenableFuture<GenerationResult>> projectGeneratorFutures = new ArrayList<>();
    for (final Cell projectCell : projectCellToBuildTargets.keySet()) {
        ImmutableMultimap.Builder<Path, BuildTarget> projectDirectoryToBuildTargetsBuilder = ImmutableMultimap
                .builder();
        final ImmutableSet<BuildTarget> cellRules = ImmutableSet
                .copyOf(projectCellToBuildTargets.get(projectCell));
        for (BuildTarget buildTarget : cellRules) {
            projectDirectoryToBuildTargetsBuilder.put(buildTarget.getBasePath(), buildTarget);
        }
        ImmutableMultimap<Path, BuildTarget> projectDirectoryToBuildTargets = projectDirectoryToBuildTargetsBuilder
                .build();
        final Path relativeTargetCell = rootCell.getRoot().relativize(projectCell.getRoot());
        for (final Path projectDirectory : projectDirectoryToBuildTargets.keySet()) {
            final ImmutableSet<BuildTarget> rules = filterRulesForProjectDirectory(projectGraph,
                    ImmutableSet.copyOf(projectDirectoryToBuildTargets.get(projectDirectory)));
            if (Sets.intersection(targetsInRequiredProjects, rules).isEmpty()) {
                continue;
            }

            projectGeneratorFutures.add(listeningExecutorService.submit(() -> {
                GenerationResult result = generateProjectForDirectory(projectGenerators, targetToBuildWithBuck,
                        projectCell, projectDirectory, rules);
                // convert the projectPath to relative to the target cell here
                result = GenerationResult.of(relativeTargetCell.resolve(result.getProjectPath()),
                        result.isProjectGenerated(), result.getRequiredBuildTargets(),
                        result.getBuildTargetToGeneratedTargetMap());
                return result;
            }));
        }
    }

    List<GenerationResult> generationResults;
    try {
        generationResults = Futures.allAsList(projectGeneratorFutures).get();
    } catch (ExecutionException e) {
        Throwables.propagateIfInstanceOf(e.getCause(), IOException.class);
        Throwables.propagateIfPossible(e.getCause());
        throw new IllegalStateException("Unexpected exception: ", e);
    }
    for (GenerationResult result : generationResults) {
        if (!result.isProjectGenerated()) {
            continue;
        }
        workspaceGenerator.addFilePath(result.getProjectPath());
        processGenerationResult(buildTargetToPbxTargetMapBuilder, targetToProjectPathMapBuilder, result);
    }
}

From source file:com.facebook.buck.apple.WorkspaceAndProjectGenerator.java

public Path generateWorkspaceAndDependentProjects(Map<Path, ProjectGenerator> projectGenerators)
        throws IOException {
    LOG.debug("Generating workspace for target %s", workspaceBuildTarget);

    String workspaceName = XcodeWorkspaceConfigDescription.getWorkspaceNameFromArg(workspaceArguments);
    Path outputDirectory;/*from   w ww.  j av  a2 s .  c  o m*/
    if (combinedProject) {
        workspaceName += "-Combined";
        outputDirectory = BuildTargets.getGenPath(workspaceBuildTarget, "%s").getParent()
                .resolve(workspaceName + ".xcodeproj");
    } else {
        outputDirectory = workspaceBuildTarget.getBasePath();
    }

    WorkspaceGenerator workspaceGenerator = new WorkspaceGenerator(projectFilesystem,
            combinedProject ? "project" : workspaceName, outputDirectory);

    ImmutableMap.Builder<String, XcodeWorkspaceConfigDescription.Arg> schemeConfigsBuilder = ImmutableMap
            .builder();
    ImmutableSetMultimap.Builder<String, Optional<TargetNode<?>>> schemeNameToSrcTargetNodeBuilder = ImmutableSetMultimap
            .builder();
    ImmutableSetMultimap.Builder<String, TargetNode<?>> buildForTestNodesBuilder = ImmutableSetMultimap
            .builder();
    ImmutableMultimap.Builder<AppleTestBundleParamsKey, TargetNode<AppleTestDescription.Arg>> groupedTestsBuilder = ImmutableMultimap
            .builder();
    ImmutableSetMultimap.Builder<String, TargetNode<AppleTestDescription.Arg>> ungroupedTestsBuilder = ImmutableSetMultimap
            .builder();

    buildWorkspaceSchemes(getTargetToBuildWithBuck(), projectGraph,
            projectGeneratorOptions.contains(ProjectGenerator.Option.INCLUDE_TESTS),
            projectGeneratorOptions.contains(ProjectGenerator.Option.INCLUDE_DEPENDENCIES_TESTS),
            groupableTests, workspaceName, workspaceArguments, schemeConfigsBuilder,
            schemeNameToSrcTargetNodeBuilder, buildForTestNodesBuilder, groupedTestsBuilder,
            ungroupedTestsBuilder);

    ImmutableMap<String, XcodeWorkspaceConfigDescription.Arg> schemeConfigs = schemeConfigsBuilder.build();
    ImmutableSetMultimap<String, Optional<TargetNode<?>>> schemeNameToSrcTargetNode = schemeNameToSrcTargetNodeBuilder
            .build();
    ImmutableSetMultimap<String, TargetNode<?>> buildForTestNodes = buildForTestNodesBuilder.build();
    ImmutableMultimap<AppleTestBundleParamsKey, TargetNode<AppleTestDescription.Arg>> groupedTests = groupedTestsBuilder
            .build();
    ImmutableSetMultimap<String, TargetNode<AppleTestDescription.Arg>> ungroupedTests = ungroupedTestsBuilder
            .build();
    Iterable<PBXTarget> synthesizedCombinedTestTargets = ImmutableList.of();

    ImmutableSet<BuildTarget> targetsInRequiredProjects = FluentIterable
            .from(Optional.presentInstances(schemeNameToSrcTargetNode.values()))
            .append(buildForTestNodes.values()).transform(HasBuildTarget.TO_TARGET).toSet();
    ImmutableMultimap.Builder<BuildTarget, PBXTarget> buildTargetToPbxTargetMapBuilder = ImmutableMultimap
            .builder();
    ImmutableMap.Builder<PBXTarget, Path> targetToProjectPathMapBuilder = ImmutableMap.builder();
    Optional<BuildTarget> targetToBuildWithBuck = getTargetToBuildWithBuck();

    if (combinedProject) {
        LOG.debug("Generating a combined project");
        ProjectGenerator generator = new ProjectGenerator(projectGraph, targetsInRequiredProjects,
                projectFilesystem, outputDirectory.getParent(), workspaceName, buildFileName,
                projectGeneratorOptions, targetToBuildWithBuck, buildWithBuckFlags, executableFinder,
                environment, cxxPlatforms, defaultCxxPlatform, sourcePathResolverForNode, buckEventBus,
                attemptToDetermineBestCxxPlatform, halideBuckConfig, cxxBuckConfig)
                        .setAdditionalCombinedTestTargets(groupedTests)
                        .setTestsToGenerateAsStaticLibraries(groupableTests);
        combinedProjectGenerator = Optional.of(generator);
        generator.createXcodeProjects();

        workspaceGenerator.addFilePath(generator.getProjectPath(), Optional.<Path>absent());
        requiredBuildTargetsBuilder.addAll(generator.getRequiredBuildTargets());

        buildTargetToPbxTargetMapBuilder.putAll(generator.getBuildTargetToGeneratedTargetMap());
        for (PBXTarget target : generator.getBuildTargetToGeneratedTargetMap().values()) {
            targetToProjectPathMapBuilder.put(target, generator.getProjectPath());
        }
        synthesizedCombinedTestTargets = generator.getBuildableCombinedTestTargets();
        for (PBXTarget target : synthesizedCombinedTestTargets) {
            targetToProjectPathMapBuilder.put(target, generator.getProjectPath());
        }
    } else {
        ImmutableMultimap.Builder<Path, BuildTarget> projectDirectoryToBuildTargetsBuilder = ImmutableMultimap
                .builder();
        for (TargetNode<?> targetNode : projectGraph.getNodes()) {
            BuildTarget buildTarget = targetNode.getBuildTarget();
            projectDirectoryToBuildTargetsBuilder.put(buildTarget.getBasePath(), buildTarget);
        }
        ImmutableMultimap<Path, BuildTarget> projectDirectoryToBuildTargets = projectDirectoryToBuildTargetsBuilder
                .build();
        for (Path projectDirectory : projectDirectoryToBuildTargets.keySet()) {
            final ImmutableSet<BuildTarget> rules = filterRulesForProjectDirectory(projectGraph,
                    ImmutableSet.copyOf(projectDirectoryToBuildTargets.get(projectDirectory)));
            if (Sets.intersection(targetsInRequiredProjects, rules).isEmpty()) {
                continue;
            }

            ProjectGenerator generator = projectGenerators.get(projectDirectory);
            if (generator == null) {
                LOG.debug("Generating project for directory %s with targets %s", projectDirectory, rules);
                String projectName;
                if (projectDirectory.getNameCount() == 0) {
                    // If we're generating a project in the root directory, use a generic name.
                    projectName = "Project";
                } else {
                    // Otherwise, name the project the same thing as the directory we're in.
                    projectName = projectDirectory.getFileName().toString();
                }
                generator = new ProjectGenerator(projectGraph, rules, projectFilesystem, projectDirectory,
                        projectName, buildFileName, projectGeneratorOptions, Optionals.bind(
                                targetToBuildWithBuck, new Function<BuildTarget, Optional<BuildTarget>>() {
                                    @Override
                                    public Optional<BuildTarget> apply(BuildTarget input) {
                                        return rules.contains(input) ? Optional.of(input)
                                                : Optional.<BuildTarget>absent();
                                    }
                                }),
                        buildWithBuckFlags, executableFinder, environment, cxxPlatforms, defaultCxxPlatform,
                        sourcePathResolverForNode, buckEventBus, attemptToDetermineBestCxxPlatform,
                        halideBuckConfig, cxxBuckConfig).setTestsToGenerateAsStaticLibraries(groupableTests);

                generator.createXcodeProjects();
                requiredBuildTargetsBuilder.addAll(generator.getRequiredBuildTargets());
                projectGenerators.put(projectDirectory, generator);
            } else {
                LOG.debug("Already generated project for target %s, skipping", projectDirectory);
            }

            workspaceGenerator.addFilePath(generator.getProjectPath());

            buildTargetToPbxTargetMapBuilder.putAll(generator.getBuildTargetToGeneratedTargetMap());
            for (PBXTarget target : generator.getBuildTargetToGeneratedTargetMap().values()) {
                targetToProjectPathMapBuilder.put(target, generator.getProjectPath());
            }
        }

        if (!groupedTests.isEmpty()) {
            ProjectGenerator combinedTestsProjectGenerator = new ProjectGenerator(projectGraph,
                    ImmutableSortedSet.<BuildTarget>of(), projectFilesystem,
                    BuildTargets.getGenPath(workspaceBuildTarget, "%s-CombinedTestBundles"),
                    "_CombinedTestBundles", buildFileName, projectGeneratorOptions,
                    Optional.<BuildTarget>absent(), buildWithBuckFlags, executableFinder, environment,
                    cxxPlatforms, defaultCxxPlatform, sourcePathResolverForNode, buckEventBus,
                    attemptToDetermineBestCxxPlatform, halideBuckConfig, cxxBuckConfig);
            combinedTestsProjectGenerator.setAdditionalCombinedTestTargets(groupedTests).createXcodeProjects();
            workspaceGenerator.addFilePath(combinedTestsProjectGenerator.getProjectPath());
            requiredBuildTargetsBuilder.addAll(combinedTestsProjectGenerator.getRequiredBuildTargets());
            for (PBXTarget target : combinedTestsProjectGenerator.getBuildTargetToGeneratedTargetMap()
                    .values()) {
                targetToProjectPathMapBuilder.put(target, combinedTestsProjectGenerator.getProjectPath());
            }
            synthesizedCombinedTestTargets = combinedTestsProjectGenerator.getBuildableCombinedTestTargets();
            for (PBXTarget target : synthesizedCombinedTestTargets) {
                targetToProjectPathMapBuilder.put(target, combinedTestsProjectGenerator.getProjectPath());
            }
            this.combinedTestsProjectGenerator = Optional.of(combinedTestsProjectGenerator);
        }
    }

    Path workspacePath = workspaceGenerator.writeWorkspace();

    final Multimap<BuildTarget, PBXTarget> buildTargetToTarget = buildTargetToPbxTargetMapBuilder.build();
    final Function<BuildTarget, PBXTarget> targetNodeToPBXTargetTransformer = new Function<BuildTarget, PBXTarget>() {
        @Override
        public PBXTarget apply(BuildTarget input) {
            ImmutableList<PBXTarget> targets = ImmutableList.copyOf(buildTargetToTarget.get(input));
            if (targets.size() == 1) {
                return targets.get(0);
            }
            // The only reason why a build target would map to more than one project target is if
            // there are two project targets: one is the usual one, the other is a target that just
            // shells out to Buck.
            Preconditions.checkState(targets.size() == 2);
            PBXTarget first = targets.get(0);
            PBXTarget second = targets.get(1);
            Preconditions.checkState(first.getName().endsWith(ProjectGenerator.BUILD_WITH_BUCK_POSTFIX)
                    ^ second.getName().endsWith(ProjectGenerator.BUILD_WITH_BUCK_POSTFIX));
            PBXTarget buildWithBuckTarget;
            PBXTarget buildWithXcodeTarget;
            if (first.getName().endsWith(ProjectGenerator.BUILD_WITH_BUCK_POSTFIX)) {
                buildWithBuckTarget = first;
                buildWithXcodeTarget = second;
            } else {
                buildWithXcodeTarget = first;
                buildWithBuckTarget = second;
            }
            return buildWithBuck ? buildWithBuckTarget : buildWithXcodeTarget;
        }
    };

    writeWorkspaceSchemes(workspaceName, outputDirectory, schemeConfigs, schemeNameToSrcTargetNode,
            buildForTestNodes, ungroupedTests, targetToProjectPathMapBuilder.build(),
            synthesizedCombinedTestTargets, new Function<TargetNode<?>, Collection<PBXTarget>>() {
                @Override
                public Collection<PBXTarget> apply(TargetNode<?> input) {
                    return buildTargetToTarget.get(input.getBuildTarget());
                }
            }, targetNodeToPBXTargetTransformer);

    return workspacePath;
}

From source file:com.facebook.buck.features.apple.project.WorkspaceAndProjectGenerator.java

private void generateProject(Map<Path, ProjectGenerator> projectGenerators,
        ListeningExecutorService listeningExecutorService, WorkspaceGenerator workspaceGenerator,
        ImmutableSet<BuildTarget> targetsInRequiredProjects,
        ImmutableSetMultimap.Builder<PBXProject, PBXTarget> generatedProjectToPbxTargetsBuilder,
        ImmutableMap.Builder<BuildTarget, PBXTarget> buildTargetToPbxTargetMapBuilder,
        ImmutableMap.Builder<PBXTarget, Path> targetToProjectPathMapBuilder)
        throws IOException, InterruptedException {
    ImmutableMultimap.Builder<Cell, BuildTarget> projectCellToBuildTargetsBuilder = ImmutableMultimap.builder();
    for (TargetNode<?> targetNode : projectGraph.getNodes()) {
        BuildTarget buildTarget = targetNode.getBuildTarget();
        projectCellToBuildTargetsBuilder.put(rootCell.getCell(buildTarget), buildTarget);
    }//from   w  ww .j  av a2  s  .co m
    ImmutableMultimap<Cell, BuildTarget> projectCellToBuildTargets = projectCellToBuildTargetsBuilder.build();
    List<ListenableFuture<GenerationResult>> projectGeneratorFutures = new ArrayList<>();
    for (Cell projectCell : projectCellToBuildTargets.keySet()) {
        ImmutableMultimap.Builder<Path, BuildTarget> projectDirectoryToBuildTargetsBuilder = ImmutableMultimap
                .builder();
        ImmutableSet<BuildTarget> cellRules = ImmutableSet.copyOf(projectCellToBuildTargets.get(projectCell));
        for (BuildTarget buildTarget : cellRules) {
            projectDirectoryToBuildTargetsBuilder.put(buildTarget.getBasePath(), buildTarget);
        }
        ImmutableMultimap<Path, BuildTarget> projectDirectoryToBuildTargets = projectDirectoryToBuildTargetsBuilder
                .build();
        Path relativeTargetCell = rootCell.getRoot().relativize(projectCell.getRoot());
        for (Path projectDirectory : projectDirectoryToBuildTargets.keySet()) {
            ImmutableSet<BuildTarget> rules = filterRulesForProjectDirectory(projectGraph,
                    ImmutableSet.copyOf(projectDirectoryToBuildTargets.get(projectDirectory)));
            if (Sets.intersection(targetsInRequiredProjects, rules).isEmpty()) {
                continue;
            }

            boolean isMainProject = workspaceArguments.getSrcTarget().isPresent()
                    && rules.contains(workspaceArguments.getSrcTarget().get());
            projectGeneratorFutures.add(listeningExecutorService.submit(() -> {
                GenerationResult result = generateProjectForDirectory(projectGenerators, projectCell,
                        projectDirectory, rules, isMainProject, targetsInRequiredProjects);
                // convert the projectPath to relative to the target cell here
                result = GenerationResult.of(relativeTargetCell.resolve(result.getProjectPath()),
                        result.isProjectGenerated(), result.getRequiredBuildTargets(),
                        result.getXcconfigPaths(), result.getFilesToCopyInXcode(),
                        result.getBuildTargetToGeneratedTargetMap(), result.getGeneratedProjectToPbxTargets());
                return result;
            }));
        }
    }

    List<GenerationResult> generationResults;
    try {
        generationResults = Futures.allAsList(projectGeneratorFutures).get();
    } catch (ExecutionException e) {
        Throwables.throwIfInstanceOf(e.getCause(), IOException.class);
        Throwables.throwIfUnchecked(e.getCause());
        throw new IllegalStateException("Unexpected exception: ", e);
    }
    for (GenerationResult result : generationResults) {
        if (!result.isProjectGenerated()) {
            continue;
        }
        workspaceGenerator.addFilePath(result.getProjectPath());
        processGenerationResult(generatedProjectToPbxTargetsBuilder, buildTargetToPbxTargetMapBuilder,
                targetToProjectPathMapBuilder, result);
    }
}

From source file:com.facebook.buck.android.dalvik.DalvikAwareZipSplitter.java

private DalvikAwareZipSplitter(ProjectFilesystem filesystem, Set<Path> inFiles, Path outPrimary,
        Path outSecondaryDir, String secondaryPattern, Path outDexStoresDir, long linearAllocLimit,
        Predicate<String> requiredInPrimaryZip, Set<String> wantedInPrimaryZip,
        ImmutableSet<String> secondaryHeadSet, ImmutableSet<String> secondaryTailSet,
        ImmutableMultimap<APKModule, String> additionalDexStoreSets, APKModule rootAPKModule,
        DexSplitStrategy dexSplitStrategy, Path reportDir) {
    if (linearAllocLimit <= 0) {
        throw new HumanReadableException("linear_alloc_hard_limit must be greater than zero.");
    }//from w w w  .j a  v  a 2s  . c o  m
    this.filesystem = filesystem;
    this.inFiles = ImmutableSet.copyOf(inFiles);
    this.outPrimary = outPrimary;
    this.secondaryDexWriter = new MySecondaryDexHelper("secondary", outSecondaryDir, secondaryPattern);
    this.additionalDexWriters = new HashMap<>();
    this.requiredInPrimaryZip = requiredInPrimaryZip;
    this.wantedInPrimaryZip = ImmutableSet.copyOf(wantedInPrimaryZip);
    this.secondaryHeadSet = secondaryHeadSet;
    this.secondaryTailSet = secondaryTailSet;
    this.classPathToDexStore = additionalDexStoreSets.inverse();
    for (APKModule dexStore : additionalDexStoreSets.keySet()) {
        if (!dexStore.equals(rootAPKModule)) {
            additionalDexWriters.put(dexStore, new MySecondaryDexHelper(dexStore.getCanaryClassName(),
                    outDexStoresDir.resolve(dexStore.getName()), secondaryPattern));
        }
    }
    this.rootModule = rootAPKModule;
    this.reportDir = reportDir;
    this.dexSplitStrategy = dexSplitStrategy;
    this.linearAllocLimit = linearAllocLimit;
    this.dalvikStatsCache = new DalvikStatsCache();
}

From source file:org.prebake.service.tools.ext.JunitHtmlReportGenerator.java

static void generateHtmlReport(Map<String, ?> jsonReport, Path reportDir) throws IOException {
    // Group tests by packages so we can let users examine the results by
    // logical groupings.
    ImmutableMultimap<String, Map<?, ?>> byPackage;
    List<String> resultTypes;
    {//from   ww  w .ja va2s . c o  m
        Set<String> resultTypeSet = Sets.newHashSet();
        ImmutableList.Builder<Map<?, ?>> b = ImmutableList.builder();
        // We can't trust the jsonReport to have the same structure as the method
        // above, since a filter could arbitrarily change it.
        Object tests = jsonReport.get(ReportKey.TESTS);
        if (tests instanceof Iterable<?>) {
            for (Object testVal : (Iterable<?>) tests) {
                if (!(testVal instanceof Map<?, ?>)) {
                    continue; // If filter nulls out elements.
                }
                Map<?, ?> test = (Map<?, ?>) testVal;
                b.add(test);
                String result = getIfOfType(test, ReportKey.RESULT, String.class);
                resultTypeSet.add(result);
            }
        }
        byPackage = groupBy(b.build(), new Function<Map<?, ?>, String>() {
            public String apply(Map<?, ?> test) {
                String className = getIfOfType(test, ReportKey.CLASS_NAME, String.class);
                if (className == null) {
                    return null;
                }
                int lastDot = className.lastIndexOf('.');
                return (lastDot >= 0) ? className.substring(0, lastDot) : "";
            }
        });
        String[] resultTypeArr = resultTypeSet.toArray(NO_STRINGS);
        Arrays.sort(resultTypeArr);
        resultTypes = ImmutableList.copyOf(resultTypeArr);
    }
    Map<String, Integer> summary = Maps.newHashMap();
    ImmutableList.Builder<Html> table = ImmutableList.builder();
    // Now, call out to create the package groupings, which in turn,
    // create the class level groupings, which in turn create pages for
    // individual tests.
    // As we descend into the test tree, each recursive call updates summary
    // info.
    Path outFile = reportDir.resolve("index.html");
    mkdirs(outFile.getParent());
    String[] packageNames = byPackage.keySet().toArray(NO_STRINGS);
    Arrays.sort(packageNames);
    for (String packageName : packageNames) {
        Collection<Map<?, ?>> tests = byPackage.get(packageName);
        Map<String, Integer> itemSummary = generateHtmlReportOnePackage(packageName, tests,
                reportDir.resolve("index"), resultTypes);
        bagPutAll(itemSummary, summary);
        table.add(htmlLink("index/" + packageName + PACKAGE_FILE_SUFFIX + ".html", packageName))
                .add(htmlSpan("summary", summaryToHtml(itemSummary, resultTypes)));
    }
    writeReport(outFile, "JUnit", KEY_VAL, table.build(), summary, jsonReport, resultTypes, "index");
    OutputStream out = reportDir.resolve("junit_report.css").newOutputStream(StandardOpenOption.CREATE,
            StandardOpenOption.TRUNCATE_EXISTING);
    try {
        Resources.copy(Resources.getResource(JunitHtmlReportGenerator.class, "junit_report.css"), out);
    } finally {
        out.close();
    }
}

From source file:com.facebook.buck.apple.project_generator.ProjectGenerator.java

private PBXNativeTarget generateBinaryTarget(PBXProject project,
        Optional<? extends TargetNode<? extends HasAppleBundleFields, ?>> bundle,
        TargetNode<? extends CxxLibraryDescription.Arg, ?> targetNode, ProductType productType,
        String productOutputFormat, Optional<Path> infoPlistOptional, boolean includeFrameworks,
        ImmutableSet<AppleResourceDescription.Arg> recursiveResources,
        ImmutableSet<AppleResourceDescription.Arg> directResources,
        ImmutableSet<AppleAssetCatalogDescription.Arg> recursiveAssetCatalogs,
        ImmutableSet<AppleAssetCatalogDescription.Arg> directAssetCatalogs,
        ImmutableSet<AppleWrapperResourceArg> wrapperResources,
        Optional<Iterable<PBXBuildPhase>> copyFilesPhases,
        Optional<TargetNode<AppleBundleDescription.Arg, ?>> bundleLoaderNode) throws IOException {

    LOG.debug("Generating binary target for node %s", targetNode);

    TargetNode<?, ?> buildTargetNode = bundle.isPresent() ? bundle.get() : targetNode;
    final BuildTarget buildTarget = buildTargetNode.getBuildTarget();

    String buildTargetName = getProductNameForBuildTarget(buildTarget);
    CxxLibraryDescription.Arg arg = targetNode.getConstructorArg();
    NewNativeTargetProjectMutator mutator = new NewNativeTargetProjectMutator(pathRelativizer,
            sourcePathResolver);// w  w  w  .  j  ava  2  s  . c  o m
    ImmutableSet<SourcePath> exportedHeaders = ImmutableSet.copyOf(getHeaderSourcePaths(arg.exportedHeaders));
    ImmutableSet<SourcePath> headers = ImmutableSet.copyOf(getHeaderSourcePaths(arg.headers));
    ImmutableMap<CxxSource.Type, ImmutableList<String>> langPreprocessorFlags = targetNode
            .getConstructorArg().langPreprocessorFlags;

    mutator.setTargetName(getXcodeTargetName(buildTarget)).setProduct(productType, buildTargetName,
            Paths.get(String.format(productOutputFormat, buildTargetName)));

    boolean isFocusedOnTarget = shouldIncludeBuildTargetIntoFocusedProject(focusModules, buildTarget);
    if (isFocusedOnTarget) {
        mutator.setLangPreprocessorFlags(langPreprocessorFlags).setPublicHeaders(exportedHeaders)
                .setPrefixHeader(arg.prefixHeader).setSourcesWithFlags(ImmutableSet.copyOf(arg.srcs))
                .setPrivateHeaders(headers).setRecursiveResources(recursiveResources)
                .setDirectResources(directResources).setWrapperResources(wrapperResources);
    }

    if (bundle.isPresent() && isFocusedOnTarget) {
        HasAppleBundleFields bundleArg = bundle.get().getConstructorArg();
        mutator.setInfoPlist(Optional.of(bundleArg.getInfoPlist()));
    }

    mutator.setBridgingHeader(arg.bridgingHeader);

    Optional<TargetNode<AppleNativeTargetDescriptionArg, ?>> appleTargetNode = targetNode
            .castArg(AppleNativeTargetDescriptionArg.class);
    if (appleTargetNode.isPresent() && isFocusedOnTarget) {
        AppleNativeTargetDescriptionArg appleArg = appleTargetNode.get().getConstructorArg();
        mutator = mutator.setExtraXcodeSources(ImmutableSet.copyOf(appleArg.extraXcodeSources));
    }

    if (options.contains(Option.CREATE_DIRECTORY_STRUCTURE) && isFocusedOnTarget) {
        mutator.setTargetGroupPath(StreamSupport.stream(buildTarget.getBasePath().spliterator(), false)
                .map(Object::toString).collect(MoreCollectors.toImmutableList()));
    }

    if (!recursiveAssetCatalogs.isEmpty() && isFocusedOnTarget) {
        mutator.setRecursiveAssetCatalogs(recursiveAssetCatalogs);
    }

    if (!directAssetCatalogs.isEmpty() && isFocusedOnTarget) {
        mutator.setDirectAssetCatalogs(directAssetCatalogs);
    }

    if (includeFrameworks && isFocusedOnTarget) {
        ImmutableSet.Builder<FrameworkPath> frameworksBuilder = ImmutableSet.builder();
        frameworksBuilder.addAll(targetNode.getConstructorArg().frameworks);
        frameworksBuilder.addAll(targetNode.getConstructorArg().libraries);
        frameworksBuilder.addAll(collectRecursiveFrameworkDependencies(ImmutableList.of(targetNode)));
        mutator.setFrameworks(frameworksBuilder.build());

        mutator.setArchives(collectRecursiveLibraryDependencies(ImmutableList.of(targetNode)));
    }

    // TODO(Task #3772930): Go through all dependencies of the rule
    // and add any shell script rules here
    ImmutableList.Builder<TargetNode<?, ?>> preScriptPhases = ImmutableList.builder();
    ImmutableList.Builder<TargetNode<?, ?>> postScriptPhases = ImmutableList.builder();
    if (bundle.isPresent() && targetNode != bundle.get() && isFocusedOnTarget) {
        collectBuildScriptDependencies(targetGraph.getAll(bundle.get().getDeclaredDeps()), preScriptPhases,
                postScriptPhases);
    }
    collectBuildScriptDependencies(targetGraph.getAll(targetNode.getDeclaredDeps()), preScriptPhases,
            postScriptPhases);
    if (isFocusedOnTarget) {
        mutator.setPreBuildRunScriptPhasesFromTargetNodes(preScriptPhases.build());
        if (copyFilesPhases.isPresent()) {
            mutator.setCopyFilesPhases(copyFilesPhases.get());
        }
        mutator.setPostBuildRunScriptPhasesFromTargetNodes(postScriptPhases.build());
    }

    NewNativeTargetProjectMutator.Result targetBuilderResult;
    targetBuilderResult = mutator.buildTargetAndAddToProject(project, isFocusedOnTarget);
    Optional<PBXGroup> targetGroup = targetBuilderResult.targetGroup;

    if (isFocusedOnTarget) {
        SourceTreePath buckFilePath = new SourceTreePath(PBXReference.SourceTree.SOURCE_ROOT,
                pathRelativizer.outputPathToBuildTargetPath(buildTarget).resolve(buildFileName),
                Optional.empty());
        PBXFileReference buckReference = targetGroup.get()
                .getOrCreateFileReferenceBySourceTreePath(buckFilePath);
        buckReference.setExplicitFileType(Optional.of("text.script.python"));
    }

    // -- configurations
    ImmutableMap.Builder<String, String> extraSettingsBuilder = ImmutableMap.builder();
    extraSettingsBuilder.put("TARGET_NAME", buildTargetName).put("SRCROOT",
            pathRelativizer.outputPathToBuildTargetPath(buildTarget).toString());
    if (productType == ProductType.UI_TEST && isFocusedOnTarget) {
        if (bundleLoaderNode.isPresent()) {
            BuildTarget testTarget = bundleLoaderNode.get().getBuildTarget();
            extraSettingsBuilder.put("TEST_TARGET_NAME", getXcodeTargetName(testTarget));
        } else {
            throw new HumanReadableException(
                    "The test rule '%s' is configured with 'is_ui_test' but has no test_host_app",
                    buildTargetName);
        }
    } else if (bundleLoaderNode.isPresent() && isFocusedOnTarget) {
        TargetNode<AppleBundleDescription.Arg, ?> bundleLoader = bundleLoaderNode.get();
        String bundleLoaderProductName = getProductNameForBuildTarget(bundleLoader.getBuildTarget());
        String bundleLoaderBundleName = bundleLoaderProductName + "."
                + getExtensionString(bundleLoader.getConstructorArg().getExtension());
        // NOTE(grp): This is a hack. We need to support both deep (OS X) and flat (iOS)
        // style bundles for the bundle loader, but at this point we don't know what platform
        // the bundle loader (or current target) is going to be built for. However, we can be
        // sure that it's the same as the target (presumably a test) we're building right now.
        //
        // Using that knowledge, we can do build setting tricks to defer choosing the bundle
        // loader path until Xcode build time, when the platform is known. There's no build
        // setting that conclusively says whether the current platform uses deep bundles:
        // that would be too easy. But in the cases we care about (unit test bundles), the
        // current bundle will have a style matching the style of the bundle loader app, so
        // we can take advantage of that to do the determination.
        //
        // Unfortunately, the build setting for the bundle structure (CONTENTS_FOLDER_PATH)
        // includes the WRAPPER_NAME, so we can't just interpolate that in. Instead, we have
        // to use another trick with build setting operations and evaluation. By using the
        // $(:file) operation, we can extract the last component of the contents path: either
        // "Contents" or the current bundle name. Then, we can interpolate with that expected
        // result in the build setting name to conditionally choose a different loader path.

        // The conditional that decdies which path is used. This is a complex Xcode build setting
        // expression that expands to one of two values, depending on the last path component of
        // the CONTENTS_FOLDER_PATH variable. As described above, this will be either "Contents"
        // for deep bundles or the bundle file name itself for flat bundles. Finally, to santiize
        // the potentially invalid build setting names from the bundle file name, it converts that
        // to an identifier. We rely on BUNDLE_LOADER_BUNDLE_STYLE_CONDITIONAL_<bundle file name>
        // being undefined (and thus expanding to nothing) for the path resolution to work.
        //
        // The operations on the CONTENTS_FOLDER_PATH are documented here:
        // http://codeworkshop.net/posts/xcode-build-setting-transformations
        String bundleLoaderOutputPathConditional = "$(BUNDLE_LOADER_BUNDLE_STYLE_CONDITIONAL_$(CONTENTS_FOLDER_PATH:file:identifier))";

        // If the $(CONTENTS_FOLDER_PATH:file:identifier) expands to this, we add the deep bundle
        // path into the bundle loader. See above for the case when it will expand to this value.
        String bundleLoaderOutputPathDeepSetting = "BUNDLE_LOADER_BUNDLE_STYLE_CONDITIONAL_Contents";
        String bundleLoaderOutputPathDeepValue = "Contents/MacOS/";

        String bundleLoaderOutputPathValue = Joiner.on('/').join(getTargetOutputPath(bundleLoader),
                bundleLoaderBundleName, bundleLoaderOutputPathConditional, bundleLoaderProductName);

        extraSettingsBuilder.put(bundleLoaderOutputPathDeepSetting, bundleLoaderOutputPathDeepValue)
                .put("BUNDLE_LOADER", bundleLoaderOutputPathValue).put("TEST_HOST", "$(BUNDLE_LOADER)");
    }
    if (infoPlistOptional.isPresent()) {
        Path infoPlistPath = pathRelativizer.outputDirToRootRelative(infoPlistOptional.get());
        extraSettingsBuilder.put("INFOPLIST_FILE", infoPlistPath.toString());
    }
    if (arg.bridgingHeader.isPresent()) {
        Path bridgingHeaderPath = pathRelativizer
                .outputDirToRootRelative(sourcePathResolver.apply(arg.bridgingHeader.get()));
        extraSettingsBuilder.put("SWIFT_OBJC_BRIDGING_HEADER",
                Joiner.on('/').join("$(SRCROOT)", bridgingHeaderPath.toString()));
    }
    Optional<String> swiftVersion = swiftBuckConfig.getVersion();
    if (swiftVersion.isPresent()) {
        extraSettingsBuilder.put("SWIFT_VERSION", swiftVersion.get());
    }
    Optional<SourcePath> prefixHeaderOptional = targetNode.getConstructorArg().prefixHeader;
    if (prefixHeaderOptional.isPresent()) {
        Path prefixHeaderRelative = sourcePathResolver.apply(prefixHeaderOptional.get());
        Path prefixHeaderPath = pathRelativizer.outputDirToRootRelative(prefixHeaderRelative);
        extraSettingsBuilder.put("GCC_PREFIX_HEADER", prefixHeaderPath.toString());
        extraSettingsBuilder.put("GCC_PRECOMPILE_PREFIX_HEADER", "YES");
    }
    extraSettingsBuilder.put("USE_HEADERMAP", "NO");

    ImmutableMap.Builder<String, String> defaultSettingsBuilder = ImmutableMap.builder();
    defaultSettingsBuilder.put("REPO_ROOT",
            projectFilesystem.getRootPath().toAbsolutePath().normalize().toString());
    defaultSettingsBuilder.put(PRODUCT_NAME, getProductName(buildTargetNode, buildTarget));
    if (bundle.isPresent()) {
        defaultSettingsBuilder.put("WRAPPER_EXTENSION",
                getExtensionString(bundle.get().getConstructorArg().getExtension()));
    }

    // We use BUILT_PRODUCTS_DIR as the root for the everything being built. Target-
    // specific output is placed within CONFIGURATION_BUILD_DIR, inside BUILT_PRODUCTS_DIR.
    // That allows Copy Files build phases to reference files in the CONFIGURATION_BUILD_DIR
    // of other targets by using paths relative to the target-independent BUILT_PRODUCTS_DIR.
    defaultSettingsBuilder.put("BUILT_PRODUCTS_DIR",
            // $EFFECTIVE_PLATFORM_NAME starts with a dash, so this expands to something like:
            // $SYMROOT/Debug-iphonesimulator
            Joiner.on('/').join("$SYMROOT", "$CONFIGURATION$EFFECTIVE_PLATFORM_NAME"));
    defaultSettingsBuilder.put("CONFIGURATION_BUILD_DIR", "$BUILT_PRODUCTS_DIR");
    boolean nodeIsAppleLibrary = targetNode.getDescription() instanceof AppleLibraryDescription;
    boolean nodeIsCxxLibrary = targetNode.getDescription() instanceof CxxLibraryDescription;
    if (!bundle.isPresent() && (nodeIsAppleLibrary || nodeIsCxxLibrary)) {
        defaultSettingsBuilder.put("EXECUTABLE_PREFIX", "lib");
    }

    ImmutableMap.Builder<String, String> appendConfigsBuilder = ImmutableMap.builder();

    if (isFocusedOnTarget) {
        ImmutableSet<Path> recursiveHeaderSearchPaths = collectRecursiveHeaderSearchPaths(targetNode);
        ImmutableSet<Path> headerMapBases = recursiveHeaderSearchPaths.isEmpty() ? ImmutableSet.of()
                : ImmutableSet.of(pathRelativizer
                        .outputDirToRootRelative(buildTargetNode.getFilesystem().getBuckPaths().getBuckOut()));

        appendConfigsBuilder
                .put("HEADER_SEARCH_PATHS",
                        Joiner.on(' ').join(Iterables.concat(recursiveHeaderSearchPaths, headerMapBases)))
                .put("LIBRARY_SEARCH_PATHS",
                        Joiner.on(' ').join(collectRecursiveLibrarySearchPaths(ImmutableSet.of(targetNode))))
                .put("FRAMEWORK_SEARCH_PATHS", Joiner.on(' ')
                        .join(collectRecursiveFrameworkSearchPaths(ImmutableList.of(targetNode))));

        Iterable<String> otherCFlags = Iterables.concat(cxxBuckConfig.getFlags("cflags").orElse(DEFAULT_CFLAGS),
                collectRecursiveExportedPreprocessorFlags(ImmutableList.of(targetNode)),
                targetNode.getConstructorArg().compilerFlags, targetNode.getConstructorArg().preprocessorFlags);
        Iterable<String> otherCxxFlags = Iterables.concat(
                cxxBuckConfig.getFlags("cxxflags").orElse(DEFAULT_CXXFLAGS),
                collectRecursiveExportedPreprocessorFlags(ImmutableList.of(targetNode)),
                targetNode.getConstructorArg().compilerFlags, targetNode.getConstructorArg().preprocessorFlags);
        Iterable<String> otherLdFlags = Iterables.concat(targetNode.getConstructorArg().linkerFlags,
                collectRecursiveExportedLinkerFlags(ImmutableList.of(targetNode)));

        appendConfigsBuilder
                .put("OTHER_CFLAGS",
                        Joiner.on(' ').join(Iterables.transform(otherCFlags, Escaper.BASH_ESCAPER)))
                .put("OTHER_CPLUSPLUSFLAGS",
                        Joiner.on(' ').join(Iterables.transform(otherCxxFlags, Escaper.BASH_ESCAPER)))
                .put("OTHER_LDFLAGS",
                        Joiner.on(' ').join(Iterables.transform(otherLdFlags, Escaper.BASH_ESCAPER)));

        ImmutableMultimap.Builder<String, ImmutableList<String>> platformFlagsBuilder = ImmutableMultimap
                .builder();
        for (Pair<Pattern, ImmutableList<String>> flags : Iterables.concat(
                targetNode.getConstructorArg().platformCompilerFlags.getPatternsAndValues(),
                targetNode.getConstructorArg().platformPreprocessorFlags.getPatternsAndValues(),
                collectRecursiveExportedPlatformPreprocessorFlags(ImmutableList.of(targetNode)))) {
            String sdk = flags.getFirst().pattern().replaceAll("[*.]", "");
            platformFlagsBuilder.put(sdk, flags.getSecond());
        }
        ImmutableMultimap<String, ImmutableList<String>> platformFlags = platformFlagsBuilder.build();
        for (String sdk : platformFlags.keySet()) {
            appendConfigsBuilder.put(String.format("OTHER_CFLAGS[sdk=*%s*]", sdk),
                    Joiner.on(' ')
                            .join(Iterables.transform(
                                    Iterables.concat(otherCFlags, Iterables.concat(platformFlags.get(sdk))),
                                    Escaper.BASH_ESCAPER)))
                    .put(String.format("OTHER_CPLUSPLUSFLAGS[sdk=*%s*]", sdk), Joiner.on(' ')
                            .join(Iterables.transform(
                                    Iterables.concat(otherCxxFlags, Iterables.concat(platformFlags.get(sdk))),
                                    Escaper.BASH_ESCAPER)));
        }

        ImmutableMultimap.Builder<String, ImmutableList<String>> platformLinkerFlagsBuilder = ImmutableMultimap
                .builder();
        for (Pair<Pattern, ImmutableList<String>> flags : Iterables.concat(
                targetNode.getConstructorArg().platformLinkerFlags.getPatternsAndValues(),
                collectRecursiveExportedPlatformLinkerFlags(ImmutableList.of(targetNode)))) {
            String sdk = flags.getFirst().pattern().replaceAll("[*.]", "");
            platformLinkerFlagsBuilder.put(sdk, flags.getSecond());
        }
        ImmutableMultimap<String, ImmutableList<String>> platformLinkerFlags = platformLinkerFlagsBuilder
                .build();
        for (String sdk : platformLinkerFlags.keySet()) {
            appendConfigsBuilder
                    .put(String.format("OTHER_LDFLAGS[sdk=*%s*]", sdk),
                            Joiner.on(
                                    ' ').join(
                                            Iterables
                                                    .transform(
                                                            Iterables.concat(otherLdFlags,
                                                                    Iterables.concat(
                                                                            platformLinkerFlags.get(sdk))),
                                                            Escaper.BASH_ESCAPER)));
        }
    }

    PBXNativeTarget target = targetBuilderResult.target;

    if (isFocusedOnTarget) {
        ImmutableMap<String, String> appendedConfig = appendConfigsBuilder.build();

        Optional<ImmutableSortedMap<String, ImmutableMap<String, String>>> configs = getXcodeBuildConfigurationsForTargetNode(
                targetNode, appendedConfig);
        setTargetBuildConfigurations(getConfigurationNameToXcconfigPath(buildTarget), target,
                project.getMainGroup(), configs.get(), extraSettingsBuilder.build(),
                defaultSettingsBuilder.build(), appendedConfig);
    }

    // -- phases
    boolean headerMapDisabled = options.contains(Option.DISABLE_HEADER_MAPS);
    createHeaderSymlinkTree(sourcePathResolver, getPublicCxxHeaders(targetNode),
            getPathToHeaderSymlinkTree(targetNode, HeaderVisibility.PUBLIC),
            arg.xcodePublicHeadersSymlinks.orElse(true) || headerMapDisabled);
    if (isFocusedOnTarget) {
        createHeaderSymlinkTree(sourcePathResolver, getPrivateCxxHeaders(targetNode),
                getPathToHeaderSymlinkTree(targetNode, HeaderVisibility.PRIVATE),
                arg.xcodePrivateHeadersSymlinks.orElse(true) || headerMapDisabled);
    }

    if (appleTargetNode.isPresent() && isFocusedOnTarget) {
        // Use Core Data models from immediate dependencies only.
        addCoreDataModelsIntoTarget(appleTargetNode.get(), targetGroup.get());
        addSceneKitAssetsIntoTarget(appleTargetNode.get(), targetGroup.get());
    }

    return target;
}

From source file:com.facebook.buck.android.NonPreDexedDexBuildable.java

/**
 * Create dex artifacts for all of the individual directories of compiled .class files (or the
 * obfuscated jar files if proguard is used). If split dex is used, multiple dex artifacts will be
 * produced.//w w w .  j  a  va 2  s  .c  o  m
 */
@VisibleForTesting
void addDexingSteps(Set<Path> classpathEntriesToDex,
        Supplier<ImmutableMap<String, HashCode>> classNamesToHashesSupplier,
        Consumer<Path> secondaryDexDirectoriesConsumer, ImmutableList.Builder<Step> steps, Path primaryDexPath,
        Optional<SourcePath> dexReorderToolFile, Optional<SourcePath> dexReorderDataDumpFile,
        ImmutableMultimap<APKModule, Path> additionalDexStoreToJarPathMap, BuildContext buildContext) {
    SourcePathResolver resolver = buildContext.getSourcePathResolver();
    Supplier<Set<Path>> primaryInputsToDex;
    Optional<Path> secondaryDexDir;
    Optional<Supplier<Multimap<Path, Path>>> secondaryOutputToInputs;
    Path secondaryDexParentDir = getSecondaryDexRoot().resolve("__secondary_dex__/");
    Path additionalDexParentDir = getSecondaryDexRoot().resolve("__additional_dex__/");
    Path additionalDexAssetsDir = additionalDexParentDir.resolve("assets");
    Optional<ImmutableSet<Path>> additionalDexDirs;

    if (shouldSplitDex) {
        Optional<Path> proguardFullConfigFile = Optional.empty();
        Optional<Path> proguardMappingFile = Optional.empty();
        if (shouldProguard) {
            proguardFullConfigFile = Optional.of(getProguardConfigDir().resolve("configuration.txt"));
            proguardMappingFile = Optional.of(getProguardConfigDir().resolve("mapping.txt"));
        }
        // DexLibLoader expects that metadata.txt and secondary jar files are under this dir
        // in assets.

        // Intermediate directory holding the primary split-zip jar.
        Path splitZipDir = getBinPath("__split_zip__");

        steps.addAll(MakeCleanDirectoryStep.of(BuildCellRelativePath.fromCellRelativePath(
                buildContext.getBuildCellRootPath(), getProjectFilesystem(), splitZipDir)));
        Path primaryJarPath = splitZipDir.resolve("primary.jar");

        Path secondaryJarMetaDirParent = getSecondaryDexRoot().resolve("secondary_meta");
        Path secondaryJarMetaDir = secondaryJarMetaDirParent.resolve(AndroidBinary.SECONDARY_DEX_SUBDIR);

        steps.addAll(MakeCleanDirectoryStep.of(BuildCellRelativePath.fromCellRelativePath(
                buildContext.getBuildCellRootPath(), getProjectFilesystem(), secondaryJarMetaDir)));
        Path secondaryJarMeta = secondaryJarMetaDir.resolve("metadata.txt");

        // Intermediate directory holding _ONLY_ the secondary split-zip jar files.  This is
        // important because SmartDexingCommand will try to dx every entry in this directory.  It
        // does this because it's impossible to know what outputs split-zip will generate until it
        // runs.
        Path secondaryZipDir = getBinPath("__secondary_zip__");

        steps.addAll(MakeCleanDirectoryStep.of(BuildCellRelativePath.fromCellRelativePath(
                buildContext.getBuildCellRootPath(), getProjectFilesystem(), secondaryZipDir)));

        // Intermediate directory holding the directories holding _ONLY_ the additional split-zip
        // jar files that are intended for that dex store.
        Path additionalDexStoresZipDir = getBinPath("__dex_stores_zip__");

        steps.addAll(MakeCleanDirectoryStep.of(BuildCellRelativePath.fromCellRelativePath(
                buildContext.getBuildCellRootPath(), getProjectFilesystem(), additionalDexStoresZipDir)));
        for (APKModule dexStore : additionalDexStoreToJarPathMap.keySet()) {

            steps.addAll(MakeCleanDirectoryStep
                    .of(BuildCellRelativePath.fromCellRelativePath(buildContext.getBuildCellRootPath(),
                            getProjectFilesystem(), additionalDexStoresZipDir.resolve(dexStore.getName()))));

            steps.addAll(MakeCleanDirectoryStep.of(BuildCellRelativePath.fromCellRelativePath(
                    buildContext.getBuildCellRootPath(), getProjectFilesystem(),
                    secondaryJarMetaDirParent.resolve("assets").resolve(dexStore.getName()))));
        }

        // Run the split-zip command which is responsible for dividing the large set of input
        // classpaths into a more compact set of jar files such that no one jar file when dexed will
        // yield a dex artifact too large for dexopt or the dx method limit to handle.
        Path zipSplitReportDir = getBinPath("__split_zip_report__");

        steps.addAll(MakeCleanDirectoryStep.of(BuildCellRelativePath.fromCellRelativePath(
                buildContext.getBuildCellRootPath(), getProjectFilesystem(), zipSplitReportDir)));
        SplitZipStep splitZipCommand = new SplitZipStep(getProjectFilesystem(), classpathEntriesToDex,
                secondaryJarMeta, primaryJarPath, secondaryZipDir, "secondary-%d.jar",
                secondaryJarMetaDirParent, additionalDexStoresZipDir, proguardFullConfigFile,
                proguardMappingFile, skipProguard, dexSplitMode,
                dexSplitMode.getPrimaryDexScenarioFile().map(resolver::getAbsolutePath),
                dexSplitMode.getPrimaryDexClassesFile().map(resolver::getAbsolutePath),
                dexSplitMode.getSecondaryDexHeadClassesFile().map(resolver::getAbsolutePath),
                dexSplitMode.getSecondaryDexTailClassesFile().map(resolver::getAbsolutePath),
                additionalDexStoreToJarPathMap, apkModuleMap, rootAPKModule, zipSplitReportDir);
        steps.add(splitZipCommand);

        // Add the secondary dex directory that has yet to be created, but will be by the
        // smart dexing command.  Smart dex will handle "cleaning" this directory properly.
        if (reorderClassesIntraDex) {
            secondaryDexDir = Optional.of(secondaryDexParentDir.resolve(SMART_DEX_SECONDARY_DEX_SUBDIR));
            Path intraDexReorderSecondaryDexDir = secondaryDexParentDir
                    .resolve(AndroidBinary.SECONDARY_DEX_SUBDIR);

            steps.addAll(MakeCleanDirectoryStep.of(BuildCellRelativePath.fromCellRelativePath(
                    buildContext.getBuildCellRootPath(), getProjectFilesystem(), secondaryDexDir.get())));

            steps.addAll(MakeCleanDirectoryStep
                    .of(BuildCellRelativePath.fromCellRelativePath(buildContext.getBuildCellRootPath(),
                            getProjectFilesystem(), intraDexReorderSecondaryDexDir)));
        } else {
            secondaryDexDir = Optional.of(secondaryDexParentDir.resolve(AndroidBinary.SECONDARY_DEX_SUBDIR));
            steps.add(MkdirStep.of(BuildCellRelativePath.fromCellRelativePath(
                    buildContext.getBuildCellRootPath(), getProjectFilesystem(), secondaryDexDir.get())));
        }

        if (additionalDexStoreToJarPathMap.isEmpty()) {
            additionalDexDirs = Optional.empty();
        } else {
            ImmutableSet.Builder<Path> builder = ImmutableSet.builder();
            for (APKModule dexStore : additionalDexStoreToJarPathMap.keySet()) {
                Path dexStorePath = additionalDexAssetsDir.resolve(dexStore.getName());
                builder.add(dexStorePath);

                steps.addAll(MakeCleanDirectoryStep.of(BuildCellRelativePath.fromCellRelativePath(
                        buildContext.getBuildCellRootPath(), getProjectFilesystem(), dexStorePath)));
            }
            additionalDexDirs = Optional.of(builder.build());
        }

        if (dexSplitMode.getDexStore() == DexStore.RAW) {
            secondaryDexDirectoriesConsumer.accept(secondaryDexDir.get());
        } else {
            secondaryDexDirectoriesConsumer.accept(secondaryJarMetaDirParent);
            secondaryDexDirectoriesConsumer.accept(secondaryDexParentDir);
        }
        if (additionalDexDirs.isPresent()) {
            secondaryDexDirectoriesConsumer.accept(additionalDexParentDir);
        }

        // Adjust smart-dex inputs for the split-zip case.
        primaryInputsToDex = Suppliers.ofInstance(ImmutableSet.of(primaryJarPath));
        Supplier<Multimap<Path, Path>> secondaryOutputToInputsMap = splitZipCommand
                .getOutputToInputsMapSupplier(secondaryDexDir.get(), additionalDexAssetsDir);
        secondaryOutputToInputs = Optional.of(secondaryOutputToInputsMap);
    } else {
        // Simple case where our inputs are the natural classpath directories and we don't have
        // to worry about secondary jar/dex files.
        primaryInputsToDex = Suppliers.ofInstance(classpathEntriesToDex);
        secondaryDexDir = Optional.empty();
        secondaryOutputToInputs = Optional.empty();
    }

    HashInputJarsToDexStep hashInputJarsToDexStep = new HashInputJarsToDexStep(getProjectFilesystem(),
            primaryInputsToDex, secondaryOutputToInputs, classNamesToHashesSupplier);
    steps.add(hashInputJarsToDexStep);

    // Stores checksum information from each invocation to intelligently decide when dx needs
    // to be re-run.
    Path successDir = getBinPath("__smart_dex__/.success");
    steps.add(MkdirStep.of(BuildCellRelativePath.fromCellRelativePath(buildContext.getBuildCellRootPath(),
            getProjectFilesystem(), successDir)));

    // Add the smart dexing tool that is capable of avoiding the external dx invocation(s) if
    // it can be shown that the inputs have not changed.  It also parallelizes dx invocations
    // where applicable.
    //
    // Note that by not specifying the number of threads this command will use it will select an
    // optimal default regardless of the value of --num-threads.  This decision was made with the
    // assumption that --num-threads specifies the threading of build rule execution and does not
    // directly apply to the internal threading/parallelization details of various build commands
    // being executed.  For example, aapt is internally threaded by default when preprocessing
    // images.
    EnumSet<DxStep.Option> dxOptions = shouldProguard ? EnumSet.of(DxStep.Option.NO_LOCALS)
            : EnumSet.of(DxStep.Option.NO_OPTIMIZE);
    Path selectedPrimaryDexPath = primaryDexPath;
    if (reorderClassesIntraDex) {
        String primaryDexFileName = primaryDexPath.getFileName().toString();
        String smartDexPrimaryDexFileName = "smart-dex-" + primaryDexFileName;
        selectedPrimaryDexPath = Paths
                .get(primaryDexPath.toString().replace(primaryDexFileName, smartDexPrimaryDexFileName));
    }
    SmartDexingStep smartDexingCommand = new SmartDexingStep(androidPlatformTarget, buildContext,
            getProjectFilesystem(), selectedPrimaryDexPath, primaryInputsToDex, secondaryDexDir,
            secondaryOutputToInputs, hashInputJarsToDexStep, successDir, dxOptions, dxExecutorService,
            xzCompressionLevel, dxMaxHeapSize, dexTool, desugarInterfaceMethods, true,
            Optional.of(additionalJarsForProguardAndDesugar.stream()
                    .map(input -> buildContext.getSourcePathResolver().getAbsolutePath(input))
                    .collect(ImmutableSet.toImmutableSet())));
    steps.add(smartDexingCommand);

    if (reorderClassesIntraDex) {
        IntraDexReorderStep intraDexReorderStep = new IntraDexReorderStep(buildContext, getProjectFilesystem(),
                resolver.getAbsolutePath(dexReorderToolFile.get()),
                resolver.getAbsolutePath(dexReorderDataDumpFile.get()), getBuildTarget(),
                selectedPrimaryDexPath, primaryDexPath, secondaryOutputToInputs, SMART_DEX_SECONDARY_DEX_SUBDIR,
                AndroidBinary.SECONDARY_DEX_SUBDIR);
        steps.add(intraDexReorderStep);
    }
}

From source file:com.facebook.buck.features.apple.project.ProjectGenerator.java

private PBXNativeTarget generateBinaryTarget(PBXProject project,
        Optional<? extends TargetNode<? extends HasAppleBundleFields>> bundle,
        TargetNode<? extends CxxLibraryDescription.CommonArg> targetNode, ProductType productType,
        String productOutputFormat, Optional<Path> infoPlistOptional, boolean includeFrameworks,
        ImmutableSet<AppleResourceDescriptionArg> recursiveResources,
        ImmutableSet<AppleResourceDescriptionArg> directResources,
        ImmutableSet<AppleAssetCatalogDescriptionArg> recursiveAssetCatalogs,
        ImmutableSet<AppleAssetCatalogDescriptionArg> directAssetCatalogs,
        ImmutableSet<AppleWrapperResourceArg> wrapperResources,
        Optional<Iterable<PBXBuildPhase>> copyFilesPhases,
        Optional<TargetNode<AppleBundleDescriptionArg>> bundleLoaderNode) throws IOException {

    LOG.debug("Generating binary target for node %s", targetNode);

    TargetNode<?> buildTargetNode = bundle.isPresent() ? bundle.get() : targetNode;
    BuildTarget buildTarget = buildTargetNode.getBuildTarget();
    boolean containsSwiftCode = projGenerationStateCache.targetContainsSwiftSourceCode(targetNode);

    String buildTargetName = getProductNameForBuildTargetNode(buildTargetNode);
    CxxLibraryDescription.CommonArg arg = targetNode.getConstructorArg();
    NewNativeTargetProjectMutator mutator = new NewNativeTargetProjectMutator(pathRelativizer,
            this::resolveSourcePath);

    // Both exported headers and exported platform headers will be put into the symlink tree
    // exported platform headers will be excluded and then included by platform
    ImmutableSet.Builder<SourcePath> exportedHeadersBuilder = ImmutableSet.builder();
    exportedHeadersBuilder.addAll(getHeaderSourcePaths(arg.getExportedHeaders()));
    PatternMatchedCollection<SourceSortedSet> exportedPlatformHeaders = arg.getExportedPlatformHeaders();
    for (SourceSortedSet headersSet : exportedPlatformHeaders.getValues()) {
        exportedHeadersBuilder.addAll(getHeaderSourcePaths(headersSet));
    }//from   w  w  w .j  a  v  a  2  s . c  o  m

    ImmutableSet<SourcePath> exportedHeaders = exportedHeadersBuilder.build();
    ImmutableSet.Builder<SourcePath> headersBuilder = ImmutableSet.builder();
    headersBuilder.addAll(getHeaderSourcePaths(arg.getHeaders()));
    for (SourceSortedSet headersSet : arg.getPlatformHeaders().getValues()) {
        headersBuilder.addAll(getHeaderSourcePaths(headersSet));
    }
    ImmutableSet<SourcePath> headers = headersBuilder.build();
    ImmutableMap<CxxSource.Type, ImmutableList<StringWithMacros>> langPreprocessorFlags = targetNode
            .getConstructorArg().getLangPreprocessorFlags();
    boolean isFocusedOnTarget = focusModules.isFocusedOn(buildTarget);

    Optional<String> swiftVersion = getSwiftVersionForTargetNode(targetNode);
    boolean hasSwiftVersionArg = swiftVersion.isPresent();
    if (!swiftVersion.isPresent()) {
        swiftVersion = swiftBuckConfig.getVersion();
    }

    mutator.setTargetName(getXcodeTargetName(buildTarget)).setProduct(productType, buildTargetName,
            Paths.get(String.format(productOutputFormat, buildTargetName)));

    boolean isModularAppleLibrary = isModularAppleLibrary(targetNode) && isFocusedOnTarget;
    mutator.setFrameworkHeadersEnabled(isModularAppleLibrary);

    ImmutableMap.Builder<String, String> swiftDepsSettingsBuilder = ImmutableMap.builder();
    ImmutableList.Builder<String> swiftDebugLinkerFlagsBuilder = ImmutableList.builder();

    ImmutableMap.Builder<String, String> extraSettingsBuilder = ImmutableMap.builder();
    ImmutableMap.Builder<String, String> defaultSettingsBuilder = ImmutableMap.builder();

    ImmutableList<Pair<Pattern, SourceSortedSet>> platformHeaders = arg.getPlatformHeaders()
            .getPatternsAndValues();
    ImmutableList.Builder<Pair<Pattern, Iterable<SourcePath>>> platformHeadersIterableBuilder = ImmutableList
            .builder();
    for (Pair<Pattern, SourceSortedSet> platformHeader : platformHeaders) {
        platformHeadersIterableBuilder
                .add(new Pair<>(platformHeader.getFirst(), getHeaderSourcePaths(platformHeader.getSecond())));
    }

    ImmutableList<Pair<Pattern, SourceSortedSet>> exportedPlatformHeadersPatternsAndValues = exportedPlatformHeaders
            .getPatternsAndValues();
    for (Pair<Pattern, SourceSortedSet> exportedPlatformHeader : exportedPlatformHeadersPatternsAndValues) {
        platformHeadersIterableBuilder.add(new Pair<>(exportedPlatformHeader.getFirst(),
                getHeaderSourcePaths(exportedPlatformHeader.getSecond())));
    }

    ImmutableList<Pair<Pattern, Iterable<SourcePath>>> platformHeadersIterable = platformHeadersIterableBuilder
            .build();

    ImmutableList<Pair<Pattern, ImmutableSortedSet<SourceWithFlags>>> platformSources = arg.getPlatformSrcs()
            .getPatternsAndValues();
    ImmutableMap<String, ImmutableSortedSet<String>> platformExcludedSourcesMapping = ProjectGenerator
            .gatherExcludedSources(
                    appleCxxFlavors.stream().map(f -> applePlatformAndArchitecture(f).getFirst())
                            .collect(ImmutableSet.toImmutableSet()),
                    platformSources, platformHeadersIterable, outputDirectory, defaultPathResolver);
    for (Map.Entry<String, ImmutableSortedSet<String>> platformExcludedSources : platformExcludedSourcesMapping
            .entrySet()) {
        if (platformExcludedSources.getValue().size() > 0) {
            extraSettingsBuilder.put(platformExcludedSources.getKey(),
                    String.join(" ", platformExcludedSources.getValue()));
        }
    }

    ImmutableSortedSet<SourceWithFlags> nonPlatformSrcs = arg.getSrcs();
    ImmutableSortedSet.Builder<SourceWithFlags> allSrcsBuilder = ImmutableSortedSet.naturalOrder();
    allSrcsBuilder.addAll(nonPlatformSrcs);
    for (Pair<Pattern, ImmutableSortedSet<SourceWithFlags>> platformSource : platformSources) {
        allSrcsBuilder.addAll(platformSource.getSecond());
    }

    ImmutableSortedSet<SourceWithFlags> allSrcs = allSrcsBuilder.build();

    if (!options.shouldGenerateHeaderSymlinkTreesOnly()) {
        if (isFocusedOnTarget) {
            filesAddedBuilder.addAll(
                    allSrcs.stream().map(s -> s.getSourcePath()).collect(ImmutableList.toImmutableList()));
            mutator.setLangPreprocessorFlags(ImmutableMap.copyOf(
                    Maps.transformValues(langPreprocessorFlags, f -> convertStringWithMacros(targetNode, f))))
                    .setPublicHeaders(exportedHeaders).setPrefixHeader(getPrefixHeaderSourcePath(arg))
                    .setSourcesWithFlags(ImmutableSet.copyOf(allSrcs)).setPrivateHeaders(headers)
                    .setRecursiveResources(recursiveResources).setDirectResources(directResources)
                    .setWrapperResources(wrapperResources)
                    .setExtraXcodeSources(ImmutableSet.copyOf(arg.getExtraXcodeSources()))
                    .setExtraXcodeFiles(ImmutableSet.copyOf(arg.getExtraXcodeFiles()));
        }

        if (bundle.isPresent() && isFocusedOnTarget) {
            HasAppleBundleFields bundleArg = bundle.get().getConstructorArg();
            mutator.setInfoPlist(Optional.of(bundleArg.getInfoPlist()));
        }

        mutator.setBridgingHeader(arg.getBridgingHeader());

        if (options.shouldCreateDirectoryStructure() && isFocusedOnTarget) {
            mutator.setTargetGroupPath(
                    RichStream.from(buildTarget.getBasePath()).map(Object::toString).toImmutableList());
        }

        if (!recursiveAssetCatalogs.isEmpty() && isFocusedOnTarget) {
            mutator.setRecursiveAssetCatalogs(recursiveAssetCatalogs);
        }

        if (!directAssetCatalogs.isEmpty() && isFocusedOnTarget) {
            mutator.setDirectAssetCatalogs(directAssetCatalogs);
        }

        FluentIterable<TargetNode<?>> depTargetNodes = collectRecursiveLibraryDepTargets(targetNode);

        if (includeFrameworks && isFocusedOnTarget) {

            if (!options.shouldAddLinkedLibrariesAsFlags()) {
                mutator.setFrameworks(getSytemFrameworksLibsForTargetNode(targetNode));
            }

            if (sharedLibraryToBundle.isPresent()) {
                // Replace target nodes of libraries which are actually constituents of embedded
                // frameworks to the bundle representing the embedded framework.
                // This will be converted to a reference to the xcode build product for the embedded
                // framework rather than the dylib
                depTargetNodes = swapSharedLibrariesForBundles(depTargetNodes, sharedLibraryToBundle.get());
            }

            ImmutableSet<PBXFileReference> targetNodeDeps = filterRecursiveLibraryDependenciesForLinkerPhase(
                    depTargetNodes);

            if (isTargetNodeApplicationTestTarget(targetNode, bundleLoaderNode)) {
                ImmutableSet<PBXFileReference> bundleLoaderDeps = bundleLoaderNode.isPresent()
                        ? collectRecursiveLibraryDependencies(bundleLoaderNode.get())
                        : ImmutableSet.of();
                mutator.setArchives(Sets.difference(targetNodeDeps, bundleLoaderDeps));
            } else {
                mutator.setArchives(targetNodeDeps);
            }
        }

        if (isFocusedOnTarget) {
            ImmutableSet<TargetNode<?>> swiftDepTargets = filterRecursiveLibraryDepTargetsWithSwiftSources(
                    depTargetNodes);

            if (!includeFrameworks && !swiftDepTargets.isEmpty()) {
                // If the current target, which is non-shared (e.g., static lib), depends on other focused
                // targets which include Swift code, we must ensure those are treated as dependencies so
                // that Xcode builds the targets in the correct order. Unfortunately, those deps can be
                // part of other projects which would require cross-project references.
                //
                // Thankfully, there's an easy workaround because we can just create a phony copy phase
                // which depends on the outputs of the deps (i.e., the static libs). The copy phase
                // will effectively say "Copy libX.a from Products Dir into Products Dir" which is a nop.
                // To be on the safe side, we're explicitly marking the copy phase as only running for
                // deployment postprocessing (i.e., "Copy only when installing") and disabling
                // deployment postprocessing (it's enabled by default for release builds).
                CopyFilePhaseDestinationSpec.Builder destSpecBuilder = CopyFilePhaseDestinationSpec.builder();
                destSpecBuilder.setDestination(PBXCopyFilesBuildPhase.Destination.PRODUCTS);
                PBXCopyFilesBuildPhase copyFiles = new PBXCopyFilesBuildPhase(destSpecBuilder.build());
                copyFiles.setRunOnlyForDeploymentPostprocessing(Optional.of(Boolean.TRUE));
                copyFiles.setName(Optional.of("Fake Swift Dependencies (Copy Files Phase)"));

                ImmutableSet<PBXFileReference> swiftDepsFileRefs = targetNodesSetToPBXFileReference(
                        swiftDepTargets);
                for (PBXFileReference fileRef : swiftDepsFileRefs) {
                    PBXBuildFile buildFile = new PBXBuildFile(fileRef);
                    copyFiles.getFiles().add(buildFile);
                }

                swiftDepsSettingsBuilder.put("DEPLOYMENT_POSTPROCESSING", "NO");

                mutator.setSwiftDependenciesBuildPhase(copyFiles);
            }

            if (includeFrameworks && !swiftDepTargets.isEmpty() && shouldEmbedSwiftRuntimeInBundleTarget(bundle)
                    && swiftBuckConfig.getProjectEmbedRuntime()) {
                // This is a binary that transitively depends on a library that uses Swift. We must ensure
                // that the Swift runtime is bundled.
                swiftDepsSettingsBuilder.put("ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES", "YES");
            }

            if (includeFrameworks && !swiftDepTargets.isEmpty() && swiftBuckConfig.getProjectAddASTPaths()) {
                for (TargetNode<?> swiftNode : swiftDepTargets) {
                    String swiftModulePath = String.format(
                            "${BUILT_PRODUCTS_DIR}/%s.swiftmodule/${CURRENT_ARCH}.swiftmodule",
                            getModuleName(swiftNode));
                    swiftDebugLinkerFlagsBuilder.add("-Xlinker");
                    swiftDebugLinkerFlagsBuilder.add("-add_ast_path");
                    swiftDebugLinkerFlagsBuilder.add("-Xlinker");
                    swiftDebugLinkerFlagsBuilder.add(swiftModulePath);
                }
            }
        }

        // TODO(Task #3772930): Go through all dependencies of the rule
        // and add any shell script rules here
        ImmutableList.Builder<TargetNode<?>> preScriptPhasesBuilder = ImmutableList.builder();
        ImmutableList.Builder<TargetNode<?>> postScriptPhasesBuilder = ImmutableList.builder();
        if (bundle.isPresent() && targetNode != bundle.get() && isFocusedOnTarget) {
            collectBuildScriptDependencies(targetGraph.getAll(bundle.get().getDeclaredDeps()),
                    preScriptPhasesBuilder, postScriptPhasesBuilder);
        }
        collectBuildScriptDependencies(targetGraph.getAll(targetNode.getDeclaredDeps()), preScriptPhasesBuilder,
                postScriptPhasesBuilder);
        if (isFocusedOnTarget) {
            ImmutableList<TargetNode<?>> preScriptPhases = preScriptPhasesBuilder.build();
            ImmutableList<TargetNode<?>> postScriptPhases = postScriptPhasesBuilder.build();

            mutator.setPreBuildRunScriptPhasesFromTargetNodes(preScriptPhases,
                    actionGraphBuilderForNode::apply);
            if (copyFilesPhases.isPresent()) {
                mutator.setCopyFilesPhases(copyFilesPhases.get());
            }
            mutator.setPostBuildRunScriptPhasesFromTargetNodes(postScriptPhases,
                    actionGraphBuilderForNode::apply);

            ImmutableList<TargetNode<?>> scriptPhases = Stream
                    .concat(preScriptPhases.stream(), postScriptPhases.stream())
                    .collect(ImmutableList.toImmutableList());
            mutator.collectFilesToCopyInXcode(filesToCopyInXcodeBuilder, scriptPhases, projectCell,
                    actionGraphBuilderForNode::apply);
        }
    }

    NewNativeTargetProjectMutator.Result targetBuilderResult = mutator.buildTargetAndAddToProject(project,
            isFocusedOnTarget);
    PBXNativeTarget target = targetBuilderResult.target;
    Optional<PBXGroup> targetGroup = targetBuilderResult.targetGroup;

    extraSettingsBuilder.putAll(swiftDepsSettingsBuilder.build());

    setAppIconSettings(recursiveAssetCatalogs, directAssetCatalogs, buildTarget, defaultSettingsBuilder);
    setLaunchImageSettings(recursiveAssetCatalogs, directAssetCatalogs, buildTarget, defaultSettingsBuilder);

    ImmutableSortedMap<Path, SourcePath> publicCxxHeaders = getPublicCxxHeaders(targetNode);
    if (isModularAppleLibrary(targetNode) && isFrameworkProductType(productType)) {
        // Modular frameworks should not include Buck-generated hmaps as they break the VFS overlay
        // that's generated by Xcode and consequently, all headers part of a framework's umbrella
        // header fail the modularity test, as they're expected to be mapped by the VFS layer under
        // $BUILT_PRODUCTS_DIR/Module.framework/Versions/A/Headers.
        publicCxxHeaders = ImmutableSortedMap.of();
    }

    if (!options.shouldGenerateHeaderSymlinkTreesOnly()) {
        if (isFocusedOnTarget) {
            SourceTreePath buckFilePath = new SourceTreePath(PBXReference.SourceTree.SOURCE_ROOT,
                    pathRelativizer.outputPathToBuildTargetPath(buildTarget).resolve(buildFileName),
                    Optional.empty());
            PBXFileReference buckReference = targetGroup.get()
                    .getOrCreateFileReferenceBySourceTreePath(buckFilePath);
            buckReference.setExplicitFileType(Optional.of("text.script.python"));
        }

        // Watch dependencies need to have explicit target dependencies setup in order for Xcode to
        // build them properly within the IDE.  It is unable to match the implicit dependency because
        // of the different in flavor between the targets (iphoneos vs watchos).
        if (bundle.isPresent() && isFocusedOnTarget) {
            collectProjectTargetWatchDependencies(targetNode.getBuildTarget().getFlavorPostfix(), target,
                    targetGraph.getAll(bundle.get().getExtraDeps()));
        }

        // -- configurations
        extraSettingsBuilder.put("TARGET_NAME", buildTargetName).put("SRCROOT",
                pathRelativizer.outputPathToBuildTargetPath(buildTarget).toString());
        if (productType == ProductTypes.UI_TEST && isFocusedOnTarget) {
            if (bundleLoaderNode.isPresent()) {
                BuildTarget testTarget = bundleLoaderNode.get().getBuildTarget();
                extraSettingsBuilder.put("TEST_TARGET_NAME", getXcodeTargetName(testTarget));
                addPBXTargetDependency(target, testTarget);
            } else {
                throw new HumanReadableException(
                        "The test rule '%s' is configured with 'is_ui_test' but has no test_host_app",
                        buildTargetName);
            }
        } else if (bundleLoaderNode.isPresent() && isFocusedOnTarget) {
            TargetNode<AppleBundleDescriptionArg> bundleLoader = bundleLoaderNode.get();
            String bundleLoaderProductName = getProductName(bundleLoader);
            String bundleLoaderBundleName = bundleLoaderProductName + "."
                    + getExtensionString(bundleLoader.getConstructorArg().getExtension());
            // NOTE(grp): This is a hack. We need to support both deep (OS X) and flat (iOS)
            // style bundles for the bundle loader, but at this point we don't know what platform
            // the bundle loader (or current target) is going to be built for. However, we can be
            // sure that it's the same as the target (presumably a test) we're building right now.
            //
            // Using that knowledge, we can do build setting tricks to defer choosing the bundle
            // loader path until Xcode build time, when the platform is known. There's no build
            // setting that conclusively says whether the current platform uses deep bundles:
            // that would be too easy. But in the cases we care about (unit test bundles), the
            // current bundle will have a style matching the style of the bundle loader app, so
            // we can take advantage of that to do the determination.
            //
            // Unfortunately, the build setting for the bundle structure (CONTENTS_FOLDER_PATH)
            // includes the WRAPPER_NAME, so we can't just interpolate that in. Instead, we have
            // to use another trick with build setting operations and evaluation. By using the
            // $(:file) operation, we can extract the last component of the contents path: either
            // "Contents" or the current bundle name. Then, we can interpolate with that expected
            // result in the build setting name to conditionally choose a different loader path.

            // The conditional that decides which path is used. This is a complex Xcode build setting
            // expression that expands to one of two values, depending on the last path component of
            // the CONTENTS_FOLDER_PATH variable. As described above, this will be either "Contents"
            // for deep bundles or the bundle file name itself for flat bundles. Finally, to santiize
            // the potentially invalid build setting names from the bundle file name, it converts that
            // to an identifier. We rely on BUNDLE_LOADER_BUNDLE_STYLE_CONDITIONAL_<bundle file name>
            // being undefined (and thus expanding to nothing) for the path resolution to work.
            //
            // The operations on the CONTENTS_FOLDER_PATH are documented here:
            // http://codeworkshop.net/posts/xcode-build-setting-transformations
            String bundleLoaderOutputPathConditional = "$(BUNDLE_LOADER_BUNDLE_STYLE_CONDITIONAL_$(CONTENTS_FOLDER_PATH:file:identifier))";

            // If the $(CONTENTS_FOLDER_PATH:file:identifier) expands to this, we add the deep bundle
            // path into the bundle loader. See above for the case when it will expand to this value.
            extraSettingsBuilder.put("BUNDLE_LOADER_BUNDLE_STYLE_CONDITIONAL_Contents",
                    Joiner.on('/').join(getTargetOutputPath(bundleLoader), bundleLoaderBundleName,
                            "Contents/MacOS", bundleLoaderProductName));

            extraSettingsBuilder.put(
                    "BUNDLE_LOADER_BUNDLE_STYLE_CONDITIONAL_" + getProductName(bundle.get()) + "_"
                            + getExtensionString(bundle.get().getConstructorArg().getExtension()),
                    Joiner.on('/').join(getTargetOutputPath(bundleLoader), bundleLoaderBundleName,
                            bundleLoaderProductName));

            extraSettingsBuilder.put("BUNDLE_LOADER", bundleLoaderOutputPathConditional).put("TEST_HOST",
                    "$(BUNDLE_LOADER)");

            addPBXTargetDependency(target, bundleLoader.getBuildTarget());
        }
        if (infoPlistOptional.isPresent()) {
            Path infoPlistPath = pathRelativizer.outputDirToRootRelative(infoPlistOptional.get());
            extraSettingsBuilder.put("INFOPLIST_FILE", infoPlistPath.toString());
        }
        if (arg.getBridgingHeader().isPresent()) {
            Path bridgingHeaderPath = pathRelativizer
                    .outputDirToRootRelative(resolveSourcePath(arg.getBridgingHeader().get()));
            extraSettingsBuilder.put("SWIFT_OBJC_BRIDGING_HEADER",
                    Joiner.on('/').join("$(SRCROOT)", bridgingHeaderPath.toString()));
        }

        swiftVersion.ifPresent(s -> extraSettingsBuilder.put("SWIFT_VERSION", s));
        swiftVersion.ifPresent(s -> extraSettingsBuilder.put("PRODUCT_MODULE_NAME", getModuleName(targetNode)));

        if (hasSwiftVersionArg && containsSwiftCode && isFocusedOnTarget) {
            extraSettingsBuilder.put("SWIFT_OBJC_INTERFACE_HEADER_NAME",
                    getSwiftObjCGeneratedHeaderName(buildTargetNode));

            if (swiftBuckConfig.getProjectWMO()) {
                // We must disable "Index While Building" as there's a bug in the LLVM infra which
                // makes the compilation fail.
                extraSettingsBuilder.put("COMPILER_INDEX_STORE_ENABLE", "NO");

                // This is a hidden Xcode setting which is needed for two reasons:
                // - Stops Xcode adding .o files for each Swift compilation unit to dependency db
                //   which is used during linking (which will fail with WMO).
                // - Turns on WMO itself.
                //
                // Note that setting SWIFT_OPTIMIZATION_LEVEL (which is public) to '-Owholemodule'
                // ends up crashing the Swift compiler for some reason while this doesn't.
                extraSettingsBuilder.put("SWIFT_WHOLE_MODULE_OPTIMIZATION", "YES");
            }
        }

        Optional<SourcePath> prefixHeaderOptional = getPrefixHeaderSourcePath(targetNode.getConstructorArg());
        if (prefixHeaderOptional.isPresent()) {
            Path prefixHeaderRelative = resolveSourcePath(prefixHeaderOptional.get());
            Path prefixHeaderPath = pathRelativizer.outputDirToRootRelative(prefixHeaderRelative);
            extraSettingsBuilder.put("GCC_PREFIX_HEADER", prefixHeaderPath.toString());
            extraSettingsBuilder.put("GCC_PRECOMPILE_PREFIX_HEADER", "YES");
        }

        boolean shouldSetUseHeadermap = false;
        if (isModularAppleLibrary) {
            extraSettingsBuilder.put("CLANG_ENABLE_MODULES", "YES");
            extraSettingsBuilder.put("DEFINES_MODULE", "YES");

            if (isFrameworkProductType(productType)) {
                // Modular frameworks need to have both USE_HEADERMAP enabled so that Xcode generates
                // .framework VFS overlays, in modular libraries we handle this in buck
                shouldSetUseHeadermap = true;
            }
        }
        extraSettingsBuilder.put("USE_HEADERMAP", shouldSetUseHeadermap ? "YES" : "NO");

        defaultSettingsBuilder.put("REPO_ROOT",
                projectFilesystem.getRootPath().toAbsolutePath().normalize().toString());
        if (hasSwiftVersionArg && containsSwiftCode && isFocusedOnTarget) {
            // We need to be able to control the directory where Xcode places the derived sources, so
            // that the Obj-C Generated Header can be included in the header map and imported through
            // a framework-style import like <Module/Module-Swift.h>
            Path derivedSourcesDir = getDerivedSourcesDirectoryForBuildTarget(buildTarget, projectFilesystem);
            Path derivedSourceDirRelativeToProjectRoot = pathRelativizer
                    .outputDirToRootRelative(derivedSourcesDir);

            defaultSettingsBuilder.put("DERIVED_FILE_DIR", derivedSourceDirRelativeToProjectRoot.toString());
        }

        defaultSettingsBuilder.put(PRODUCT_NAME, getProductName(buildTargetNode));
        bundle.ifPresent(bundleNode -> defaultSettingsBuilder.put("WRAPPER_EXTENSION",
                getExtensionString(bundleNode.getConstructorArg().getExtension())));

        // We use BUILT_PRODUCTS_DIR as the root for the everything being built. Target-
        // specific output is placed within CONFIGURATION_BUILD_DIR, inside BUILT_PRODUCTS_DIR.
        // That allows Copy Files build phases to reference files in the CONFIGURATION_BUILD_DIR
        // of other targets by using paths relative to the target-independent BUILT_PRODUCTS_DIR.
        defaultSettingsBuilder.put("BUILT_PRODUCTS_DIR",
                // $EFFECTIVE_PLATFORM_NAME starts with a dash, so this expands to something like:
                // $SYMROOT/Debug-iphonesimulator
                Joiner.on('/').join("$SYMROOT", "$CONFIGURATION$EFFECTIVE_PLATFORM_NAME"));
        defaultSettingsBuilder.put("CONFIGURATION_BUILD_DIR", "$BUILT_PRODUCTS_DIR");
        boolean nodeIsAppleLibrary = targetNode.getDescription() instanceof AppleLibraryDescription;
        boolean nodeIsCxxLibrary = targetNode.getDescription() instanceof CxxLibraryDescription;
        if (!bundle.isPresent() && (nodeIsAppleLibrary || nodeIsCxxLibrary)) {
            defaultSettingsBuilder.put("EXECUTABLE_PREFIX", "lib");
        }

        if (isFocusedOnTarget) {
            ImmutableSet<Path> recursiveHeaderSearchPaths = collectRecursiveHeaderSearchPaths(targetNode);
            ImmutableSet<Path> headerMapBases = collectRecursiveHeaderMapBases(targetNode);

            ImmutableMap.Builder<String, String> appendConfigsBuilder = ImmutableMap.builder();
            appendConfigsBuilder.putAll(getFrameworkAndLibrarySearchPathConfigs(targetNode, includeFrameworks));
            appendConfigsBuilder.put("HEADER_SEARCH_PATHS",
                    Joiner.on(' ').join(Iterables.concat(recursiveHeaderSearchPaths, headerMapBases)));
            if (hasSwiftVersionArg && containsSwiftCode && isFocusedOnTarget) {
                ImmutableSet<Path> swiftIncludePaths = collectRecursiveSwiftIncludePaths(targetNode);
                Stream<String> allValues = Streams.concat(Stream.of("$BUILT_PRODUCTS_DIR"), Streams
                        .stream(swiftIncludePaths).map((path) -> path.toString()).map(Escaper.BASH_ESCAPER));
                appendConfigsBuilder.put("SWIFT_INCLUDE_PATHS", allValues.collect(Collectors.joining(" ")));
            }

            ImmutableList.Builder<String> targetSpecificSwiftFlags = ImmutableList.builder();
            Optional<TargetNode<SwiftCommonArg>> swiftTargetNode = TargetNodes.castArg(targetNode,
                    SwiftCommonArg.class);
            targetSpecificSwiftFlags.addAll(swiftTargetNode.map(
                    x -> convertStringWithMacros(targetNode, x.getConstructorArg().getSwiftCompilerFlags()))
                    .orElse(ImmutableList.of()));

            if (containsSwiftCode && isModularAppleLibrary && publicCxxHeaders.size() > 0) {
                targetSpecificSwiftFlags.addAll(collectModularTargetSpecificSwiftFlags(targetNode));
            }

            ImmutableList<String> testingOverlay = getFlagsForExcludesForModulesUnderTests(targetNode);
            Iterable<String> otherSwiftFlags = Iterables.concat(
                    swiftBuckConfig.getCompilerFlags().orElse(DEFAULT_SWIFTFLAGS),
                    targetSpecificSwiftFlags.build());

            Iterable<String> otherCFlags = ImmutableList.<String>builder()
                    .addAll(cxxBuckConfig.getCflags().orElse(DEFAULT_CFLAGS))
                    .addAll(cxxBuckConfig.getCppflags().orElse(DEFAULT_CPPFLAGS))
                    .addAll(convertStringWithMacros(targetNode,
                            collectRecursiveExportedPreprocessorFlags(targetNode)))
                    .addAll(convertStringWithMacros(targetNode,
                            targetNode.getConstructorArg().getCompilerFlags()))
                    .addAll(convertStringWithMacros(targetNode,
                            targetNode.getConstructorArg().getPreprocessorFlags()))
                    .addAll(convertStringWithMacros(targetNode,
                            collectRecursiveSystemPreprocessorFlags(targetNode)))
                    .addAll(testingOverlay).build();
            Iterable<String> otherCxxFlags = ImmutableList.<String>builder()
                    .addAll(cxxBuckConfig.getCxxflags().orElse(DEFAULT_CXXFLAGS))
                    .addAll(cxxBuckConfig.getCxxppflags().orElse(DEFAULT_CXXPPFLAGS))
                    .addAll(convertStringWithMacros(targetNode,
                            collectRecursiveExportedPreprocessorFlags(targetNode)))
                    .addAll(convertStringWithMacros(targetNode,
                            targetNode.getConstructorArg().getCompilerFlags()))
                    .addAll(convertStringWithMacros(targetNode,
                            targetNode.getConstructorArg().getPreprocessorFlags()))
                    .addAll(convertStringWithMacros(targetNode,
                            collectRecursiveSystemPreprocessorFlags(targetNode)))
                    .addAll(testingOverlay).build();

            appendConfigsBuilder
                    .put("OTHER_SWIFT_FLAGS",
                            Streams.stream(otherSwiftFlags).map(Escaper.BASH_ESCAPER)
                                    .collect(Collectors.joining(" ")))
                    .put("OTHER_CFLAGS",
                            Streams.stream(otherCFlags).map(Escaper.BASH_ESCAPER)
                                    .collect(Collectors.joining(" ")))
                    .put("OTHER_CPLUSPLUSFLAGS", Streams.stream(otherCxxFlags).map(Escaper.BASH_ESCAPER)
                            .collect(Collectors.joining(" ")));

            Iterable<String> otherLdFlags = ImmutableList.<String>builder()
                    .addAll(cxxBuckConfig.getLdflags().orElse(DEFAULT_LDFLAGS))
                    .addAll(appleConfig.linkAllObjC() ? ImmutableList.of("-ObjC") : ImmutableList.of())
                    .addAll(convertStringWithMacros(targetNode,
                            Iterables.concat(targetNode.getConstructorArg().getLinkerFlags(),
                                    collectRecursiveExportedLinkerFlags(targetNode))))
                    .addAll(swiftDebugLinkerFlagsBuilder.build()).build();

            updateOtherLinkerFlagsForOptions(targetNode, bundleLoaderNode, appendConfigsBuilder, otherLdFlags);

            ImmutableMultimap<String, ImmutableList<String>> platformFlags = convertPlatformFlags(targetNode,
                    Iterables.concat(
                            ImmutableList.of(targetNode.getConstructorArg().getPlatformCompilerFlags()),
                            ImmutableList.of(targetNode.getConstructorArg().getPlatformPreprocessorFlags()),
                            collectRecursiveExportedPlatformPreprocessorFlags(targetNode)));
            for (String platform : platformFlags.keySet()) {
                appendConfigsBuilder.put(generateConfigKey("OTHER_CFLAGS", platform),
                        Streams.stream(Iterables.transform(
                                Iterables.concat(otherCFlags, Iterables.concat(platformFlags.get(platform))),
                                Escaper.BASH_ESCAPER::apply)).collect(
                                        Collectors.joining(" ")))
                        .put(generateConfigKey("OTHER_CPLUSPLUSFLAGS", platform),
                                Streams.stream(Iterables.transform(
                                        Iterables.concat(otherCxxFlags,
                                                Iterables.concat(platformFlags.get(platform))),
                                        Escaper.BASH_ESCAPER::apply)).collect(Collectors.joining(" ")));
            }

            ImmutableMultimap<String, ImmutableList<String>> platformLinkerFlags = convertPlatformFlags(
                    targetNode,
                    Iterables.concat(ImmutableList.of(targetNode.getConstructorArg().getPlatformLinkerFlags()),
                            collectRecursiveExportedPlatformLinkerFlags(targetNode)));
            for (String platform : platformLinkerFlags.keySet()) {
                appendConfigsBuilder
                        .put(generateConfigKey("OTHER_LDFLAGS", platform),
                                Streams.stream(
                                        Iterables
                                                .transform(
                                                        Iterables.concat(otherLdFlags,
                                                                Iterables.concat(
                                                                        platformLinkerFlags.get(platform))),
                                                        Escaper.BASH_ESCAPER::apply))
                                        .collect(Collectors.joining(" ")));
            }

            ImmutableMap<String, String> appendedConfig = appendConfigsBuilder.build();

            Optional<ImmutableSortedMap<String, ImmutableMap<String, String>>> configs = getXcodeBuildConfigurationsForTargetNode(
                    targetNode);
            setTargetBuildConfigurations(buildTarget, target, project.getMainGroup(), configs.get(),
                    getTargetCxxBuildConfigurationForTargetNode(targetNode, appendedConfig),
                    extraSettingsBuilder.build(), defaultSettingsBuilder.build(), appendedConfig);
        }
    }

    Optional<String> moduleName = isModularAppleLibrary ? Optional.of(getModuleName(targetNode))
            : Optional.empty();
    // -- phases
    createHeaderSymlinkTree(publicCxxHeaders, getSwiftPublicHeaderMapEntriesForTarget(targetNode), moduleName,
            getPathToHeaderSymlinkTree(targetNode, HeaderVisibility.PUBLIC),
            arg.getXcodePublicHeadersSymlinks().orElse(cxxBuckConfig.getPublicHeadersSymlinksEnabled())
                    || !options.shouldUseHeaderMaps() || isModularAppleLibrary,
            !shouldMergeHeaderMaps(), options.shouldGenerateMissingUmbrellaHeader());
    if (isFocusedOnTarget) {
        createHeaderSymlinkTree(getPrivateCxxHeaders(targetNode), ImmutableMap.of(), // private interfaces never have a modulemap
                Optional.empty(), getPathToHeaderSymlinkTree(targetNode, HeaderVisibility.PRIVATE),
                arg.getXcodePrivateHeadersSymlinks().orElse(cxxBuckConfig.getPrivateHeadersSymlinksEnabled())
                        || !options.shouldUseHeaderMaps(),
                options.shouldUseHeaderMaps(), options.shouldGenerateMissingUmbrellaHeader());
    }

    Optional<TargetNode<AppleNativeTargetDescriptionArg>> appleTargetNode = TargetNodes.castArg(targetNode,
            AppleNativeTargetDescriptionArg.class);
    if (appleTargetNode.isPresent() && isFocusedOnTarget && !options.shouldGenerateHeaderSymlinkTreesOnly()) {
        // Use Core Data models from immediate dependencies only.
        addCoreDataModelsIntoTarget(appleTargetNode.get(), targetGroup.get());
        addSceneKitAssetsIntoTarget(appleTargetNode.get(), targetGroup.get());
    }

    if (bundle.isPresent() && isFocusedOnTarget && !options.shouldGenerateHeaderSymlinkTreesOnly()) {
        addEntitlementsPlistIntoTarget(bundle.get(), targetGroup.get());
    }

    return target;
}