// 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.actions; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.collect.Interner; import com.google.devtools.build.lib.concurrent.BlazeInterners; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe; import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec; import com.google.devtools.build.lib.vfs.PathFragment; import com.google.devtools.build.lib.vfs.RootedPath; import com.google.devtools.build.skyframe.AbstractSkyKey; import com.google.devtools.build.skyframe.SkyFunctionName; import com.google.devtools.build.skyframe.SkyValue; import java.util.Objects; import javax.annotation.Nullable; /** * A value that corresponds to a file (or directory or symlink or non-existent file), fully * accounting for symlinks (e.g. proper dependencies on ancestor symlinks so as to be incrementally * correct). Anything in Skyframe that cares about the fully resolved path of a file (e.g. anything * that cares about the contents of a file) should have a dependency on the corresponding {@link * FileValue}. * *
Note that the existence of a file value does not imply that the file exists on the filesystem. * File values for missing files will be created on purpose in order to facilitate incremental * builds in the case those files have reappeared. * *
This class contains the relevant metadata for a file, although not the contents. Note that * since a FileValue doesn't store its corresponding SkyKey, it's possible for the FileValues for * two different paths to be the same. * *
This should not be used for build outputs; use {@link ArtifactSkyKey} to create keys for * those. */ @Immutable @ThreadSafe public abstract class FileValue implements SkyValue { // Depends non-hermetically on package path. public static final SkyFunctionName FILE = SkyFunctionName.createNonHermetic("FILE"); /** * Exists to accommodate the control flow of {@link ActionMetadataHandler#getMetadata}. * *
{@link ActionMetadataHandler#getMetadata} always checks {@link * ActionMetadataHandler#outputArtifactData} before checking {@link * ActionMetadataHandler#additionalOutputData} so some placeholder value is needed to allow an * injected {@link FileArtifactValue} to be returned. */ @AutoCodec public static final FileValue PLACEHOLDER = new PlaceholderFileValue(); public boolean exists() { return realFileStateValue().getType() != FileStateType.NONEXISTENT; } /** Returns true if the original path is a symlink; the target path can never be a symlink. */ public boolean isSymlink() { return false; } /** * Returns true if this value corresponds to a file or symlink to an existing regular or special * file. If so, its parent directory is guaranteed to exist. */ public boolean isFile() { return realFileStateValue().getType() == FileStateType.REGULAR_FILE || realFileStateValue().getType() == FileStateType.SPECIAL_FILE; } /** * Returns true if this value corresponds to a file or symlink to an existing special file. If so, * its parent directory is guaranteed to exist. */ public boolean isSpecialFile() { return realFileStateValue().getType() == FileStateType.SPECIAL_FILE; } /** * Returns true if the file is a directory or a symlink to an existing directory. If so, its * parent directory is guaranteed to exist. */ public boolean isDirectory() { return realFileStateValue().getType() == FileStateType.DIRECTORY; } /** * Returns the real rooted path of the file, taking ancestor symlinks into account. For example, * the rooted path ['root']/['a/b'] is really ['root']/['c/b'] if 'a' is a symlink to 'c'. Note * that ancestor symlinks outside the root boundary are not taken into consideration. */ public abstract RootedPath realRootedPath(); public abstract FileStateValue realFileStateValue(); /** * Returns the unresolved link target if {@link #isSymlink()}. * *
This is useful if the caller wants to, for example, duplicate a relative symlink. An actual
* example could be a build rule that copies a set of input files to the output directory, but
* upon encountering symbolic links it can decide between copying or following them.
*/
public PathFragment getUnresolvedLinkTarget() {
throw new IllegalStateException(this.toString());
}
public long getSize() {
Preconditions.checkState(isFile(), this);
return realFileStateValue().getSize();
}
@Nullable
public byte[] getDigest() {
Preconditions.checkState(isFile(), this);
return realFileStateValue().getDigest();
}
/** Returns a key for building a file value for the given root-relative path. */
@ThreadSafe
public static Key key(RootedPath rootedPath) {
return Key.create(rootedPath);
}
@AutoCodec.VisibleForSerialization
@AutoCodec
static class Key extends AbstractSkyKey