aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build
diff options
context:
space:
mode:
authorGravatar Brian <bsilver16384@gmail.com>2015-08-19 18:52:13 +0000
committerGravatar Lukacs Berki <lberki@google.com>2015-08-20 14:50:03 +0000
commitdfc44a4f14582fdfdebd7f0a6d56ec23fc2ed68f (patch)
tree73ebd2f4dbf5fd0e2f879451f6ec62a4bcafb050 /src/main/java/com/google/devtools/build
parentf292aa028a63b549a7933d98ab89a2f3a66c110e (diff)
Fix {new_,}git_repository after shutdown.
Previously, after a server shutdown they would fail because the repository already exists. This change fixes that and avoids re-downloading if the local repository is already the correct version and unmodified. An example of the error before: $ bazel fetch ... ....... INFO: Loading package: tools/cpp java.lang.RuntimeException: Unrecoverable error while evaluating node 'GIT_CLONE:file:///tmp/gtest-1.7.0 -> /home/brian/.cache/bazel/_bazel_brian/46af2c6e62e13aca9af015360f8fb1da/external/gtest_repo (091e69312f2c133860e71e6b01118c1f5a8c943d) submodules: false' (requested by nodes 'NEW_GIT_REPOSITORY:@gtest_repo') at com.google.devtools.build.skyframe.ParallelEvaluator$Evaluate.run(ParallelEvaluator.java:745) at com.google.devtools.build.lib.concurrent.AbstractQueueVisitor$1.run(AbstractQueueVisitor.java:346) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:745) Caused by: org.eclipse.jgit.api.errors.JGitInternalException: Destination path "gtest_repo" already exists and is not an empty directory at org.eclipse.jgit.api.CloneCommand.init(CloneCommand.java:152) at org.eclipse.jgit.api.CloneCommand.call(CloneCommand.java:132) at com.google.devtools.build.lib.bazel.repository.GitCloneFunction.compute(GitCloneFunction.java:68) at com.google.devtools.build.skyframe.ParallelEvaluator$Evaluate.run(ParallelEvaluator.java:709) ... 4 more -- Change-Id: Ifca46302537248106740941b70bc5bd11fa1eeb1 Reviewed-on: https://bazel-review.googlesource.com/#/c/1650 MOS_MIGRATED_REVID=101045419
Diffstat (limited to 'src/main/java/com/google/devtools/build')
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/repository/GitCloneFunction.java74
1 files changed, 65 insertions, 9 deletions
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
index 2c8e50a684..29c7b729f6 100644
--- 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
@@ -20,6 +20,7 @@ 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.FileSystemUtils;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.skyframe.SkyFunction;
import com.google.devtools.build.skyframe.SkyFunctionException.Transience;
@@ -28,14 +29,19 @@ 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.Status;
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 org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
-import java.io.File;
import java.io.IOException;
import java.util.Objects;
+import java.util.Set;
import javax.annotation.Nullable;
@@ -51,21 +57,71 @@ public class GitCloneFunction implements SkyFunction {
this.reporter = reporter;
}
+ private boolean isUpToDate(GitRepositoryDescriptor descriptor) {
+ // Initializing/checking status of/etc submodules cleanly is hard, so don't try for now.
+ if (descriptor.initSubmodules) {
+ return false;
+ }
+ Repository repository = null;
+ try {
+ repository =
+ new FileRepositoryBuilder()
+ .setGitDir(descriptor.directory.getChild(Constants.DOT_GIT).getPathFile())
+ .setMustExist(true)
+ .build();
+ ObjectId head = repository.resolve(Constants.HEAD);
+ ObjectId checkout = repository.resolve(descriptor.checkout);
+ if (head != null && checkout != null && head.equals(checkout)) {
+ Status status = Git.wrap(repository).status().call();
+ if (!status.hasUncommittedChanges()) {
+ // new_git_repository puts (only) BUILD and WORKSPACE, and
+ // git_repository doesn't add any files.
+ Set<String> untracked = status.getUntracked();
+ if (untracked.isEmpty()
+ || (untracked.size() == 2
+ && untracked.contains("BUILD")
+ && untracked.contains("WORKSPACE"))) {
+ return true;
+ }
+ }
+ }
+ } catch (GitAPIException | IOException e) {
+ // Any exceptions here, we'll just blow it away and try cloning fresh.
+ // The fresh clone avoids any weirdness due to what's there and has nicer
+ // error reporting.
+ } finally {
+ if (repository != null) {
+ repository.close();
+ }
+ }
+ return false;
+ }
+
@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();
+ if (descriptor.directory.exists()) {
+ if (isUpToDate(descriptor)) {
+ return new HttpDownloadValue(descriptor.directory);
+ }
+ try {
+ FileSystemUtils.deleteTree(descriptor.directory);
+ } catch (IOException e) {
+ throw new RepositoryFunctionException(e, Transience.TRANSIENT);
+ }
+ }
+ git =
+ Git.cloneRepository()
+ .setURI(descriptor.remote)
+ .setDirectory(descriptor.directory.getPathFile())
+ .setCloneSubmodules(false)
+ .setNoCheckout(true)
+ .setProgressMonitor(new GitProgressMonitor("Cloning " + descriptor.remote, reporter))
+ .call();
git.checkout()
.setCreateBranch(true)
.setName("bazel-checkout")