diff options
author | 2015-07-16 13:23:01 +0000 | |
---|---|---|
committer | 2015-07-17 13:17:26 +0000 | |
commit | deb003fae0e0da7d45156f5ea0b36900aa9e5790 (patch) | |
tree | 4989137a972c6e6e19f4fcb8cebf6085d0745513 /src/main/java/com/google/devtools/build/lib | |
parent | 768b5ccdfad99e3ead5bd8c1c861b3f52506f748 (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')
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 -->*/ |