aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Damien Martin-Guillerez <dmarting@google.com>2016-02-23 15:43:12 +0000
committerGravatar Damien Martin-Guillerez <dmarting@google.com>2016-02-23 22:17:20 +0000
commitaa731afb731ffb2db0f33127dbe8ba649bf2888d (patch)
tree13166017a2cb9a7cabcfbcc907c255a1cc80ce8d
parent14255283843a455b7f5ce0588777d7b2cec84b4a (diff)
Implements repository_ctx.file
repository_ctx.file enable writing random file in the remote repository tree. Issue #893: Step 4 of http://goo.gl/OZV3o0. See http://goo.gl/fD4ZsY. -- MOS_MIGRATED_REVID=115338910
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryContext.java43
-rw-r--r--src/test/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryContextTest.java48
2 files changed, 91 insertions, 0 deletions
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 04a868b9d0..c48a964d82 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
@@ -34,6 +34,8 @@ import com.google.devtools.build.skyframe.SkyFunctionException.Transience;
import java.io.File;
import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
@@ -124,6 +126,7 @@ public class SkylarkRepositoryContext {
)
public void symlink(SkylarkPath from, SkylarkPath to) throws RepositoryFunctionException {
try {
+ checkInOutputDirectory(to);
to.path.createSymbolicLink(from.path);
} catch (IOException e) {
throw new RepositoryFunctionException(
@@ -133,6 +136,46 @@ public class SkylarkRepositoryContext {
}
}
+ private void checkInOutputDirectory(SkylarkPath path) throws RepositoryFunctionException {
+ if (!path.path.getPathString().startsWith(outputDirectory.getPathString())) {
+ throw new RepositoryFunctionException(
+ new IOException("Cannot write outside of the output directory for path " + path),
+ Transience.TRANSIENT);
+ }
+ }
+
+ @SkylarkCallable(name = "file", documented = false)
+ public void createFile(SkylarkPath path) throws RepositoryFunctionException {
+ createFile(path, "");
+ }
+
+ @SkylarkCallable(
+ name = "file",
+ doc = "Generate a file in the output directory with the provided content"
+ )
+ public void createFile(SkylarkPath path, String content) throws RepositoryFunctionException {
+ try {
+ checkInOutputDirectory(path);
+ makeDirectories(path.path);
+ try (OutputStream stream = path.path.getOutputStream()) {
+ stream.write(content.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()) {
+ Path parent = path.getParentDirectory();
+ if (!parent.exists()) {
+ makeDirectories(path.getParentDirectory());
+ parent.createDirectory();
+ }
+ }
+ }
+
@SkylarkCallable(
name = "os",
structField = true,
diff --git a/src/test/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryContextTest.java b/src/test/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryContextTest.java
index e2db60ace4..22b185e603 100644
--- a/src/test/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryContextTest.java
+++ b/src/test/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryContextTest.java
@@ -15,15 +15,18 @@
package com.google.devtools.build.lib.bazel.repository.skylark;
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
+import com.google.common.io.CharStreams;
import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.packages.Attribute;
import com.google.devtools.build.lib.packages.Package;
import com.google.devtools.build.lib.packages.Rule;
import com.google.devtools.build.lib.packages.RuleClass;
import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType;
+import com.google.devtools.build.lib.rules.repository.RepositoryFunction.RepositoryFunctionException;
import com.google.devtools.build.lib.syntax.Argument.Passed;
import com.google.devtools.build.lib.syntax.BuiltinFunction;
import com.google.devtools.build.lib.syntax.FuncallExpression;
@@ -38,6 +41,9 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
import java.util.Map;
/**
@@ -115,4 +121,46 @@ public class SkylarkRepositoryContextTest {
assertThat(context.which("true").toString()).isEqualTo("/bin/true");
assertThat(context.which("false").toString()).isEqualTo("/path/sbin/false");
}
+
+ @Test
+ public void testFile() throws Exception {
+ setUpContexForRule("test");
+ context.createFile(context.path("foobar"));
+ context.createFile(context.path("foo/bar"), "foobar");
+ context.createFile(context.path("bar/foo/bar"));
+
+ testOutputFile(outputDirectory.getChild("foobar"), "");
+ testOutputFile(outputDirectory.getRelative("foo/bar"), "foobar");
+ testOutputFile(outputDirectory.getRelative("bar/foo/bar"), "");
+
+ try {
+ context.createFile(context.path("/absolute"));
+ fail("Expected error on creating path outside of the output directory");
+ } catch (RepositoryFunctionException ex) {
+ assertThat(ex.getCause().getMessage())
+ .isEqualTo("Cannot write outside of the output directory for path /absolute");
+ }
+ try {
+ context.createFile(context.path("../somepath"));
+ fail("Expected error on creating path outside of the output directory");
+ } catch (RepositoryFunctionException ex) {
+ assertThat(ex.getCause().getMessage())
+ .isEqualTo("Cannot write outside of the output directory for path /somepath");
+ }
+ try {
+ context.createFile(context.path("foo/../../somepath"));
+ fail("Expected error on creating path outside of the output directory");
+ } catch (RepositoryFunctionException ex) {
+ assertThat(ex.getCause().getMessage())
+ .isEqualTo("Cannot write outside of the output directory for path /somepath");
+ }
+ }
+
+ private void testOutputFile(Path path, String content) throws IOException {
+ assertThat(path.exists()).isTrue();
+ assertThat(
+ CharStreams.toString(
+ new InputStreamReader(path.getInputStream(), StandardCharsets.UTF_8)))
+ .isEqualTo(content);
+ }
}