aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryFunction.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryFunction.java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryFunction.java94
1 files changed, 79 insertions, 15 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryFunction.java b/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryFunction.java
index 2bba0bfcd5..f949e0a8b1 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryFunction.java
@@ -24,6 +24,7 @@ import com.google.devtools.build.lib.packages.BuildFileContainsErrorsException;
import com.google.devtools.build.lib.packages.BuildFileNotFoundException;
import com.google.devtools.build.lib.packages.NoSuchPackageException;
import com.google.devtools.build.lib.packages.Package;
+import com.google.devtools.build.lib.packages.PackageSerializer;
import com.google.devtools.build.lib.packages.Rule;
import com.google.devtools.build.lib.skyframe.FileSymlinkException;
import com.google.devtools.build.lib.skyframe.FileValue;
@@ -32,6 +33,7 @@ import com.google.devtools.build.lib.skyframe.PackageValue;
import com.google.devtools.build.lib.skyframe.RepositoryValue;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.Type;
+import com.google.devtools.build.lib.util.Fingerprint;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.PathFragment;
@@ -44,6 +46,7 @@ import com.google.devtools.build.skyframe.SkyKey;
import java.io.IOException;
import java.nio.charset.Charset;
+import java.util.Arrays;
import javax.annotation.Nullable;
@@ -51,6 +54,8 @@ import javax.annotation.Nullable;
* Parent class for repository-related Skyframe functions.
*/
public abstract class RepositoryFunction implements SkyFunction {
+ protected static final byte[] NO_RULE_SPECIFIC_DATA = new byte[] {};
+
/**
* Exception thrown when something goes wrong accessing a remote repository.
*
@@ -79,6 +84,58 @@ public abstract class RepositoryFunction implements SkyFunction {
private BlazeDirectories directories;
+ private byte[] computeRuleKey(Rule rule, byte[] ruleSpecificData) {
+
+ return new Fingerprint()
+ .addBytes(new PackageSerializer().serializeRule(rule).toByteArray())
+ .addBytes(ruleSpecificData)
+ .digestAndReset();
+ }
+
+ private Path getMarkerPath(Rule rule) {
+ return getExternalRepositoryDirectory().getChild("@" + rule.getName() + ".marker");
+ }
+
+ /**
+ * Checks if the state of the repository in the file system is consistent with the rule in the
+ * WORKSPACE file.
+ *
+ * <p>Deletes the marker file if not so that no matter what happens after, the state of the file
+ * system stays consistent.
+ */
+ protected boolean isFilesystemUpToDate(Rule rule, byte[] ruleSpecificData)
+ throws RepositoryFunctionException {
+ try {
+ Path markerPath = getMarkerPath(rule);
+ if (!markerPath.exists()) {
+ return false;
+ }
+
+ boolean result = Arrays.equals(
+ computeRuleKey(rule, ruleSpecificData),
+ FileSystemUtils.readContent(markerPath));
+ if (!result) {
+ // So that we are in a consistent state if something happens while fetching the repository
+ markerPath.delete();
+ }
+
+ return result;
+
+ } catch (IOException e) {
+ throw new RepositoryFunctionException(e, Transience.TRANSIENT);
+ }
+ }
+
+ protected void writeMarkerFile(Rule rule, byte[] ruleSpecificData)
+ throws RepositoryFunctionException {
+ try {
+ FileSystemUtils.writeContent(getMarkerPath(rule), computeRuleKey(rule, ruleSpecificData));
+ } catch (IOException e) {
+ throw new RepositoryFunctionException(e, Transience.TRANSIENT);
+ }
+ }
+
+
protected Path prepareLocalRepositorySymlinkTree(Rule rule, Environment env)
throws RepositoryFunctionException {
Path repositoryDirectory = getExternalRepositoryDirectory().getRelative(rule.getName());
@@ -117,22 +174,11 @@ public abstract class RepositoryFunction implements SkyFunction {
return RepositoryValue.create(repositoryDirectory);
}
- /**
- * Symlinks a BUILD file from the local filesystem into the external repository's root.
- * @param rule the rule that declares the build_file path.
- * @param workspaceDirectory the workspace root for the build.
- * @param outputDirectory the directory of the remote repository
- * @param env the Skyframe environment.
- * @return the file value of the symlink created.
- * @throws RepositoryFunctionException if the BUILD file specified does not exist or cannot be
- * linked.
- */
- protected RepositoryValue symlinkBuildFile(
- Rule rule, Path workspaceDirectory, Path outputDirectory, Environment env)
+ protected FileValue getBuildFileValue(Rule rule, Environment env)
throws RepositoryFunctionException {
AggregatingAttributeMapper mapper = AggregatingAttributeMapper.of(rule);
PathFragment buildFile = new PathFragment(mapper.get("build_file", Type.STRING));
- Path buildFileTarget = workspaceDirectory.getRelative(buildFile);
+ Path buildFileTarget = directories.getWorkspace().getRelative(buildFile);
if (!buildFileTarget.exists()) {
throw new RepositoryFunctionException(
new EvalException(rule.getLocation(),
@@ -146,7 +192,7 @@ public abstract class RepositoryFunction implements SkyFunction {
rootedBuild = RootedPath.toRootedPath(
buildFileTarget.getParentDirectory(), new PathFragment(buildFileTarget.getBaseName()));
} else {
- rootedBuild = RootedPath.toRootedPath(workspaceDirectory, buildFile);
+ rootedBuild = RootedPath.toRootedPath(directories.getWorkspace(), buildFile);
}
SkyKey buildFileKey = FileValue.key(rootedBuild);
FileValue buildFileValue;
@@ -162,8 +208,26 @@ public abstract class RepositoryFunction implements SkyFunction {
Transience.TRANSIENT);
}
+ return buildFileValue;
+ }
+
+ /**
+ * Symlinks a BUILD file from the local filesystem into the external repository's root.
+ * @param rule the rule that declares the build_file path.
+ * @param outputDirectory the directory of the remote repository
+ * @param env the Skyframe environment.
+ * @return the file value of the symlink created.
+ * @throws RepositoryFunctionException if the BUILD file specified does not exist or cannot be
+ * linked.
+ */
+ protected RepositoryValue symlinkBuildFile(Rule rule, Path outputDirectory, Environment env)
+ throws RepositoryFunctionException {
+ FileValue buildFileValue = getBuildFileValue(rule, env);
+ if (env.valuesMissing()) {
+ return null;
+ }
Path buildFilePath = outputDirectory.getRelative("BUILD");
- if (createSymbolicLink(buildFilePath, buildFileTarget, env) == null) {
+ if (createSymbolicLink(buildFilePath, buildFileValue.realRootedPath().asPath(), env) == null) {
return null;
}
return RepositoryValue.createNew(outputDirectory, buildFileValue);