aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib
diff options
context:
space:
mode:
authorGravatar David Chen <dzc@google.com>2015-07-16 13:23:01 +0000
committerGravatar Philipp Wollermann <philwo@google.com>2015-07-17 13:17:26 +0000
commitdeb003fae0e0da7d45156f5ea0b36900aa9e5790 (patch)
tree4989137a972c6e6e19f4fcb8cebf6085d0745513 /src/main/java/com/google/devtools/build/lib
parent768b5ccdfad99e3ead5bd8c1c861b3f52506f748 (diff)
Add git_repository and new_git_repository workspace rules.
TESTED=Added integration tests. -- MOS_MIGRATED_REVID=98396197
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib')
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java11
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/repository/GitCloneFunction.java180
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/repository/GitProgressMonitor.java72
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/repository/GitRepositoryFunction.java84
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/repository/NewGitRepositoryFunction.java66
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java4
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/GitRepositoryRule.java126
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/NewGitRepositoryRule.java135
8 files changed, 678 insertions, 0 deletions
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 7e3265b26b..555f0cbbfe 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
@@ -22,12 +22,15 @@ import com.google.devtools.build.lib.analysis.BlazeVersionInfo;
import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
import com.google.devtools.build.lib.analysis.RuleDefinition;
import com.google.devtools.build.lib.bazel.commands.FetchCommand;
+import com.google.devtools.build.lib.bazel.repository.GitCloneFunction;
+import com.google.devtools.build.lib.bazel.repository.GitRepositoryFunction;
import com.google.devtools.build.lib.bazel.repository.HttpArchiveFunction;
import com.google.devtools.build.lib.bazel.repository.HttpDownloadFunction;
import com.google.devtools.build.lib.bazel.repository.HttpJarFunction;
import com.google.devtools.build.lib.bazel.repository.JarFunction;
import com.google.devtools.build.lib.bazel.repository.LocalRepositoryFunction;
import com.google.devtools.build.lib.bazel.repository.MavenJarFunction;
+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.NewLocalRepositoryFunction;
import com.google.devtools.build.lib.bazel.repository.RepositoryDelegatorFunction;
@@ -42,10 +45,12 @@ import com.google.devtools.build.lib.bazel.rules.android.AndroidRepositoryRules;
import com.google.devtools.build.lib.bazel.rules.android.AndroidRepositoryRules.AndroidHttpToolsRepositoryRule;
import com.google.devtools.build.lib.bazel.rules.android.AndroidSdkRepositoryFunction;
import com.google.devtools.build.lib.bazel.rules.android.AndroidSdkRepositoryRule;
+import com.google.devtools.build.lib.bazel.rules.workspace.GitRepositoryRule;
import com.google.devtools.build.lib.bazel.rules.workspace.HttpArchiveRule;
import com.google.devtools.build.lib.bazel.rules.workspace.HttpJarRule;
import com.google.devtools.build.lib.bazel.rules.workspace.LocalRepositoryRule;
import com.google.devtools.build.lib.bazel.rules.workspace.MavenJarRule;
+import com.google.devtools.build.lib.bazel.rules.workspace.NewGitRepositoryRule;
import com.google.devtools.build.lib.bazel.rules.workspace.NewHttpArchiveRule;
import com.google.devtools.build.lib.bazel.rules.workspace.NewLocalRepositoryRule;
import com.google.devtools.build.lib.pkgcache.PackageCacheOptions;
@@ -75,14 +80,17 @@ public class BazelRepositoryModule extends BlazeModule {
private final ImmutableMap<String, RepositoryFunction> repositoryHandlers;
private final AtomicBoolean isFetch = new AtomicBoolean(false);
private HttpDownloadFunction downloadFunction;
+ private GitCloneFunction gitCloneFunction;
public BazelRepositoryModule() {
repositoryHandlers = ImmutableMap.<String, RepositoryFunction>builder()
.put(LocalRepositoryRule.NAME, new LocalRepositoryFunction())
.put(HttpArchiveRule.NAME, new HttpArchiveFunction())
+ .put(GitRepositoryRule.NAME, new GitRepositoryFunction())
.put(HttpJarRule.NAME, new HttpJarFunction())
.put(MavenJarRule.NAME, new MavenJarFunction())
.put(NewHttpArchiveRule.NAME, new NewHttpArchiveFunction())
+ .put(NewGitRepositoryRule.NAME, new NewGitRepositoryFunction())
.put(NewLocalRepositoryRule.NAME, new NewLocalRepositoryFunction())
.put(AndroidSdkRepositoryRule.NAME, new AndroidSdkRepositoryFunction())
.put(AndroidNdkRepositoryRule.NAME, new AndroidNdkRepositoryFunction())
@@ -96,6 +104,7 @@ public class BazelRepositoryModule extends BlazeModule {
@Override
public void beforeCommand(BlazeRuntime runtime, Command command) {
downloadFunction.setReporter(runtime.getReporter());
+ gitCloneFunction.setReporter(runtime.getReporter());
}
@Override
@@ -154,6 +163,8 @@ public class BazelRepositoryModule extends BlazeModule {
// Helper SkyFunctions.
downloadFunction = new HttpDownloadFunction();
builder.put(SkyFunctionName.create(HttpDownloadFunction.NAME), downloadFunction);
+ gitCloneFunction = new GitCloneFunction();
+ builder.put(SkyFunctionName.create(GitCloneFunction.NAME), gitCloneFunction);
builder.put(JarFunction.NAME, new JarFunction());
builder.put(ZipFunction.NAME, new ZipFunction());
builder.put(TarGzFunction.NAME, new TarGzFunction());
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/GitCloneFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/GitCloneFunction.java
new file mode 100644
index 0000000000..2c8e50a684
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/GitCloneFunction.java
@@ -0,0 +1,180 @@
+// Copyright 2015 Google Inc. 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;
+
+import com.google.devtools.build.lib.bazel.repository.RepositoryFunction.RepositoryFunctionException;
+import com.google.devtools.build.lib.events.Reporter;
+import com.google.devtools.build.lib.packages.AggregatingAttributeMapper;
+import com.google.devtools.build.lib.packages.Rule;
+import com.google.devtools.build.lib.packages.Type;
+import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.vfs.Path;
+import com.google.devtools.build.skyframe.SkyFunction;
+import com.google.devtools.build.skyframe.SkyFunctionException.Transience;
+import com.google.devtools.build.skyframe.SkyFunctionName;
+import com.google.devtools.build.skyframe.SkyKey;
+import com.google.devtools.build.skyframe.SkyValue;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.api.errors.InvalidRefNameException;
+import org.eclipse.jgit.api.errors.InvalidRemoteException;
+import org.eclipse.jgit.api.errors.RefNotFoundException;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Objects;
+
+import javax.annotation.Nullable;
+
+/**
+ * Clones a Git repository, checks out the provided branch, tag, or commit, and
+ * clones submodules if specified.
+ */
+public class GitCloneFunction implements SkyFunction {
+ public static final String NAME = "GIT_CLONE";
+ private Reporter reporter;
+
+ public void setReporter(Reporter reporter) {
+ this.reporter = reporter;
+ }
+
+ @Nullable
+ @Override
+ public SkyValue compute(SkyKey skyKey, Environment env) throws RepositoryFunctionException {
+ GitRepositoryDescriptor descriptor = (GitRepositoryDescriptor) skyKey.argument();
+ String outputDirectory = descriptor.directory.toString();
+
+ Git git = null;
+ try {
+ git = Git.cloneRepository()
+ .setURI(descriptor.remote)
+ .setDirectory(new File(outputDirectory))
+ .setCloneSubmodules(false)
+ .setProgressMonitor(
+ new GitProgressMonitor("Cloning " + descriptor.remote, reporter))
+ .call();
+ git.checkout()
+ .setCreateBranch(true)
+ .setName("bazel-checkout")
+ .setStartPoint(descriptor.checkout)
+ .call();
+
+ // Using CloneCommand.setCloneSubmodules() results in SubmoduleInitCommand and
+ // SubmoduleUpdateCommand to be called recursively for all submodules. This is not
+ // desirable for repositories, such as github.com/rust-lang/rust-installer, which
+ // recursively includes itself as a submodule, which would result in an infinite
+ // loop if submodules are cloned recursively. For now, limit submodules to only
+ // the first level.
+ if (descriptor.initSubmodules) {
+ if (!git.submoduleInit().call().isEmpty()) {
+ git.submoduleUpdate()
+ .setProgressMonitor(
+ new GitProgressMonitor("Cloning submodules for " + descriptor.remote, reporter))
+ .call();
+ }
+ }
+ } catch (InvalidRemoteException e) {
+ throw new RepositoryFunctionException(
+ new IOException("Invalid Git repository URI: " + e.getMessage()),
+ Transience.PERSISTENT);
+ } catch (RefNotFoundException|InvalidRefNameException e) {
+ throw new RepositoryFunctionException(
+ new IOException("Invalid branch, tag, or commit: " + e.getMessage()),
+ Transience.PERSISTENT);
+ } catch (GitAPIException e) {
+ throw new RepositoryFunctionException(
+ new IOException(e.getMessage()), Transience.TRANSIENT);
+ } finally {
+ if (git != null) {
+ git.close();
+ }
+ }
+ return new HttpDownloadValue(descriptor.directory);
+ }
+
+ @Nullable
+ @Override
+ public String extractTag(SkyKey skyKey) {
+ return null;
+ }
+
+ public static SkyKey key(Rule rule, Path outputDirectory)
+ throws RepositoryFunctionException {
+ AggregatingAttributeMapper mapper = AggregatingAttributeMapper.of(rule);
+ if ((mapper.has("commit", Type.STRING) == mapper.has("tag", Type.STRING))
+ && (mapper.get("commit", Type.STRING).isEmpty()
+ == mapper.get("tag", Type.STRING).isEmpty())) {
+ throw new RepositoryFunctionException(
+ new EvalException(rule.getLocation(), "One of either commit or tag must be defined"),
+ Transience.PERSISTENT);
+ }
+ String startingPoint;
+ if (mapper.has("commit", Type.STRING) && !mapper.get("commit", Type.STRING).isEmpty()) {
+ startingPoint = mapper.get("commit", Type.STRING);
+ } else {
+ startingPoint = "tags/" + mapper.get("tag", Type.STRING);
+ }
+
+ return new SkyKey(
+ SkyFunctionName.create(NAME),
+ new GitCloneFunction.GitRepositoryDescriptor(
+ mapper.get("remote", Type.STRING),
+ startingPoint,
+ mapper.get("init_submodules", Type.BOOLEAN),
+ outputDirectory));
+ }
+
+ static final class GitRepositoryDescriptor {
+ private String remote;
+ private String checkout;
+ private boolean initSubmodules;
+ private Path directory;
+
+ public GitRepositoryDescriptor(String remote, String checkout, boolean initSubmodules,
+ Path directory) {
+ this.remote = remote;
+ this.checkout = checkout;
+ this.initSubmodules = initSubmodules;
+ this.directory = directory;
+ }
+
+ @Override
+ public String toString() {
+ return remote + " -> " + directory + " (" + checkout + ") submodules: "
+ + initSubmodules;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj == null || !(obj instanceof GitRepositoryDescriptor)) {
+ return false;
+ }
+ GitRepositoryDescriptor other = (GitRepositoryDescriptor) obj;
+ return Objects.equals(remote, other.remote)
+ && Objects.equals(checkout, other.checkout)
+ && Objects.equals(initSubmodules, other.initSubmodules)
+ && Objects.equals(directory, other.directory);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(remote, checkout, initSubmodules, directory);
+ }
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/GitProgressMonitor.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/GitProgressMonitor.java
new file mode 100644
index 0000000000..fce6ef1c77
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/GitProgressMonitor.java
@@ -0,0 +1,72 @@
+// Copyright 2015 Google Inc. 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;
+
+import com.google.devtools.build.lib.events.Event;
+import com.google.devtools.build.lib.events.Reporter;
+
+import org.eclipse.jgit.lib.ProgressMonitor;
+
+/**
+ * ProgressMonitor for reporting progress for Git repository rules.
+ */
+class GitProgressMonitor implements ProgressMonitor {
+ private String message;
+ private Reporter reporter;
+ private int totalTasks;
+ private int currentTask;
+
+ private String workTitle;
+ private int totalWork;
+ private int completedWork;
+
+ GitProgressMonitor(String message, Reporter reporter) {
+ this.message = message;
+ this.reporter = reporter;
+ }
+
+ public void start(int totalTasks) {
+ this.totalTasks = totalTasks;
+ this.currentTask = 0;
+ }
+
+ private void report() {
+ reporter.handle(
+ Event.progress("[" + currentTask + " / " + totalTasks + "] "
+ + message + ": " + workTitle + " ("
+ + completedWork + " / " + totalWork + ")"));
+ }
+
+ public void beginTask(String title, int totalWork) {
+ ++currentTask;
+ // TODO(dzc): Remove this when jgit reports totalTasks correctly in start().
+ if (currentTask > totalTasks) {
+ totalTasks = currentTask;
+ }
+ this.totalWork = totalWork;
+ this.completedWork = 0;
+ this.workTitle = title;
+ report();
+ }
+
+ public boolean isCancelled() { return false; }
+
+ public void update(int completed) {
+ completedWork += completed;
+ report();
+ }
+
+ public void endTask() { }
+}
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
new file mode 100644
index 0000000000..789e76cd18
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/GitRepositoryFunction.java
@@ -0,0 +1,84 @@
+// Copyright 2015 Google Inc. 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;
+
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.bazel.rules.workspace.GitRepositoryRule;
+import com.google.devtools.build.lib.packages.PackageIdentifier.RepositoryName;
+import com.google.devtools.build.lib.packages.Rule;
+import com.google.devtools.build.lib.skyframe.FileValue;
+import com.google.devtools.build.lib.skyframe.RepositoryValue;
+import com.google.devtools.build.lib.vfs.FileSystemUtils;
+import com.google.devtools.build.lib.vfs.Path;
+import com.google.devtools.build.skyframe.SkyFunctionException;
+import com.google.devtools.build.skyframe.SkyFunctionException.Transience;
+import com.google.devtools.build.skyframe.SkyFunctionName;
+import com.google.devtools.build.skyframe.SkyKey;
+import com.google.devtools.build.skyframe.SkyValue;
+
+import java.io.IOException;
+
+/**
+ * Clones a Git repository.
+ */
+public class GitRepositoryFunction extends RepositoryFunction {
+ @Override
+ public SkyValue compute(SkyKey skyKey, Environment env) throws SkyFunctionException {
+ RepositoryName repositoryName = (RepositoryName) skyKey.argument();
+ Rule rule = RepositoryFunction.getRule(repositoryName, GitRepositoryRule.NAME, env);
+ if (rule == null) {
+ return null;
+ }
+
+ Path outputDirectory = getExternalRepositoryDirectory().getRelative(rule.getName());
+ FileValue directoryValue = createDirectory(outputDirectory, env, rule);
+ if (directoryValue == null) {
+ return null;
+ }
+
+ try {
+ HttpDownloadValue value = (HttpDownloadValue) env.getValueOrThrow(
+ GitCloneFunction.key(rule, outputDirectory), IOException.class);
+ if (value == null) {
+ return null;
+ }
+ } catch (IOException e) {
+ throw new RepositoryFunctionException(e, Transience.TRANSIENT);
+ }
+
+ return RepositoryValue.create(directoryValue);
+ }
+
+ protected FileValue createDirectory(Path path, Environment env, Rule rule)
+ throws RepositoryFunctionException {
+ try {
+ FileSystemUtils.createDirectoryAndParents(path);
+ } catch (IOException e) {
+ throw new RepositoryFunctionException(new IOException("Could not create directory for "
+ + rule.getName() + ": " + e.getMessage()), Transience.TRANSIENT);
+ }
+ return getRepositoryDirectory(path, env);
+ }
+
+ @Override
+ public SkyFunctionName getSkyFunctionName() {
+ return SkyFunctionName.create(GitRepositoryRule.NAME.toUpperCase());
+ }
+
+ @Override
+ public Class<? extends RuleDefinition> getRuleDefinition() {
+ return GitRepositoryRule.class;
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/NewGitRepositoryFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/NewGitRepositoryFunction.java
new file mode 100644
index 0000000000..5858332acc
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/NewGitRepositoryFunction.java
@@ -0,0 +1,66 @@
+// Copyright 2015 Google Inc. 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;
+
+import com.google.devtools.build.lib.bazel.rules.workspace.NewGitRepositoryRule;
+import com.google.devtools.build.lib.packages.PackageIdentifier.RepositoryName;
+import com.google.devtools.build.lib.packages.Rule;
+import com.google.devtools.build.lib.skyframe.FileValue;
+import com.google.devtools.build.lib.vfs.Path;
+import com.google.devtools.build.skyframe.SkyFunctionException;
+import com.google.devtools.build.skyframe.SkyFunctionException.Transience;
+import com.google.devtools.build.skyframe.SkyFunctionName;
+import com.google.devtools.build.skyframe.SkyKey;
+import com.google.devtools.build.skyframe.SkyValue;
+
+import java.io.IOException;
+
+/**
+ * Clones a Git repository, creates a WORKSPACE file, and adds a BUILD file for it.
+ */
+public class NewGitRepositoryFunction extends GitRepositoryFunction {
+ @Override
+ public SkyFunctionName getSkyFunctionName() {
+ return SkyFunctionName.create(NewGitRepositoryRule.NAME.toUpperCase());
+ }
+
+ @Override
+ public SkyValue compute(SkyKey skyKey, Environment env) throws SkyFunctionException {
+ RepositoryName repositoryName = (RepositoryName) skyKey.argument();
+ Rule rule = RepositoryFunction.getRule(repositoryName, NewGitRepositoryRule.NAME, env);
+ if (rule == null) {
+ return null;
+ }
+
+ Path outputDirectory = getExternalRepositoryDirectory().getRelative(rule.getName());
+ FileValue directoryValue = createDirectory(outputDirectory, env, rule);
+ if (directoryValue == null) {
+ return null;
+ }
+
+ try {
+ HttpDownloadValue value = (HttpDownloadValue) env.getValueOrThrow(
+ GitCloneFunction.key(rule, outputDirectory), IOException.class);
+ if (value == null) {
+ return null;
+ }
+ } catch (IOException e) {
+ throw new RepositoryFunctionException(e, Transience.TRANSIENT);
+ }
+
+ createWorkspaceFile(outputDirectory, rule);
+ return symlinkBuildFile(rule, getWorkspace(), directoryValue, env);
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
index 80959767da..d7ec9ff977 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
@@ -60,10 +60,12 @@ import com.google.devtools.build.lib.bazel.rules.sh.BazelShBinaryRule;
import com.google.devtools.build.lib.bazel.rules.sh.BazelShLibraryRule;
import com.google.devtools.build.lib.bazel.rules.sh.BazelShRuleClasses;
import com.google.devtools.build.lib.bazel.rules.sh.BazelShTestRule;
+import com.google.devtools.build.lib.bazel.rules.workspace.GitRepositoryRule;
import com.google.devtools.build.lib.bazel.rules.workspace.HttpArchiveRule;
import com.google.devtools.build.lib.bazel.rules.workspace.HttpJarRule;
import com.google.devtools.build.lib.bazel.rules.workspace.LocalRepositoryRule;
import com.google.devtools.build.lib.bazel.rules.workspace.MavenJarRule;
+import com.google.devtools.build.lib.bazel.rules.workspace.NewGitRepositoryRule;
import com.google.devtools.build.lib.bazel.rules.workspace.NewHttpArchiveRule;
import com.google.devtools.build.lib.bazel.rules.workspace.NewLocalRepositoryRule;
import com.google.devtools.build.lib.bazel.rules.workspace.WorkspaceBaseRule;
@@ -338,11 +340,13 @@ public class BazelRuleClassProvider {
builder.addRuleDefinition(new BazelActionListenerRule());
builder.addRuleDefinition(new BindRule());
+ builder.addRuleDefinition(new GitRepositoryRule());
builder.addRuleDefinition(new HttpArchiveRule());
builder.addRuleDefinition(new HttpJarRule());
builder.addRuleDefinition(new LocalRepositoryRule());
builder.addRuleDefinition(new MavenJarRule());
builder.addRuleDefinition(new NewHttpArchiveRule());
+ builder.addRuleDefinition(new NewGitRepositoryRule());
builder.addRuleDefinition(new NewLocalRepositoryRule());
builder.addRuleDefinition(new AndroidSdkRepositoryRule());
builder.addRuleDefinition(new AndroidNdkRepositoryRule());
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/GitRepositoryRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/GitRepositoryRule.java
new file mode 100644
index 0000000000..5b5756e271
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/GitRepositoryRule.java
@@ -0,0 +1,126 @@
+// Copyright 2015 Google Inc. 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.rules.workspace;
+
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.Type.BOOLEAN;
+import static com.google.devtools.build.lib.packages.Type.STRING;
+
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+import com.google.devtools.build.lib.packages.RuleClass;
+
+/**
+ * Rule definition for the git_repository rule.
+ */
+public class GitRepositoryRule implements RuleDefinition {
+ public static final String NAME = "git_repository";
+
+ @Override
+ public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment environment) {
+ return builder
+ /* <!-- #BLAZE_RULE(git_repository).ATTRIBUTE(remote) -->
+ The URI of the remote Git repository.
+ ${SYNOPSIS}
+
+ <p>This must be a HTTP URL. There is currently no support for authentication.</p>
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("remote", STRING).mandatory())
+ /* <!-- #BLAZE_RULE(git_repository).ATTRIBUTE(commit) -->
+ The commit hash to check out in the repository.
+ ${SYNOPSIS}
+
+ <p>Note that one of either <code>commit</code> or <code>tag</code> must be defined.</p>
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("commit", STRING))
+ /* <!-- #BLAZE_RULE(git_repository).ATTRIBUTE(tag) -->
+ The Git tag to check out in the repository.
+ ${SYNOPSIS}
+
+ <p>Note that one of either <code>commit</code> or <code>tag</code> must be defined.</p>
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("tag", STRING))
+ /* <!-- #BLAZE_RULE(git_repository).ATTRIBUTE(init_submodules) -->
+ Whether to clone submodules in the repository.
+ ${SYNOPSIS}
+
+ <p>Currently, only cloning the top-level submodules is supported</p>
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("init_submodules", BOOLEAN).value(false))
+ .setWorkspaceOnly()
+ .build();
+ }
+
+ @Override
+ public Metadata getMetadata() {
+ return RuleDefinition.Metadata.builder()
+ .name(GitRepositoryRule.NAME)
+ .type(RuleClass.Builder.RuleClassType.WORKSPACE)
+ .ancestors(WorkspaceBaseRule.class)
+ .factoryClass(WorkspaceConfiguredTargetFactory.class)
+ .build();
+ }
+}
+
+/*<!-- #BLAZE_RULE (NAME = git_repository, TYPE = OTHER, FAMILY = Workspace)[GENERIC_RULE] -->
+
+${ATTRIBUTE_SIGNATURE}
+
+<p>Clones a Git repository, checks out the specified tag, or commit, and makes its targets
+available for binding.</p>
+
+${ATTRIBUTE_DEFINITION}
+
+<h4 id="git_repository_examples">Examples</h4>
+
+<p>Suppose the current repository contains the source code for a chat program, rooted at the
+ directory <i>~/chat-app</i>. It needs to depend on an SSL library which is available in the
+ remote Git repository <i>http://example.com/openssl/openssl.git</i>. The chat app depends
+ on version 1.0.2 of the SSL library, which is tagged by the v1.0.2 Git tag.<p>
+
+<p>This Git repository contains the following directory structure:</p>
+
+<pre class="code">
+WORKSPACE
+src/
+ BUILD
+ openssl.cc
+ openssl.h
+</pre>
+
+<p><i>src/BUILD</i> contains the following target definition:</p>
+
+<pre class="code">
+cc_library(
+ name = "openssl-lib",
+ srcs = ["openssl.cc"],
+ hdrs = ["openssl.h"],
+)
+</pre>
+
+<p>Targets in the <i>~/chat-app</i> repository can depend on this target if the following lines are
+ added to <i>~/chat-app/WORKSPACE</i>:</p>
+
+<pre class="code">
+git_repository(
+ name = "my-ssl",
+ remote = "http://example.com/openssl/openssl.git",
+ tag = "v1.0.2",
+)
+</pre>
+
+<p>Then targets would specify <code>@my-ssl//src:openssl-lib</code> as a dependency.</p>
+
+<!-- #END_BLAZE_RULE -->*/
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/NewGitRepositoryRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/NewGitRepositoryRule.java
new file mode 100644
index 0000000000..2a57a9bb24
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/NewGitRepositoryRule.java
@@ -0,0 +1,135 @@
+// Copyright 2015 Google Inc. 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.rules.workspace;
+
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.Type.BOOLEAN;
+import static com.google.devtools.build.lib.packages.Type.STRING;
+
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+import com.google.devtools.build.lib.packages.RuleClass;
+
+/**
+ * Rule definition for the new_git_repository rule.
+ */
+public class NewGitRepositoryRule implements RuleDefinition {
+ public static final String NAME = "new_git_repository";
+
+ @Override
+ public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment environment) {
+ return builder
+ /* <!-- #BLAZE_RULE(new_git_repository).ATTRIBUTE(remote) -->
+ The URI of the remote Git repository.
+ ${SYNOPSIS}
+
+ <p>This must be a HTTP URL. There is currently no support for authentication.</p>
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("remote", STRING).mandatory())
+ /* <!-- #BLAZE_RULE(git_repository).ATTRIBUTE(commit) -->
+ The commit hash to check out in the repository.
+ ${SYNOPSIS}
+
+ <p>Note that one of either <code>commit</code> or <code>tag</code> must be defined.</p>
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("commit", STRING))
+ /* <!-- #BLAZE_RULE(git_repository).ATTRIBUTE(tag) -->
+ The Git tag to check out in the repository.
+ ${SYNOPSIS}
+
+ <p>Note that one of either <code>commit</code> or <code>tag</code> must be defined.</p>
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("tag", STRING))
+ /* <!-- #BLAZE_RULE(new_git_repository).ATTRIBUTE(build_file) -->
+ A file to use as a BUILD file for this directory.
+ ${SYNOPSIS}
+
+ <p>This path is relative to the build's workspace. The file does not need to be named
+ BUILD, but can be (something like BUILD.new-repo-name may work well for distinguishing it
+ from the repository's actual BUILD files.</p>
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("build_file", STRING).mandatory())
+ /* <!-- #BLAZE_RULE(new_git_repository).ATTRIBUTE(init_submodules) -->
+ Whether to clone submodules in the repository.
+ ${SYNOPSIS}
+
+ <p>Currently, only cloning the top-level submodules is supported</p>
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("init_submodules", BOOLEAN).value(false))
+ .setWorkspaceOnly()
+ .build();
+ }
+
+ @Override
+ public Metadata getMetadata() {
+ return RuleDefinition.Metadata.builder()
+ .name(NewGitRepositoryRule.NAME)
+ .type(RuleClass.Builder.RuleClassType.WORKSPACE)
+ .ancestors(WorkspaceBaseRule.class)
+ .factoryClass(WorkspaceConfiguredTargetFactory.class)
+ .build();
+ }
+}
+
+/*<!-- #BLAZE_RULE (NAME = new_git_repository, TYPE = OTHER, FAMILY = Workspace)[GENERIC_RULE] -->
+
+${ATTRIBUTE_SIGNATURE}
+
+<p>Clones a Git repository, checks out the specified tag, or commit, and makes its targets
+available for binding.</p>
+
+${ATTRIBUTE_DEFINITION}
+
+<h4 id="git_repository_examples">Examples</h4>
+
+<p>Suppose the current repository contains the source code for a chat program, rooted at the
+ directory <i>~/chat-app</i>. It needs to depend on an SSL library which is available in the
+ remote Git repository <i>http://example.com/openssl/openssl.git</i>. The chat app depends
+ on version 1.0.2 of the SSL library, which is tagged by the v1.0.2 Git tag.<p>
+
+<p>This Git repository contains the following directory structure:</p>
+
+<pre class="code">
+src/
+ openssl.cc
+ openssl.h
+</pre>
+
+<p>In the local repository, the user creates a <i>ssl.BUILD</i> file which contains the following
+target definition:</p>
+
+<pre class="code">
+cc_library(
+ name = "openssl-lib",
+ srcs = ["openssl.cc"],
+ hdrs = ["openssl.h"],
+)
+</pre>
+
+<p>Targets in the <i>~/chat-app</i> repository can depend on this target if the following lines are
+ added to <i>~/chat-app/WORKSPACE</i>:</p>
+
+<pre class="code">
+new_git_repository(
+ name = "my-ssl",
+ remote = "http://example.com/openssl/openssl.git",
+ tag = "v1.0.2",
+ build_file = "ssl.BUILD",
+)
+</pre>
+
+<p>Then targets would specify <code>@my-ssl//src:openssl-lib</code> as a dependency.</p>
+
+<!-- #END_BLAZE_RULE -->*/