com.google.devtools.build.lib.actions.ActionInputHelper.java Source code

Java tutorial

Introduction

Here is the source code for com.google.devtools.build.lib.actions.ActionInputHelper.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.lib.actions;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.actions.Artifact.ArtifactExpander;
import com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact;
import com.google.devtools.build.lib.util.Preconditions;
import com.google.devtools.build.lib.vfs.PathFragment;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;

/**
 * Helper utility to create ActionInput instances.
 */
public final class ActionInputHelper {
    private ActionInputHelper() {
    }

    @VisibleForTesting
    public static ArtifactExpander actionGraphArtifactExpander(final ActionGraph actionGraph) {
        return new ArtifactExpander() {
            @Override
            public void expand(Artifact mm, Collection<? super Artifact> output) {
                // Skyframe is stricter in that it checks that "mm" is a input of the action, because
                // it cannot expand arbitrary middlemen without access to a global action graph.
                // We could check this constraint here too, but it seems unnecessary. This code is
                // going away anyway.
                Preconditions.checkArgument(mm.isMiddlemanArtifact(), "%s is not a middleman artifact", mm);
                ActionAnalysisMetadata middlemanAction = actionGraph.getGeneratingAction(mm);
                Preconditions.checkState(middlemanAction != null, mm);
                // TODO(bazel-team): Consider expanding recursively or throwing an exception here.
                // Most likely, this code will cause silent errors if we ever have a middleman that
                // contains a middleman.
                if (middlemanAction.getActionType() == Action.MiddlemanType.AGGREGATING_MIDDLEMAN) {
                    Artifact.addNonMiddlemanArtifacts(middlemanAction.getInputs(), output,
                            Functions.<Artifact>identity());
                }

            }
        };
    }

    /**
     * Most ActionInputs are created and never used again. On the off chance that one is, however, we
     * implement equality via path comparison. Since file caches are keyed by ActionInput, equality
     * checking does come up.
     */
    private static class BasicActionInput implements ActionInput {
        private final String path;

        public BasicActionInput(String path) {
            this.path = Preconditions.checkNotNull(path);
        }

        @Override
        public String getExecPathString() {
            return path;
        }

        @Override
        public int hashCode() {
            return path.hashCode();
        }

        @Override
        public boolean equals(Object other) {
            if (this == other) {
                return true;
            }
            if (other == null) {
                return false;
            }
            if (!this.getClass().equals(other.getClass())) {
                return false;
            }
            return this.path.equals(((BasicActionInput) other).path);
        }

        @Override
        public String toString() {
            return "BasicActionInput: " + path;
        }
    }

    /**
     * Creates an ActionInput with just the given relative path and no digest.
     *
     * @param path the relative path of the input.
     * @return a ActionInput.
     */
    public static ActionInput fromPath(String path) {
        return new BasicActionInput(path);
    }

    /**
     * Creates an ActionInput with just the given relative path and no digest.
     *
     * @param path the relative path of the input.
     * @return a ActionInput.
     */
    public static ActionInput fromPath(PathFragment path) {
        return fromPath(path.getPathString());
    }

    private static final Function<String, ActionInput> FROM_PATH = new Function<String, ActionInput>() {
        @Override
        public ActionInput apply(String path) {
            return fromPath(path);
        }
    };

    /**
     * Creates a sequence of {@link ActionInput}s from a sequence of string paths.
     */
    public static Collection<ActionInput> fromPaths(Collection<String> paths) {
        return Collections2.transform(paths, FROM_PATH);
    }

    /**
     * Instantiates a concrete TreeFileArtifact with the given parent Artifact and path
     * relative to that Artifact.
     */
    public static TreeFileArtifact treeFileArtifact(Artifact parent, PathFragment relativePath) {
        Preconditions.checkState(parent.isTreeArtifact(), "Given parent %s must be a TreeArtifact", parent);
        return new TreeFileArtifact(parent, relativePath);
    }

    public static TreeFileArtifact treeFileArtifact(Artifact parent, PathFragment relativePath,
            ArtifactOwner artifactOwner) {
        Preconditions.checkState(parent.isTreeArtifact(), "Given parent %s must be a TreeArtifact", parent);
        return new TreeFileArtifact(parent, relativePath, artifactOwner);
    }

    /**
     * Instantiates a concrete TreeFileArtifact with the given parent Artifact and path
     * relative to that Artifact.
     */
    public static TreeFileArtifact treeFileArtifact(Artifact parent, String relativePath) {
        return treeFileArtifact(parent, new PathFragment(relativePath));
    }

    /** Returns an Iterable of TreeFileArtifacts with the given parent and parent relative paths. */
    public static Iterable<TreeFileArtifact> asTreeFileArtifacts(final Artifact parent,
            Iterable<? extends PathFragment> parentRelativePaths) {
        Preconditions.checkState(parent.isTreeArtifact(), "Given parent %s must be a TreeArtifact", parent);
        return Iterables.transform(parentRelativePaths, new Function<PathFragment, TreeFileArtifact>() {
            @Override
            public TreeFileArtifact apply(PathFragment pathFragment) {
                return treeFileArtifact(parent, pathFragment);
            }
        });
    }

    /** Returns a Set of TreeFileArtifacts with the given parent and parent-relative paths. */
    public static Set<TreeFileArtifact> asTreeFileArtifacts(final Artifact parent,
            Set<? extends PathFragment> parentRelativePaths) {
        Preconditions.checkState(parent.isTreeArtifact(), "Given parent %s must be a TreeArtifact", parent);

        ImmutableSet.Builder<TreeFileArtifact> builder = ImmutableSet.builder();
        for (PathFragment path : parentRelativePaths) {
            builder.add(treeFileArtifact(parent, path));
        }

        return builder.build();
    }

    /**
     * Expands middleman artifacts in a sequence of {@link ActionInput}s.
     *
     * <p>Non-middleman artifacts are returned untouched.
     */
    public static List<ActionInput> expandArtifacts(Iterable<? extends ActionInput> inputs,
            ArtifactExpander artifactExpander) {

        List<ActionInput> result = new ArrayList<>();
        List<Artifact> containedArtifacts = new ArrayList<>();
        for (ActionInput input : inputs) {
            if (!(input instanceof Artifact)) {
                result.add(input);
                continue;
            }
            containedArtifacts.add((Artifact) input);
        }
        Artifact.addExpandedArtifacts(containedArtifacts, result, artifactExpander);
        return result;
    }

    /** Formatter for execPath String output. Public because {@link Artifact} uses it directly. */
    public static final Function<ActionInput, String> EXEC_PATH_STRING_FORMATTER = new Function<ActionInput, String>() {
        @Override
        public String apply(ActionInput input) {
            return input.getExecPathString();
        }
    };

    public static Iterable<String> toExecPaths(Iterable<? extends ActionInput> artifacts) {
        return Iterables.transform(artifacts, EXEC_PATH_STRING_FORMATTER);
    }
}