aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/rules/java/JavaProvider.java
blob: 434cf2ac7006b9ee9b3303fdac82ec9b3614f8cd (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
161
162
163
// Copyright 2016 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.java;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.analysis.SkylarkProviders;
import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
import com.google.devtools.build.lib.analysis.TransitiveInfoProviderMap;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.lib.packages.SkylarkClassObject;
import com.google.devtools.build.lib.packages.SkylarkClassObjectConstructor;
import com.google.devtools.build.lib.syntax.SkylarkList;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import javax.annotation.Nullable;

/** A Skylark declared provider that encapsulates all providers that are needed by Java rules. */
@Immutable
public final class JavaProvider extends SkylarkClassObject implements TransitiveInfoProvider {

  public static final SkylarkClassObjectConstructor JAVA_PROVIDER =
      SkylarkClassObjectConstructor.createNative("java_common.provider");

  private static final Set<Class<? extends TransitiveInfoProvider>> ALLOWED_PROVIDERS =
      ImmutableSet.of(
        JavaCompilationArgsProvider.class,
        JavaSourceJarsProvider.class);

  private final TransitiveInfoProviderMap providers;

  /** Returns the instance for the provided providerClass, or <tt>null</tt> if not present. */
  @Nullable
  public <P extends TransitiveInfoProvider> P getProvider(Class<P> providerClass) {
    return providers.getProvider(providerClass);
  }

  public TransitiveInfoProviderMap getProviders() {
    return providers;
  }

  /**
   * Merges the given providers into one {@link JavaProvider}. All the providers with the same type
   * in the given list are merged into one provider that is added to the resulting
   * {@link JavaProvider}.
   */
  public static JavaProvider merge(List<JavaProvider> providers) {
    List<JavaCompilationArgsProvider> javaCompilationArgsProviders =
        JavaProvider.fetchProvidersFromList(providers, JavaCompilationArgsProvider.class);
    List<JavaSourceJarsProvider> javaSourceJarsProviders =
        JavaProvider.fetchProvidersFromList(providers, JavaSourceJarsProvider.class);

    return JavaProvider.Builder.create()
        .addProvider(
            JavaCompilationArgsProvider.class,
            JavaCompilationArgsProvider.merge(javaCompilationArgsProviders))
        .addProvider(
          JavaSourceJarsProvider.class, JavaSourceJarsProvider.merge(javaSourceJarsProviders))
        .build();
  }

  /**
   * Returns a list of providers of the specified class, fetched from the given list of
   * {@link JavaProvider}s.
   * Returns an empty list if no providers can be fetched.
   * Returns a list of the same size as the given list if the requested providers are of type
   * JavaCompilationArgsProvider.
   */
  public static <C extends TransitiveInfoProvider> List<C> fetchProvidersFromList(
      List<JavaProvider> javaProviders, Class<C> providersClass) {
    List<C> fetchedProviders = new LinkedList<>();
    for (JavaProvider javaProvider : javaProviders) {
      C provider = javaProvider.getProvider(providersClass);
      if (provider != null) {
        fetchedProviders.add(provider);
      }
    }
    return fetchedProviders;
  }

  /**
   * Returns a provider of the specified class, fetched from the specified target or, if not found,
   * from the JavaProvider of the given target. JavaProvider can be found as a declared provider
   * in SkylarkProviders.
   * Returns null if no such provider exists.
   *
   * <p>A target can either have both the specified provider and JavaProvider that encapsulates the
   * same information, or just one of them.</p>
   */
  @Nullable
  public static <T extends TransitiveInfoProvider> T getProvider(
      Class<T> providerClass, TransitiveInfoCollection target) {
    T provider = target.getProvider(providerClass);
    if (provider != null) {
      return provider;
    }
    SkylarkProviders skylarkProviders = target.getProvider(SkylarkProviders.class);
    if (skylarkProviders == null) {
      return null;
    }
    JavaProvider javaProvider =
        (JavaProvider) skylarkProviders.getDeclaredProvider(JavaProvider.JAVA_PROVIDER.getKey());
    if (javaProvider == null) {
      return null;
    }
    return javaProvider.getProvider(providerClass);
  }

  private JavaProvider(TransitiveInfoProviderMap providers) {
    super(JAVA_PROVIDER, ImmutableMap.<String, Object>of(
        "transitive_runtime_jars", SkylarkList.createImmutable(
            providers.getProvider(JavaCompilationArgsProvider.class)
                .getRecursiveJavaCompilationArgs()
                .getRuntimeJars())
    ));
    this.providers = providers;
  }

  /**
   * A Builder for {@link JavaProvider}.
   */
  public static class Builder {
    TransitiveInfoProviderMap.Builder providerMap;
   
    private Builder(TransitiveInfoProviderMap.Builder providerMap) {
      this.providerMap = providerMap;
    }

    public static Builder create() {
      return new Builder(new TransitiveInfoProviderMap.Builder());
    }

    public static Builder copyOf(JavaProvider javaProvider) {
      return new Builder(javaProvider.getProviders().toBuilder());
    }

    public <P extends TransitiveInfoProvider> Builder addProvider(
        Class<P> providerClass, TransitiveInfoProvider provider) {
      Preconditions.checkArgument(ALLOWED_PROVIDERS.contains(providerClass));
      providerMap.put(providerClass, provider);
      return this;
    }

    public JavaProvider build() {
      Preconditions.checkArgument(providerMap.contains(JavaCompilationArgsProvider.class));
      return new JavaProvider(providerMap.build());
    }
  }
}