com.google.devtools.build.xcode.xcodegen.XcodeGen.java Source code

Java tutorial

Introduction

Here is the source code for com.google.devtools.build.xcode.xcodegen.XcodeGen.java

Source

// Copyright 2014 The Bazel Authors. All rights reserved.
//
// 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.google.devtools.build.xcode.xcodegen;

import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.devtools.build.xcode.xcodegen.proto.XcodeGenProtos.Control;
import com.google.devtools.build.xcode.xcodegen.proto.XcodeGenProtos.TargetControl;
import com.google.devtools.common.options.Option;
import com.google.devtools.common.options.Options;
import com.google.devtools.common.options.OptionsBase;
import com.google.devtools.common.options.OptionsParser;
import com.google.devtools.common.options.OptionsParsingException;

import com.facebook.buck.apple.xcode.xcodeproj.PBXProject;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Iterator;
import java.util.List;

/**
 * Entry-point for the command-line Xcode project generator.
 */
public class XcodeGen {
    /**
     * Options for {@link XcodeGen}.
     */
    public static class XcodeGenOptions extends OptionsBase {
        @Option(name = "control", help = "Path to a control file, which contains only a binary serialized instance of "
                + "the Control protocol buffer. Required.", defaultValue = "null")
        public String control;
    }

    public static void main(String[] args) throws IOException, OptionsParsingException {
        OptionsParser parser = OptionsParser.newOptionsParser(XcodeGenOptions.class);
        parser.parse(args);
        XcodeGenOptions options = parser.getOptions(XcodeGenOptions.class);
        if (options.control == null) {
            throw new IllegalArgumentException(
                    "--control must be specified\n" + Options.getUsage(XcodeGenOptions.class));
        }
        FileSystem fileSystem = FileSystems.getDefault();

        Control controlPb;
        try (InputStream in = Files.newInputStream(fileSystem.getPath(options.control))) {
            controlPb = Control.parseFrom(in);
        }
        Path pbxprojPath = fileSystem.getPath(controlPb.getPbxproj());

        Iterator<String> srcList = allSourceFilePaths(controlPb).iterator();
        Path workspaceRoot;

        // TODO(bazel-team): Remove this if-else clause once Bazel passes in the workspace root.
        if (controlPb.hasWorkspaceRoot()) {
            workspaceRoot = fileSystem.getPath(controlPb.getWorkspaceRoot());
        } else if (!srcList.hasNext()) {
            workspaceRoot = XcodeprojGeneration.relativeWorkspaceRoot(pbxprojPath);
        } else {
            // Get the absolute path to the workspace root.

            // TODO(bazel-team): Remove this hack, possibly by converting Xcodegen to be run with
            // "bazel run" and using RUNFILES to get the workspace root. For now, this is needed to work
            // around Xcode's handling of symlinks not playing nicely with how Bazel stores output
            // artifacts in /private/var/tmp. This means a relative path from .xcodeproj in bazel-out to
            // the workspace root in .xcodeproj will not work properly at certain times during
            // Xcode/xcodebuild execution. Walking up the path of a known source file prevents having
            // to reason about a file that might only be accessible through a symlink, like a tools jar.
            Path relSourceFilePath = fileSystem.getPath(srcList.next());
            Path absSourceFilePath = relSourceFilePath.toAbsolutePath();
            workspaceRoot = absSourceFilePath;
            for (int i = 0; i < relSourceFilePath.getNameCount(); i++) {
                workspaceRoot = workspaceRoot.getParent();
            }
        }

        try (OutputStream out = Files.newOutputStream(pbxprojPath)) {
            // This workspace root here is relative to the PWD, so that the .xccurrentversion
            // files can actually be read. The other workspaceRoot is relative to the .xcodeproj
            // root or is absolute.
            Path relativeWorkspaceRoot = fileSystem.getPath(".");
            PBXProject project = XcodeprojGeneration.xcodeproj(workspaceRoot, controlPb, ImmutableList
                    .of(new CurrentVersionSetter(relativeWorkspaceRoot), new PbxReferencesGrouper(fileSystem)));
            XcodeprojGeneration.write(out, project);
        }
    }

    private static Iterable<String> allSourceFilePaths(Control control) {
        return Iterables
                .concat(Iterables.transform(control.getTargetList(), new Function<TargetControl, List<String>>() {
                    public List<String> apply(TargetControl tc) {
                        return tc.getSourceFileList();
                    }
                }));
    }
}