summaryrefslogtreecommitdiffstatsabout
diff options
context:
space:
mode:
authorMathias Kinzler2010-12-20 04:21:49 (EST)
committer Mathias Kinzler2010-12-20 04:21:49 (EST)
commit645d262de6da32fdb05aba5a48dbf6188dfa7776 (patch)
tree3f3af8b99eb6e77c6ece0a94578455f482334d5b
parent94a2cbb40750c0f5b4f873fa109d339393ee6888 (diff)
downloadjgit-645d262de6da32fdb05aba5a48dbf6188dfa7776.zip
jgit-645d262de6da32fdb05aba5a48dbf6188dfa7776.tar.gz
jgit-645d262de6da32fdb05aba5a48dbf6188dfa7776.tar.bz2
Checkout: expose a CheckoutResultrefs/changes/27/2127/3
This is needed by callers to determine checkout conflicts and possible files that were not deleted during the checkout so that they can present the end user with a better Exception description and retry to delete the undeleted files later, respectively. Change-Id: I037930da7b1a4dfb24cfa3205afb51dc29e4a5b8 Signed-off-by: Mathias Kinzler <mathias.kinzler@sap.com>
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java51
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java62
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutResult.java141
3 files changed, 240 insertions, 14 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java
index 295a284..cf78a0e 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java
@@ -42,8 +42,11 @@
*/
package org.eclipse.jgit.api;
+import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
+import org.eclipse.jgit.api.CheckoutResult.Status;
import org.eclipse.jgit.api.errors.InvalidRefNameException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.api.errors.RefAlreadyExistsException;
@@ -52,6 +55,7 @@ import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.RepositoryTestCase;
import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.util.FileUtils;
public class CheckoutCommandTest extends RepositoryTestCase {
private Git git;
@@ -120,4 +124,51 @@ public class CheckoutCommandTest extends RepositoryTestCase {
}
}
+ public void testCheckoutWithConflict() {
+ CheckoutCommand co = git.checkout();
+ try {
+ writeTrashFile("Test.txt", "Another change");
+ assertEquals(Status.NOT_TRIED, co.getResult().getStatus());
+ co.setName("master").call();
+ fail("Should have failed");
+ } catch (Exception e) {
+ assertEquals(Status.CONFLICTS, co.getResult().getStatus());
+ assertTrue(co.getResult().getConflictList().contains("Test.txt"));
+ }
+ }
+
+ public void testCheckoutWithNonDeletedFiles() throws Exception {
+ File testFile = writeTrashFile("temp", "");
+ FileInputStream fis = new FileInputStream(testFile);
+ try {
+ FileUtils.delete(testFile);
+ return;
+ } catch (IOException e) {
+ // the test makes only sense if deletion of
+ // a file with open stream fails
+ }
+ fis.close();
+ FileUtils.delete(testFile);
+ CheckoutCommand co = git.checkout();
+ // delete Test.txt in branch test
+ testFile = new File(db.getWorkTree(), "Test.txt");
+ assertTrue(testFile.exists());
+ FileUtils.delete(testFile);
+ assertFalse(testFile.exists());
+ git.add().addFilepattern("Test.txt");
+ git.commit().setMessage("Delete Test.txt").setAll(true).call();
+ git.checkout().setName("master").call();
+ assertTrue(testFile.exists());
+ // lock the file so it can't be deleted (in Windows, that is)
+ fis = new FileInputStream(testFile);
+ try {
+ assertEquals(Status.NOT_TRIED, co.getResult().getStatus());
+ co.setName("test").call();
+ assertTrue(testFile.exists());
+ assertEquals(Status.NONDELETED, co.getResult().getStatus());
+ assertTrue(co.getResult().getUndeletedList().contains("Test.txt"));
+ } finally {
+ fis.close();
+ }
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
index 4e74a54..2546231 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
@@ -42,22 +42,27 @@
*/
package org.eclipse.jgit.api;
+import java.io.File;
import java.io.IOException;
import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
import org.eclipse.jgit.JGitText;
+import org.eclipse.jgit.api.CheckoutResult.Status;
import org.eclipse.jgit.api.errors.InvalidRefNameException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.api.errors.RefAlreadyExistsException;
import org.eclipse.jgit.api.errors.RefNotFoundException;
import org.eclipse.jgit.dircache.DirCacheCheckout;
import org.eclipse.jgit.errors.AmbiguousObjectException;
+import org.eclipse.jgit.errors.CheckoutConflictException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefUpdate;
-import org.eclipse.jgit.lib.RefUpdate.Result;
import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.RefUpdate.Result;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
@@ -81,6 +86,8 @@ public class CheckoutCommand extends GitCommand<Ref> {
private RevCommit startCommit;
+ private CheckoutResult status;
+
/**
* @param repo
*/
@@ -105,7 +112,7 @@ public class CheckoutCommand extends GitCommand<Ref> {
processOptions();
try {
- if(createBranch) {
+ if (createBranch) {
Git git = new Git(repo);
CreateBranchCommand command = git.branchCreate();
command.setName(name);
@@ -123,20 +130,28 @@ public class CheckoutCommand extends GitCommand<Ref> {
ObjectId branch = repo.resolve(name);
Ref ref = repo.getRef(name);
if (branch == null)
- throw new RefNotFoundException(MessageFormat.format(
- JGitText.get().refNotResolved, name));
+ throw new RefNotFoundException(MessageFormat.format(JGitText
+ .get().refNotResolved, name));
RevCommit newCommit = revWalk.parseCommit(branch);
- DirCacheCheckout dco = new DirCacheCheckout(repo,
- headCommit.getTree(), repo.lockDirCache(),
- newCommit.getTree());
+ DirCacheCheckout dco = new DirCacheCheckout(repo, headCommit
+ .getTree(), repo.lockDirCache(), newCommit.getTree());
dco.setFailOnConflict(true);
- dco.checkout();
+ try {
+ dco.checkout();
+ } catch (CheckoutConflictException e) {
+ List<File> fileList = new ArrayList<File>();
+ for (String filePath : dco.getConflicts()) {
+ fileList.add(new File(repo.getWorkTree(), filePath));
+ }
+ status = new CheckoutResult(Status.CONFLICTS, fileList);
+ throw e;
+ }
RefUpdate refUpdate = repo.updateRef(Constants.HEAD);
refUpdate.setForceUpdate(force);
- refUpdate.setRefLogMessage(
- refLogMessage + "to " + newCommit.getName(), false);
+ refUpdate.setRefLogMessage(refLogMessage + "to "
+ + newCommit.getName(), false);
Result updateResult = refUpdate.link(ref.getName());
setCallable(false);
@@ -156,16 +171,26 @@ public class CheckoutCommand extends GitCommand<Ref> {
}
if (!ok)
- throw new JGitInternalException(MessageFormat.format(
- JGitText.get().checkoutUnexpectedResult,
- updateResult
- .name()));
+ throw new JGitInternalException(MessageFormat.format(JGitText
+ .get().checkoutUnexpectedResult, updateResult.name()));
Ref result = repo.getRef(name);
+ if (!repo.isBare() && !dco.getToBeDeleted().isEmpty()) {
+ List<File> fileList = new ArrayList<File>();
+ for (String filePath : dco.getToBeDeleted()) {
+ fileList.add(new File(repo.getWorkTree(), filePath));
+ }
+ status = new CheckoutResult(Status.NONDELETED, fileList);
+ }
+ else
+ status = CheckoutResult.OK_RESULT;
return result;
} catch (IOException ioe) {
throw new JGitInternalException(ioe.getMessage(), ioe);
+ } finally {
+ if (status == null)
+ status = CheckoutResult.ERROR_RESULT;
}
}
@@ -269,4 +294,13 @@ public class CheckoutCommand extends GitCommand<Ref> {
this.upstreamMode = mode;
return this;
}
+
+ /**
+ * @return the result
+ */
+ public CheckoutResult getResult() {
+ if (status == null)
+ return CheckoutResult.NOT_TRIED_RESULT;
+ return status;
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutResult.java
new file mode 100644
index 0000000..bddfe2b
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutResult.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.api;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Encapsulates the result of a {@link CheckoutCommand}
+ *
+ */
+public class CheckoutResult {
+
+ /**
+ * The {@link Status#OK} result;
+ */
+ public static CheckoutResult OK_RESULT = new CheckoutResult(Status.OK, null);
+
+ /**
+ * The {@link Status#ERROR} result;
+ */
+ public static CheckoutResult ERROR_RESULT = new CheckoutResult(
+ Status.ERROR, null);
+
+ /**
+ * The {@link Status#NOT_TRIED} result;
+ */
+ public static CheckoutResult NOT_TRIED_RESULT = new CheckoutResult(
+ Status.NOT_TRIED, null);
+
+ /**
+ * The status
+ */
+ public enum Status {
+ /**
+ * The call() method has not yet been executed
+ */
+ NOT_TRIED,
+ /**
+ * Checkout completed normally
+ */
+ OK,
+ /**
+ * Checkout has not completed because of checkout conflicts
+ */
+ CONFLICTS,
+ /**
+ * Checkout has completed, but some files could not be deleted
+ */
+ NONDELETED,
+ /**
+ * An Exception occurred during checkout
+ */
+ ERROR;
+ }
+
+ private final Status myStatus;
+
+ private final List<File> conflictList;
+
+ private final List<File> undeletedList;
+
+ CheckoutResult(Status status, List<File> fileList) {
+ myStatus = status;
+ if (status == Status.CONFLICTS)
+ this.conflictList = fileList;
+ else
+ this.conflictList = new ArrayList<File>(0);
+ if (status == Status.NONDELETED)
+ this.undeletedList = fileList;
+ else
+ this.undeletedList = new ArrayList<File>(0);
+
+ }
+
+ /**
+ * @return the status
+ */
+ public Status getStatus() {
+ return myStatus;
+ }
+
+ /**
+ * @return the list of files that created a checkout conflict, or an empty
+ * list if {@link #getStatus()} is not {@link Status#CONFLICTS};
+ */
+ public List<File> getConflictList() {
+ return conflictList;
+ }
+
+ /**
+ * @return the list of files that could not be deleted during checkout, or
+ * an empty list if {@link #getStatus()} is not
+ * {@link Status#NONDELETED};
+ */
+ public List<File> getUndeletedList() {
+ return undeletedList;
+ }
+
+}