aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/actions/ActionInputHelper.java
blob: b4c6121265c58a987f1012733ebf043021894c0f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// 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.base.Preconditions;
import com.google.common.collect.Collections2;
import com.google.common.collect.Iterables;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

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

  @VisibleForTesting
  public static Artifact.MiddlemanExpander actionGraphMiddlemanExpander(
      final ActionGraph actionGraph) {
    return new Artifact.MiddlemanExpander() {
      @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);
        Action 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);
  }

  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);
  }

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

    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, middlemanExpander);
    return result;
  }

  /** Formatter for execPath String output. Public because 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);
  }
}