diff options
author | jcater <jcater@google.com> | 2017-03-30 20:09:33 +0000 |
---|---|---|
committer | Philipp Wollermann <philwo@google.com> | 2017-03-31 17:11:00 +0200 |
commit | 18a4c841d48df2eb52f27817ed566833809a92cc (patch) | |
tree | 7d2963e4e82f34f1cf4d039e6d8e62df4e8874a1 /src/main/java/com/google/devtools/build/lib/rules/repository | |
parent | 63111882e794f786ab857c92b01383a457e843a4 (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')
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 { |