org.gradle.api.internal.tasks.execution.ResolveTaskOutputCachingStateExecuter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle-api Show documentation
Show all versions of gradle-api Show documentation
Gradle 6.9.1 API redistribution.
/*
* Copyright 2017 the original author or authors.
*
* 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 org.gradle.api.internal.tasks.execution;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSortedMap;
import org.gradle.api.internal.OverlappingOutputs;
import org.gradle.api.internal.TaskInternal;
import org.gradle.api.internal.TaskOutputCachingState;
import org.gradle.api.internal.tasks.CacheableTaskOutputFilePropertySpec;
import org.gradle.api.internal.tasks.DefaultTaskOutputCachingState;
import org.gradle.api.internal.tasks.TaskExecuter;
import org.gradle.api.internal.tasks.TaskExecuterResult;
import org.gradle.api.internal.tasks.TaskExecutionContext;
import org.gradle.api.internal.tasks.TaskOutputCachingDisabledReasonCategory;
import org.gradle.api.internal.tasks.TaskOutputFilePropertySpec;
import org.gradle.api.internal.tasks.TaskStateInternal;
import org.gradle.caching.internal.tasks.BuildCacheKeyInputs;
import org.gradle.caching.internal.tasks.TaskOutputCachingBuildCacheKey;
import org.gradle.internal.file.RelativeFilePathResolver;
import org.gradle.internal.snapshot.impl.ImplementationSnapshot;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import static org.gradle.api.internal.tasks.TaskOutputCachingDisabledReasonCategory.BUILD_CACHE_DISABLED;
import static org.gradle.api.internal.tasks.TaskOutputCachingDisabledReasonCategory.CACHE_IF_SPEC_NOT_SATISFIED;
import static org.gradle.api.internal.tasks.TaskOutputCachingDisabledReasonCategory.DO_NOT_CACHE_IF_SPEC_SATISFIED;
import static org.gradle.api.internal.tasks.TaskOutputCachingDisabledReasonCategory.NON_CACHEABLE_INPUTS;
import static org.gradle.api.internal.tasks.TaskOutputCachingDisabledReasonCategory.NON_CACHEABLE_TASK_ACTION;
import static org.gradle.api.internal.tasks.TaskOutputCachingDisabledReasonCategory.NON_CACHEABLE_TASK_IMPLEMENTATION;
import static org.gradle.api.internal.tasks.TaskOutputCachingDisabledReasonCategory.NON_CACHEABLE_TREE_OUTPUT;
public class ResolveTaskOutputCachingStateExecuter implements TaskExecuter {
private static final Logger LOGGER = LoggerFactory.getLogger(ResolveTaskOutputCachingStateExecuter.class);
private static final TaskOutputCachingState ENABLED = DefaultTaskOutputCachingState.enabled();
private static final TaskOutputCachingState DISABLED = DefaultTaskOutputCachingState.disabled(BUILD_CACHE_DISABLED, "Task output caching is disabled");
private static final TaskOutputCachingState CACHING_NOT_ENABLED = DefaultTaskOutputCachingState.disabled(TaskOutputCachingDisabledReasonCategory.NOT_ENABLED_FOR_TASK, "Caching has not been enabled for the task");
private static final TaskOutputCachingState NO_OUTPUTS_DECLARED = DefaultTaskOutputCachingState.disabled(TaskOutputCachingDisabledReasonCategory.NO_OUTPUTS_DECLARED, "No outputs declared");
private final boolean buildCacheEnabled;
private final RelativeFilePathResolver relativeFilePathResolver;
private final TaskExecuter delegate;
public ResolveTaskOutputCachingStateExecuter(boolean buildCacheEnabled, RelativeFilePathResolver relativeFilePathResolver, TaskExecuter delegate) {
this.buildCacheEnabled = buildCacheEnabled;
this.relativeFilePathResolver = relativeFilePathResolver;
this.delegate = delegate;
}
@Override
public TaskExecuterResult execute(TaskInternal task, TaskStateInternal state, TaskExecutionContext context) {
if (buildCacheEnabled) {
TaskOutputCachingState taskOutputCachingState = resolveCachingState(
context.getTaskProperties().hasDeclaredOutputs(),
context.getTaskProperties().getOutputFileProperties(),
context.getBuildCacheKey(),
task,
task.getOutputs().getCacheIfSpecs(),
task.getOutputs().getDoNotCacheIfSpecs(),
context.getOverlappingOutputs().orElse(null),
relativeFilePathResolver);
context.setTaskCachingEnabled(taskOutputCachingState.isEnabled());
state.setTaskOutputCaching(taskOutputCachingState);
if (!taskOutputCachingState.isEnabled()) {
LOGGER.info("Caching disabled for {}: {}", task, taskOutputCachingState.getDisabledReason());
}
} else {
state.setTaskOutputCaching(DISABLED);
}
return delegate.execute(task, state, context);
}
@VisibleForTesting
static TaskOutputCachingState resolveCachingState(
boolean hasDeclaredOutputs,
Collection outputFileProperties,
TaskOutputCachingBuildCacheKey buildCacheKey,
TaskInternal task,
Collection> cacheIfSpecs,
Collection> doNotCacheIfSpecs,
@Nullable OverlappingOutputs overlappingOutputs,
RelativeFilePathResolver relativeFilePathResolver) {
if (cacheIfSpecs.isEmpty()) {
return CACHING_NOT_ENABLED;
}
if (!hasDeclaredOutputs) {
return NO_OUTPUTS_DECLARED;
}
if (overlappingOutputs != null) {
String relativePath = relativeFilePathResolver.resolveAsRelativePath(overlappingOutputs.getOverlappedFilePath());
return DefaultTaskOutputCachingState.disabled(TaskOutputCachingDisabledReasonCategory.OVERLAPPING_OUTPUTS,
String.format("Gradle does not know how file '%s' was created (output property '%s'). Task output caching requires exclusive access to output paths to guarantee correctness.",
relativePath, overlappingOutputs.getPropertyName()));
}
for (TaskOutputFilePropertySpec spec : outputFileProperties) {
if (!(spec instanceof CacheableTaskOutputFilePropertySpec)) {
return DefaultTaskOutputCachingState.disabled(
NON_CACHEABLE_TREE_OUTPUT,
"Output property '"
+ spec.getPropertyName()
+ "' contains a file tree"
);
}
}
for (SelfDescribingSpec cacheIfSpec : cacheIfSpecs) {
if (!cacheIfSpec.isSatisfiedBy(task)) {
return DefaultTaskOutputCachingState.disabled(
CACHE_IF_SPEC_NOT_SATISFIED,
"'" + cacheIfSpec.getDisplayName() + "' not satisfied"
);
}
}
for (SelfDescribingSpec doNotCacheIfSpec : doNotCacheIfSpecs) {
if (doNotCacheIfSpec.isSatisfiedBy(task)) {
return DefaultTaskOutputCachingState.disabled(
DO_NOT_CACHE_IF_SPEC_SATISFIED,
"'" + doNotCacheIfSpec.getDisplayName() + "' satisfied"
);
}
}
if (!buildCacheKey.isValid()) {
return getCachingStateForInvalidCacheKey(buildCacheKey);
}
return ENABLED;
}
private static TaskOutputCachingState getCachingStateForInvalidCacheKey(TaskOutputCachingBuildCacheKey buildCacheKey) {
BuildCacheKeyInputs buildCacheKeyInputs = buildCacheKey.getInputs();
ImplementationSnapshot taskImplementation = buildCacheKeyInputs.getTaskImplementation();
if (taskImplementation != null && taskImplementation.isUnknown()) {
return DefaultTaskOutputCachingState.disabled(NON_CACHEABLE_TASK_IMPLEMENTATION, "Task class " + taskImplementation.getUnknownReason());
}
List actionImplementations = buildCacheKeyInputs.getActionImplementations();
if (actionImplementations != null && !actionImplementations.isEmpty()) {
for (ImplementationSnapshot actionImplementation : actionImplementations) {
if (actionImplementation.isUnknown()) {
return DefaultTaskOutputCachingState.disabled(NON_CACHEABLE_TASK_ACTION, "Task action " + actionImplementation.getUnknownReason());
}
}
}
ImmutableSortedMap invalidInputProperties = buildCacheKeyInputs.getNonCacheableInputProperties();
if (invalidInputProperties != null && !invalidInputProperties.isEmpty()) {
StringBuilder builder = new StringBuilder();
builder.append("Non-cacheable inputs: ");
boolean first = true;
for (Map.Entry entry : Preconditions.checkNotNull(invalidInputProperties).entrySet()) {
if (!first) {
builder.append(", ");
}
first = false;
builder
.append("property '")
.append(entry.getKey())
.append("' ")
.append(entry.getValue());
}
return DefaultTaskOutputCachingState.disabled(
NON_CACHEABLE_INPUTS,
builder.toString()
);
}
throw new IllegalStateException("Cache key is invalid without a known reason: " + buildCacheKey);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy