Damien Martin-Guillerez | f88f4d8 | 2015-09-25 13:56:55 +0000 | [diff] [blame] | 1 | // Copyright 2014 The Bazel Authors. All rights reserved. |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 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. |
| 14 | |
| 15 | package com.google.devtools.build.lib.analysis; |
| 16 | |
Carmi Grushko | eaaa9d0d | 2015-11-17 01:54:45 +0000 | [diff] [blame] | 17 | import static com.google.devtools.build.lib.analysis.ExtraActionUtils.createExtraActionProvider; |
| 18 | |
Dmitry Lomov | 2473b9f | 2015-09-14 08:53:10 +0000 | [diff] [blame] | 19 | import com.google.common.annotations.VisibleForTesting; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 20 | import com.google.common.collect.ImmutableMap; |
Carmi Grushko | 4076e44 | 2016-01-21 20:05:42 +0000 | [diff] [blame] | 21 | import com.google.common.collect.ImmutableSet; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 22 | import com.google.common.collect.UnmodifiableIterator; |
Rumou Duan | 33bab46 | 2016-04-25 17:55:12 +0000 | [diff] [blame] | 23 | import com.google.devtools.build.lib.actions.ActionAnalysisMetadata; |
Dmitry Lomov | e2033b1 | 2015-08-19 16:57:49 +0000 | [diff] [blame] | 24 | import com.google.devtools.build.lib.actions.Artifact; |
| 25 | import com.google.devtools.build.lib.collect.nestedset.NestedSet; |
| 26 | import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 27 | import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; |
Dmitry Lomov | 0b832ce | 2015-10-20 10:03:14 +0000 | [diff] [blame] | 28 | import com.google.devtools.build.lib.events.Location; |
Dmitry Lomov | dce0170 | 2016-11-28 15:51:32 +0000 | [diff] [blame] | 29 | import com.google.devtools.build.lib.packages.AspectClass; |
Dmitry Lomov | 1575652 | 2016-12-16 16:52:37 +0000 | [diff] [blame] | 30 | import com.google.devtools.build.lib.packages.AspectDescriptor; |
Dmitry Lomov | dce0170 | 2016-11-28 15:51:32 +0000 | [diff] [blame] | 31 | import com.google.devtools.build.lib.packages.AspectParameters; |
Dmitry Lomov | 654717f | 2017-03-02 14:39:52 +0000 | [diff] [blame] | 32 | import com.google.devtools.build.lib.packages.ClassObjectConstructor; |
dslomov | f969734 | 2017-05-02 16:26:39 +0200 | [diff] [blame^] | 33 | import com.google.devtools.build.lib.packages.ClassObjectConstructor.Key; |
Dmitry Lomov | 37a1c1c | 2016-09-01 09:11:02 +0000 | [diff] [blame] | 34 | import com.google.devtools.build.lib.packages.SkylarkClassObject; |
Vladimir Moskva | 6c28fe9 | 2017-03-03 12:55:08 +0000 | [diff] [blame] | 35 | import com.google.devtools.build.lib.packages.SkylarkClassObjectConstructor; |
Dmitry Lomov | 2aa1a98 | 2015-10-20 12:18:36 +0000 | [diff] [blame] | 36 | import com.google.devtools.build.lib.syntax.EvalException; |
Mark Schaller | 6df8179 | 2015-12-10 18:47:47 +0000 | [diff] [blame] | 37 | import com.google.devtools.build.lib.util.Preconditions; |
Googler | 94d35de | 2016-09-16 15:21:39 +0000 | [diff] [blame] | 38 | import java.util.Arrays; |
dslomov | f969734 | 2017-05-02 16:26:39 +0200 | [diff] [blame^] | 39 | import java.util.LinkedHashMap; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 40 | import java.util.Map; |
Dmitry Lomov | e2033b1 | 2015-08-19 16:57:49 +0000 | [diff] [blame] | 41 | import java.util.TreeMap; |
Dmitry Lomov | e2033b1 | 2015-08-19 16:57:49 +0000 | [diff] [blame] | 42 | import javax.annotation.Nullable; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 43 | |
| 44 | /** |
| 45 | * Extra information about a configured target computed on request of a dependent. |
| 46 | * |
| 47 | * <p>Analogous to {@link ConfiguredTarget}: contains a bunch of transitive info providers, which |
| 48 | * are merged with the providers of the associated configured target before they are passed to |
| 49 | * the configured target factories that depend on the configured target to which this aspect is |
| 50 | * added. |
| 51 | * |
| 52 | * <p>Aspects are created alongside configured targets on request from dependents. |
Lukacs Berki | 2300cd6 | 2016-05-19 11:06:37 +0000 | [diff] [blame] | 53 | * |
| 54 | * <p>For more information about aspects, see |
| 55 | * {@link com.google.devtools.build.lib.packages.AspectClass}. |
| 56 | * |
| 57 | * @see com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory |
| 58 | * @see com.google.devtools.build.lib.packages.AspectClass |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 59 | */ |
| 60 | @Immutable |
Dmitry Lomov | b487ac6 | 2015-11-09 13:09:12 +0000 | [diff] [blame] | 61 | public final class ConfiguredAspect implements Iterable<TransitiveInfoProvider> { |
Googler | 94d35de | 2016-09-16 15:21:39 +0000 | [diff] [blame] | 62 | private final TransitiveInfoProviderMap providers; |
Dmitry Lomov | dce0170 | 2016-11-28 15:51:32 +0000 | [diff] [blame] | 63 | private final AspectDescriptor descriptor; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 64 | |
Dmitry Lomov | dce0170 | 2016-11-28 15:51:32 +0000 | [diff] [blame] | 65 | private ConfiguredAspect(AspectDescriptor descriptor, TransitiveInfoProviderMap providers) { |
| 66 | this.descriptor = descriptor; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 67 | this.providers = providers; |
| 68 | } |
| 69 | |
| 70 | /** |
Dmitry Lomov | e2033b1 | 2015-08-19 16:57:49 +0000 | [diff] [blame] | 71 | * Returns the aspect name. |
| 72 | */ |
| 73 | public String getName() { |
Dmitry Lomov | dce0170 | 2016-11-28 15:51:32 +0000 | [diff] [blame] | 74 | return descriptor.getAspectClass().getName(); |
| 75 | } |
| 76 | |
| 77 | /** |
| 78 | * The aspect descriptor originating this ConfiguredAspect. |
| 79 | */ |
| 80 | public AspectDescriptor getDescriptor() { |
| 81 | return descriptor; |
Dmitry Lomov | e2033b1 | 2015-08-19 16:57:49 +0000 | [diff] [blame] | 82 | } |
| 83 | |
Googler | 94d35de | 2016-09-16 15:21:39 +0000 | [diff] [blame] | 84 | /** Returns the providers created by the aspect. */ |
| 85 | public TransitiveInfoProviderMap getProviders() { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 86 | return providers; |
| 87 | } |
| 88 | |
Dmitry Lomov | e2033b1 | 2015-08-19 16:57:49 +0000 | [diff] [blame] | 89 | @Nullable |
Dmitry Lomov | 2473b9f | 2015-09-14 08:53:10 +0000 | [diff] [blame] | 90 | @VisibleForTesting |
| 91 | public <P extends TransitiveInfoProvider> P getProvider(Class<P> providerClass) { |
Googler | 94d35de | 2016-09-16 15:21:39 +0000 | [diff] [blame] | 92 | return providers.getProvider(providerClass); |
Dmitry Lomov | e2033b1 | 2015-08-19 16:57:49 +0000 | [diff] [blame] | 93 | } |
| 94 | |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 95 | @Override |
| 96 | public UnmodifiableIterator<TransitiveInfoProvider> iterator() { |
| 97 | return providers.values().iterator(); |
| 98 | } |
| 99 | |
Lukacs Berki | 549bfce | 2016-04-22 15:29:12 +0000 | [diff] [blame] | 100 | public static ConfiguredAspect forAlias(ConfiguredAspect real) { |
Dmitry Lomov | dce0170 | 2016-11-28 15:51:32 +0000 | [diff] [blame] | 101 | return new ConfiguredAspect(real.descriptor, real.getProviders()); |
Lukacs Berki | 549bfce | 2016-04-22 15:29:12 +0000 | [diff] [blame] | 102 | } |
| 103 | |
Dmitry Lomov | 6cd9897 | 2017-03-01 15:44:00 +0000 | [diff] [blame] | 104 | public static ConfiguredAspect forNonapplicableTarget(AspectDescriptor descriptor) { |
| 105 | return new ConfiguredAspect(descriptor, TransitiveInfoProviderMap.of()); |
| 106 | } |
| 107 | |
dslomov | 99ea6b4 | 2017-04-25 17:46:17 +0200 | [diff] [blame] | 108 | public static Builder builder( |
| 109 | AspectClass aspectClass, AspectParameters parameters, RuleContext ruleContext) { |
| 110 | return new Builder(aspectClass, parameters, ruleContext); |
| 111 | } |
| 112 | |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 113 | /** |
Dmitry Lomov | b487ac6 | 2015-11-09 13:09:12 +0000 | [diff] [blame] | 114 | * Builder for {@link ConfiguredAspect}. |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 115 | */ |
| 116 | public static class Builder { |
Googler | 94d35de | 2016-09-16 15:21:39 +0000 | [diff] [blame] | 117 | private final TransitiveInfoProviderMap.Builder providers = TransitiveInfoProviderMap.builder(); |
Dmitry Lomov | e2033b1 | 2015-08-19 16:57:49 +0000 | [diff] [blame] | 118 | private final Map<String, NestedSetBuilder<Artifact>> outputGroupBuilders = new TreeMap<>(); |
Dmitry Lomov | 0b832ce | 2015-10-20 10:03:14 +0000 | [diff] [blame] | 119 | private final ImmutableMap.Builder<String, Object> skylarkProviderBuilder = |
| 120 | ImmutableMap.builder(); |
dslomov | f969734 | 2017-05-02 16:26:39 +0200 | [diff] [blame^] | 121 | private final LinkedHashMap<Key, SkylarkClassObject> |
| 122 | skylarkDeclaredProvidersBuilder = new LinkedHashMap<>(); |
Carmi Grushko | eaaa9d0d | 2015-11-17 01:54:45 +0000 | [diff] [blame] | 123 | private final RuleContext ruleContext; |
Dmitry Lomov | dce0170 | 2016-11-28 15:51:32 +0000 | [diff] [blame] | 124 | private final AspectDescriptor descriptor; |
Dmitry Lomov | e2033b1 | 2015-08-19 16:57:49 +0000 | [diff] [blame] | 125 | |
Dmitry Lomov | dce0170 | 2016-11-28 15:51:32 +0000 | [diff] [blame] | 126 | public Builder( |
| 127 | AspectClass aspectClass, |
| 128 | AspectParameters parameters, |
| 129 | RuleContext context) { |
| 130 | this(new AspectDescriptor(aspectClass, parameters), context); |
| 131 | } |
| 132 | |
| 133 | public Builder(AspectDescriptor descriptor, RuleContext ruleContext) { |
| 134 | this.descriptor = descriptor; |
Carmi Grushko | eaaa9d0d | 2015-11-17 01:54:45 +0000 | [diff] [blame] | 135 | this.ruleContext = ruleContext; |
Dmitry Lomov | e2033b1 | 2015-08-19 16:57:49 +0000 | [diff] [blame] | 136 | } |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 137 | |
Googler | 94d35de | 2016-09-16 15:21:39 +0000 | [diff] [blame] | 138 | public <T extends TransitiveInfoProvider> Builder addProvider( |
| 139 | Class<? extends T> providerClass, T provider) { |
| 140 | Preconditions.checkNotNull(provider); |
| 141 | checkProviderClass(providerClass); |
| 142 | providers.put(providerClass, provider); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 143 | return this; |
| 144 | } |
| 145 | |
Googler | 94d35de | 2016-09-16 15:21:39 +0000 | [diff] [blame] | 146 | /** Adds a provider to the aspect. */ |
| 147 | public Builder addProvider(TransitiveInfoProvider provider) { |
| 148 | Preconditions.checkNotNull(provider); |
| 149 | addProvider(TransitiveInfoProviderMap.getEffectiveProviderClass(provider), provider); |
| 150 | return this; |
| 151 | } |
| 152 | |
| 153 | private void checkProviderClass(Class<? extends TransitiveInfoProvider> providerClass) { |
| 154 | Preconditions.checkNotNull(providerClass); |
| 155 | Preconditions.checkArgument( |
| 156 | !SkylarkProviders.class.equals(providerClass), |
| 157 | "Do not provide SkylarkProviders directly"); |
| 158 | } |
| 159 | |
| 160 | /** Adds providers to the aspect. */ |
| 161 | public Builder addProviders(TransitiveInfoProviderMap providers) { |
| 162 | for (Map.Entry<Class<? extends TransitiveInfoProvider>, TransitiveInfoProvider> entry : |
Carmi Grushko | 261f5bb | 2015-12-09 19:38:38 +0000 | [diff] [blame] | 163 | providers.entrySet()) { |
Googler | 94d35de | 2016-09-16 15:21:39 +0000 | [diff] [blame] | 164 | addProvider(entry.getKey(), entry.getKey().cast(entry.getValue())); |
| 165 | } |
| 166 | return this; |
| 167 | } |
| 168 | |
| 169 | /** Adds providers to the aspect. */ |
| 170 | public Builder addProviders(TransitiveInfoProvider... providers) { |
| 171 | return addProviders(Arrays.asList(providers)); |
| 172 | } |
| 173 | |
| 174 | /** Adds providers to the aspect. */ |
| 175 | public Builder addProviders(Iterable<TransitiveInfoProvider> providers) { |
| 176 | for (TransitiveInfoProvider provider : providers) { |
| 177 | addProvider(provider); |
Carmi Grushko | b8f0e86 | 2015-11-23 23:26:15 +0000 | [diff] [blame] | 178 | } |
| 179 | return this; |
| 180 | } |
| 181 | |
Carmi Grushko | 65ac355 | 2015-08-21 16:43:26 +0000 | [diff] [blame] | 182 | /** |
Dmitry Lomov | e2033b1 | 2015-08-19 16:57:49 +0000 | [diff] [blame] | 183 | * Adds a set of files to an output group. |
| 184 | */ |
| 185 | public Builder addOutputGroup(String name, NestedSet<Artifact> artifacts) { |
| 186 | NestedSetBuilder<Artifact> nestedSetBuilder = outputGroupBuilders.get(name); |
| 187 | if (nestedSetBuilder == null) { |
| 188 | nestedSetBuilder = NestedSetBuilder.<Artifact>stableOrder(); |
| 189 | outputGroupBuilders.put(name, nestedSetBuilder); |
| 190 | } |
| 191 | nestedSetBuilder.addTransitive(artifacts); |
| 192 | return this; |
| 193 | } |
| 194 | |
Googler | 63ce8f2 | 2017-01-09 15:32:16 +0000 | [diff] [blame] | 195 | public Builder addSkylarkTransitiveInfo(String name, Object value) { |
Googler | 63ce8f2 | 2017-01-09 15:32:16 +0000 | [diff] [blame] | 196 | skylarkProviderBuilder.put(name, value); |
| 197 | return this; |
| 198 | } |
| 199 | |
Dmitry Lomov | 2aa1a98 | 2015-10-20 12:18:36 +0000 | [diff] [blame] | 200 | public Builder addSkylarkTransitiveInfo(String name, Object value, Location loc) |
| 201 | throws EvalException { |
Dmitry Lomov | 0b832ce | 2015-10-20 10:03:14 +0000 | [diff] [blame] | 202 | skylarkProviderBuilder.put(name, value); |
| 203 | return this; |
| 204 | } |
| 205 | |
Vladimir Moskva | 6c28fe9 | 2017-03-03 12:55:08 +0000 | [diff] [blame] | 206 | public Builder addSkylarkDeclaredProvider(SkylarkClassObject declaredProvider, Location loc) |
| 207 | throws EvalException { |
| 208 | ClassObjectConstructor constructor = declaredProvider.getConstructor(); |
Vladimir Moskva | 6c28fe9 | 2017-03-03 12:55:08 +0000 | [diff] [blame] | 209 | if (!constructor.isExported()) { |
| 210 | throw new EvalException( |
| 211 | constructor.getLocation(), "All providers must be top level values"); |
| 212 | } |
| 213 | skylarkDeclaredProvidersBuilder.put(constructor.getKey(), declaredProvider); |
| 214 | return this; |
| 215 | } |
| 216 | |
dslomov | f969734 | 2017-05-02 16:26:39 +0200 | [diff] [blame^] | 217 | public Builder addNativeDeclaredProvider(SkylarkClassObject declaredProvider) { |
| 218 | ClassObjectConstructor constructor = declaredProvider.getConstructor(); |
| 219 | Preconditions.checkState(constructor.isExported()); |
| 220 | skylarkDeclaredProvidersBuilder.put(constructor.getKey(), declaredProvider); |
| 221 | return this; |
| 222 | } |
| 223 | |
| 224 | |
Dmitry Lomov | b487ac6 | 2015-11-09 13:09:12 +0000 | [diff] [blame] | 225 | public ConfiguredAspect build() { |
Dmitry Lomov | e2033b1 | 2015-08-19 16:57:49 +0000 | [diff] [blame] | 226 | if (!outputGroupBuilders.isEmpty()) { |
| 227 | ImmutableMap.Builder<String, NestedSet<Artifact>> outputGroups = ImmutableMap.builder(); |
| 228 | for (Map.Entry<String, NestedSetBuilder<Artifact>> entry : outputGroupBuilders.entrySet()) { |
| 229 | outputGroups.put(entry.getKey(), entry.getValue().build()); |
| 230 | } |
| 231 | |
dslomov | f969734 | 2017-05-02 16:26:39 +0200 | [diff] [blame^] | 232 | if (skylarkDeclaredProvidersBuilder.containsKey( |
| 233 | OutputGroupProvider.SKYLARK_CONSTRUCTOR.getKey())) { |
Dmitry Lomov | e2033b1 | 2015-08-19 16:57:49 +0000 | [diff] [blame] | 234 | throw new IllegalStateException( |
| 235 | "OutputGroupProvider was provided explicitly; do not use addOutputGroup"); |
| 236 | } |
dslomov | f969734 | 2017-05-02 16:26:39 +0200 | [diff] [blame^] | 237 | skylarkDeclaredProvidersBuilder.put( |
| 238 | OutputGroupProvider.SKYLARK_CONSTRUCTOR.getKey(), |
| 239 | new OutputGroupProvider(outputGroups.build())); |
Dmitry Lomov | e2033b1 | 2015-08-19 16:57:49 +0000 | [diff] [blame] | 240 | } |
| 241 | |
Dmitry Lomov | 0b832ce | 2015-10-20 10:03:14 +0000 | [diff] [blame] | 242 | ImmutableMap<String, Object> skylarkProvidersMap = skylarkProviderBuilder.build(); |
Vladimir Moskva | 6c28fe9 | 2017-03-03 12:55:08 +0000 | [diff] [blame] | 243 | ImmutableMap<SkylarkClassObjectConstructor.Key, SkylarkClassObject> |
dslomov | f969734 | 2017-05-02 16:26:39 +0200 | [diff] [blame^] | 244 | skylarkDeclaredProvidersMap = ImmutableMap.copyOf(skylarkDeclaredProvidersBuilder); |
Vladimir Moskva | 6c28fe9 | 2017-03-03 12:55:08 +0000 | [diff] [blame] | 245 | if (!skylarkProvidersMap.isEmpty() || !skylarkDeclaredProvidersMap.isEmpty()) { |
| 246 | providers.add(new SkylarkProviders(skylarkProvidersMap, skylarkDeclaredProvidersMap)); |
Dmitry Lomov | 0b832ce | 2015-10-20 10:03:14 +0000 | [diff] [blame] | 247 | } |
| 248 | |
Carmi Grushko | 4076e44 | 2016-01-21 20:05:42 +0000 | [diff] [blame] | 249 | addProvider( |
Carmi Grushko | 4076e44 | 2016-01-21 20:05:42 +0000 | [diff] [blame] | 250 | createExtraActionProvider( |
Rumou Duan | 33bab46 | 2016-04-25 17:55:12 +0000 | [diff] [blame] | 251 | ImmutableSet.<ActionAnalysisMetadata>of() /* actionsWithoutExtraAction */, |
| 252 | ruleContext)); |
Carmi Grushko | eaaa9d0d | 2015-11-17 01:54:45 +0000 | [diff] [blame] | 253 | |
Dmitry Lomov | dce0170 | 2016-11-28 15:51:32 +0000 | [diff] [blame] | 254 | return new ConfiguredAspect(descriptor, providers.build()); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 255 | } |
| 256 | } |
Carmi Grushko | 65ac355 | 2015-08-21 16:43:26 +0000 | [diff] [blame] | 257 | } |