aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/rules/repository
diff options
context:
space:
mode:
authorGravatar jcater <jcater@google.com>2017-03-30 20:09:33 +0000
committerGravatar Philipp Wollermann <philwo@google.com>2017-03-31 17:11:00 +0200
commit18a4c841d48df2eb52f27817ed566833809a92cc (patch)
tree7d2963e4e82f34f1cf4d039e6d8e62df4e8874a1 /src/main/java/com/google/devtools/build/lib/rules/repository
parent63111882e794f786ab857c92b01383a457e843a4 (diff)
Add workspace_file and workspace_file_content attributes to new_foo_repository rules.
Change-Id: Iadcc24bb2a207126cec9aa31faba6d76ee80da41 PiperOrigin-RevId: 151739968
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules/repository')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/repository/NewLocalRepositoryFunction.java19
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/repository/NewLocalRepositoryRule.java16
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/repository/NewRepositoryBuildFileHandler.java210
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/repository/NewRepositoryFileHandler.java314
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryFunction.java20
5 files changed, 346 insertions, 233 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/repository/NewLocalRepositoryFunction.java b/src/main/java/com/google/devtools/build/lib/rules/repository/NewLocalRepositoryFunction.java
index 91aadb7364..3670dcdd44 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/repository/NewLocalRepositoryFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/repository/NewLocalRepositoryFunction.java
@@ -47,9 +47,8 @@ public class NewLocalRepositoryFunction extends RepositoryFunction {
BlazeDirectories directories, Environment env, Map<String, String> markerData)
throws SkyFunctionException, InterruptedException {
- NewRepositoryBuildFileHandler buildFileHandler =
- new NewRepositoryBuildFileHandler(directories.getWorkspace());
- if (!buildFileHandler.prepareBuildFile(rule, env)) {
+ NewRepositoryFileHandler fileHandler = new NewRepositoryFileHandler(directories.getWorkspace());
+ if (!fileHandler.prepareFile(rule, env)) {
return null;
}
@@ -118,19 +117,7 @@ public class NewLocalRepositoryFunction extends RepositoryFunction {
return null;
}
- buildFileHandler.finishBuildFile(outputDirectory);
-
- // If someone specified *new*_local_repository, we can assume they didn't want the existing
- // repository info.
- Path workspaceFile = outputDirectory.getRelative("WORKSPACE");
- if (workspaceFile.exists()) {
- try {
- workspaceFile.delete();
- } catch (IOException e) {
- throw new RepositoryFunctionException(e, Transience.TRANSIENT);
- }
- }
- createWorkspaceFile(outputDirectory, rule.getTargetKind(), rule.getName());
+ fileHandler.finishFile(outputDirectory);
return RepositoryDirectoryValue.builder().setPath(outputDirectory).setSourceDir(directoryValue);
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/repository/NewLocalRepositoryRule.java b/src/main/java/com/google/devtools/build/lib/rules/repository/NewLocalRepositoryRule.java
index a83091edaf..66f4608506 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/repository/NewLocalRepositoryRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/repository/NewLocalRepositoryRule.java
@@ -54,6 +54,22 @@ public class NewLocalRepositoryRule implements RuleDefinition {
<p>Either build_file or build_file_content must be specified.</p>
<!-- #END_BLAZE_RULE.ATTRIBUTE --> */
.add(attr("build_file_content", STRING))
+ /* <!-- #BLAZE_RULE(new_http_archive).ATTRIBUTE(workspace_file) -->
+ The file to use as the WORKSPACE file for this repository.
+
+ <p>Either workspace_file or workspace_file_content can be specified, but not both.</p>
+
+ <p>This attribute is a label relative to the main workspace. The file does not need to be
+ named WORKSPACE, but can be (something like WORKSPACE.new-repo-name may work well for
+ distinguishing it from the repository's actual WORKSPACE files.</p>
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("workspace_file", STRING))
+ /* <!-- #BLAZE_RULE(new_http_archive).ATTRIBUTE(workspace_file_content) -->
+ The content for the WORKSPACE file for this repository.
+
+ <p>Either workspace_file or workspace_file_content can be specified, but not both.</p>
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("workspace_file_content", STRING))
.setWorkspaceOnly()
.build();
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/repository/NewRepositoryBuildFileHandler.java b/src/main/java/com/google/devtools/build/lib/rules/repository/NewRepositoryBuildFileHandler.java
deleted file mode 100644
index 76868d77e4..0000000000
--- a/src/main/java/com/google/devtools/build/lib/rules/repository/NewRepositoryBuildFileHandler.java
+++ /dev/null
@@ -1,210 +0,0 @@
-// 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.rules.repository;
-
-import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
-import com.google.devtools.build.lib.cmdline.LabelValidator;
-import com.google.devtools.build.lib.packages.Rule;
-import com.google.devtools.build.lib.rules.repository.RepositoryFunction.RepositoryFunctionException;
-import com.google.devtools.build.lib.skyframe.FileSymlinkException;
-import com.google.devtools.build.lib.skyframe.FileValue;
-import com.google.devtools.build.lib.skyframe.InconsistentFilesystemException;
-import com.google.devtools.build.lib.skyframe.PackageLookupValue;
-import com.google.devtools.build.lib.syntax.EvalException;
-import com.google.devtools.build.lib.syntax.Type;
-import com.google.devtools.build.lib.vfs.Path;
-import com.google.devtools.build.lib.vfs.PathFragment;
-import com.google.devtools.build.lib.vfs.RootedPath;
-import com.google.devtools.build.skyframe.SkyFunction.Environment;
-import com.google.devtools.build.skyframe.SkyFunctionException.Transience;
-import com.google.devtools.build.skyframe.SkyKey;
-import java.io.IOException;
-
-/**
- * Encapsulates the 2-step behavior of creating build files for the new_*_repository rules.
- */
-public class NewRepositoryBuildFileHandler {
-
- private final Path workspacePath;
- private FileValue buildFileValue;
- private String buildFileContent;
-
- public NewRepositoryBuildFileHandler(Path workspacePath) {
- this.workspacePath = workspacePath;
- }
-
- /**
- * Prepares for writing a build file by validating the build_file and build_file_content
- * attributes of the rule.
- *
- * @return true if the build file was successfully created, false if the environment is missing
- * values (the calling fetch() function should return null in this case).
- * @throws RepositoryFunctionException if the rule does not define the build_file or
- * build_file_content attributes, or if it defines both, or if the build file could not be
- * retrieved, written, or symlinked.
- */
- public boolean prepareBuildFile(Rule rule, Environment env)
- throws RepositoryFunctionException, InterruptedException {
-
- WorkspaceAttributeMapper mapper = WorkspaceAttributeMapper.of(rule);
- boolean hasBuildFile = mapper.isAttributeValueExplicitlySpecified("build_file");
- boolean hasBuildFileContent = mapper.isAttributeValueExplicitlySpecified("build_file_content");
-
- if (hasBuildFile && hasBuildFileContent) {
-
- String error = String.format(
- "Rule %s cannot have both a 'build_file' and 'build_file_content' attribute", rule);
- throw new RepositoryFunctionException(
- new EvalException(rule.getLocation(), error), Transience.PERSISTENT);
-
- } else if (hasBuildFile) {
-
- buildFileValue = getBuildFileValue(rule, env);
- if (env.valuesMissing()) {
- return false;
- }
-
- } else if (hasBuildFileContent) {
-
- try {
- buildFileContent = mapper.get("build_file_content", Type.STRING);
- } catch (EvalException e) {
- throw new RepositoryFunctionException(e, Transience.PERSISTENT);
- }
-
- } else {
-
- String error = String.format(
- "Rule %s requires a 'build_file' or 'build_file_content' attribute", rule);
- throw new RepositoryFunctionException(
- new EvalException(rule.getLocation(), error), Transience.PERSISTENT);
- }
-
- return true;
- }
-
- /**
- * Writes the build file, based on the state set by prepareBuildFile().
- *
- * @param outputDirectory the directory to write the build file.
- * @throws RepositoryFunctionException if the build file could not be written or symlinked
- * @throws IllegalStateException if prepareBuildFile() was not called before this, or if
- * prepareBuildFile() failed and this was called.
- */
- public void finishBuildFile(Path outputDirectory) throws RepositoryFunctionException {
- if (buildFileValue != null) {
- // Link x/BUILD to <build_root>/x.BUILD.bazel.
- symlinkBuildFile(buildFileValue, outputDirectory);
- } else if (buildFileContent != null) {
- RepositoryFunction.writeBuildFile(outputDirectory, buildFileContent);
- } else {
- throw new IllegalStateException(
- "prepareBuildFile() must be called before finishBuildFile()");
- }
- }
-
- private FileValue getBuildFileValue(Rule rule, Environment env)
- throws RepositoryFunctionException, InterruptedException {
- WorkspaceAttributeMapper mapper = WorkspaceAttributeMapper.of(rule);
- String buildFileAttribute;
- try {
- buildFileAttribute = mapper.get("build_file", Type.STRING);
- } catch (EvalException e) {
- throw new RepositoryFunctionException(e, Transience.PERSISTENT);
- }
- RootedPath rootedBuild;
-
- if (LabelValidator.isAbsolute(buildFileAttribute)) {
- try {
- // Parse a label
- Label label = Label.parseAbsolute(buildFileAttribute);
- SkyKey pkgSkyKey = PackageLookupValue.key(label.getPackageIdentifier());
- PackageLookupValue pkgLookupValue = (PackageLookupValue) env.getValue(pkgSkyKey);
- if (pkgLookupValue == null) {
- return null;
- }
- if (!pkgLookupValue.packageExists()) {
- throw new RepositoryFunctionException(
- new EvalException(rule.getLocation(),
- "Unable to load package for " + buildFileAttribute + ": not found."),
- Transience.PERSISTENT);
- }
-
- // And now for the file
- Path packageRoot = pkgLookupValue.getRoot();
- rootedBuild = RootedPath.toRootedPath(packageRoot, label.toPathFragment());
- } catch (LabelSyntaxException ex) {
- throw new RepositoryFunctionException(
- new EvalException(rule.getLocation(),
- String.format("In %s the 'build_file' attribute does not specify a valid label: %s",
- rule, ex.getMessage())),
- Transience.PERSISTENT);
- }
- } else {
- // TODO(dmarting): deprecate using a path for the build_file attribute.
- PathFragment buildFile = new PathFragment(buildFileAttribute);
- Path buildFileTarget = workspacePath.getRelative(buildFile);
- if (!buildFileTarget.exists()) {
- throw new RepositoryFunctionException(
- new EvalException(rule.getLocation(),
- String.format("In %s the 'build_file' attribute does not specify an existing file "
- + "(%s does not exist)", rule, buildFileTarget)),
- Transience.PERSISTENT);
- }
-
- if (buildFile.isAbsolute()) {
- rootedBuild = RootedPath.toRootedPath(
- buildFileTarget.getParentDirectory(), new PathFragment(buildFileTarget.getBaseName()));
- } else {
- rootedBuild = RootedPath.toRootedPath(workspacePath, buildFile);
- }
- }
- SkyKey buildFileKey = FileValue.key(rootedBuild);
- FileValue buildFileValue;
- try {
- // Note that this dependency is, strictly speaking, not necessary: the symlink could simply
- // point to this FileValue and the symlink chasing could be done while loading the package
- // but this results in a nicer error message and it's correct as long as RepositoryFunctions
- // don't write to things in the file system this FileValue depends on. In theory, the latter
- // is possible if the file referenced by build_file is a symlink to somewhere under the
- // external/ directory, but if you do that, you are really asking for trouble.
- buildFileValue = (FileValue) env.getValueOrThrow(buildFileKey, IOException.class,
- FileSymlinkException.class, InconsistentFilesystemException.class);
- if (buildFileValue == null) {
- return null;
- }
- } catch (IOException | FileSymlinkException | InconsistentFilesystemException e) {
- throw new RepositoryFunctionException(
- new IOException("Cannot lookup " + buildFileAttribute + ": " + e.getMessage()),
- Transience.TRANSIENT);
- }
-
- return buildFileValue;
- }
-
- /**
- * Symlinks a BUILD file from the local filesystem into the external repository's root.
- * @param buildFileValue {@link FileValue} representing the BUILD file to be linked in
- * @param outputDirectory the directory of the remote repository
- * @throws RepositoryFunctionException if the BUILD file specified does not exist or cannot be
- * linked.
- */
- private void symlinkBuildFile(
- FileValue buildFileValue, Path outputDirectory) throws RepositoryFunctionException {
- Path buildFilePath = outputDirectory.getRelative("BUILD.bazel");
- RepositoryFunction.createSymbolicLink(buildFilePath, buildFileValue.realRootedPath().asPath());
- }
-}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/repository/NewRepositoryFileHandler.java b/src/main/java/com/google/devtools/build/lib/rules/repository/NewRepositoryFileHandler.java
new file mode 100644
index 0000000000..29efc78faa
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/repository/NewRepositoryFileHandler.java
@@ -0,0 +1,314 @@
+// 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.rules.repository;
+
+import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
+import com.google.devtools.build.lib.cmdline.LabelValidator;
+import com.google.devtools.build.lib.packages.Rule;
+import com.google.devtools.build.lib.rules.repository.RepositoryFunction.RepositoryFunctionException;
+import com.google.devtools.build.lib.skyframe.FileSymlinkException;
+import com.google.devtools.build.lib.skyframe.FileValue;
+import com.google.devtools.build.lib.skyframe.InconsistentFilesystemException;
+import com.google.devtools.build.lib.skyframe.PackageLookupValue;
+import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.syntax.Type;
+import com.google.devtools.build.lib.vfs.Path;
+import com.google.devtools.build.lib.vfs.PathFragment;
+import com.google.devtools.build.lib.vfs.RootedPath;
+import com.google.devtools.build.skyframe.SkyFunction.Environment;
+import com.google.devtools.build.skyframe.SkyFunctionException.Transience;
+import com.google.devtools.build.skyframe.SkyKey;
+import java.io.IOException;
+
+/**
+ * Encapsulates the 2-step behavior of creating workspace and build files for the new_*_repository
+ * rules.
+ */
+public class NewRepositoryFileHandler {
+
+ private NewRepositoryWorkspaceFileHandler workspaceFileHandler;
+ private NewRepositoryBuildFileHandler buildFileHandler;
+
+ public NewRepositoryFileHandler(Path workspacePath) {
+ this.workspaceFileHandler = new NewRepositoryWorkspaceFileHandler(workspacePath);
+ this.buildFileHandler = new NewRepositoryBuildFileHandler(workspacePath);
+ }
+
+ public boolean prepareFile(Rule rule, Environment env)
+ throws RepositoryFunctionException, InterruptedException {
+ if (!this.workspaceFileHandler.prepareFile(rule, env)) {
+ return false;
+ }
+ if (!this.buildFileHandler.prepareFile(rule, env)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public void finishFile(Path outputDirectory) throws RepositoryFunctionException {
+ this.workspaceFileHandler.finishFile(outputDirectory);
+ this.buildFileHandler.finishFile(outputDirectory);
+ }
+
+ /**
+ * Encapsulates the 2-step behavior of creating files for the new_*_repository rules, based on a
+ * pair of attributes defined in {@link #getFileAttrName()} and {@link #getFileContentAttrName()}.
+ */
+ private abstract static class BaseFileHandler {
+
+ private final Path workspacePath;
+ private final String filename;
+ private FileValue fileValue;
+ private String fileContent;
+
+ private BaseFileHandler(Path workspacePath, String filename) {
+ this.workspacePath = workspacePath;
+ this.filename = filename;
+ }
+
+ protected abstract String getFileAttrName();
+
+ protected abstract String getFileContentAttrName();
+
+ protected abstract String getDefaultContent(Rule rule) throws RepositoryFunctionException;
+
+ /**
+ * Prepares for writing a file by validating the FOO_file and FOO_file_content attributes of the
+ * rule.
+ *
+ * @return true if the file was successfully created, false if the environment is missing values
+ * (the calling fetch() function should return null in this case).
+ * @throws RepositoryFunctionException if the rule does defines both the FOO_file and
+ * FOO_file_content attributes, or if the workspace file could not be retrieved, written, or
+ * symlinked.
+ */
+ public boolean prepareFile(Rule rule, Environment env)
+ throws RepositoryFunctionException, InterruptedException {
+
+ WorkspaceAttributeMapper mapper = WorkspaceAttributeMapper.of(rule);
+ boolean hasFile = mapper.isAttributeValueExplicitlySpecified(getFileAttrName());
+ boolean hasFileContent = mapper.isAttributeValueExplicitlySpecified(getFileContentAttrName());
+
+ if (hasFile && hasFileContent) {
+
+ String error =
+ String.format(
+ "Rule %s cannot have both a '%s' and '%s' attribute",
+ rule, getFileAttrName(), getFileContentAttrName());
+ throw new RepositoryFunctionException(
+ new EvalException(rule.getLocation(), error), Transience.PERSISTENT);
+
+ } else if (hasFile) {
+
+ fileValue = getFileValue(rule, env);
+ if (env.valuesMissing()) {
+ return false;
+ }
+
+ } else if (hasFileContent) {
+
+ try {
+ fileContent = mapper.get(getFileContentAttrName(), Type.STRING);
+ } catch (EvalException e) {
+ throw new RepositoryFunctionException(e, Transience.PERSISTENT);
+ }
+
+ } else {
+ fileContent = getDefaultContent(rule);
+ }
+
+ return true;
+ }
+
+ /**
+ * Writes the file, based on the state set by prepareFile().
+ *
+ * @param outputDirectory the directory to write the file.
+ * @throws RepositoryFunctionException if the file could not be written or symlinked
+ * @throws IllegalStateException if {@link #prepareFile} was not called before this, or if
+ * {@link #prepareFile} failed and this was called.
+ */
+ public void finishFile(Path outputDirectory) throws RepositoryFunctionException {
+ if (fileValue != null) {
+ // Link x/FILENAME to <build_root>/x.FILENAME.
+ symlinkFile(fileValue, filename, outputDirectory);
+ } else if (fileContent != null) {
+ RepositoryFunction.writeFile(outputDirectory, filename, fileContent);
+ } else {
+ throw new IllegalStateException("prepareFile() must be called before finishFile()");
+ }
+ }
+
+ private FileValue getFileValue(Rule rule, Environment env)
+ throws RepositoryFunctionException, InterruptedException {
+ WorkspaceAttributeMapper mapper = WorkspaceAttributeMapper.of(rule);
+ String fileAttribute;
+ try {
+ fileAttribute = mapper.get(getFileAttrName(), Type.STRING);
+ } catch (EvalException e) {
+ throw new RepositoryFunctionException(e, Transience.PERSISTENT);
+ }
+ RootedPath rootedFile;
+
+ if (LabelValidator.isAbsolute(fileAttribute)) {
+ try {
+ // Parse a label
+ Label label = Label.parseAbsolute(fileAttribute);
+ SkyKey pkgSkyKey = PackageLookupValue.key(label.getPackageIdentifier());
+ PackageLookupValue pkgLookupValue = (PackageLookupValue) env.getValue(pkgSkyKey);
+ if (pkgLookupValue == null) {
+ return null;
+ }
+ if (!pkgLookupValue.packageExists()) {
+ throw new RepositoryFunctionException(
+ new EvalException(
+ rule.getLocation(),
+ "Unable to load package for " + fileAttribute + ": not found."),
+ Transience.PERSISTENT);
+ }
+
+ // And now for the file
+ Path packageRoot = pkgLookupValue.getRoot();
+ rootedFile = RootedPath.toRootedPath(packageRoot, label.toPathFragment());
+ } catch (LabelSyntaxException ex) {
+ throw new RepositoryFunctionException(
+ new EvalException(
+ rule.getLocation(),
+ String.format(
+ "In %s the '%s' attribute does not specify a valid label: %s",
+ rule, getFileAttrName(), ex.getMessage())),
+ Transience.PERSISTENT);
+ }
+ } else {
+ // TODO(dmarting): deprecate using a path for the workspace_file attribute.
+ PathFragment file = new PathFragment(fileAttribute);
+ Path fileTarget = workspacePath.getRelative(file);
+ if (!fileTarget.exists()) {
+ throw new RepositoryFunctionException(
+ new EvalException(
+ rule.getLocation(),
+ String.format(
+ "In %s the '%s' attribute does not specify an existing file "
+ + "(%s does not exist)",
+ rule, getFileAttrName(), fileTarget)),
+ Transience.PERSISTENT);
+ }
+
+ if (file.isAbsolute()) {
+ rootedFile =
+ RootedPath.toRootedPath(
+ fileTarget.getParentDirectory(), new PathFragment(fileTarget.getBaseName()));
+ } else {
+ rootedFile = RootedPath.toRootedPath(workspacePath, file);
+ }
+ }
+ SkyKey fileKey = FileValue.key(rootedFile);
+ FileValue fileValue;
+ try {
+ // Note that this dependency is, strictly speaking, not necessary: the symlink could simply
+ // point to this FileValue and the symlink chasing could be done while loading the package
+ // but this results in a nicer error message and it's correct as long as RepositoryFunctions
+ // don't write to things in the file system this FileValue depends on. In theory, the latter
+ // is possible if the file referenced by workspace_file is a symlink to somewhere under the
+ // external/ directory, but if you do that, you are really asking for trouble.
+ fileValue =
+ (FileValue)
+ env.getValueOrThrow(
+ fileKey,
+ IOException.class,
+ FileSymlinkException.class,
+ InconsistentFilesystemException.class);
+ if (fileValue == null) {
+ return null;
+ }
+ } catch (IOException | FileSymlinkException | InconsistentFilesystemException e) {
+ throw new RepositoryFunctionException(
+ new IOException("Cannot lookup " + fileAttribute + ": " + e.getMessage()),
+ Transience.TRANSIENT);
+ }
+
+ return fileValue;
+ }
+
+ /**
+ * Symlinks a file from the local filesystem into the external repository's root.
+ *
+ * @param fileValue {@link FileValue} representing the file to be linked in
+ * @param outputDirectory the directory of the remote repository
+ * @throws RepositoryFunctionException if the file specified does not exist or cannot be linked.
+ */
+ private static void symlinkFile(FileValue fileValue, String filename, Path outputDirectory)
+ throws RepositoryFunctionException {
+ Path filePath = outputDirectory.getRelative(filename);
+ RepositoryFunction.createSymbolicLink(filePath, fileValue.realRootedPath().asPath());
+ }
+ }
+
+ /**
+ * Encapsulates the 2-step behavior of creating workspace files for the new_*_repository rules.
+ */
+ public static class NewRepositoryWorkspaceFileHandler extends BaseFileHandler {
+
+ public NewRepositoryWorkspaceFileHandler(Path workspacePath) {
+ super(workspacePath, "WORKSPACE");
+ }
+
+ @Override
+ protected String getFileAttrName() {
+ return "workspace_file";
+ }
+
+ @Override
+ protected String getFileContentAttrName() {
+ return "workspace_file_content";
+ }
+
+ @Override
+ protected String getDefaultContent(Rule rule) {
+ return String.format(
+ "# DO NOT EDIT: automatically generated WORKSPACE file for %s\n"
+ + "workspace(name = \"%s\")\n",
+ rule.getTargetKind(), rule.getName());
+ }
+ }
+
+ /** Encapsulates the 2-step behavior of creating build files for the new_*_repository rules. */
+ public static class NewRepositoryBuildFileHandler extends BaseFileHandler {
+
+ public NewRepositoryBuildFileHandler(Path workspacePath) {
+ super(workspacePath, "BUILD.bazel");
+ }
+
+ @Override
+ protected String getFileAttrName() {
+ return "build_file";
+ }
+
+ @Override
+ protected String getFileContentAttrName() {
+ return "build_file_content";
+ }
+
+ @Override
+ protected String getDefaultContent(Rule rule) throws RepositoryFunctionException {
+ String error =
+ String.format("Rule %s requires a 'build_file' or 'build_file_content' attribute", rule);
+ throw new RepositoryFunctionException(
+ new EvalException(rule.getLocation(), error), Transience.PERSISTENT);
+ }
+ }
+}
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 f0ad02a67c..0b92f0ac7a 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
@@ -264,17 +264,18 @@ public abstract class RepositoryFunction {
}
}
- protected static RepositoryDirectoryValue.Builder writeBuildFile(
- Path repositoryDirectory, String contents) throws RepositoryFunctionException {
- Path buildFilePath = repositoryDirectory.getRelative("BUILD.bazel");
+ protected static RepositoryDirectoryValue.Builder writeFile(
+ Path repositoryDirectory, String filename, String contents)
+ throws RepositoryFunctionException {
+ Path filePath = repositoryDirectory.getRelative(filename);
try {
- // The repository could have an existing BUILD file that's either a regular file (for remote
+ // The repository could have an existing file that's either a regular file (for remote
// repositories) or a symlink (for local repositories). Either way, we want to remove it and
// write our own.
- if (buildFilePath.exists(Symlinks.NOFOLLOW)) {
- buildFilePath.delete();
+ if (filePath.exists(Symlinks.NOFOLLOW)) {
+ filePath.delete();
}
- FileSystemUtils.writeContentAsLatin1(buildFilePath, contents);
+ FileSystemUtils.writeContentAsLatin1(filePath, contents);
} catch (IOException e) {
throw new RepositoryFunctionException(e, Transience.TRANSIENT);
}
@@ -282,6 +283,11 @@ public abstract class RepositoryFunction {
return RepositoryDirectoryValue.builder().setPath(repositoryDirectory);
}
+ protected static RepositoryDirectoryValue.Builder writeBuildFile(
+ Path repositoryDirectory, String contents) throws RepositoryFunctionException {
+ return writeFile(repositoryDirectory, "BUILD.bazel", contents);
+ }
+
@VisibleForTesting
protected static PathFragment getTargetPath(Rule rule, Path workspace)
throws RepositoryFunctionException {