aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com')
-rw-r--r--src/main/java/com/google/devtools/build/lib/BUILD3
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java10
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/repository/GitRepositoryFunction.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/repository/HttpArchiveFunction.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/repository/MavenJarFunction.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/repository/MavenServerRepositoryFunction.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkPath.java75
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryContext.java132
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryFunction.java103
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryModule.java166
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidNdkRepositoryFunction.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidSdkRepositoryFunction.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/Package.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java7
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/RuleClass.java9
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/repository/LocalRepositoryFunction.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/repository/NewLocalRepositoryFunction.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorFunction.java22
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryFunction.java2
20 files changed, 527 insertions, 22 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD
index 25fab2153e..124d3c58fb 100644
--- a/src/main/java/com/google/devtools/build/lib/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/BUILD
@@ -570,7 +570,7 @@ java_library(
name = "bazel-repository",
srcs = glob(
[
- "bazel/repository/*.java",
+ "bazel/repository/**/*.java",
"bazel/rules/workspace/*.java",
],
exclude = ["bazel/repository/MavenConnector.java"],
@@ -596,6 +596,7 @@ java_library(
"//src/java_tools/singlejar/java/com/google/devtools/build/zip",
"//src/main/java/com/google/devtools/build/lib:build-base",
"//src/main/java/com/google/devtools/build/lib:packages-internal",
+ "//src/main/java/com/google/devtools/build/lib:skylarkinterface",
"//src/main/java/com/google/devtools/build/lib:vfs",
"//src/main/java/com/google/devtools/build/skyframe",
"//third_party:aether",
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java b/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java
index 0befcba0e8..dab80039c6 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java
@@ -30,6 +30,8 @@ import com.google.devtools.build.lib.bazel.repository.MavenServerFunction;
import com.google.devtools.build.lib.bazel.repository.MavenServerRepositoryFunction;
import com.google.devtools.build.lib.bazel.repository.NewGitRepositoryFunction;
import com.google.devtools.build.lib.bazel.repository.NewHttpArchiveFunction;
+import com.google.devtools.build.lib.bazel.repository.skylark.SkylarkRepositoryFunction;
+import com.google.devtools.build.lib.bazel.repository.skylark.SkylarkRepositoryModule;
import com.google.devtools.build.lib.bazel.rules.android.AndroidNdkRepositoryFunction;
import com.google.devtools.build.lib.bazel.rules.android.AndroidNdkRepositoryRule;
import com.google.devtools.build.lib.bazel.rules.android.AndroidSdkRepositoryFunction;
@@ -151,6 +153,7 @@ public class BazelRepositoryModule extends BlazeModule {
}
builder.addRuleDefinition(ruleDefinition);
}
+ builder.addSkylarkModule(SkylarkRepositoryModule.class);
}
@Override
@@ -171,9 +174,10 @@ public class BazelRepositoryModule extends BlazeModule {
// Create the repository function everything flows through.
builder.put(SkyFunctions.REPOSITORY, new RepositoryLoaderFunction());
- // Helper SkyFunctions.
- builder.put(SkyFunctions.REPOSITORY_DIRECTORY,
- new RepositoryDelegatorFunction(directories, repositoryHandlers, isFetch));
+ builder.put(
+ SkyFunctions.REPOSITORY_DIRECTORY,
+ new RepositoryDelegatorFunction(
+ directories, repositoryHandlers, new SkylarkRepositoryFunction(), isFetch));
builder.put(MavenServerFunction.NAME, new MavenServerFunction(directories));
return builder.build();
}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/GitRepositoryFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/GitRepositoryFunction.java
index 7ba85c6a40..4bb282eb97 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/repository/GitRepositoryFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/GitRepositoryFunction.java
@@ -33,7 +33,7 @@ import java.io.IOException;
*/
public class GitRepositoryFunction extends RepositoryFunction {
@Override
- public boolean isLocal() {
+ public boolean isLocal(Rule rule) {
return false;
}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/HttpArchiveFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/HttpArchiveFunction.java
index 5158bc6212..3952360e1e 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/repository/HttpArchiveFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/HttpArchiveFunction.java
@@ -34,7 +34,7 @@ import java.io.IOException;
*/
public class HttpArchiveFunction extends RepositoryFunction {
@Override
- public boolean isLocal() {
+ public boolean isLocal(Rule rule) {
return false;
}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/MavenJarFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/MavenJarFunction.java
index be4e9f7cb0..44c6ca33a9 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/repository/MavenJarFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/MavenJarFunction.java
@@ -61,7 +61,7 @@ public class MavenJarFunction extends HttpArchiveFunction {
private static final String DEFAULT_SERVER = "default";
@Override
- public boolean isLocal() {
+ public boolean isLocal(Rule rule) {
return false;
}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/MavenServerRepositoryFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/MavenServerRepositoryFunction.java
index 084e073daf..4ddf40e4f5 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/repository/MavenServerRepositoryFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/MavenServerRepositoryFunction.java
@@ -33,7 +33,7 @@ import javax.annotation.Nullable;
public class MavenServerRepositoryFunction extends RepositoryFunction {
@Override
- public boolean isLocal() {
+ public boolean isLocal(Rule rule) {
return true;
}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkPath.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkPath.java
new file mode 100644
index 0000000000..5b7217fb74
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkPath.java
@@ -0,0 +1,75 @@
+// Copyright 2016 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.bazel.repository.skylark;
+
+import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
+import com.google.devtools.build.lib.vfs.Path;
+
+/**
+ * A Path object to be used into Skylark remote repository.
+ */
+@Immutable
+@SkylarkModule(name = "path", doc = "A structure representing a file to be used inside a repository"
+)
+final class SkylarkPath {
+ final Path path;
+
+ public SkylarkPath(Path path) {
+ this.path = path;
+ }
+
+ @SkylarkCallable(
+ name = "basename",
+ structField = true,
+ doc = "A string giving the basename of the file."
+ )
+ public String getBasename() {
+ return path.getBaseName();
+ }
+
+ @SkylarkCallable(
+ name = "dirname",
+ structField = true,
+ doc = "The parent directory of this file, or None if this file does not have a parent."
+ )
+ public SkylarkPath getDirname() {
+ Path parentPath = path.getParentDirectory();
+ return parentPath == null ? null : new SkylarkPath(parentPath);
+ }
+
+ @SkylarkCallable(
+ name = "get_child",
+ doc = "Append the given path to this path and return the resulted path."
+ )
+ public SkylarkPath getChild(String childPath) {
+ return new SkylarkPath(path.getChild(childPath));
+ }
+
+ @SkylarkCallable(
+ name = "exists",
+ structField = true,
+ doc = "Returns true if the file denoted by this path exists."
+ )
+ public boolean exists() {
+ return path.exists();
+ }
+
+ @Override
+ public String toString() {
+ return path.toString();
+ }
+}
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
new file mode 100644
index 0000000000..cdd211812b
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryContext.java
@@ -0,0 +1,132 @@
+// Copyright 2016 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.bazel.repository.skylark;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.packages.AggregatingAttributeMapper;
+import com.google.devtools.build.lib.packages.Rule;
+import com.google.devtools.build.lib.rules.repository.RepositoryFunction.RepositoryFunctionException;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
+import com.google.devtools.build.lib.syntax.ClassObject.SkylarkClassObject;
+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.vfs.Path;
+import com.google.devtools.build.lib.vfs.PathFragment;
+import com.google.devtools.build.skyframe.SkyFunctionException.Transience;
+
+import java.io.IOException;
+
+/**
+ * Skylark API for the repository_rule's context.
+ */
+@SkylarkModule(
+ name = "repository_ctx",
+ doc =
+ "The context of the repository rule containing"
+ + " helper functions and information about attributes. You get a repository_ctx object"
+ + " as an argument to the <code>implementation</code> function when you create a"
+ + " repository rule."
+)
+public class SkylarkRepositoryContext {
+
+ private final Rule rule;
+ private final Path outputDirectory;
+ private final SkylarkClassObject attrObject;
+
+ /**
+ * In native code, private values start with $. In Skylark, private values start with _, because
+ * of the grammar.
+ */
+ private String attributeToSkylark(String oldName) {
+ if (!oldName.isEmpty() && (oldName.charAt(0) == '$' || oldName.charAt(0) == ':')) {
+ return "_" + oldName.substring(1);
+ }
+ return oldName;
+ }
+
+ /**
+ * Create a new context (ctx) object for a skylark repository rule ({@code rule} argument). The
+ * environment
+ */
+ SkylarkRepositoryContext(Rule rule, Path outputDirectory) {
+ this.rule = rule;
+ this.outputDirectory = outputDirectory;
+ AggregatingAttributeMapper attrs = AggregatingAttributeMapper.of(rule);
+ ImmutableMap.Builder<String, Object> attrBuilder = new ImmutableMap.Builder<>();
+ for (String name : attrs.getAttributeNames()) {
+ if (!name.equals("$local")) {
+ Type<?> type = attrs.getAttributeType(name);
+ Object val = attrs.get(name, type);
+ attrBuilder.put(
+ attributeToSkylark(name),
+ val == null
+ ? Runtime.NONE
+ // Attribute values should be type safe
+ : SkylarkType.convertToSkylark(val, null));
+ }
+ }
+ attrObject = new SkylarkClassObject(attrBuilder.build(), "No such attribute '%s'");
+ }
+
+ @SkylarkCallable(
+ name = "attr",
+ structField = true,
+ doc =
+ "A struct to access the values of the attributes. The values are provided by "
+ + "the user (if not, a default value is used)."
+ )
+ public SkylarkClassObject getAttr() {
+ return attrObject;
+ }
+
+ @SkylarkCallable(
+ name = "path",
+ doc =
+ "Returns a path from a string. If the path is relative, it will resolved relative "
+ + "to the output directory."
+ )
+ public SkylarkPath path(String path) {
+ PathFragment pathFragment = new PathFragment(path);
+ if (pathFragment.isAbsolute()) {
+ return new SkylarkPath(outputDirectory.getFileSystem().getPath(path));
+ } else {
+ return new SkylarkPath(outputDirectory.getRelative(pathFragment));
+ }
+ }
+
+ @SkylarkCallable(
+ name = "symlink",
+ doc =
+ "Create a symlink on the filesystem, the destination of the symlink should be in the "
+ + "output directory."
+ )
+ public void symlink(SkylarkPath from, SkylarkPath to) throws RepositoryFunctionException {
+ try {
+ to.path.createSymbolicLink(from.path);
+ } catch (IOException e) {
+ throw new RepositoryFunctionException(
+ new IOException(
+ "Could not create symlink from " + from + " to " + to + ": " + e.getMessage(), e),
+ Transience.TRANSIENT);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "repository_ctx[" + rule.getLabel() + "]";
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryFunction.java
new file mode 100644
index 0000000000..51bbe832f3
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryFunction.java
@@ -0,0 +1,103 @@
+// Copyright 2016 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.bazel.repository.skylark;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.packages.Rule;
+import com.google.devtools.build.lib.rules.repository.RepositoryDirectoryValue;
+import com.google.devtools.build.lib.rules.repository.RepositoryFunction;
+import com.google.devtools.build.lib.skyframe.FileValue;
+import com.google.devtools.build.lib.syntax.BaseFunction;
+import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.syntax.Mutability;
+import com.google.devtools.build.lib.syntax.Runtime;
+import com.google.devtools.build.lib.vfs.Path;
+import com.google.devtools.build.skyframe.SkyFunction.Environment;
+import com.google.devtools.build.skyframe.SkyFunctionException;
+import com.google.devtools.build.skyframe.SkyFunctionException.Transience;
+import com.google.devtools.build.skyframe.SkyValue;
+
+import java.io.IOException;
+
+import javax.annotation.Nullable;
+
+/**
+ * A repository function to delegate work done by skylark remote repositories.
+ */
+public class SkylarkRepositoryFunction extends RepositoryFunction {
+ @Nullable
+ @Override
+ public SkyValue fetch(Rule rule, Path outputDirectory, Environment env)
+ throws SkyFunctionException, InterruptedException {
+ BaseFunction function = rule.getRuleClassObject().getConfiguredTargetFunction();
+ try (Mutability mutability = Mutability.create("skylark repository")) {
+ com.google.devtools.build.lib.syntax.Environment buildEnv =
+ com.google.devtools.build.lib.syntax.Environment.builder(mutability)
+ .setGlobals(rule.getRuleClassObject().getRuleDefinitionEnvironment().getGlobals())
+ .setSkylark()
+ .setEventHandler(env.getListener())
+ .build();
+ SkylarkRepositoryContext skylarkRepositoryContext =
+ new SkylarkRepositoryContext(rule, outputDirectory);
+ // This has side-effect, we don't care about the output.
+ // Also we do a lot of stuff in there, maybe blocking operations and we should certainly make
+ // it possible to return null and not block but it doesn't seem to be easy with Skylark
+ // structure as it is.
+ Object retValue =
+ function.call(
+ ImmutableList.<Object>of(skylarkRepositoryContext),
+ ImmutableMap.<String, Object>of(),
+ null,
+ buildEnv);
+ if (retValue != Runtime.NONE) {
+ throw new RepositoryFunctionException(
+ new EvalException(
+ rule.getLocation(),
+ "Call to repository rule "
+ + rule.getName()
+ + " returned a non-None value, None expected."),
+ Transience.PERSISTENT);
+ }
+ } catch (EvalException e) {
+ throw new RepositoryFunctionException(e, Transience.TRANSIENT);
+ }
+
+ FileValue repositoryValue = getRepositoryDirectory(outputDirectory, env);
+ if (repositoryValue == null) {
+ // TODO(bazel-team): If this returns null, we unnecessarily recreate the symlink above on the
+ // second execution.
+ return null;
+ }
+
+ if (!repositoryValue.isDirectory()) {
+ throw new RepositoryFunctionException(
+ new IOException(rule + " must create a directory"), Transience.TRANSIENT);
+ }
+
+ return RepositoryDirectoryValue.create(outputDirectory);
+ }
+
+ @Override
+ protected boolean isLocal(Rule rule) {
+ return (Boolean) rule.getAttributeContainer().getAttr("$local");
+ }
+
+ @Override
+ public Class<? extends RuleDefinition> getRuleDefinition() {
+ return null; // unused so safe to return null
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryModule.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryModule.java
new file mode 100644
index 0000000000..252ecdaac3
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/skylark/SkylarkRepositoryModule.java
@@ -0,0 +1,166 @@
+// Copyright 2016 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.bazel.repository.skylark;
+
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.syntax.SkylarkType.castMap;
+import static com.google.devtools.build.lib.syntax.Type.BOOLEAN;
+
+import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
+import com.google.devtools.build.lib.packages.Attribute;
+import com.google.devtools.build.lib.packages.Package.NameConflictException;
+import com.google.devtools.build.lib.packages.PackageFactory;
+import com.google.devtools.build.lib.packages.PackageFactory.PackageContext;
+import com.google.devtools.build.lib.packages.RuleClass;
+import com.google.devtools.build.lib.packages.RuleClass.Builder;
+import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType;
+import com.google.devtools.build.lib.packages.RuleFactory.InvalidRuleException;
+import com.google.devtools.build.lib.rules.SkylarkAttr.Descriptor;
+import com.google.devtools.build.lib.rules.SkylarkRuleClassFunctions;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkSignature;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkSignature.Param;
+import com.google.devtools.build.lib.syntax.BaseFunction;
+import com.google.devtools.build.lib.syntax.BuiltinFunction;
+import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.syntax.FuncallExpression;
+import com.google.devtools.build.lib.syntax.FunctionSignature;
+import com.google.devtools.build.lib.syntax.Runtime;
+import com.google.devtools.build.lib.syntax.SkylarkDict;
+import com.google.devtools.build.lib.syntax.SkylarkSignatureProcessor;
+
+import java.util.Map;
+
+/**
+ * The Skylark module containing the definition of {@code repository_rule} function to define a
+ * skylark remote repository.
+ */
+public class SkylarkRepositoryModule {
+
+ @SkylarkSignature(
+ name = "repository_rule",
+ doc =
+ "Creates a new repository rule. Store it in a global value, so that it can be loaded and "
+ + "called from the WORKSPACE file.",
+ returnType = BaseFunction.class,
+ mandatoryPositionals = {
+ @Param(
+ name = "implementation",
+ type = BaseFunction.class,
+ doc =
+ "the function implementing this rule, has to have exactly one parameter: "
+ + "<code>ctx</code>. The function is called during analysis phase for each "
+ + "instance of the rule."
+ )
+ },
+ optionalNamedOnly = {
+ @Param(
+ name = "attrs",
+ type = SkylarkDict.class,
+ noneable = true,
+ defaultValue = "None",
+ doc =
+ "dictionary to declare all the attributes of the rule. It maps from an attribute "
+ + "name to an attribute object (see <a href=\"#modules.attr\">attr</a> "
+ + "module). Attributes starting with <code>_</code> are private, and can be "
+ + "used to add an implicit dependency on a label to a file (a repository "
+ + "rule cannot depend on a generated artifact). The attribute "
+ + "<code>name</code> is implicitly added and must not be specified."
+ ),
+ @Param(
+ name = "local",
+ type = Boolean.class,
+ defaultValue = "False",
+ doc =
+ "Indicate that this rule fetches everything from the local system and should be "
+ + "reevaluated at every fetch."
+ )
+ },
+ useAst = true,
+ useEnvironment = true
+ )
+ private static final BuiltinFunction repositoryRule =
+ new BuiltinFunction("repository_rule") {
+ @SuppressWarnings({"rawtypes", "unused"})
+ // an Attribute.Builder instead of a Attribute.Builder<?> but it's OK.
+ public BaseFunction invoke(
+ BaseFunction implementation,
+ Object attrs,
+ Boolean local,
+ FuncallExpression ast,
+ com.google.devtools.build.lib.syntax.Environment funcallEnv)
+ throws EvalException {
+ funcallEnv.checkLoadingPhase("repository_rule", ast.getLocation());
+ // We'll set the name later, pass the empty string for now.
+ Builder builder = new Builder("", RuleClassType.WORKSPACE, true);
+
+ if (attrs != Runtime.NONE) {
+ for (Map.Entry<String, Descriptor> attr :
+ castMap(attrs, String.class, Descriptor.class, "attrs").entrySet()) {
+ Descriptor attrDescriptor = attr.getValue();
+ String attrName =
+ SkylarkRuleClassFunctions.attributeToNative(
+ attr.getKey(),
+ ast.getLocation(),
+ attrDescriptor.getAttributeBuilder().hasLateBoundValue());
+ Attribute.Builder<?> attrBuilder = attrDescriptor.getAttributeBuilder();
+ builder.addOrOverrideAttribute(attrBuilder.build(attrName));
+ }
+ }
+ builder.addOrOverrideAttribute(attr("$local", BOOLEAN).defaultValue(local).build());
+ builder.setConfiguredTargetFunction(implementation);
+ builder.setRuleDefinitionEnvironment(funcallEnv);
+ builder.setWorkspaceOnly();
+ return new RepositoryRuleFunction(builder);
+ }
+ };
+
+ private static final class RepositoryRuleFunction extends BaseFunction {
+ private final Builder builder;
+
+ public RepositoryRuleFunction(Builder builder) {
+ super("repository_rule", FunctionSignature.KWARGS);
+ this.builder = builder;
+ }
+
+ @Override
+ public Object call(
+ Object[] args, FuncallExpression ast, com.google.devtools.build.lib.syntax.Environment env)
+ throws EvalException, InterruptedException {
+ String ruleClassName = ast.getFunction().getName();
+ try {
+ if (ruleClassName.startsWith("_")) {
+ throw new EvalException(
+ ast.getLocation(),
+ "Invalid rule class name '" + ruleClassName + "', cannot be private");
+ }
+ RuleClass ruleClass = builder.build(ruleClassName);
+ PackageContext context = PackageFactory.getContext(env, ast);
+ @SuppressWarnings("unchecked")
+ Map<String, Object> attributeValues = (Map<String, Object>) args[0];
+ return context
+ .getBuilder()
+ .externalPackageData()
+ .createAndAddRepositoryRule(
+ context.getBuilder(), ruleClass, null, attributeValues, ast);
+ } catch (InvalidRuleException | NameConflictException | LabelSyntaxException e) {
+ throw new EvalException(ast.getLocation(), e.getMessage());
+ }
+ }
+ }
+
+ static {
+ SkylarkSignatureProcessor.configureSkylarkFunctions(SkylarkRepositoryModule.class);
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidNdkRepositoryFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidNdkRepositoryFunction.java
index 04d9c5b8b8..7b3a7686ab 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidNdkRepositoryFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidNdkRepositoryFunction.java
@@ -69,7 +69,7 @@ public class AndroidNdkRepositoryFunction extends RepositoryFunction {
}
@Override
- public boolean isLocal() {
+ public boolean isLocal(Rule rule) {
return true;
}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidSdkRepositoryFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidSdkRepositoryFunction.java
index f3f4dc9299..f9b1c65935 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidSdkRepositoryFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidSdkRepositoryFunction.java
@@ -34,7 +34,7 @@ import java.io.IOException;
*/
public class AndroidSdkRepositoryFunction extends RepositoryFunction {
@Override
- public boolean isLocal() {
+ public boolean isLocal(Rule rule) {
return true;
}
diff --git a/src/main/java/com/google/devtools/build/lib/packages/Package.java b/src/main/java/com/google/devtools/build/lib/packages/Package.java
index e01787adbb..1776ed6626 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/Package.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/Package.java
@@ -1294,7 +1294,7 @@ public class Package {
return pkg;
}
- protected ExternalPackageBuilder externalPackageData() {
+ public ExternalPackageBuilder externalPackageData() {
return externalPackageData;
}
diff --git a/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java b/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java
index 055ef73bf9..36213d53fe 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java
@@ -1398,6 +1398,13 @@ public final class PackageFactory {
public MakeEnvironment.Builder getMakeEnvironment() {
return pkgBuilder.getMakeEnvironment();
}
+
+ /**
+ * Returns the builder of this Package.
+ */
+ public Package.Builder getBuilder() {
+ return pkgBuilder;
+ }
}
private final ClassObject nativeModule;
diff --git a/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java b/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java
index 137aeb8775..8064936556 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java
@@ -559,10 +559,11 @@ public final class RuleClass {
Preconditions.checkState(
(type == RuleClassType.ABSTRACT)
== (configuredTargetFactory == null && configuredTargetFunction == null));
- Preconditions.checkState(skylarkExecutable == (configuredTargetFunction != null));
- Preconditions.checkState(skylarkExecutable == (ruleDefinitionEnvironment != null));
- Preconditions.checkState(workspaceOnly || externalBindingsFunction == NO_EXTERNAL_BINDINGS);
-
+ if (!workspaceOnly) {
+ Preconditions.checkState(skylarkExecutable == (configuredTargetFunction != null));
+ Preconditions.checkState(skylarkExecutable == (ruleDefinitionEnvironment != null));
+ Preconditions.checkState(externalBindingsFunction == NO_EXTERNAL_BINDINGS);
+ }
return new RuleClass(name, skylark, skylarkExecutable, documented, publicByDefault,
binaryOutput, workspaceOnly, outputsDefaultExecutable, implicitOutputsFunction,
configurator, configuredTargetFactory, validityPredicate, preferredDependencyPredicate,
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
index d9ce457863..3558cf24bf 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
@@ -236,7 +236,7 @@ public class SkylarkRuleClassFunctions {
* In native code, private values start with $.
* In Skylark, private values start with _, because of the grammar.
*/
- private static String attributeToNative(String oldName, Location loc, boolean isLateBound)
+ public static String attributeToNative(String oldName, Location loc, boolean isLateBound)
throws EvalException {
if (oldName.isEmpty()) {
throw new EvalException(loc, "Attribute name cannot be empty");
diff --git a/src/main/java/com/google/devtools/build/lib/rules/repository/LocalRepositoryFunction.java b/src/main/java/com/google/devtools/build/lib/rules/repository/LocalRepositoryFunction.java
index eb527befc9..f706daa559 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/repository/LocalRepositoryFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/repository/LocalRepositoryFunction.java
@@ -33,7 +33,7 @@ import java.io.IOException;
*/
public class LocalRepositoryFunction extends RepositoryFunction {
@Override
- public boolean isLocal() {
+ public boolean isLocal(Rule rule) {
return true;
}
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 4fec7696ff..e5537c4a65 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
@@ -28,7 +28,7 @@ import com.google.devtools.build.skyframe.SkyValue;
public class NewLocalRepositoryFunction extends RepositoryFunction {
@Override
- public boolean isLocal() {
+ public boolean isLocal(Rule rule) {
return true;
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorFunction.java b/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorFunction.java
index e83433b082..c5cd01ef05 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorFunction.java
@@ -34,6 +34,8 @@ import com.google.devtools.build.skyframe.SkyValue;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;
+import javax.annotation.Nullable;
+
/**
* A {@link SkyFunction} that implements delegation to the correct repository fetcher.
*
@@ -42,19 +44,28 @@ import java.util.concurrent.atomic.AtomicBoolean;
*/
public class RepositoryDelegatorFunction implements SkyFunction {
+ // A special repository delegate used to handle Skylark remote repositories if present.
+ public static final String SKYLARK_DELEGATE_NAME = "$skylark";
+
// Mapping of rule class name to RepositoryFunction.
private final ImmutableMap<String, RepositoryFunction> handlers;
+ // Delegate function to handle skylark remote repositories
+ private final RepositoryFunction skylarkHandler;
+
// This is a reference to isFetch in BazelRepositoryModule, which tracks whether the current
// command is a fetch. Remote repository lookups are only allowed during fetches.
private final AtomicBoolean isFetch;
private final BlazeDirectories directories;
public RepositoryDelegatorFunction(
- BlazeDirectories directories, ImmutableMap<String, RepositoryFunction> handlers,
+ BlazeDirectories directories,
+ ImmutableMap<String, RepositoryFunction> handlers,
+ @Nullable RepositoryFunction skylarkHandler,
AtomicBoolean isFetch) {
this.directories = directories;
this.handlers = handlers;
+ this.skylarkHandler = skylarkHandler;
this.isFetch = isFetch;
}
@@ -77,7 +88,12 @@ public class RepositoryDelegatorFunction implements SkyFunction {
return null;
}
- RepositoryFunction handler = handlers.get(rule.getRuleClass());
+ RepositoryFunction handler;
+ if (rule.getRuleClassObject().isSkylark()) {
+ handler = skylarkHandler;
+ } else {
+ handler = handlers.get(rule.getRuleClass());
+ }
if (handler == null) {
throw new RepositoryFunctionException(new EvalException(
Location.fromFile(directories.getWorkspace().getRelative("WORKSPACE")),
@@ -87,7 +103,7 @@ public class RepositoryDelegatorFunction implements SkyFunction {
Path repoRoot =
RepositoryFunction.getExternalRepositoryDirectory(directories).getRelative(rule.getName());
- if (handler.isLocal()) {
+ if (handler.isLocal(rule)) {
// Local repositories are always fetched because the operation is generally fast and they do
// not depend on non-local data, so it does not make much sense to try to catch from across
// server instances.
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 c2f327d749..2e0843ca33 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
@@ -159,7 +159,7 @@ public abstract class RepositoryFunction {
* <p>If this is false, Bazel may decide not to re-fetch the repository, for example when the
* {@code --nofetch} command line option is used.
*/
- protected abstract boolean isLocal();
+ protected abstract boolean isLocal(Rule rule);
/**
* Returns a block of data that must be equal for two Rules for them to be considered the same.