blob: de8dbd8b9f5bda491f13ea2e6ccc831e24688f41 [file] [log] [blame]
Lukacs Berki549bfce2016-04-22 15:29:12 +00001// Copyright 2016 The Bazel Authors. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14package com.google.devtools.build.lib.analysis;
15
Dmitry Lomov81d3c3e2017-03-22 12:58:06 +000016import com.google.common.collect.ImmutableList;
Lukacs Berki549bfce2016-04-22 15:29:12 +000017import com.google.common.collect.Iterables;
dslomovde965ac2017-07-31 21:07:51 +020018import com.google.devtools.build.lib.packages.Info;
19import com.google.devtools.build.lib.packages.Provider;
20import com.google.devtools.build.lib.packages.Provider.Key;
vladmos632d9612017-07-07 13:01:00 -040021import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
Lukacs Berki549bfce2016-04-22 15:29:12 +000022import java.util.ArrayList;
Lukacs Berki549bfce2016-04-22 15:29:12 +000023import java.util.List;
dslomovf6a7e5a2017-07-05 07:23:31 -040024import java.util.function.Consumer;
Lukacs Berki549bfce2016-04-22 15:29:12 +000025
26/**
27 * A single dependency with its configured target and aspects merged together.
28 *
Googler94d35de2016-09-16 15:21:39 +000029 * <p>This is an ephemeral object created only for the analysis of a single configured target. After
30 * that configured target is analyzed, this is thrown away.
Lukacs Berki549bfce2016-04-22 15:29:12 +000031 */
Googler94d35de2016-09-16 15:21:39 +000032public final class MergedConfiguredTarget extends AbstractConfiguredTarget {
Lukacs Berki549bfce2016-04-22 15:29:12 +000033 private final ConfiguredTarget base;
Googler94d35de2016-09-16 15:21:39 +000034 private final TransitiveInfoProviderMap providers;
Lukacs Berki549bfce2016-04-22 15:29:12 +000035
Dmitry Lomov9b2fc5c2016-11-11 11:18:48 +000036 /**
37 * This exception is thrown when configured targets and aspects
38 * being merged provide duplicate things that they shouldn't
39 * (output groups or providers).
40 */
41 public static final class DuplicateException extends Exception {
42 public DuplicateException(String message) {
43 super(message);
44 }
45 }
46
Dmitry Lomov57784442017-02-23 10:18:09 +000047 private MergedConfiguredTarget(ConfiguredTarget base, TransitiveInfoProviderMap providers) {
Lukacs Berki549bfce2016-04-22 15:29:12 +000048 super(base.getTarget(), base.getConfiguration());
49 this.base = base;
50 this.providers = providers;
51 }
52
Lukacs Berki549bfce2016-04-22 15:29:12 +000053 @Override
54 public <P extends TransitiveInfoProvider> P getProvider(Class<P> providerClass) {
55 AnalysisUtils.checkProvider(providerClass);
56
Googler94d35de2016-09-16 15:21:39 +000057 P provider = providers.getProvider(providerClass);
Lukacs Berki549bfce2016-04-22 15:29:12 +000058 if (provider == null) {
59 provider = base.getProvider(providerClass);
60 }
61
Googler94d35de2016-09-16 15:21:39 +000062 return provider;
Lukacs Berki549bfce2016-04-22 15:29:12 +000063 }
64
dslomovf6a7e5a2017-07-05 07:23:31 -040065 @Override
66 protected void addExtraSkylarkKeys(Consumer<String> result) {
67 if (base instanceof AbstractConfiguredTarget) {
68 ((AbstractConfiguredTarget) base).addExtraSkylarkKeys(result);
69 }
70 for (int i = 0; i < providers.getProviderCount(); i++) {
71 Object classAt = providers.getProviderKeyAt(i);
72 if (classAt instanceof String) {
73 result.accept((String) classAt);
74 }
75 }
76 }
77
78 @Override
dslomovde965ac2017-07-31 21:07:51 +020079 protected Info rawGetSkylarkProvider(Provider.Key providerKey) {
80 Info provider = providers.getProvider(providerKey);
dslomovf6a7e5a2017-07-05 07:23:31 -040081 if (provider == null) {
82 provider = base.get(providerKey);
83 }
84 return provider;
85 }
86
87 @Override
88 protected Object rawGetSkylarkProvider(String providerKey) {
89 Object provider = providers.getProvider(providerKey);
90 if (provider == null) {
91 provider = base.get(providerKey);
92 }
93 return provider;
94 }
95
Googler94d35de2016-09-16 15:21:39 +000096 /** Creates an instance based on a configured target and a set of aspects. */
Dmitry Lomov9b2fc5c2016-11-11 11:18:48 +000097 public static ConfiguredTarget of(ConfiguredTarget base, Iterable<ConfiguredAspect> aspects)
98 throws DuplicateException {
Lukacs Berki549bfce2016-04-22 15:29:12 +000099 if (Iterables.isEmpty(aspects)) {
100 // If there are no aspects, don't bother with creating a proxy object
101 return base;
102 }
103
Lukacs Berki549bfce2016-04-22 15:29:12 +0000104 // Merge output group providers.
105 OutputGroupProvider mergedOutputGroupProvider =
dslomovf9697342017-05-02 16:26:39 +0200106 OutputGroupProvider.merge(getAllOutputGroupProviders(base, aspects));
Lukacs Berki549bfce2016-04-22 15:29:12 +0000107
Lukacs Berki549bfce2016-04-22 15:29:12 +0000108 // Merge extra-actions provider.
109 ExtraActionArtifactsProvider mergedExtraActionProviders = ExtraActionArtifactsProvider.merge(
110 getAllProviders(base, aspects, ExtraActionArtifactsProvider.class));
111
Googler4b7aae42017-05-04 17:16:09 -0400112 TransitiveInfoProviderMapBuilder aspectProviders = new TransitiveInfoProviderMapBuilder();
dslomov202c5b32017-05-03 12:06:58 +0200113 if (mergedOutputGroupProvider != null) {
dslomov11da2202017-07-27 23:48:56 +0200114 aspectProviders.put(mergedOutputGroupProvider);
dslomov202c5b32017-05-03 12:06:58 +0200115 }
Lukacs Berki549bfce2016-04-22 15:29:12 +0000116 if (mergedExtraActionProviders != null) {
Googler94d35de2016-09-16 15:21:39 +0000117 aspectProviders.add(mergedExtraActionProviders);
Lukacs Berki549bfce2016-04-22 15:29:12 +0000118 }
119
120 for (ConfiguredAspect aspect : aspects) {
Googler4e0a5cb2017-04-09 17:58:18 -0400121 TransitiveInfoProviderMap providers = aspect.getProviders();
122 for (int i = 0; i < providers.getProviderCount(); ++i) {
dslomovf6a7e5a2017-07-05 07:23:31 -0400123 Object providerKey = providers.getProviderKeyAt(i);
dslomov11da2202017-07-27 23:48:56 +0200124 if (OutputGroupProvider.SKYLARK_CONSTRUCTOR.getKey().equals(providerKey)
dslomovf6a7e5a2017-07-05 07:23:31 -0400125 || ExtraActionArtifactsProvider.class.equals(providerKey)) {
Lukacs Berki549bfce2016-04-22 15:29:12 +0000126 continue;
127 }
128
dslomovf6a7e5a2017-07-05 07:23:31 -0400129 if (providerKey instanceof Class<?>) {
130 @SuppressWarnings("unchecked")
131 Class<? extends TransitiveInfoProvider> providerClass =
132 (Class<? extends TransitiveInfoProvider>) providerKey;
133 if (base.getProvider(providerClass) != null
134 || aspectProviders.contains(providerClass)) {
135 throw new DuplicateException("Provider " + providerKey + " provided twice");
136 }
137 aspectProviders.put(
138 providerClass, (TransitiveInfoProvider) providers.getProviderInstanceAt(i));
139 } else if (providerKey instanceof String) {
140 String legacyId = (String) providerKey;
141 if (base.get(legacyId) != null || aspectProviders.contains(legacyId)) {
142 throw new DuplicateException("Provider " + legacyId + " provided twice");
143 }
144 aspectProviders.put(legacyId, providers.getProviderInstanceAt(i));
dslomovde965ac2017-07-31 21:07:51 +0200145 } else if (providerKey instanceof Provider.Key) {
146 Provider.Key key = (Key) providerKey;
dslomovf6a7e5a2017-07-05 07:23:31 -0400147 if (base.get(key) != null || aspectProviders.contains(key)) {
148 throw new DuplicateException("Provider " + key + " provided twice");
149 }
dslomovde965ac2017-07-31 21:07:51 +0200150 aspectProviders.put((Info) providers.getProviderInstanceAt(i));
Lukacs Berki549bfce2016-04-22 15:29:12 +0000151 }
Lukacs Berki549bfce2016-04-22 15:29:12 +0000152 }
153 }
Dmitry Lomov57784442017-02-23 10:18:09 +0000154 return new MergedConfiguredTarget(base, aspectProviders.build());
Lukacs Berki549bfce2016-04-22 15:29:12 +0000155 }
156
dslomovf9697342017-05-02 16:26:39 +0200157 private static ImmutableList<OutputGroupProvider> getAllOutputGroupProviders(
158 ConfiguredTarget base, Iterable<ConfiguredAspect> aspects) {
159 OutputGroupProvider baseProvider = OutputGroupProvider.get(base);
160 ImmutableList.Builder<OutputGroupProvider> providers = ImmutableList.builder();
161 if (baseProvider != null) {
162 providers.add(baseProvider);
163 }
164
165 for (ConfiguredAspect configuredAspect : aspects) {
dslomov11da2202017-07-27 23:48:56 +0200166 OutputGroupProvider aspectProvider = OutputGroupProvider.get(configuredAspect);
dslomovf9697342017-05-02 16:26:39 +0200167 if (aspectProvider == null) {
168 continue;
169 }
170 providers.add(aspectProvider);
171 }
172 return providers.build();
173 }
174
Lukacs Berki549bfce2016-04-22 15:29:12 +0000175 private static <T extends TransitiveInfoProvider> List<T> getAllProviders(
176 ConfiguredTarget base, Iterable<ConfiguredAspect> aspects, Class<T> providerClass) {
177 T baseProvider = base.getProvider(providerClass);
178 List<T> providers = new ArrayList<>();
179 if (baseProvider != null) {
180 providers.add(baseProvider);
181 }
182
183 for (ConfiguredAspect configuredAspect : aspects) {
Googler94d35de2016-09-16 15:21:39 +0000184 T aspectProvider = configuredAspect.getProvider(providerClass);
Lukacs Berki549bfce2016-04-22 15:29:12 +0000185 if (aspectProvider == null) {
186 continue;
187 }
188 providers.add(aspectProvider);
189 }
190 return providers;
191 }
vladmos632d9612017-07-07 13:01:00 -0400192
193 @Override
194 public void repr(SkylarkPrinter printer) {
195 printer.append("<merged target " + getLabel() + ">");
196 }
Lukacs Berki549bfce2016-04-22 15:29:12 +0000197}