com.facebook.buck.apple.AppleToolchainDiscovery.java Source code

Java tutorial

Introduction

Here is the source code for com.facebook.buck.apple.AppleToolchainDiscovery.java

Source

/*
 * Copyright 2014-present Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may obtain
 * a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

package com.facebook.buck.apple;

import com.dd.plist.NSDictionary;
import com.dd.plist.NSObject;
import com.dd.plist.PropertyListFormatException;
import com.dd.plist.PropertyListParser;
import com.facebook.buck.log.Logger;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;

import org.xml.sax.SAXException;

import java.io.BufferedInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.text.ParseException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Optional;

import javax.xml.parsers.ParserConfigurationException;

/**
 * Utility class to discover the location of toolchains contained inside an Xcode
 * installation.
 */
public class AppleToolchainDiscovery {

    private static final Logger LOG = Logger.get(AppleToolchainDiscovery.class);

    // Utility class; do not instantiate.
    private AppleToolchainDiscovery() {
    }

    /**
     * Given a path to an Xcode developer directory, walks through the
     * toolchains and builds a map of (identifier: path) pairs of the
     * toolchains inside.
     */
    public static ImmutableMap<String, AppleToolchain> discoverAppleToolchains(Optional<Path> developerDir,
            ImmutableList<Path> extraDirs) throws IOException {
        ImmutableMap.Builder<String, AppleToolchain> toolchainIdentifiersToToolchainsBuilder = ImmutableMap
                .builder();

        HashSet<Path> toolchainPaths = new HashSet<Path>(extraDirs);
        if (developerDir.isPresent()) {
            Path toolchainsDir = developerDir.get().resolve("Toolchains");
            LOG.debug("Searching for Xcode toolchains under %s", toolchainsDir);
            toolchainPaths.add(toolchainsDir);
        }

        for (Path toolchains : toolchainPaths) {
            if (!Files.exists(toolchains)) {
                LOG.debug("Skipping toolchain search path %s that does not exist", toolchains);
                continue;
            }

            LOG.debug("Searching for Xcode toolchains in %s", toolchains);

            try (DirectoryStream<Path> toolchainStream = Files.newDirectoryStream(toolchains, "*.xctoolchain")) {
                for (Path toolchainPath : toolchainStream) {
                    LOG.debug("Getting identifier for for Xcode toolchain under %s", toolchainPath);
                    addIdentifierForToolchain(toolchainPath, toolchainIdentifiersToToolchainsBuilder);
                }
            }
        }

        return toolchainIdentifiersToToolchainsBuilder.build();
    }

    private static void addIdentifierForToolchain(Path toolchainDir,
            ImmutableMap.Builder<String, AppleToolchain> identifierToToolchainBuilder) throws IOException {

        boolean addedToolchain = false;
        String[] potentialPlistNames = { "ToolchainInfo.plist", "Info.plist" };
        for (String plistName : potentialPlistNames) {
            try {
                Optional<AppleToolchain> toolchain = toolchainFromPlist(toolchainDir, plistName);
                if (toolchain.isPresent()) {
                    identifierToToolchainBuilder.put(toolchain.get().getIdentifier(), toolchain.get());
                    addedToolchain = true;
                    break;
                }
            } catch (FileNotFoundException | NoSuchFileException e) {
                LOG.debug("Loading toolchain from plist %s for %s failed", plistName, toolchainDir);
            }
        }

        if (!addedToolchain) {
            LOG.error("Failed to resolve info about toolchain %s from plist files %s", toolchainDir.toString(),
                    Arrays.toString(potentialPlistNames));
        }
    }

    private static Optional<AppleToolchain> toolchainFromPlist(Path toolchainDir, String plistName)
            throws IOException {
        Path toolchainInfoPlistPath = toolchainDir.resolve(plistName);
        InputStream toolchainInfoPlist = Files.newInputStream(toolchainInfoPlistPath);
        BufferedInputStream bufferedToolchainInfoPlist = new BufferedInputStream(toolchainInfoPlist);

        NSDictionary parsedToolchainInfoPlist;
        try {
            parsedToolchainInfoPlist = (NSDictionary) PropertyListParser.parse(bufferedToolchainInfoPlist);
        } catch (PropertyListFormatException | ParseException | ParserConfigurationException | SAXException e) {
            LOG.error(e, "Failed to parse %s: %s, ignoring", plistName, toolchainInfoPlistPath);
            return Optional.empty();
        }
        NSObject identifierObject = parsedToolchainInfoPlist.objectForKey("Identifier");
        if (identifierObject == null) {
            LOG.error("Identifier not found for toolchain path %s, ignoring", toolchainDir);
            return Optional.empty();
        }
        String identifier = identifierObject.toString();

        NSObject versionObject = parsedToolchainInfoPlist.objectForKey("DTSDKBuild");
        Optional<String> version = versionObject == null ? Optional.empty() : Optional.of(versionObject.toString());
        LOG.debug("Mapped SDK identifier %s to path %s", identifier, toolchainDir);

        AppleToolchain.Builder toolchainBuilder = AppleToolchain.builder();
        toolchainBuilder.setIdentifier(identifier);
        toolchainBuilder.setVersion(version);
        toolchainBuilder.setPath(toolchainDir);

        return Optional.of(toolchainBuilder.build());
    }
}