Implements repository_ctx.template repository_ctx.template enable writing a file in the remote repository tree using a template and a list of substitution in a similar way as the ctx.template_action for regular skylark rule. Issue #893: Step 4 of http://goo.gl/OZV3o0. See http://goo.gl/fD4ZsY. -- MOS_MIGRATED_REVID=115439344
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryContext.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryContext.java index 45138da..e2500da 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryContext.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryContext.java
@@ -33,6 +33,8 @@ import com.google.devtools.build.lib.syntax.Runtime; import com.google.devtools.build.lib.syntax.SkylarkType; import com.google.devtools.build.lib.syntax.Type; +import com.google.devtools.build.lib.util.StringUtilities; +import com.google.devtools.build.lib.vfs.FileSystemUtils; import com.google.devtools.build.lib.vfs.Path; import com.google.devtools.build.lib.vfs.PathFragment; import com.google.devtools.build.lib.vfs.RootedPath; @@ -201,6 +203,34 @@ } } + @SkylarkCallable( + name = "template", + doc = + "Generate a new file using a <code>template</code>. Every occurrence in " + + "<code>template</code> of a key of <code>substitutions</code> will be replaced by " + + "the corresponding value. The result is written in <code>path</code>." + ) + public void createFileFromTemplate( + Object path, Object template, Map<String, String> substitutions) + throws RepositoryFunctionException, EvalException { + SkylarkPath p = getPath("template()", path); + SkylarkPath t = getPath("template()", template); + try { + checkInOutputDirectory(p); + makeDirectories(p.path); + String tpl = FileSystemUtils.readContent(t.path, StandardCharsets.UTF_8); + for (Map.Entry<String, String> substitution : substitutions.entrySet()) { + tpl = + StringUtilities.replaceAllLiteral(tpl, substitution.getKey(), substitution.getValue()); + } + try (OutputStream stream = p.path.getOutputStream()) { + stream.write(tpl.getBytes(StandardCharsets.UTF_8)); + } + } catch (IOException e) { + throw new RepositoryFunctionException(e, Transience.TRANSIENT); + } + } + // Create parent directories for the given path private void makeDirectories(Path path) throws IOException { if (!path.isRootDirectory()) {
diff --git a/src/test/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryIntegrationTest.java b/src/test/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryIntegrationTest.java index aaca4d0..dcdc6e4 100644 --- a/src/test/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryIntegrationTest.java +++ b/src/test/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryIntegrationTest.java
@@ -195,4 +195,30 @@ Object path = target.getTarget().getAssociatedRule().getAttributeContainer().getAttr("path"); assertThat(path).isEqualTo("foo"); } + + @Test + public void testSkylarkRepositoryTemplate() throws Exception { + scratch.file("/repo2/bar.txt", "filegroup(name='{target}', srcs=['foo.txt'], path='{path}')"); + scratch.file("/repo2/BUILD"); + scratch.file("/repo2/WORKSPACE"); + scratch.file( + "def.bzl", + "def _impl(ctx):", + " ctx.template('BUILD', Label('@repo2//:bar.txt'), {'{target}': 'bar', '{path}': 'foo'})", + " ctx.file('foo.txt', 'foo')", + "", + "repo = repository_rule(", + " implementation=_impl,", + " local=True)"); + scratch.file(rootDirectory.getRelative("BUILD").getPathString()); + scratch.overwriteFile( + rootDirectory.getRelative("WORKSPACE").getPathString(), + "local_repository(name='repo2', path='/repo2')", + "load('//:def.bzl', 'repo')", + "repo(name='foo')"); + invalidatePackages(); + ConfiguredTarget target = getConfiguredTarget("@foo//:bar"); + Object path = target.getTarget().getAssociatedRule().getAttributeContainer().getAttr("path"); + assertThat(path).isEqualTo("foo"); + } }