aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools
diff options
context:
space:
mode:
authorGravatar dslomov <dslomov@google.com>2017-06-27 14:38:45 +0200
committerGravatar Marcel Hlopko <hlopko@google.com>2017-06-27 15:06:32 +0200
commit2e84e7ccba814253bf1402242c2ba6dab9293c6e (patch)
tree09594e73f3dcf1218194cdebba86f3114be7fd09 /src/main/java/com/google/devtools
parentc5ddd422180b85e44a39bb7f7b6119be6a44918b (diff)
Add 'ctx.actions' and implement 'ctx.action.declare_file'.
RELNOTES: None. PiperOrigin-RevId: 160264501
Diffstat (limited to 'src/main/java/com/google/devtools')
-rw-r--r--src/main/java/com/google/devtools/build/lib/actions/Artifact.java4
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkActionFactory.java110
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java15
3 files changed, 126 insertions, 3 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/actions/Artifact.java b/src/main/java/com/google/devtools/build/lib/actions/Artifact.java
index 74c7682f09..4a956db6aa 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/Artifact.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/Artifact.java
@@ -99,8 +99,8 @@ import javax.annotation.Nullable;
+ "Files. If you have a Skylark rule that needs to create a new File, you might need to "
+ "add the label to the attrs (if it's an input) or the outputs (if it's an output). Then "
+ "you can access the File through the rule's <a href='ctx.html'>context</a>. You can "
- + "also use <a href='ctx.html#new_file'>ctx.new_file</a> to create a new file in the rule "
- + "implementation.</p>")
+ + "also use <a href='actions.html#declare_file'>ctx.actions.declare_file</a> to "
+ + "declare a new file in the rule implementation.</p>")
public class Artifact
implements FileType.HasFilename, ActionInput, SkylarkValue, Comparable<Object> {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkActionFactory.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkActionFactory.java
new file mode 100644
index 0000000000..6157392a68
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkActionFactory.java
@@ -0,0 +1,110 @@
+// Copyright 2017 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;
+
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.Root;
+import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.skylarkinterface.Param;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
+import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.syntax.Printer;
+import com.google.devtools.build.lib.syntax.Runtime;
+import com.google.devtools.build.lib.vfs.PathFragment;
+
+/**
+ * Provides a Skylark interface for all action creation needs.
+ */
+@SkylarkModule(
+ name = "actions",
+ category = SkylarkModuleCategory.BUILTIN,
+ doc = "Module providing functions to create actions."
+)
+
+public class SkylarkActionFactory implements SkylarkValue {
+ private final SkylarkRuleContext context;
+ private RuleContext ruleContext;
+
+
+ public SkylarkActionFactory(SkylarkRuleContext context, RuleContext ruleContext) {
+ this.context = context;
+ this.ruleContext = ruleContext;
+ }
+
+ Root newFileRoot() throws EvalException {
+ return context.isForAspect()
+ ? ruleContext.getConfiguration().getBinDirectory(ruleContext.getRule().getRepository())
+ : ruleContext.getBinOrGenfilesDirectory();
+ }
+
+
+ @SkylarkCallable(
+ name = "declare_file",
+ doc =
+ "Declares that rule or aspect creates a file with the given filename. "
+ + "If <code>sibling</code> is not specified, file name is relative to "
+ + "package directory, otherwise the file is in the same directory as "
+ + "<code>sibling</code>. "
+ + "You must create an action that generates the file. <br>"
+ + "Files that are specified in rule's outputs do not need to be declared and are "
+ + "available through <a href=\"ctx.html#outputs\">ctx.outputs</a>.",
+ parameters = {
+ @Param(
+ name = "filename",
+ type = String.class,
+ doc =
+ "If no 'sibling' provided, path of the new file, relative "
+ + "to the current package. Otherwise a base name for a file "
+ + "('sibling' determines a directory)."
+ ),
+ @Param(
+ name = "sibling",
+ doc = "A file that lives in the same directory as the newly created file.",
+ type = Artifact.class,
+ noneable = true,
+ positional = false,
+ named = true,
+ defaultValue = "None"
+ )
+ }
+ )
+ public Artifact declareFile(String filename, Object sibling) throws EvalException {
+ context.checkMutable("actions.declareFile");
+ if (Runtime.NONE.equals(sibling)) {
+ return ruleContext.getPackageRelativeArtifact(filename, newFileRoot());
+ } else {
+ PathFragment original = ((Artifact) sibling).getRootRelativePath();
+ PathFragment fragment = original.replaceName(filename);
+ return ruleContext.getDerivedArtifact(fragment, newFileRoot());
+ }
+ }
+
+ @Override
+ public boolean isImmutable() {
+ return context.isImmutable();
+ }
+
+ @Override
+ public void write(Appendable buffer, char quotationMark) {
+ Printer.append(buffer, "actions for");
+ context.write(buffer, quotationMark);
+ }
+
+ void nullify() {
+ ruleContext = null;
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java
index d85a2ecf16..8fee2dda42 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleContext.java
@@ -169,6 +169,8 @@ public final class SkylarkRuleContext implements SkylarkValue {
// after this object has been nullified.
private final String ruleLabelCanonicalName;
+ private final SkylarkActionFactory actionFactory;
+
// The fields below intended to be final except that they can be cleared by calling `nullify()`
// when the object becomes featureless.
private RuleContext ruleContext;
@@ -195,6 +197,7 @@ public final class SkylarkRuleContext implements SkylarkValue {
public SkylarkRuleContext(RuleContext ruleContext,
@Nullable AspectDescriptor aspectDescriptor)
throws EvalException, InterruptedException {
+ this.actionFactory = new SkylarkActionFactory(this, ruleContext);
this.ruleContext = Preconditions.checkNotNull(ruleContext);
this.ruleLabelCanonicalName = ruleContext.getLabel().getCanonicalForm();
this.fragments = new FragmentCollection(ruleContext, ConfigurationTransition.NONE);
@@ -293,6 +296,7 @@ public final class SkylarkRuleContext implements SkylarkValue {
* rule implementation function has exited).
*/
public void nullify() {
+ actionFactory.nullify();
ruleContext = null;
fragments = null;
hostFragments = null;
@@ -611,6 +615,15 @@ public final class SkylarkRuleContext implements SkylarkValue {
return DefaultProvider.SKYLARK_CONSTRUCTOR;
}
+ @SkylarkCallable(
+ name = "actions",
+ structField = true,
+ doc = "Functions to declare files and create actions."
+ )
+ public SkylarkActionFactory actions() {
+ return actionFactory;
+ }
+
@SkylarkCallable(name = "created_actions",
doc = "For rules with <a href=\"globals.html#rule._skylark_testable\">_skylark_testable"
+ "</a> set to <code>True</code>, this returns an "
@@ -867,7 +880,7 @@ public final class SkylarkRuleContext implements SkylarkValue {
}
}
- private boolean isForAspect() {
+ boolean isForAspect() {
return ruleAttributesCollection != null;
}