com.google.devtools.build.lib.rules.cpp.UmbrellaHeaderAction.java Source code

Java tutorial

Introduction

Here is the source code for com.google.devtools.build.lib.rules.cpp.UmbrellaHeaderAction.java

Source

// Copyright 2017 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.lib.rules.cpp;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.actions.ActionExecutionContext;
import com.google.devtools.build.lib.actions.ActionOwner;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.Artifact.ArtifactExpander;
import com.google.devtools.build.lib.analysis.actions.AbstractFileWriteAction;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.lib.util.Fingerprint;
import com.google.devtools.build.lib.vfs.PathFragment;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

/**
 * Action for generating an umbrella header. All the headers are #included in the umbrella header.
 */
@Immutable
public final class UmbrellaHeaderAction extends AbstractFileWriteAction {

    private static final String GUID = "62ea2952-bf28-92c3-efb1-e34621646910";

    // NOTE: If you add a field here, you'll likely need to add it to the cache key in computeKey().
    private final Artifact umbrellaHeader;
    private final ImmutableList<Artifact> publicHeaders;
    private final ImmutableList<PathFragment> additionalExportedHeaders;

    public UmbrellaHeaderAction(ActionOwner owner, Artifact umbrellaHeader, Iterable<Artifact> publicHeaders,
            Iterable<PathFragment> additionalExportedHeaders) {
        super(owner, ImmutableList.copyOf(Iterables.filter(publicHeaders, Artifact.IS_TREE_ARTIFACT)),
                umbrellaHeader, /*makeExecutable=*/false);
        this.umbrellaHeader = umbrellaHeader;
        this.publicHeaders = ImmutableList.copyOf(publicHeaders);
        this.additionalExportedHeaders = ImmutableList.copyOf(additionalExportedHeaders);
    }

    @Override
    public DeterministicWriter newDeterministicWriter(ActionExecutionContext ctx) {
        final ArtifactExpander artifactExpander = ctx.getArtifactExpander();
        return new DeterministicWriter() {
            @Override
            public void writeOutputFile(OutputStream out) throws IOException {
                StringBuilder content = new StringBuilder();
                HashSet<PathFragment> deduper = new HashSet<>();
                for (Artifact artifact : expandedHeaders(artifactExpander, publicHeaders)) {
                    appendHeader(content, artifact.getExecPath(), deduper);
                }
                for (PathFragment additionalExportedHeader : additionalExportedHeaders) {
                    appendHeader(content, additionalExportedHeader, deduper);
                }
                out.write(content.toString().getBytes(StandardCharsets.ISO_8859_1));
            }
        };
    }

    private static Iterable<Artifact> expandedHeaders(ArtifactExpander artifactExpander,
            Iterable<Artifact> unexpandedHeaders) {
        List<Artifact> expandedHeaders = new ArrayList<>();
        for (Artifact unexpandedHeader : unexpandedHeaders) {
            if (unexpandedHeader.isTreeArtifact()) {
                artifactExpander.expand(unexpandedHeader, expandedHeaders);
            } else {
                expandedHeaders.add(unexpandedHeader);
            }
        }
        return ImmutableList.copyOf(expandedHeaders);
    }

    private void appendHeader(StringBuilder content, PathFragment path, HashSet<PathFragment> deduper) {
        if (deduper.contains(path)) {
            return;
        }
        deduper.add(path);
        // #include headers. The #import directive is incompatible with J2ObjC segmented headers.
        content.append("#include \"").append(path).append("\"");
        content.append("\n");
    }

    @Override
    public String getMnemonic() {
        return "UmbrellaHeader";
    }

    @Override
    protected String computeKey() {
        Fingerprint f = new Fingerprint();
        f.addString(GUID);
        f.addPath(umbrellaHeader.getExecPath());
        f.addInt(publicHeaders.size());
        for (Artifact artifact : publicHeaders) {
            f.addPath(artifact.getExecPath());
        }
        f.addInt(additionalExportedHeaders.size());
        for (PathFragment path : additionalExportedHeaders) {
            f.addPath(path);
        }
        return f.hexDigestAndReset();
    }
}