blob: 8a801924efc59df53d58b84918a3de862c43212a [file] [log] [blame]
// 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.skyframe;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
import com.google.devtools.build.lib.actions.ActionLookupValue;
import com.google.devtools.build.lib.analysis.ConfiguredAspect;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.packages.Aspect;
import com.google.devtools.build.lib.packages.AspectClass;
import com.google.devtools.build.lib.packages.AspectDescriptor;
import com.google.devtools.build.lib.packages.AspectParameters;
import com.google.devtools.build.lib.packages.Package;
import com.google.devtools.build.lib.syntax.SkylarkImport;
import com.google.devtools.build.skyframe.SkyFunctionName;
import java.util.List;
import javax.annotation.Nullable;
/**
* An aspect in the context of the Skyframe graph.
*/
public final class AspectValue extends ActionLookupValue {
/**
* A base class for keys that have AspectValue as a Sky value.
*/
public abstract static class AspectValueKey extends ActionLookupKey {
public abstract String getDescription();
}
/**
* A base class for a key representing an aspect applied to a particular target.
*/
public static final class AspectKey extends AspectValueKey {
private final Label label;
private final ImmutableList<AspectKey> baseKeys;
private final BuildConfiguration aspectConfiguration;
private final BuildConfiguration baseConfiguration;
private final AspectDescriptor aspectDescriptor;
private AspectKey(
Label label,
BuildConfiguration baseConfiguration,
ImmutableList<AspectKey> baseKeys,
AspectDescriptor aspectDescriptor,
BuildConfiguration aspectConfiguration) {
this.baseKeys = baseKeys;
this.label = label;
this.baseConfiguration = baseConfiguration;
this.aspectConfiguration = aspectConfiguration;
this.aspectDescriptor = aspectDescriptor;
}
@Override
protected SkyFunctionName getType() {
return SkyFunctions.ASPECT;
}
@Override
public Label getLabel() {
return label;
}
public AspectClass getAspectClass() {
return aspectDescriptor.getAspectClass();
}
@Nullable
public AspectParameters getParameters() {
return aspectDescriptor.getParameters();
}
public AspectDescriptor getAspectDescriptor() {
return aspectDescriptor;
}
@Nullable
public ImmutableList<AspectKey> getBaseKeys() {
return baseKeys;
}
@Override
public String getDescription() {
if (baseKeys.isEmpty()) {
return String.format("%s of %s",
aspectDescriptor.getAspectClass().getName(), getLabel());
} else {
return String.format("%s on top of %s",
aspectDescriptor.getAspectClass().getName(), baseKeys.toString());
}
}
/**
* Returns the configuration to be used for the evaluation of the aspect itself.
*
* <p>In trimmed configuration mode, the aspect may require more fragments than the target on
* which it is being evaluated; in addition to configuration fragments required by the target
* and its dependencies, an aspect has configuration fragment requirements of its own, as well
* as dependencies of its own with their own configuration fragment requirements.
*
* <p>The aspect configuration contains all of these fragments, and is used to create the
* aspect's RuleContext and to retrieve the dependencies. Note that dependencies will have their
* configurations trimmed from this one as normal.
*
* <p>Because of these properties, this configuration is always a superset of that returned by
* {@link #getBaseConfiguration()}. In untrimmed configuration mode, this configuration will be
* equivalent to that returned by {@link #getBaseConfiguration()}.
*
* @see #getBaseConfiguration()
*/
public BuildConfiguration getAspectConfiguration() {
return aspectConfiguration;
}
/**
* Returns the configuration to be used for the base target.
*
* <p>In trimmed configuration mode, the configured target this aspect is attached to may have
* a different configuration than the aspect itself (see the documentation for
* {@link #getAspectConfiguration()} for an explanation why). The base configuration is the one
* used to construct a key to look up the base configured target.
*
* @see #getAspectConfiguration()
*/
public BuildConfiguration getBaseConfiguration() {
return baseConfiguration;
}
@Override
public int hashCode() {
return Objects.hashCode(
label,
baseKeys,
aspectConfiguration,
baseConfiguration,
aspectDescriptor);
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof AspectKey)) {
return false;
}
AspectKey that = (AspectKey) other;
return Objects.equal(label, that.label)
&& Objects.equal(baseKeys, that.baseKeys)
&& Objects.equal(aspectConfiguration, that.aspectConfiguration)
&& Objects.equal(baseConfiguration, that.baseConfiguration)
&& Objects.equal(aspectDescriptor, that.aspectDescriptor);
}
public String prettyPrint() {
if (label == null) {
return "null";
}
String baseKeysString =
baseKeys.isEmpty()
? ""
: String.format(" (over %s)", baseKeys.toString());
return String.format("%s with aspect %s%s%s",
label.toString(),
aspectDescriptor.getAspectClass().getName(),
(aspectConfiguration != null && aspectConfiguration.isHostConfiguration())
? "(host) " : "",
baseKeysString
);
}
@Override
public String toString() {
return (baseKeys == null ? label : baseKeys.toString())
+ "#"
+ aspectDescriptor.getAspectClass().getName()
+ " "
+ (aspectConfiguration == null ? "null" : aspectConfiguration.checksum())
+ " "
+ (baseConfiguration == null ? "null" : baseConfiguration.checksum())
+ " "
+ aspectDescriptor.getParameters();
}
public AspectKey withLabel(Label label) {
ImmutableList.Builder<AspectKey> newBaseKeys = ImmutableList.builder();
for (AspectKey baseKey : baseKeys) {
newBaseKeys.add(baseKey.withLabel(label));
}
return new AspectKey(
label, baseConfiguration,
newBaseKeys.build(), aspectDescriptor, aspectConfiguration);
}
}
/**
* The key for a skylark aspect.
*/
public static class SkylarkAspectLoadingKey extends AspectValueKey {
private final Label targetLabel;
private final BuildConfiguration aspectConfiguration;
private final BuildConfiguration targetConfiguration;
private final SkylarkImport skylarkImport;
private final String skylarkValueName;
private SkylarkAspectLoadingKey(
Label targetLabel,
BuildConfiguration aspectConfiguration,
BuildConfiguration targetConfiguration,
SkylarkImport skylarkImport,
String skylarkFunctionName) {
this.targetLabel = targetLabel;
this.aspectConfiguration = aspectConfiguration;
this.targetConfiguration = targetConfiguration;
this.skylarkImport = skylarkImport;
this.skylarkValueName = skylarkFunctionName;
}
@Override
protected SkyFunctionName getType() {
return SkyFunctions.LOAD_SKYLARK_ASPECT;
}
public Label getTargetLabel() {
return targetLabel;
}
public String getSkylarkValueName() {
return skylarkValueName;
}
public SkylarkImport getSkylarkImport() {
return skylarkImport;
}
/**
* @see AspectKey#getAspectConfiguration()
*/
public BuildConfiguration getAspectConfiguration() {
return aspectConfiguration;
}
/**
* @see AspectKey#getBaseConfiguration()
*/
public BuildConfiguration getTargetConfiguration() {
return targetConfiguration;
}
@Override
public String getDescription() {
// Skylark aspects are referred to on command line with <file>%<value ame>
return String.format("%s%%%s of %s", skylarkImport.getImportString(),
skylarkValueName, targetLabel);
}
@Override
public int hashCode() {
return Objects.hashCode(targetLabel,
aspectConfiguration,
targetConfiguration,
skylarkImport,
skylarkValueName);
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof SkylarkAspectLoadingKey)) {
return false;
}
SkylarkAspectLoadingKey that = (SkylarkAspectLoadingKey) o;
return Objects.equal(targetLabel, that.targetLabel)
&& Objects.equal(aspectConfiguration, that.aspectConfiguration)
&& Objects.equal(targetConfiguration, that.targetConfiguration)
&& Objects.equal(skylarkImport, that.skylarkImport)
&& Objects.equal(skylarkValueName, that.skylarkValueName);
}
}
// These variables are only non-final because they may be clear()ed to save memory. They are null
// only after they are cleared.
@Nullable private Label label;
@Nullable private Aspect aspect;
@Nullable private Location location;
@Nullable private AspectKey key;
@Nullable private ConfiguredAspect configuredAspect;
@Nullable private NestedSet<Package> transitivePackages;
public AspectValue(
AspectKey key,
Aspect aspect,
Label label,
Location location,
ConfiguredAspect configuredAspect,
List<ActionAnalysisMetadata> actions,
NestedSet<Package> transitivePackages,
boolean removeActionsAfterEvaluation) {
super(actions, removeActionsAfterEvaluation);
this.label = Preconditions.checkNotNull(label, actions);
this.aspect = Preconditions.checkNotNull(aspect, label);
this.location = Preconditions.checkNotNull(location, label);
this.key = Preconditions.checkNotNull(key, label);
this.configuredAspect = Preconditions.checkNotNull(configuredAspect, label);
this.transitivePackages = Preconditions.checkNotNull(transitivePackages, label);
}
public ConfiguredAspect getConfiguredAspect() {
return Preconditions.checkNotNull(configuredAspect);
}
public Label getLabel() {
return Preconditions.checkNotNull(label);
}
public Location getLocation() {
return Preconditions.checkNotNull(location);
}
public AspectKey getKey() {
return Preconditions.checkNotNull(key);
}
public Aspect getAspect() {
return Preconditions.checkNotNull(aspect);
}
void clear(boolean clearEverything) {
Preconditions.checkNotNull(label, this);
Preconditions.checkNotNull(aspect, this);
Preconditions.checkNotNull(location, this);
Preconditions.checkNotNull(key, this);
Preconditions.checkNotNull(configuredAspect, this);
Preconditions.checkNotNull(transitivePackages, this);
if (clearEverything) {
label = null;
aspect = null;
location = null;
key = null;
configuredAspect = null;
}
transitivePackages = null;
}
public NestedSet<Package> getTransitivePackages() {
return Preconditions.checkNotNull(transitivePackages);
}
// TODO(janakr): Add a nice toString after cl/150542180 is submitted.
public static AspectKey createAspectKey(
Label label,
BuildConfiguration baseConfiguration,
ImmutableList<AspectKey> baseKeys,
AspectDescriptor aspectDescriptor,
BuildConfiguration aspectConfiguration) {
return new AspectKey(
label, baseConfiguration,
baseKeys,
aspectDescriptor,
aspectConfiguration
);
}
public static AspectKey createAspectKey(
Label label,
BuildConfiguration baseConfiguration, AspectDescriptor aspectDescriptor,
BuildConfiguration aspectConfiguration) {
return new AspectKey(
label, baseConfiguration, ImmutableList.<AspectKey>of(),
aspectDescriptor, aspectConfiguration);
}
public static SkylarkAspectLoadingKey createSkylarkAspectKey(
Label targetLabel,
BuildConfiguration aspectConfiguration,
BuildConfiguration targetConfiguration,
SkylarkImport skylarkImport,
String skylarkExportName) {
return new SkylarkAspectLoadingKey(
targetLabel, aspectConfiguration, targetConfiguration, skylarkImport, skylarkExportName);
}
}