Java tutorial
// 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.analysis; import com.google.common.base.Function; import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.analysis.MergedConfiguredTarget.DuplicateException; 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.rules.SkylarkApiProvider; import com.google.devtools.build.lib.syntax.EvalException; import com.google.devtools.build.lib.syntax.SkylarkType; import com.google.devtools.build.lib.util.Preconditions; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; /** * A helper class for transitive infos provided by Skylark rule implementations. */ @Immutable public final class SkylarkProviders implements TransitiveInfoProvider { private final ImmutableMap<SkylarkClassObjectConstructor.Key, SkylarkClassObject> declaredProviders; private final ImmutableMap<String, Object> skylarkProviders; SkylarkProviders(ImmutableMap<String, Object> skylarkProviders, ImmutableMap<SkylarkClassObjectConstructor.Key, SkylarkClassObject> declaredProviders) { this.declaredProviders = Preconditions.checkNotNull(declaredProviders); this.skylarkProviders = Preconditions.checkNotNull(skylarkProviders); } public void init(ConfiguredTarget target) { for (Object o : skylarkProviders.values()) { if (o instanceof SkylarkApiProvider) { ((SkylarkApiProvider) o).init(target); } } } /** * Returns the keys for the Skylark providers. */ public ImmutableCollection<String> getKeys() { return skylarkProviders.keySet(); } /** * Returns a Skylark provider; "key" must be one from {@link #getKeys()}. */ public Object getValue(String key) { return skylarkProviders.get(key); } /** * Returns a Skylark provider and try to cast it into the specified type */ public <TYPE> TYPE getValue(String key, Class<TYPE> type) throws EvalException { Object obj = skylarkProviders.get(key); if (obj == null) { return null; } SkylarkType.checkType(obj, type, key); return type.cast(obj); } public SkylarkClassObject getDeclaredProvider(SkylarkClassObjectConstructor.Key key) { return declaredProviders.get(key); } private static final Function<SkylarkProviders, Map<String, Object>> SKYLARK_PROVIDERS_MAP_FUNCTION = new Function<SkylarkProviders, Map<String, Object>>() { @Override public Map<String, Object> apply(SkylarkProviders skylarkProviders) { return skylarkProviders.skylarkProviders; } }; public static final Function<SkylarkProviders, Map<SkylarkClassObjectConstructor.Key, SkylarkClassObject>> DECLARED_PROVIDERS_MAP_FUNCTION = new Function<SkylarkProviders, Map<SkylarkClassObjectConstructor.Key, SkylarkClassObject>>() { @Override public Map<SkylarkClassObjectConstructor.Key, SkylarkClassObject> apply(SkylarkProviders skylarkProviders) { return skylarkProviders.declaredProviders; } }; /** * Merges skylark providers. The set of providers must be disjoint. * * @param premergedProviders providers that has already been merged. They will * be put into the result as-is and their presence will be ignored among {@code providers}. * @param providers providers to merge {@code this} with. */ public static SkylarkProviders merge(Map<String, Object> premergedProviders, List<SkylarkProviders> providers) throws DuplicateException { if (premergedProviders.size() == 0 && providers.size() == 0) { return null; } if (premergedProviders.size() == 0 && providers.size() == 1) { return providers.get(0); } ImmutableMap<String, Object> skylarkProviders = mergeMaps(providers, SKYLARK_PROVIDERS_MAP_FUNCTION, premergedProviders); ImmutableMap<SkylarkClassObjectConstructor.Key, SkylarkClassObject> declaredProviders = mergeMaps(providers, DECLARED_PROVIDERS_MAP_FUNCTION, ImmutableMap.<SkylarkClassObjectConstructor.Key, SkylarkClassObject>of()); return new SkylarkProviders(skylarkProviders, declaredProviders); } private static <K, V> ImmutableMap<K, V> mergeMaps(List<SkylarkProviders> providers, Function<SkylarkProviders, Map<K, V>> mapGetter, Map<K, V> premerged) throws DuplicateException { Set<K> seenKeys = new HashSet<>(); ImmutableMap.Builder<K, V> resultBuilder = ImmutableMap.builder(); resultBuilder.putAll(premerged); for (SkylarkProviders provider : providers) { Map<K, V> map = mapGetter.apply(provider); for (K key : map.keySet()) { if (premerged.containsKey(key)) { continue; } if (!seenKeys.add(key)) { // TODO(dslomov): add better diagnostics. throw new DuplicateException("Provider " + key + " provided twice"); } resultBuilder.put(key, map.get(key)); } } return resultBuilder.build(); } }