summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--org.eclipse.jgit.console/META-INF/MANIFEST.MF3
-rw-r--r--org.eclipse.jgit.console/src/org/eclipse/jgit/console/ConsoleCredentialsProvider.java175
-rw-r--r--org.eclipse.jgit.console/src/org/eclipse/jgit/console/ConsoleSshSessionFactory.java145
-rw-r--r--org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java31
-rw-r--r--org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin1
-rw-r--r--org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties18
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Add.java71
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java2
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java2
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Init.java3
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java6
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowCommands.java2
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTests.java40
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java98
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java31
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeAlgorithmTest.java126
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeMessageFormatterTest.java155
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java14
-rw-r--r--org.eclipse.jgit.ui/META-INF/MANIFEST.MF3
-rw-r--r--org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/AwtCredentialsProvider.java204
-rw-r--r--org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/AwtSshSessionFactory.java185
-rw-r--r--org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties3
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java3
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java8
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedCredentialItem.java69
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java3
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/RefRename.java5
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeAlgorithm.java8
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java132
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java36
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialItem.java283
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialsProvider.java137
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialsProviderUserInfo.java150
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java36
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java3
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/SshConfigSessionFactory.java8
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/SshSessionFactory.java8
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/SshTransport.java3
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java24
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java6
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java32
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/UsernamePasswordCredentialsProvider.java124
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java44
45 files changed, 1986 insertions, 458 deletions
diff --git a/org.eclipse.jgit.console/META-INF/MANIFEST.MF b/org.eclipse.jgit.console/META-INF/MANIFEST.MF
index a29b348b0e..9607bdc160 100644
--- a/org.eclipse.jgit.console/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.console/META-INF/MANIFEST.MF
@@ -7,7 +7,8 @@ Bundle-Version: 0.10.0.qualifier
Bundle-Vendor: %provider_name
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Export-Package: org.eclipse.jgit.console;version="0.10.0"
-Import-Package: org.eclipse.jgit.nls;version="[0.10.0,0.11.0)",
+Import-Package: org.eclipse.jgit.errors;version="[0.10.0,0.11.0)",
+ org.eclipse.jgit.nls;version="[0.10.0,0.11.0)",
org.eclipse.jgit.transport;version="[0.10.0,0.11.0)",
org.eclipse.jgit.util;version="[0.10.0,0.11.0)"
Require-Bundle: com.jcraft.jsch;bundle-version="[0.1.37,0.2.0)"
diff --git a/org.eclipse.jgit.console/src/org/eclipse/jgit/console/ConsoleCredentialsProvider.java b/org.eclipse.jgit.console/src/org/eclipse/jgit/console/ConsoleCredentialsProvider.java
new file mode 100644
index 0000000000..f8f8ff9bcf
--- /dev/null
+++ b/org.eclipse.jgit.console/src/org/eclipse/jgit/console/ConsoleCredentialsProvider.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2010, Google Inc.
+ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ * 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.console;
+
+import java.io.Console;
+
+import org.eclipse.jgit.errors.UnsupportedCredentialItem;
+import org.eclipse.jgit.transport.CredentialItem;
+import org.eclipse.jgit.transport.CredentialsProvider;
+import org.eclipse.jgit.transport.URIish;
+
+/** Interacts with the user during authentication by using the text console. */
+public class ConsoleCredentialsProvider extends CredentialsProvider {
+ /** Install this implementation as the default. */
+ public static void install() {
+ final ConsoleCredentialsProvider c = new ConsoleCredentialsProvider();
+ if (c.cons == null)
+ throw new NoClassDefFoundError(
+ ConsoleText.get().noSystemConsoleAvailable);
+ CredentialsProvider.setDefault(c);
+ }
+
+ private final Console cons = System.console();
+
+ @Override
+ public boolean isInteractive() {
+ return true;
+ }
+
+ @Override
+ public boolean supports(CredentialItem... items) {
+ for (CredentialItem i : items) {
+ if (i instanceof CredentialItem.StringType)
+ continue;
+
+ else if (i instanceof CredentialItem.CharArrayType)
+ continue;
+
+ else if (i instanceof CredentialItem.YesNoType)
+ continue;
+
+ else if (i instanceof CredentialItem.InformationalMessage)
+ continue;
+
+ else
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean get(URIish uri, CredentialItem... items)
+ throws UnsupportedCredentialItem {
+ boolean ok = true;
+ for (int i = 0; i < items.length && ok; i++) {
+ CredentialItem item = items[i];
+
+ if (item instanceof CredentialItem.StringType)
+ ok = get(uri, (CredentialItem.StringType) item);
+
+ else if (item instanceof CredentialItem.CharArrayType)
+ ok = get(uri, (CredentialItem.CharArrayType) item);
+
+ else if (item instanceof CredentialItem.YesNoType)
+ ok = get(uri, (CredentialItem.YesNoType) item);
+
+ else if (item instanceof CredentialItem.InformationalMessage)
+ ok = get(uri, (CredentialItem.InformationalMessage) item);
+
+ else
+ throw new UnsupportedCredentialItem(uri, item.getPromptText());
+ }
+ return ok;
+ }
+
+ private boolean get(URIish uri, CredentialItem.StringType item) {
+ if (item.isValueSecure()) {
+ char[] v = cons.readPassword("%s: ", item.getPromptText());
+ if (v != null) {
+ item.setValue(new String(v));
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ String v = cons.readLine("%s: ", item.getPromptText());
+ if (v != null) {
+ item.setValue(v);
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ private boolean get(URIish uri, CredentialItem.CharArrayType item) {
+ if (item.isValueSecure()) {
+ char[] v = cons.readPassword("%s: ", item.getPromptText());
+ if (v != null) {
+ item.setValueNoCopy(v);
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ String v = cons.readLine("%s: ", item.getPromptText());
+ if (v != null) {
+ item.setValueNoCopy(v.toCharArray());
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ private boolean get(URIish uri, CredentialItem.InformationalMessage item) {
+ cons.printf("%s\n", item.getPromptText());
+ cons.flush();
+ return true;
+ }
+
+ private boolean get(URIish uri, CredentialItem.YesNoType item) {
+ String r = cons.readLine("%s [%s/%s]? ", item.getPromptText(),
+ ConsoleText.get().answerYes, ConsoleText.get().answerNo);
+ if (r != null) {
+ item.setValue(ConsoleText.get().answerYes.equalsIgnoreCase(r));
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/org.eclipse.jgit.console/src/org/eclipse/jgit/console/ConsoleSshSessionFactory.java b/org.eclipse.jgit.console/src/org/eclipse/jgit/console/ConsoleSshSessionFactory.java
deleted file mode 100644
index b11078dea8..0000000000
--- a/org.eclipse.jgit.console/src/org/eclipse/jgit/console/ConsoleSshSessionFactory.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2009, Google Inc.
- * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
- * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
- * 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.console;
-
-import java.io.Console;
-
-import org.eclipse.jgit.transport.OpenSshConfig;
-import org.eclipse.jgit.transport.SshConfigSessionFactory;
-import org.eclipse.jgit.transport.SshSessionFactory;
-
-import com.jcraft.jsch.Session;
-import com.jcraft.jsch.UIKeyboardInteractive;
-import com.jcraft.jsch.UserInfo;
-
-/**
- * Loads known hosts and private keys from <code>$HOME/.ssh</code>.
- * <p>
- * This is the default implementation used by JGit and provides most of the
- * compatibility necessary to match OpenSSH, a popular implementation of SSH
- * used by C Git.
- * <p>
- * If user interactivity is required by SSH (e.g. to obtain a password) the
- * system console is used to display a prompt to the end-user.
- */
-public class ConsoleSshSessionFactory extends SshConfigSessionFactory {
- /** Install this session factory implementation into the JVM. */
- public static void install() {
- final ConsoleSshSessionFactory c = new ConsoleSshSessionFactory();
- if (c.cons == null)
- throw new NoClassDefFoundError(ConsoleText.get().noSystemConsoleAvailable);
- SshSessionFactory.setInstance(c);
- }
-
- private final Console cons = System.console();
-
- @Override
- protected void configure(final OpenSshConfig.Host hc, final Session session) {
- if (!hc.isBatchMode())
- session.setUserInfo(new ConsoleUserInfo());
- }
-
- private class ConsoleUserInfo implements UserInfo, UIKeyboardInteractive {
- private String passwd;
-
- private String passphrase;
-
- public void showMessage(final String msg) {
- cons.printf("%s\n", msg);
- cons.flush();
- }
-
- public boolean promptYesNo(final String msg) {
- String r = cons.readLine("%s [%s/%s]? ", msg, ConsoleText.get().answerYes, ConsoleText.get().answerNo);
- return ConsoleText.get().answerYes.equalsIgnoreCase(r);
- }
-
- public boolean promptPassword(final String msg) {
- passwd = null;
- char[] p = cons.readPassword("%s: ", msg);
- if (p != null) {
- passwd = new String(p);
- return true;
- }
- return false;
- }
-
- public boolean promptPassphrase(final String msg) {
- passphrase = null;
- char[] p = cons.readPassword("%s: ", msg);
- if (p != null) {
- passphrase = new String(p);
- return true;
- }
- return false;
- }
-
- public String getPassword() {
- return passwd;
- }
-
- public String getPassphrase() {
- return passphrase;
- }
-
- public String[] promptKeyboardInteractive(final String destination,
- final String name, final String instruction,
- final String[] prompt, final boolean[] echo) {
- cons.printf("%s: %s\n", destination, name);
- cons.printf("%s\n", instruction);
- final String[] response = new String[prompt.length];
- for (int i = 0; i < prompt.length; i++) {
- if (echo[i]) {
- response[i] = cons.readLine("%s: ", prompt[i]);
- } else {
- final char[] p = cons.readPassword("%s: ", prompt[i]);
- response[i] = p != null ? new String(p) : "";
- }
- }
- return response;
- }
- }
-}
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java
index 06a4eb6a73..92584cbe10 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java
@@ -60,6 +60,7 @@ import org.eclipse.jgit.http.server.GitServlet;
import org.eclipse.jgit.http.server.resolver.RepositoryResolver;
import org.eclipse.jgit.http.server.resolver.ServiceNotEnabledException;
import org.eclipse.jgit.http.test.util.AccessEvent;
+import org.eclipse.jgit.http.test.util.AppServer;
import org.eclipse.jgit.http.test.util.HttpTestCase;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.Constants;
@@ -71,6 +72,7 @@ import org.eclipse.jgit.storage.file.FileRepository;
import org.eclipse.jgit.transport.FetchConnection;
import org.eclipse.jgit.transport.Transport;
import org.eclipse.jgit.transport.URIish;
+import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
public class HttpClientTests extends HttpTestCase {
private TestRepository<FileRepository> remoteRepository;
@@ -282,7 +284,7 @@ public class HttpClientTests extends HttpTestCase {
fail("connection opened even info/refs needs auth basic");
} catch (TransportException err) {
String exp = dumbAuthBasicURI + ": "
- + JGitText.get().authenticationNotSupported;
+ + JGitText.get().notAuthorized;
assertEquals(exp, err.getMessage());
}
} finally {
@@ -290,6 +292,31 @@ public class HttpClientTests extends HttpTestCase {
}
}
+ public void testListRemote_Dumb_Auth() throws Exception {
+ Repository dst = createBareRepository();
+ Transport t = Transport.open(dst, dumbAuthBasicURI);
+ t.setCredentialsProvider(new UsernamePasswordCredentialsProvider(
+ AppServer.username, AppServer.password));
+ try {
+ t.openFetch();
+ } finally {
+ t.close();
+ }
+ t = Transport.open(dst, dumbAuthBasicURI);
+ t.setCredentialsProvider(new UsernamePasswordCredentialsProvider(
+ AppServer.username, ""));
+ try {
+ t.openFetch();
+ fail("connection opened even info/refs needs auth basic and we provide wrong password");
+ } catch (TransportException err) {
+ String exp = dumbAuthBasicURI + ": "
+ + JGitText.get().notAuthorized;
+ assertEquals(exp, err.getMessage());
+ } finally {
+ t.close();
+ }
+ }
+
public void testListRemote_Smart_UploadPackNeedsAuth() throws Exception {
Repository dst = createBareRepository();
Transport t = Transport.open(dst, smartAuthBasicURI);
@@ -299,7 +326,7 @@ public class HttpClientTests extends HttpTestCase {
fail("connection opened even though service disabled");
} catch (TransportException err) {
String exp = smartAuthBasicURI + ": "
- + JGitText.get().authenticationNotSupported;
+ + JGitText.get().notAuthorized;
assertEquals(exp, err.getMessage());
}
} finally {
diff --git a/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin b/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin
index d98ed113c6..f5d45f0d78 100644
--- a/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin
+++ b/org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin
@@ -1,3 +1,4 @@
+org.eclipse.jgit.pgm.Add
org.eclipse.jgit.pgm.AmazonS3Client
org.eclipse.jgit.pgm.Branch
org.eclipse.jgit.pgm.Clone
diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties
index 488cff0b9b..f709e15ffe 100644
--- a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties
+++ b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties
@@ -8,13 +8,12 @@ N=N
IPZillaPasswordPrompt=IPZilla Password
authorInfo=Author: {0} <{1}>
averageMSPerRead=average {0} ms/read
-branchDetachedHEAD=detached HEAD
branchAlreadyExists=branch {0} already exists
branchCreatedFrom =branch: Created from {0}
+branchDetachedHEAD=detached HEAD
branchIsNotAnAncestorOfYourCurrentHEAD=The branch '{0}' is not an ancestor of your current HEAD.\nIf you are sure you want to delete it, run 'jgit branch -D {0}'.
branchNotFound=branch '{0}' not found.
cacheTreePathInfo="{0}": {1} entries, {2} children
-configFileNotFound=configuration file {0} not found
cannotBeRenamed={0} cannot be renamed
cannotChekoutNoHeadsAdvertisedByRemote=cannot checkout; no HEAD advertised by remote
cannotCreateCommand=Cannot create command {0}
@@ -33,6 +32,7 @@ cannotWrite=Cannot write {0}
cantFindGitDirectory=error: can't find git directory
cantWrite=Can't write {0}
commitLabel=commit
+configFileNotFound=configuration file {0} not found
conflictingUsageOf_git_dir_andArguments=conflicting usage of --git-dir and arguments
couldNotCreateBranch=Could not create branch {0}: {1}
dateInfo=Date: {0}
@@ -61,12 +61,15 @@ metaVar_author=AUTHOR
metaVar_base=base
metaVar_bucket=BUCKET
metaVar_command=command
+metaVar_commandDetail=DETAIL
metaVar_commitOrTag=COMMIT|TAG
metaVar_commitish=commit-ish
metaVar_configFile=FILE
metaVar_connProp=conn.prop
+metaVar_diffAlg=ALGORITHM
metaVar_directory=DIRECTORY
metaVar_file=FILE
+metaVar_filepattern=filepattern
metaVar_gitDir=GIT_DIR
metaVar_hostName=HOSTNAME
metaVar_linesOfContext=lines
@@ -117,9 +120,9 @@ skippingObject=skipping {0} {1}
timeInMilliSeconds={0} ms
tooManyRefsGiven=Too many refs given
unsupportedOperation=Unsupported operation: {0}
+usage_CommandLineClientForamazonsS3Service=Command line client for Amazon's S3 service
usage_CommitAuthor=Override the author name used in the commit. You can use the standard A U Thor <author@example.com> format.
usage_CommitMessage=Use the given <msg> as the commit message
-usage_CommandLineClientForamazonsS3Service=Command line client for Amazon's S3 service
usage_CreateABareRepository=Create a bare repository
usage_CreateATag=Create a tag
usage_CreateAnEmptyGitRepository=Create an empty git repository
@@ -136,6 +139,7 @@ usage_StopTrackingAFile=Stop tracking a file
usage_UpdateRemoteRepositoryFromLocalRefs=Update remote repository from local refs
usage_abortConnectionIfNoActivity=abort connection if no activity
usage_actOnRemoteTrackingBranches=act on remote-tracking branches
+usage_addFileContentsToTheIndex=Add file contents to the index
usage_alterTheDetailShown=alter the detail shown
usage_approveDestructionOfRepository=approve destruction of repository
usage_beMoreVerbose=be more verbose
@@ -147,7 +151,7 @@ usage_configureTheServiceInDaemonServicename=configure the service in daemon.ser
usage_deleteBranchEvenIfNotMerged=delete branch (even if not merged)
usage_deleteFullyMergedBranch=delete fully merged branch
usage_detectRenames=detect renamed files
-usage_diffAlgorithm=the diff algorithm to use
+usage_diffAlgorithm=the diff algorithm to use. Currently supported are: 'myers', 'histogram'
usage_directoriesToExport=directories to export
usage_disableTheServiceInAllRepositories=disable the service in all repositories
usage_displayAListOfAllRegisteredJgitCommands=Display a list of all registered jgit commands
@@ -159,6 +163,7 @@ usage_enableTheServiceInAllRepositories=enable the service in all repositories
usage_exportRepositoriesOverGit=Export repositories over git://
usage_exportWithoutGitDaemonExportOk=export without git-daemon-export-ok
usage_fetchThinPack=fetch thin pack
+usage_filesToAddContentFrom=Files to add content from
usage_fixAThinPackToBeComplete=fix a thin pack to be complete
usage_forEachRefOutput=for-each-ref output
usage_forceCreateBranchEvenExists=force create branch even exists
@@ -173,18 +178,19 @@ usage_moveRenameABranch=move/rename a branch
usage_nameStatus=show only name and status of files
usage_noPrefix=do not show any source or destination prefix
usage_noRenames=disable rename detection
+usage_onlyMatchAgainstAlreadyTrackedFiles=Only match <filepattern> against already tracked files in the index rather than the working tree
usage_outputFile=Output file
usage_path=path
usage_performFsckStyleChecksOnReceive=perform fsck style checks on receive
usage_portNumberToListenOn=port number to listen on
usage_produceAnEclipseIPLog=Produce an Eclipse IP log
usage_pruneStaleTrackingRefs=prune stale tracking refs
-usage_recurseIntoSubtrees=recurse into subtrees
usage_recordChangesToRepository=Record changes to the repository
+usage_recurseIntoSubtrees=recurse into subtrees
usage_renameLimit=limit size of rename matrix
usage_setTheGitRepositoryToOperateOn=set the git repository to operate on
-usage_showRefNamesMatchingCommits=Show ref names matching commits
usage_showPatch=display patch
+usage_showRefNamesMatchingCommits=Show ref names matching commits
usage_srcPrefix=show the source prefix instead of "a/"
usage_symbolicVersionForTheProject=Symbolic version for the project
usage_synchronizeIPZillaData=Synchronize IPZilla data
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Add.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Add.java
new file mode 100644
index 0000000000..4670b3508e
--- /dev/null
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Add.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2010, Sasa Zivkov <sasa.zivkov@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.pgm;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jgit.api.AddCommand;
+import org.eclipse.jgit.api.Git;
+import org.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.Option;
+
+@Command(common = true, usage = "usage_addFileContentsToTheIndex")
+class Add extends TextBuiltin {
+
+ @Option(name = "--update", aliases = { "-u" }, usage = "usage_onlyMatchAgainstAlreadyTrackedFiles")
+ private boolean update = false;
+
+ @Argument(required = true, metaVar = "metavar_filepattern", usage = "usage_filesToAddContentFrom")
+ private List<String> filepatterns = new ArrayList<String>();
+
+ @Override
+ protected void run() throws Exception {
+ AddCommand addCmd = new Git(db).add();
+ addCmd.setUpdate(update);
+ for (String p : filepatterns)
+ addCmd.addFilepattern(p);
+ addCmd.call();
+ }
+}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java
index b1c8254626..5fb4a963e1 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java
@@ -150,7 +150,7 @@ class Branch extends TextBuiltin {
startBranch = startRef.getName();
else
startBranch = startAt.name();
- startBranch = db.shortenRefName(startBranch);
+ startBranch = Repository.shortenRefName(startBranch);
String newRefName = newHead;
if (!newRefName.startsWith(Constants.R_HEADS))
newRefName = Constants.R_HEADS + newRefName;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java
index 19d11d629e..6062f35827 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java
@@ -111,7 +111,7 @@ class Diff extends TextBuiltin {
}
};
- @Option(name = "--algorithm", usage = "usage_diffAlgorithm")
+ @Option(name = "--algorithm", metaVar = "metaVar_diffAlg", usage = "usage_diffAlgorithm")
void setAlgorithm(SupportedAlgorithm s) {
diffFmt.setDiffAlgorithm(s.algorithm);
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Init.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Init.java
index c5a696a57f..89a08fda62 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Init.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Init.java
@@ -2,6 +2,7 @@
* Copyright (C) 2009, Constantine Plotnikov <constantine.plotnikov@gmail.com>
* Copyright (C) 2008, Google Inc.
* Copyright (C) 2010, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2010, Sasa Zivkov <sasa.zivkov@sap.com>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -66,6 +67,8 @@ class Init extends TextBuiltin {
protected void run() throws Exception {
if (gitdir == null)
gitdir = new File(bare ? "." : Constants.DOT_GIT);
+ else
+ bare = true;
db = new FileRepository(gitdir);
db.create(bare);
out.println(MessageFormat.format(CLIText.get().initializedEmptyGitRepositoryIn, gitdir.getAbsolutePath()));
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java
index ca3960e97b..62ffd8d9ca 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java
@@ -55,7 +55,7 @@ import java.util.ArrayList;
import java.util.List;
import org.eclipse.jgit.awtui.AwtAuthenticator;
-import org.eclipse.jgit.awtui.AwtSshSessionFactory;
+import org.eclipse.jgit.awtui.AwtCredentialsProvider;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryBuilder;
@@ -114,7 +114,7 @@ public class Main {
try {
if (!installConsole()) {
AwtAuthenticator.install();
- AwtSshSessionFactory.install();
+ AwtCredentialsProvider.install();
}
configureHttpProxy();
execute(argv);
@@ -218,7 +218,7 @@ public class Main {
private static boolean installConsole() {
try {
install("org.eclipse.jgit.console.ConsoleAuthenticator");
- install("org.eclipse.jgit.console.ConsoleSshSessionFactory");
+ install("org.eclipse.jgit.console.ConsoleCredentialsProvider");
return true;
} catch (ClassNotFoundException e) {
return false;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowCommands.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowCommands.java
index 78fc1453d1..e96e6543c6 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowCommands.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/ShowCommands.java
@@ -54,7 +54,7 @@ import org.eclipse.jgit.pgm.TextBuiltin;
@Command(usage = "usage_displayAListOfAllRegisteredJgitCommands")
class ShowCommands extends TextBuiltin {
- @Option(name = "--pretty", usage = "usage_alterTheDetailShown")
+ @Option(name = "--pretty", metaVar = "metaVar_commandDetail", usage = "usage_alterTheDetailShown")
private Format pretty = Format.USAGE;
@Override
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTests.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTests.java
index 9106cc2c04..3d7f77972e 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTests.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTests.java
@@ -53,6 +53,8 @@ import org.eclipse.jgit.api.errors.NoFilepatternException;
import org.eclipse.jgit.api.errors.NoHeadException;
import org.eclipse.jgit.api.errors.NoMessageException;
import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.errors.UnmergedPathException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
@@ -105,6 +107,7 @@ public class CommitAndLogCommandTests extends RepositoryTestCase {
git.commit().setAuthor(author).call();
fail("Didn't get the expected exception");
} catch (NoMessageException e) {
+ // expected
}
}
@@ -122,6 +125,7 @@ public class CommitAndLogCommandTests extends RepositoryTestCase {
commitCmd.setAuthor(author);
fail("didn't catch the expected exception");
} catch (IllegalStateException e) {
+ // expected
}
LogCommand logCmd = git.log();
logCmd.call();
@@ -130,6 +134,7 @@ public class CommitAndLogCommandTests extends RepositoryTestCase {
logCmd.call();
fail("didn't catch the expected exception");
} catch (IllegalStateException e) {
+ // expected
}
}
@@ -191,4 +196,39 @@ public class CommitAndLogCommandTests extends RepositoryTestCase {
assertEquals("db00fd65b218578127ea51f3dffac701f12f486a",
tw.getObjectId(0).getName());
}
+
+ public void testCommitRange() throws NoHeadException, NoMessageException,
+ UnmergedPathException, ConcurrentRefUpdateException,
+ JGitInternalException, WrongRepositoryStateException,
+ IncorrectObjectTypeException, MissingObjectException {
+ // do 4 commits and set the range to the second and fourth one
+ Git git = new Git(db);
+ git.commit().setMessage("first commit").call();
+ RevCommit second = git.commit().setMessage("second commit")
+ .setCommitter(committer).call();
+ git.commit().setMessage("third commit").setAuthor(author).call();
+ RevCommit last = git.commit().setMessage("fourth commit").setAuthor(
+ author)
+ .setCommitter(committer).call();
+ Iterable<RevCommit> commits = git.log().addRange(second.getId(),
+ last.getId()).call();
+
+ // check that we have the third and fourth commit
+ PersonIdent defaultCommitter = new PersonIdent(db);
+ PersonIdent expectedAuthors[] = new PersonIdent[] { author, author };
+ PersonIdent expectedCommitters[] = new PersonIdent[] {
+ defaultCommitter, committer };
+ String expectedMessages[] = new String[] { "third commit",
+ "fourth commit" };
+ int l = expectedAuthors.length - 1;
+ for (RevCommit c : commits) {
+ assertEquals(expectedAuthors[l].getName(), c.getAuthorIdent()
+ .getName());
+ assertEquals(expectedCommitters[l].getName(), c.getCommitterIdent()
+ .getName());
+ assertEquals(c.getFullMessage(), expectedMessages[l]);
+ l--;
+ }
+ assertEquals(l, -1);
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java
index 02d4b0e15b..231b009764 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java
@@ -247,7 +247,7 @@ public class MergeCommandTest extends RepositoryTestCase {
assertEquals(thirdCommit, newHead.getParent(0));
assertEquals(secondCommit, newHead.getParent(1));
assertEquals(
- "merging 3fa334456d236a92db020289fe0bf481d91777b4 into HEAD",
+ "Merge commit '3fa334456d236a92db020289fe0bf481d91777b4' into HEAD",
newHead.getFullMessage());
// @TODO fix me
assertEquals(RepositoryState.SAFE, db.getRepositoryState());
@@ -307,12 +307,106 @@ public class MergeCommandTest extends RepositoryTestCase {
assertEquals(thirdCommit, newHead.getParent(0));
assertEquals(secondCommit, newHead.getParent(1));
assertEquals(
- "merging 064d54d98a4cdb0fed1802a21c656bfda67fe879 into HEAD",
+ "Merge commit '064d54d98a4cdb0fed1802a21c656bfda67fe879' into HEAD",
newHead.getFullMessage());
assertEquals(RepositoryState.SAFE, db.getRepositoryState());
}
+ public void testSingleDeletion() throws Exception {
+ Git git = new Git(db);
+
+ writeTrashFile("a", "1\na\n3\n");
+ writeTrashFile("b", "1\nb\n3\n");
+ writeTrashFile("d", "1\nd\n3\n");
+ writeTrashFile("c/c/c", "1\nc\n3\n");
+ git.add().addFilepattern("a").addFilepattern("b")
+ .addFilepattern("c/c/c").addFilepattern("d").call();
+ RevCommit initialCommit = git.commit().setMessage("initial").call();
+
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
+
+ assertTrue(new File(db.getWorkTree(), "b").delete());
+ git.add().addFilepattern("b").setUpdate(true).call();
+ RevCommit secondCommit = git.commit().setMessage("side").call();
+
+ assertFalse(new File(db.getWorkTree(), "b").exists());
+ checkoutBranch("refs/heads/master");
+ assertTrue(new File(db.getWorkTree(), "b").exists());
+
+ writeTrashFile("a", "1\na\n3(main)\n");
+ writeTrashFile("c/c/c", "1\nc(main)\n3\n");
+ git.add().addFilepattern("a").addFilepattern("c/c/c").call();
+ RevCommit thirdCommit = git.commit().setMessage("main").call();
+
+ // We are merging a deletion into our branch
+ MergeResult result = git.merge().include(secondCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
+ assertEquals(MergeStatus.MERGED, result.getMergeStatus());
+
+ assertEquals("1\na\n3(main)\n", read(new File(db.getWorkTree(), "a")));
+ assertFalse(new File(db.getWorkTree(), "b").exists());
+ assertEquals("1\nc(main)\n3\n",
+ read(new File(db.getWorkTree(), "c/c/c")));
+
+ // Do the opposite, be on a branch where we have deleted a file and
+ // merge in a old commit where this file was not deleted
+ checkoutBranch("refs/heads/side");
+ assertFalse(new File(db.getWorkTree(), "b").exists());
+
+ result = git.merge().include(thirdCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
+ assertEquals(MergeStatus.MERGED, result.getMergeStatus());
+
+ assertEquals("1\na\n3(main)\n", read(new File(db.getWorkTree(), "a")));
+ assertFalse(new File(db.getWorkTree(), "b").exists());
+ assertEquals("1\nc(main)\n3\n",
+ read(new File(db.getWorkTree(), "c/c/c")));
+ }
+
+ public void testDeletionAndConflict() throws Exception {
+ Git git = new Git(db);
+
+ writeTrashFile("a", "1\na\n3\n");
+ writeTrashFile("b", "1\nb\n3\n");
+ writeTrashFile("d", "1\nd\n3\n");
+ writeTrashFile("c/c/c", "1\nc\n3\n");
+ git.add().addFilepattern("a").addFilepattern("b")
+ .addFilepattern("c/c/c").addFilepattern("d").call();
+ RevCommit initialCommit = git.commit().setMessage("initial").call();
+
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
+
+ assertTrue(new File(db.getWorkTree(), "b").delete());
+ writeTrashFile("a", "1\na\n3(side)\n");
+ git.add().addFilepattern("b").setUpdate(true).call();
+ git.add().addFilepattern("a").setUpdate(true).call();
+ RevCommit secondCommit = git.commit().setMessage("side").call();
+
+ assertFalse(new File(db.getWorkTree(), "b").exists());
+ checkoutBranch("refs/heads/master");
+ assertTrue(new File(db.getWorkTree(), "b").exists());
+
+ writeTrashFile("a", "1\na\n3(main)\n");
+ writeTrashFile("c/c/c", "1\nc(main)\n3\n");
+ git.add().addFilepattern("a").addFilepattern("c/c/c").call();
+ git.commit().setMessage("main").call();
+
+ // We are merging a deletion into our branch
+ MergeResult result = git.merge().include(secondCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
+ assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
+
+ assertEquals(
+ "1\na\n<<<<<<< HEAD\n3(main)\n=======\n3(side)\n>>>>>>> 54ffed45d62d252715fc20e41da92d44c48fb0ff\n",
+ read(new File(db.getWorkTree(), "a")));
+ assertFalse(new File(db.getWorkTree(), "b").exists());
+ assertEquals("1\nc(main)\n3\n",
+ read(new File(db.getWorkTree(), "c/c/c")));
+ }
+
public void testMergeFailingWithDirtyWorkingTree() throws Exception {
Git git = new Git(db);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java
index 3d19576758..c73764a990 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java
@@ -48,6 +48,9 @@ package org.eclipse.jgit.lib;
import java.io.File;
import java.io.IOException;
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.dircache.DirCache;
+import org.eclipse.jgit.dircache.DirCacheEditor;
import org.eclipse.jgit.treewalk.FileTreeIterator;
public class IndexDiffTest extends RepositoryTestCase {
@@ -210,4 +213,32 @@ public class IndexDiffTest extends RepositoryTestCase {
oi.release();
}
}
+
+ /**
+ * A file is removed from the index but stays in the working directory. It
+ * is checked if IndexDiff detects this file as removed and untracked.
+ *
+ * @throws Exception
+ */
+ public void testRemovedUntracked() throws Exception{
+ Git git = new Git(db);
+ String path = "file";
+ writeTrashFile(path, "content");
+ git.add().addFilepattern(path).call();
+ git.commit().setMessage("commit").call();
+ removeFromIndex(path);
+ FileTreeIterator iterator = new FileTreeIterator(db);
+ IndexDiff diff = new IndexDiff(db, Constants.HEAD, iterator);
+ diff.diff();
+ assertTrue(diff.getRemoved().contains(path));
+ assertTrue(diff.getUntracked().contains(path));
+ }
+
+ private void removeFromIndex(String path) throws IOException {
+ final DirCache dirc = db.lockDirCache();
+ final DirCacheEditor edit = dirc.editor();
+ edit.add(new DirCacheEditor.DeletePath(path));
+ if (!edit.commit())
+ throw new IOException("could not commit");
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeAlgorithmTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeAlgorithmTest.java
index b51329e29f..9b4b7146f6 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeAlgorithmTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeAlgorithmTest.java
@@ -55,51 +55,6 @@ import org.eclipse.jgit.lib.Constants;
public class MergeAlgorithmTest extends TestCase {
MergeFormatter fmt=new MergeFormatter();
- // the texts which are used in this merge-tests are constructed by
- // concatenating fixed chunks of text defined by the String constants
- // A..Y. The common base text is always the text A+B+C+D+E+F+G+H+I+J.
- // The two texts being merged are constructed by deleting some chunks
- // or inserting new chunks. Some of the chunks are one-liners, others
- // contain more than one line.
- private static final String A = "aaa\n";
- private static final String B = "bbbbb\nbb\nbbb\n";
- private static final String C = "c\n";
- private static final String D = "dd\n";
- private static final String E = "ee\n";
- private static final String F = "fff\nff\n";
- private static final String G = "gg\n";
- private static final String H = "h\nhhh\nhh\n";
- private static final String I = "iiii\n";
- private static final String J = "jj\n";
- private static final String Z = "zzz\n";
- private static final String Y = "y\n";
-
- // constants which define how conflict-regions are expected to be reported.
- private static final String XXX_0 = "<<<<<<< O\n";
- private static final String XXX_1 = "=======\n";
- private static final String XXX_2 = ">>>>>>> T\n";
-
- // the common base from which all merges texts derive from
- String base=A+B+C+D+E+F+G+H+I+J;
-
- // the following constants define the merged texts. The name of the
- // constants describe how they are created out of the common base. E.g.
- // the constant named replace_XYZ_by_MNO stands for the text which is
- // created from common base by replacing first chunk X by chunk M, then
- // Y by N and then Z by O.
- String replace_C_by_Z=A+B+Z+D+E+F+G+H+I+J;
- String replace_A_by_Y=Y+B+C+D+E+F+G+H+I+J;
- String replace_A_by_Z=Z+B+C+D+E+F+G+H+I+J;
- String replace_J_by_Y=A+B+C+D+E+F+G+H+I+Y;
- String replace_J_by_Z=A+B+C+D+E+F+G+H+I+Z;
- String replace_BC_by_ZZ=A+Z+Z+D+E+F+G+H+I+J;
- String replace_BCD_by_ZZZ=A+Z+Z+Z+E+F+G+H+I+J;
- String replace_BD_by_ZZ=A+Z+C+Z+E+F+G+H+I+J;
- String replace_BCDEGI_by_ZZZZZZ=A+Z+Z+Z+Z+F+Z+H+Z+J;
- String replace_CEFGHJ_by_YYYYYY=A+B+Y+D+Y+Y+Y+Y+I+Y;
- String replace_BDE_by_ZZY=A+Z+C+Z+Y+F+G+H+I+J;
- String delete_C=A+B+D+E+F+G+H+I+J;
-
/**
* Check for a conflict where the second text was changed similar to the
* first one, but the second texts modification covers one more line.
@@ -107,9 +62,8 @@ public class MergeAlgorithmTest extends TestCase {
* @throws IOException
*/
public void testTwoConflictingModifications() throws IOException {
- assertEquals(A + XXX_0 + B + XXX_1 + Z + XXX_2 + Z + D + E + F + G
- + H + I + J,
- merge(base, replace_C_by_Z, replace_BC_by_ZZ));
+ assertEquals(t("a<b=Z>Zdefghij"),
+ merge("abcdefghij", "abZdefghij", "aZZdefghij"));
}
/**
@@ -120,9 +74,8 @@ public class MergeAlgorithmTest extends TestCase {
* @throws IOException
*/
public void testOneAgainstTwoConflictingModifications() throws IOException {
- assertEquals(A + Z + XXX_0 + Z + XXX_1 + C + XXX_2 + Z + E + F
- + G + H + I + J,
- merge(base, replace_BCD_by_ZZZ, replace_BD_by_ZZ));
+ assertEquals(t("aZ<Z=c>Zefghij"),
+ merge("abcdefghij", "aZZZefghij", "aZcZefghij"));
}
/**
@@ -132,8 +85,8 @@ public class MergeAlgorithmTest extends TestCase {
* @throws IOException
*/
public void testNoAgainstOneModification() throws IOException {
- assertEquals(replace_BD_by_ZZ.toString(),
- merge(base, base, replace_BD_by_ZZ));
+ assertEquals(t("aZcZefghij"),
+ merge("abcdefghij", "abcdefghij", "aZcZefghij"));
}
/**
@@ -143,8 +96,8 @@ public class MergeAlgorithmTest extends TestCase {
* @throws IOException
*/
public void testTwoNonConflictingModifications() throws IOException {
- assertEquals(Y + B + Z + D + E + F + G + H + I + J,
- merge(base, replace_C_by_Z, replace_A_by_Y));
+ assertEquals(t("YbZdefghij"),
+ merge("abcdefghij", "abZdefghij", "Ybcdefghij"));
}
/**
@@ -154,11 +107,8 @@ public class MergeAlgorithmTest extends TestCase {
* @throws IOException
*/
public void testTwoComplicatedModifications() throws IOException {
- assertEquals(A + XXX_0 + Z + Z + Z + Z + F + Z + H + XXX_1 + B + Y + D
- + Y + Y + Y + Y + XXX_2 + Z + Y,
- merge(base,
- replace_BCDEGI_by_ZZZZZZ,
- replace_CEFGHJ_by_YYYYYY));
+ assertEquals(t("a<ZZZZfZhZj=bYdYYYYiY>"),
+ merge("abcdefghij", "aZZZZfZhZj", "abYdYYYYiY"));
}
/**
@@ -167,8 +117,8 @@ public class MergeAlgorithmTest extends TestCase {
* @throws IOException
*/
public void testConflictAtStart() throws IOException {
- assertEquals(XXX_0 + Z + XXX_1 + Y + XXX_2 + B + C + D + E + F + G + H
- + I + J, merge(base, replace_A_by_Z, replace_A_by_Y));
+ assertEquals(t("<Z=Y>bcdefghij"),
+ merge("abcdefghij", "Zbcdefghij", "Ybcdefghij"));
}
/**
@@ -177,7 +127,8 @@ public class MergeAlgorithmTest extends TestCase {
* @throws IOException
*/
public void testConflictAtEnd() throws IOException {
- assertEquals(A+B+C+D+E+F+G+H+I+XXX_0+Z+XXX_1+Y+XXX_2, merge(base, replace_J_by_Z, replace_J_by_Y));
+ assertEquals(t("abcdefghi<Z=Y>"),
+ merge("abcdefghij", "abcdefghiZ", "abcdefghiY"));
}
/**
@@ -187,8 +138,8 @@ public class MergeAlgorithmTest extends TestCase {
* @throws IOException
*/
public void testSameModification() throws IOException {
- assertEquals(replace_C_by_Z,
- merge(base, replace_C_by_Z, replace_C_by_Z));
+ assertEquals(t("abZdefghij"),
+ merge("abcdefghij", "abZdefghij", "abZdefghij"));
}
/**
@@ -198,13 +149,54 @@ public class MergeAlgorithmTest extends TestCase {
* @throws IOException
*/
public void testDeleteVsModify() throws IOException {
- assertEquals(A+B+XXX_0+XXX_1+Z+XXX_2+D+E+F+G+H+I+J, merge(base, delete_C, replace_C_by_Z));
+ assertEquals(t("ab<=Z>defghij"),
+ merge("abcdefghij", "abdefghij", "abZdefghij"));
+ }
+
+ public void testInsertVsModify() throws IOException {
+ assertEquals(t("a<bZ=XY>"), merge("ab", "abZ", "aXY"));
+ }
+
+ public void testAdjacentModifications() throws IOException {
+ assertEquals(t("a<Zc=bY>d"), merge("abcd", "aZcd", "abYd"));
+ }
+
+ public void testSeperateModifications() throws IOException {
+ assertEquals(t("aZcYe"), merge("abcde", "aZcde", "abcYe"));
}
private String merge(String commonBase, String ours, String theirs) throws IOException {
- MergeResult r=MergeAlgorithm.merge(RawTextComparator.DEFAULT, new RawText(Constants.encode(commonBase)), new RawText(Constants.encode(ours)), new RawText(Constants.encode(theirs)));
+ MergeResult r = MergeAlgorithm.merge(RawTextComparator.DEFAULT,
+ T(commonBase), T(ours), T(theirs));
ByteArrayOutputStream bo=new ByteArrayOutputStream(50);
fmt.formatMerge(bo, r, "B", "O", "T", Constants.CHARACTER_ENCODING);
return new String(bo.toByteArray(), Constants.CHARACTER_ENCODING);
}
+
+ public static String t(String text) {
+ StringBuilder r = new StringBuilder();
+ for (int i = 0; i < text.length(); i++) {
+ char c = text.charAt(i);
+ switch (c) {
+ case '<':
+ r.append("<<<<<<< O\n");
+ break;
+ case '=':
+ r.append("=======\n");
+ break;
+ case '>':
+ r.append(">>>>>>> T\n");
+ break;
+ default:
+ r.append(c);
+ r.append('\n');
+ }
+ }
+ return r.toString();
+ }
+
+ public static RawText T(String text) {
+ return new RawText(Constants.encode(t(text)));
+ }
+
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeMessageFormatterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeMessageFormatterTest.java
new file mode 100644
index 0000000000..9f7bc40b99
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeMessageFormatterTest.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2010, Robin Stocker <robin@nibor.org>
+ * 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.merge;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectIdRef;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.SampleDataRepositoryTestCase;
+import org.eclipse.jgit.lib.Ref.Storage;
+
+/**
+ * Test construction of merge message by {@link MergeMessageFormatter}.
+ */
+public class MergeMessageFormatterTest extends SampleDataRepositoryTestCase {
+
+ private MergeMessageFormatter formatter;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ RefUpdate createRemoteRefA = db
+ .updateRef("refs/remotes/origin/remote-a");
+ createRemoteRefA.setNewObjectId(db.resolve("refs/heads/a"));
+ createRemoteRefA.update();
+
+ RefUpdate createRemoteRefB = db
+ .updateRef("refs/remotes/origin/remote-b");
+ createRemoteRefB.setNewObjectId(db.resolve("refs/heads/b"));
+ createRemoteRefB.update();
+
+ formatter = new MergeMessageFormatter();
+ }
+
+ public void testOneBranch() throws IOException {
+ Ref a = db.getRef("refs/heads/a");
+ Ref master = db.getRef("refs/heads/master");
+ String message = formatter.format(Arrays.asList(a), master);
+ assertEquals("Merge branch 'a'", message);
+ }
+
+ public void testTwoBranches() throws IOException {
+ Ref a = db.getRef("refs/heads/a");
+ Ref b = db.getRef("refs/heads/b");
+ Ref master = db.getRef("refs/heads/master");
+ String message = formatter.format(Arrays.asList(a, b), master);
+ assertEquals("Merge branches 'a' and 'b'", message);
+ }
+
+ public void testThreeBranches() throws IOException {
+ Ref c = db.getRef("refs/heads/c");
+ Ref b = db.getRef("refs/heads/b");
+ Ref a = db.getRef("refs/heads/a");
+ Ref master = db.getRef("refs/heads/master");
+ String message = formatter.format(Arrays.asList(c, b, a), master);
+ assertEquals("Merge branches 'c', 'b' and 'a'", message);
+ }
+
+ public void testRemoteBranch() throws Exception {
+ Ref remoteA = db.getRef("refs/remotes/origin/remote-a");
+ Ref master = db.getRef("refs/heads/master");
+ String message = formatter.format(Arrays.asList(remoteA), master);
+ assertEquals("Merge remote branch 'origin/remote-a'", message);
+ }
+
+ public void testMixed() throws IOException {
+ Ref c = db.getRef("refs/heads/c");
+ Ref remoteA = db.getRef("refs/remotes/origin/remote-a");
+ Ref master = db.getRef("refs/heads/master");
+ String message = formatter.format(Arrays.asList(c, remoteA), master);
+ assertEquals("Merge branch 'c', remote branch 'origin/remote-a'",
+ message);
+ }
+
+ public void testTag() throws IOException {
+ Ref tagA = db.getRef("refs/tags/A");
+ Ref master = db.getRef("refs/heads/master");
+ String message = formatter.format(Arrays.asList(tagA), master);
+ assertEquals("Merge tag 'A'", message);
+ }
+
+ public void testCommit() throws IOException {
+ ObjectId objectId = ObjectId
+ .fromString("6db9c2ebf75590eef973081736730a9ea169a0c4");
+ Ref commit = new ObjectIdRef.Unpeeled(Storage.LOOSE,
+ objectId.getName(), objectId);
+ Ref master = db.getRef("refs/heads/master");
+ String message = formatter.format(Arrays.asList(commit), master);
+ assertEquals("Merge commit '6db9c2ebf75590eef973081736730a9ea169a0c4'",
+ message);
+ }
+
+ public void testPullWithUri() throws IOException {
+ String name = "branch 'test' of http://egit.eclipse.org/jgit.git";
+ ObjectId objectId = ObjectId
+ .fromString("6db9c2ebf75590eef973081736730a9ea169a0c4");
+ Ref remoteBranch = new ObjectIdRef.Unpeeled(Storage.LOOSE, name,
+ objectId);
+ Ref master = db.getRef("refs/heads/master");
+ String message = formatter.format(Arrays.asList(remoteBranch), master);
+ assertEquals("Merge branch 'test' of http://egit.eclipse.org/jgit.git",
+ message);
+ }
+
+ public void testIntoOtherThanMaster() throws IOException {
+ Ref a = db.getRef("refs/heads/a");
+ Ref b = db.getRef("refs/heads/b");
+ String message = formatter.format(Arrays.asList(a), b);
+ assertEquals("Merge branch 'a' into b", message);
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java
index fe8e38fc7e..93d909d7db 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java
@@ -172,7 +172,7 @@ public class URIishTest extends TestCase {
assertEquals(u, new URIish(str));
}
- public void testScpStyleWithoutUser() throws Exception {
+ public void testScpStyleWithoutUserRelativePath() throws Exception {
final String str = "example.com:some/p ath";
URIish u = new URIish(str);
assertNull(u.getScheme());
@@ -184,6 +184,18 @@ public class URIishTest extends TestCase {
assertEquals(u, new URIish(str));
}
+ public void testScpStyleWithoutUserAbsolutePath() throws Exception {
+ final String str = "example.com:/some/p ath";
+ URIish u = new URIish(str);
+ assertNull(u.getScheme());
+ assertTrue(u.isRemote());
+ assertEquals("/some/p ath", u.getPath());
+ assertEquals("example.com", u.getHost());
+ assertEquals(-1, u.getPort());
+ assertEquals(str, u.toString());
+ assertEquals(u, new URIish(str));
+ }
+
public void testScpStyleWithUser() throws Exception {
final String str = "user@example.com:some/p ath";
URIish u = new URIish(str);
diff --git a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
index a3afa6772f..36fbae9f3c 100644
--- a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
@@ -7,7 +7,8 @@ Bundle-Version: 0.10.0.qualifier
Bundle-Vendor: %provider_name
Bundle-RequiredExecutionEnvironment: J2SE-1.5
Export-Package: org.eclipse.jgit.awtui;version="0.10.0"
-Import-Package: org.eclipse.jgit.lib;version="[0.10.0,0.11.0)",
+Import-Package: org.eclipse.jgit.errors;version="[0.10.0,0.11.0)",
+ org.eclipse.jgit.lib;version="[0.10.0,0.11.0)",
org.eclipse.jgit.nls;version="[0.10.0,0.11.0)",
org.eclipse.jgit.revplot;version="[0.10.0,0.11.0)",
org.eclipse.jgit.revwalk;version="[0.10.0,0.11.0)",
diff --git a/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/AwtCredentialsProvider.java b/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/AwtCredentialsProvider.java
new file mode 100644
index 0000000000..0e6f78ab49
--- /dev/null
+++ b/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/AwtCredentialsProvider.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2010, Google Inc.
+ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ * 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.awtui;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JPasswordField;
+import javax.swing.JTextField;
+
+import org.eclipse.jgit.errors.UnsupportedCredentialItem;
+import org.eclipse.jgit.transport.CredentialItem;
+import org.eclipse.jgit.transport.CredentialsProvider;
+import org.eclipse.jgit.transport.URIish;
+
+/** Interacts with the user during authentication by using AWT/Swing dialogs. */
+public class AwtCredentialsProvider extends CredentialsProvider {
+ /** Install this implementation as the default. */
+ public static void install() {
+ CredentialsProvider.setDefault(new AwtCredentialsProvider());
+ }
+
+ @Override
+ public boolean isInteractive() {
+ return true;
+ }
+
+ @Override
+ public boolean supports(CredentialItem... items) {
+ for (CredentialItem i : items) {
+ if (i instanceof CredentialItem.StringType)
+ continue;
+
+ else if (i instanceof CredentialItem.CharArrayType)
+ continue;
+
+ else if (i instanceof CredentialItem.YesNoType)
+ continue;
+
+ else if (i instanceof CredentialItem.InformationalMessage)
+ continue;
+
+ else
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean get(URIish uri, CredentialItem... items)
+ throws UnsupportedCredentialItem {
+ if (items.length == 0) {
+ return true;
+
+ } else if (items.length == 1) {
+ final CredentialItem item = items[0];
+
+ if (item instanceof CredentialItem.InformationalMessage) {
+ JOptionPane.showMessageDialog(null, item.getPromptText(),
+ UIText.get().warning, JOptionPane.INFORMATION_MESSAGE);
+ return true;
+
+ } else if (item instanceof CredentialItem.YesNoType) {
+ CredentialItem.YesNoType v = (CredentialItem.YesNoType) item;
+ int r = JOptionPane.showConfirmDialog(null, v.getPromptText(),
+ UIText.get().warning, JOptionPane.YES_NO_OPTION);
+ switch (r) {
+ case JOptionPane.YES_OPTION:
+ v.setValue(true);
+ return true;
+
+ case JOptionPane.NO_OPTION:
+ v.setValue(false);
+ return true;
+
+ case JOptionPane.CANCEL_OPTION:
+ case JOptionPane.CLOSED_OPTION:
+ default:
+ return false;
+ }
+
+ } else {
+ return interactive(uri, items);
+ }
+
+ } else {
+ return interactive(uri, items);
+ }
+ }
+
+ private boolean interactive(URIish uri, CredentialItem[] items) {
+ final GridBagConstraints gbc = new GridBagConstraints(0, 0, 1, 1, 1, 1,
+ GridBagConstraints.NORTHWEST, GridBagConstraints.NONE,
+ new Insets(0, 0, 0, 0), 0, 0);
+ final JPanel panel = new JPanel();
+ panel.setLayout(new GridBagLayout());
+
+ final JTextField[] texts = new JTextField[items.length];
+ for (int i = 0; i < items.length; i++) {
+ CredentialItem item = items[i];
+
+ if (item instanceof CredentialItem.StringType
+ || item instanceof CredentialItem.CharArrayType) {
+ gbc.fill = GridBagConstraints.NONE;
+ gbc.gridwidth = GridBagConstraints.RELATIVE;
+ gbc.gridx = 0;
+ panel.add(new JLabel(item.getPromptText()), gbc);
+
+ gbc.fill = GridBagConstraints.HORIZONTAL;
+ gbc.gridwidth = GridBagConstraints.RELATIVE;
+ gbc.gridx = 1;
+ if (item.isValueSecure())
+ texts[i] = new JPasswordField(20);
+ else
+ texts[i] = new JTextField(20);
+ panel.add(texts[i], gbc);
+ gbc.gridy++;
+
+ } else if (item instanceof CredentialItem.InformationalMessage) {
+ gbc.fill = GridBagConstraints.NONE;
+ gbc.gridwidth = GridBagConstraints.REMAINDER;
+ gbc.gridx = 0;
+ panel.add(new JLabel(item.getPromptText()), gbc);
+ gbc.gridy++;
+
+ } else {
+ throw new UnsupportedCredentialItem(uri, item.getPromptText());
+ }
+ }
+
+ if (JOptionPane.showConfirmDialog(null, panel,
+ UIText.get().authenticationRequired,
+ JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE) != JOptionPane.OK_OPTION)
+ return false; // cancel
+
+ for (int i = 0; i < items.length; i++) {
+ CredentialItem item = items[i];
+ JTextField f = texts[i];
+
+ if (item instanceof CredentialItem.StringType) {
+ CredentialItem.StringType v = (CredentialItem.StringType) item;
+ if (f instanceof JPasswordField)
+ v.setValue(new String(((JPasswordField) f).getPassword()));
+ else
+ v.setValue(f.getText());
+
+ } else if (item instanceof CredentialItem.CharArrayType) {
+ CredentialItem.CharArrayType v = (CredentialItem.CharArrayType) item;
+ if (f instanceof JPasswordField)
+ v.setValueNoCopy(((JPasswordField) f).getPassword());
+ else
+ v.setValueNoCopy(f.getText().toCharArray());
+ }
+ }
+ return true;
+ }
+}
diff --git a/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/AwtSshSessionFactory.java b/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/AwtSshSessionFactory.java
deleted file mode 100644
index f0de7ceb70..0000000000
--- a/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/AwtSshSessionFactory.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
- * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
- * 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.awtui;
-
-import java.awt.Container;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JPasswordField;
-import javax.swing.JTextField;
-
-import org.eclipse.jgit.transport.OpenSshConfig;
-import org.eclipse.jgit.transport.SshConfigSessionFactory;
-import org.eclipse.jgit.transport.SshSessionFactory;
-
-import com.jcraft.jsch.Session;
-import com.jcraft.jsch.UIKeyboardInteractive;
-import com.jcraft.jsch.UserInfo;
-
-/**
- * Loads known hosts and private keys from <code>$HOME/.ssh</code>.
- * <p>
- * This is the default implementation used by JGit and provides most of the
- * compatibility necessary to match OpenSSH, a popular implementation of SSH
- * used by C Git.
- * <p>
- * If user interactivity is required by SSH (e.g. to obtain a password) AWT is
- * used to display a password input field to the end-user.
- */
-public class AwtSshSessionFactory extends SshConfigSessionFactory {
- /** Install this session factory implementation into the JVM. */
- public static void install() {
- SshSessionFactory.setInstance(new AwtSshSessionFactory());
- }
-
- @Override
- protected void configure(final OpenSshConfig.Host hc, final Session session) {
- if (!hc.isBatchMode())
- session.setUserInfo(new AWT_UserInfo());
- }
-
- private static class AWT_UserInfo implements UserInfo,
- UIKeyboardInteractive {
- private String passwd;
-
- private String passphrase;
-
- public void showMessage(final String msg) {
- JOptionPane.showMessageDialog(null, msg);
- }
-
- public boolean promptYesNo(final String msg) {
- return JOptionPane.showConfirmDialog(null, msg, UIText.get().warning,
- JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION;
- }
-
- public boolean promptPassword(final String msg) {
- passwd = null;
- final JPasswordField passwordField = new JPasswordField(20);
- final int result = JOptionPane.showConfirmDialog(null,
- new Object[] { passwordField }, msg,
- JOptionPane.OK_CANCEL_OPTION);
- if (result == JOptionPane.OK_OPTION) {
- passwd = new String(passwordField.getPassword());
- return true;
- }
- return false;
- }
-
- public boolean promptPassphrase(final String msg) {
- passphrase = null;
- final JPasswordField passwordField = new JPasswordField(20);
- final int result = JOptionPane.showConfirmDialog(null,
- new Object[] { passwordField }, msg,
- JOptionPane.OK_CANCEL_OPTION);
- if (result == JOptionPane.OK_OPTION) {
- passphrase = new String(passwordField.getPassword());
- return true;
- }
- return false;
- }
-
- public String getPassword() {
- return passwd;
- }
-
- public String getPassphrase() {
- return passphrase;
- }
-
- public String[] promptKeyboardInteractive(final String destination,
- final String name, final String instruction,
- final String[] prompt, final boolean[] echo) {
- final GridBagConstraints gbc = new GridBagConstraints(0, 0, 1, 1,
- 1, 1, GridBagConstraints.NORTHWEST,
- GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0);
- final Container panel = new JPanel();
- panel.setLayout(new GridBagLayout());
-
- gbc.weightx = 1.0;
- gbc.gridwidth = GridBagConstraints.REMAINDER;
- gbc.gridx = 0;
- panel.add(new JLabel(instruction), gbc);
- gbc.gridy++;
-
- gbc.gridwidth = GridBagConstraints.RELATIVE;
-
- final JTextField[] texts = new JTextField[prompt.length];
- for (int i = 0; i < prompt.length; i++) {
- gbc.fill = GridBagConstraints.NONE;
- gbc.gridx = 0;
- gbc.weightx = 1;
- panel.add(new JLabel(prompt[i]), gbc);
-
- gbc.gridx = 1;
- gbc.fill = GridBagConstraints.HORIZONTAL;
- gbc.weighty = 1;
- if (echo[i]) {
- texts[i] = new JTextField(20);
- } else {
- texts[i] = new JPasswordField(20);
- }
- panel.add(texts[i], gbc);
- gbc.gridy++;
- }
-
- if (JOptionPane.showConfirmDialog(null, panel, destination + ": "
- + name, JOptionPane.OK_CANCEL_OPTION,
- JOptionPane.QUESTION_MESSAGE) == JOptionPane.OK_OPTION) {
- String[] response = new String[prompt.length];
- for (int i = 0; i < prompt.length; i++) {
- response[i] = texts[i].getText();
- }
- return response;
- }
- return null; // cancel
- }
- }
-}
diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties
index 8af6e315fc..ab4ec61325 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties
@@ -124,7 +124,8 @@ couldNotWriteFile=Could not write file {0}
countingObjects=Counting objects
createBranchFailedUnknownReason=Create branch failed for unknown reason
createBranchUnexpectedResult=Create branch returned unexpected result {0}
-creatingDeltasIsNotImplemented=creating deltas is not implemented
+credentialPassword=Password
+credentialUsername=Username
daemonAlreadyRunning=Daemon already running
deleteBranchUnexpectedResult=Delete branch returned unexpected result {0}
deletingNotSupported=Deleting {0} not supported.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java
index 6a75a9eb86..2eb316e85c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java
@@ -184,7 +184,8 @@ public class JGitText extends TranslationBundle {
/***/ public String countingObjects;
/***/ public String createBranchFailedUnknownReason;
/***/ public String createBranchUnexpectedResult;
- /***/ public String creatingDeltasIsNotImplemented;
+ /***/ public String credentialPassword;
+ /***/ public String credentialUsername;
/***/ public String daemonAlreadyRunning;
/***/ public String deleteBranchUnexpectedResult;
/***/ public String deletingNotSupported;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
index 9e31c47c37..1528e799ae 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
@@ -69,6 +69,7 @@ import org.eclipse.jgit.lib.Ref.Storage;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.RefUpdate.Result;
import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.merge.MergeMessageFormatter;
import org.eclipse.jgit.merge.MergeStrategy;
import org.eclipse.jgit.merge.ResolveMerger;
import org.eclipse.jgit.merge.ResolveMerger.MergeFailureReason;
@@ -132,7 +133,7 @@ public class MergeCommand extends GitCommand<MergeResult> {
revWalk = new RevWalk(repo);
RevCommit headCommit = revWalk.lookupCommit(head.getObjectId());
- // we know for know there is only one commit
+ // we know for now there is only one commit
Ref ref = commits.get(0);
refLogMessage.append(ref.getName());
@@ -164,8 +165,9 @@ public class MergeCommand extends GitCommand<MergeResult> {
headCommit, srcCommit }, MergeStatus.FAST_FORWARD,
mergeStrategy, null, null);
} else {
- repo.writeMergeCommitMsg("merging " + ref.getName() + " into "
- + head.getName());
+
+ repo.writeMergeCommitMsg(new MergeMessageFormatter().format(
+ commits, head));
repo.writeMergeHeads(Arrays.asList(ref.getObjectId()));
ThreeWayMerger merger = (ThreeWayMerger) mergeStrategy
.newMerger(repo);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
index c7b9eb5db0..5b71dc091f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
@@ -406,7 +406,7 @@ public class DirCacheCheckout {
// File/Directory conflict case #20
if (walk.isDirectoryFileConflict())
// TODO: check whether it is always correct to report a conflict here
- conflict(name, null, h, m);
+ conflict(name, null, null, null);
// file only exists in working tree -> ignore it
return;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedCredentialItem.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedCredentialItem.java
new file mode 100644
index 0000000000..eb09588fb5
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedCredentialItem.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com>,
+ * Copyright (C) 2010, Stefan Lay <stefan.lay@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.errors;
+
+import org.eclipse.jgit.transport.CredentialItem;
+import org.eclipse.jgit.transport.CredentialsProvider;
+import org.eclipse.jgit.transport.URIish;
+
+/**
+ * An exception thrown when a {@link CredentialItem} is requested from a
+ * {@link CredentialsProvider} which is not supported by this provider.
+ */
+public class UnsupportedCredentialItem extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Constructs an UnsupportedCredentialItem with the specified detail message
+ * prefixed with provided URI.
+ *
+ * @param uri
+ * URI used for transport
+ * @param s
+ * message
+ */
+ public UnsupportedCredentialItem(final URIish uri, final String s) {
+ super(uri.setPass(null) + ": " + s);
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
index 4319fedd63..f5aaa5e8f8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
@@ -203,6 +203,9 @@ public class IndexDiff {
if (!fileModeTree.equals(FileMode.TYPE_TREE)) {
removed.add(treeIterator.getEntryPathString());
changesExist = true;
+ if (workingTreeIterator != null)
+ untracked.add(workingTreeIterator
+ .getEntryPathString());
}
}
} else {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefRename.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefRename.java
index 2ff5c614b5..3cfb75a609 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefRename.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefRename.java
@@ -77,14 +77,13 @@ public abstract class RefRename {
source = src;
destination = dst;
- Repository repo = destination.getRepository();
String cmd = "";
if (source.getName().startsWith(Constants.R_HEADS)
&& destination.getName().startsWith(Constants.R_HEADS))
cmd = "Branch: ";
setRefLogMessage(cmd + "renamed "
- + repo.shortenRefName(source.getName()) + " to "
- + repo.shortenRefName(destination.getName()));
+ + Repository.shortenRefName(source.getName()) + " to "
+ + Repository.shortenRefName(destination.getName()));
}
/** @return identity of the user making the change in the reflog. */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
index 5c8b15f5a6..8ba6ba5b99 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
@@ -1119,7 +1119,7 @@ public abstract class Repository {
*
* @return a more user friendly ref name
*/
- public String shortenRefName(String refName) {
+ public static String shortenRefName(String refName) {
if (refName.startsWith(Constants.R_HEADS))
return refName.substring(Constants.R_HEADS.length());
if (refName.startsWith(Constants.R_TAGS))
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeAlgorithm.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeAlgorithm.java
index 8682487139..aee0ba940a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeAlgorithm.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeAlgorithm.java
@@ -103,7 +103,7 @@ public final class MergeAlgorithm {
// leave the loop when there are no edits more for ours or for theirs
// (or both)
while (theirsEdit != END_EDIT || oursEdit != END_EDIT) {
- if (oursEdit.getEndA() <= theirsEdit.getBeginA()) {
+ if (oursEdit.getEndA() < theirsEdit.getBeginA()) {
// something was changed in ours not overlapping with any change
// from theirs. First add the common part in front of the edit
// then the edit.
@@ -115,7 +115,7 @@ public final class MergeAlgorithm {
ConflictState.NO_CONFLICT);
current = oursEdit.getEndA();
oursEdit = nextEdit(baseToOurs);
- } else if (theirsEdit.getEndA() <= oursEdit.getBeginA()) {
+ } else if (theirsEdit.getEndA() < oursEdit.getBeginA()) {
// something was changed in theirs not overlapping with any
// from ours. First add the common part in front of the edit
// then the edit.
@@ -179,10 +179,10 @@ public final class MergeAlgorithm {
Edit nextOursEdit = nextEdit(baseToOurs);
Edit nextTheirsEdit = nextEdit(baseToTheirs);
for (;;) {
- if (oursEdit.getEndA() > nextTheirsEdit.getBeginA()) {
+ if (oursEdit.getEndA() >= nextTheirsEdit.getBeginA()) {
theirsEdit = nextTheirsEdit;
nextTheirsEdit = nextEdit(baseToTheirs);
- } else if (theirsEdit.getEndA() > nextOursEdit.getBeginA()) {
+ } else if (theirsEdit.getEndA() >= nextOursEdit.getBeginA()) {
oursEdit = nextOursEdit;
nextOursEdit = nextEdit(baseToOurs);
} else {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java
new file mode 100644
index 0000000000..cb2f8a522c
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2010, Robin Stocker <robin@nibor.org>
+ * 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.merge;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.util.StringUtils;
+
+/**
+ * Formatter for constructing the commit message for a merge commit.
+ * <p>
+ * The format should be the same as C Git does it, for compatibility.
+ */
+public class MergeMessageFormatter {
+ /**
+ * Construct the merge commit message.
+ *
+ * @param refsToMerge
+ * the refs which will be merged
+ * @param target
+ * the branch ref which will be merged into
+ * @return merge commit message
+ */
+ public String format(List<Ref> refsToMerge, Ref target) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Merge ");
+
+ List<String> branches = new ArrayList<String>();
+ List<String> remoteBranches = new ArrayList<String>();
+ List<String> tags = new ArrayList<String>();
+ List<String> commits = new ArrayList<String>();
+ List<String> others = new ArrayList<String>();
+ for (Ref ref : refsToMerge) {
+ if (ref.getName().startsWith(Constants.R_HEADS))
+ branches.add("'" + Repository.shortenRefName(ref.getName())
+ + "'");
+
+ else if (ref.getName().startsWith(Constants.R_REMOTES))
+ remoteBranches.add("'"
+ + Repository.shortenRefName(ref.getName()) + "'");
+
+ else if (ref.getName().startsWith(Constants.R_TAGS))
+ tags.add("'" + Repository.shortenRefName(ref.getName()) + "'");
+
+ else if (ref.getName().equals(ref.getObjectId().getName()))
+ commits.add("'" + ref.getName() + "'");
+
+ else
+ others.add(ref.getName());
+ }
+
+ List<String> listings = new ArrayList<String>();
+
+ if (!branches.isEmpty())
+ listings.add(joinNames(branches, "branch", "branches"));
+
+ if (!remoteBranches.isEmpty())
+ listings.add(joinNames(remoteBranches, "remote branch",
+ "remote branches"));
+
+ if (!tags.isEmpty())
+ listings.add(joinNames(tags, "tag", "tags"));
+
+ if (!commits.isEmpty())
+ listings.add(joinNames(commits, "commit", "commits"));
+
+ if (!others.isEmpty())
+ listings.add(StringUtils.join(others, ", ", " and "));
+
+ sb.append(StringUtils.join(listings, ", "));
+
+ if (!target.getName().equals(Constants.R_HEADS + Constants.MASTER)) {
+ String targetShortName = Repository
+ .shortenRefName(target.getName());
+ sb.append(" into " + targetShortName);
+ }
+
+ return sb.toString();
+ }
+
+ private static String joinNames(List<String> names, String singular,
+ String plural) {
+ if (names.size() == 1)
+ return singular + " " + names.get(0);
+ else
+ return plural + " " + StringUtils.join(names, ", ", " and ");
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
index a8ab433fb5..1b6ec23bae 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
@@ -93,7 +93,9 @@ public class ResolveMerger extends ThreeWayMerger {
/** the merge failed because of a dirty index */
DIRTY_INDEX,
/** the merge failed because of a dirty workingtree */
- DIRTY_WORKTREE
+ DIRTY_WORKTREE,
+ /** the merge failed because of a file could not be deleted */
+ COULD_NOT_DELETE
}
private NameConflictTreeWalk tw;
@@ -229,10 +231,16 @@ public class ResolveMerger extends ThreeWayMerger {
private void checkout() throws NoWorkTreeException, IOException {
for (Map.Entry<String, DirCacheEntry> entry : toBeCheckedOut.entrySet()) {
File f = new File(db.getWorkTree(), entry.getKey());
- createDir(f.getParentFile());
- DirCacheCheckout.checkoutEntry(db,
- f,
- entry.getValue(), true);
+ if (entry.getValue() != null) {
+ createDir(f.getParentFile());
+ DirCacheCheckout.checkoutEntry(db,
+ f,
+ entry.getValue(), true);
+ } else {
+ if (!f.delete())
+ failingPathes.put(entry.getKey(),
+ MergeFailureReason.COULD_NOT_DELETE);
+ }
modifiedFiles.add(entry.getKey());
}
}
@@ -373,13 +381,21 @@ public class ResolveMerger extends ThreeWayMerger {
return true;
}
- if (nonTree(modeT) && modeB == modeO && tw.idEqual(T_BASE, T_OURS)) {
+ if (modeB == modeO && tw.idEqual(T_BASE, T_OURS)) {
// OURS was not changed compared to base. All changes must be in
// THEIRS. Choose THEIRS.
- DirCacheEntry e=add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_0);
- if (e!=null)
- toBeCheckedOut.put(tw.getPathString(), e);
- return true;
+ if (nonTree(modeT)) {
+ DirCacheEntry e = add(tw.getRawPath(), theirs,
+ DirCacheEntry.STAGE_0);
+ if (e != null)
+ toBeCheckedOut.put(tw.getPathString(), e);
+ return true;
+ } else if (modeT == 0) {
+ // we want THEIRS ... but THEIRS contains the deletion of the
+ // file
+ toBeCheckedOut.put(tw.getPathString(), null);
+ return true;
+ }
}
if (tw.isSubtree()) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialItem.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialItem.java
new file mode 100644
index 0000000000..55ce4db626
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialItem.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2010, Google Inc.
+ * 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.transport;
+
+import java.util.Arrays;
+
+import org.eclipse.jgit.JGitText;
+
+/**
+ * A credential requested from a {@link CredentialsProvider}.
+ *
+ * Most users should work with the specialized subclasses:
+ * <ul>
+ * <li>{@link Username} for usernames</li>
+ * <li>{@link Password} for passwords</li>
+ * <li>{@link StringType} for other general string information</li>
+ * <li>{@link CharArrayType} for other general secret information</li>
+ * </ul>
+ *
+ * This class is not thread-safe. Applications should construct their own
+ * instance for each use, as the value is held within the CredentialItem object.
+ */
+public abstract class CredentialItem {
+ private final String promptText;
+
+ private final boolean valueSecure;
+
+ /**
+ * Initialize a prompt.
+ *
+ * @param promptText
+ * prompt to display to the user alongside of the input field.
+ * Should be sufficient text to indicate what to supply for this
+ * item.
+ * @param maskValue
+ * true if the value should be masked from displaying during
+ * input. This should be true for passwords and other secrets,
+ * false for names and other public data.
+ */
+ public CredentialItem(String promptText, boolean maskValue) {
+ this.promptText = promptText;
+ this.valueSecure = maskValue;
+ }
+
+ /** @return prompt to display to the user. */
+ public String getPromptText() {
+ return promptText;
+ }
+
+ /** @return true if the value should be masked when entered. */
+ public boolean isValueSecure() {
+ return valueSecure;
+ }
+
+ /** Clear the stored value, destroying it as much as possible. */
+ public abstract void clear();
+
+ /**
+ * An item whose value is stored as a string.
+ *
+ * When working with secret data, consider {@link CharArrayType} instead, as
+ * the internal members of the array can be cleared, reducing the chances
+ * that the password is left in memory after authentication is completed.
+ */
+ public static class StringType extends CredentialItem {
+ private String value;
+
+ /**
+ * Initialize a prompt for a single string.
+ *
+ * @param promptText
+ * prompt to display to the user alongside of the input
+ * field. Should be sufficient text to indicate what to
+ * supply for this item.
+ * @param maskValue
+ * true if the value should be masked from displaying during
+ * input. This should be true for passwords and other
+ * secrets, false for names and other public data.
+ */
+ public StringType(String promptText, boolean maskValue) {
+ super(promptText, maskValue);
+ }
+
+ @Override
+ public void clear() {
+ value = null;
+ }
+
+ /** @return the current value */
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ *
+ * @param newValue
+ */
+ public void setValue(String newValue) {
+ value = newValue;
+ }
+ }
+
+ /** An item whose value is stored as a char[] and is therefore clearable. */
+ public static class CharArrayType extends CredentialItem {
+ private char[] value;
+
+ /**
+ * Initialize a prompt for a secure value stored in a character array.
+ *
+ * @param promptText
+ * prompt to display to the user alongside of the input
+ * field. Should be sufficient text to indicate what to
+ * supply for this item.
+ * @param maskValue
+ * true if the value should be masked from displaying during
+ * input. This should be true for passwords and other
+ * secrets, false for names and other public data.
+ */
+ public CharArrayType(String promptText, boolean maskValue) {
+ super(promptText, maskValue);
+ }
+
+ /** Destroys the current value, clearing the internal array. */
+ @Override
+ public void clear() {
+ if (value != null) {
+ Arrays.fill(value, (char) 0);
+ value = null;
+ }
+ }
+
+ /**
+ * Get the current value.
+ *
+ * The returned array will be cleared out when {@link #clear()} is
+ * called. Callers that need the array elements to survive should delay
+ * invoking {@code clear()} until the value is no longer necessary.
+ *
+ * @return the current value array. The actual internal array is
+ * returned, reducing the number of copies present in memory.
+ */
+ public char[] getValue() {
+ return value;
+ }
+
+ /**
+ * Set the new value, clearing the old value array.
+ *
+ * @param newValue
+ * if not null, the array is copied.
+ */
+ public void setValue(char[] newValue) {
+ clear();
+
+ if (newValue != null) {
+ value = new char[newValue.length];
+ System.arraycopy(newValue, 0, value, 0, newValue.length);
+ }
+ }
+
+ /**
+ * Set the new value, clearing the old value array.
+ *
+ * @param newValue
+ * the new internal array. The array is <b>NOT</b> copied.
+ */
+ public void setValueNoCopy(char[] newValue) {
+ clear();
+ value = newValue;
+ }
+ }
+
+ /** An item whose value is a boolean choice, presented as Yes/No. */
+ public static class YesNoType extends CredentialItem {
+ private boolean value;
+
+ /**
+ * Initialize a prompt for a single boolean answer.
+ *
+ * @param promptText
+ * prompt to display to the user alongside of the input
+ * field. Should be sufficient text to indicate what to
+ * supply for this item.
+ */
+ public YesNoType(String promptText) {
+ super(promptText, false);
+ }
+
+ @Override
+ public void clear() {
+ value = false;
+ }
+
+ /** @return the current value */
+ public boolean getValue() {
+ return value;
+ }
+
+ /**
+ * Set the new value.
+ *
+ * @param newValue
+ */
+ public void setValue(boolean newValue) {
+ value = newValue;
+ }
+ }
+
+ /** An advice message presented to the user, with no response required. */
+ public static class InformationalMessage extends CredentialItem {
+ /**
+ * Initialize an informational message.
+ *
+ * @param messageText
+ * message to display to the user.
+ */
+ public InformationalMessage(String messageText) {
+ super(messageText, false);
+ }
+
+ @Override
+ public void clear() {
+ // Nothing to clear.
+ }
+ }
+
+ /** Prompt for a username, which is not masked on input. */
+ public static class Username extends StringType {
+ /** Initialize a new username item, with a default username prompt. */
+ public Username() {
+ super(JGitText.get().credentialUsername, false);
+ }
+ }
+
+ /** Prompt for a password, which is masked on input. */
+ public static class Password extends CharArrayType {
+ /** Initialize a new password item, with a default password prompt. */
+ public Password() {
+ super(JGitText.get().credentialPassword, true);
+ }
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialsProvider.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialsProvider.java
new file mode 100644
index 0000000000..194268f1f9
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialsProvider.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com>,
+ * Copyright (C) 2010, Stefan Lay <stefan.lay@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.transport;
+
+import java.util.List;
+
+import org.eclipse.jgit.errors.UnsupportedCredentialItem;
+
+/**
+ * Provide credentials for use in connecting to Git repositories.
+ *
+ * Implementors are strongly encouraged to support at least the minimal
+ * {@link CredentialItem.Username} and {@link CredentialItem.Password} items.
+ * More sophisticated implementors may implement additional types, such as
+ * {@link CredentialItem.StringType}.
+ *
+ * CredentialItems are usually presented in bulk, allowing implementors to
+ * combine them into a single UI widget and streamline the authentication
+ * process for an end-user.
+ *
+ * @see UsernamePasswordCredentialsProvider
+ */
+public abstract class CredentialsProvider {
+ private static volatile CredentialsProvider defaultProvider;
+
+ /** @return the default credentials provider, or null. */
+ public static CredentialsProvider getDefault() {
+ return defaultProvider;
+ }
+
+ /**
+ * Set the default credentials provider.
+ *
+ * @param p
+ * the new default provider, may be null to select no default.
+ */
+ public static void setDefault(CredentialsProvider p) {
+ defaultProvider = p;
+ }
+
+ /**
+ * Check if the provider is interactive with the end-user.
+ *
+ * An interactive provider may try to open a dialog box, or prompt for input
+ * on the terminal, and will wait for a user response. A non-interactive
+ * provider will either populate CredentialItems, or fail.
+ *
+ * @return {@code true} if the provider is interactive with the end-user.
+ */
+ public abstract boolean isInteractive();
+
+ /**
+ * Check if the provider can supply the necessary {@link CredentialItem}s.
+ *
+ * @param items
+ * the items the application requires to complete authentication.
+ * @return {@code true} if this {@link CredentialsProvider} supports all of
+ * the items supplied.
+ */
+ public abstract boolean supports(CredentialItem... items);
+
+ /**
+ * Ask for the credential items to be populated.
+ *
+ * @param uri
+ * the URI of the remote resource that needs authentication.
+ * @param items
+ * the items the application requires to complete authentication.
+ * @return {@code true} if the request was successful and values were
+ * supplied; {@code false} if the user canceled the request and did
+ * not supply all requested values.
+ * @throws UnsupportedCredentialItem
+ * if one of the items supplied is not supported.
+ */
+ public abstract boolean get(URIish uri, CredentialItem... items)
+ throws UnsupportedCredentialItem;
+
+ /**
+ * Ask for the credential items to be populated.
+ *
+ * @param uri
+ * the URI of the remote resource that needs authentication.
+ * @param items
+ * the items the application requires to complete authentication.
+ * @return {@code true} if the request was successful and values were
+ * supplied; {@code false} if the user canceled the request and did
+ * not supply all requested values.
+ * @throws UnsupportedCredentialItem
+ * if one of the items supplied is not supported.
+ */
+ public boolean get(URIish uri, List<CredentialItem> items)
+ throws UnsupportedCredentialItem {
+ return get(uri, items.toArray(new CredentialItem[items.size()]));
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialsProviderUserInfo.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialsProviderUserInfo.java
new file mode 100644
index 0000000000..8f259c6765
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/CredentialsProviderUserInfo.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2010, Google Inc.
+ * 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.transport;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import com.jcraft.jsch.Session;
+import com.jcraft.jsch.UIKeyboardInteractive;
+import com.jcraft.jsch.UserInfo;
+
+/** A JSch {@link UserInfo} adapter for a {@link CredentialsProvider}. */
+public class CredentialsProviderUserInfo implements UserInfo,
+ UIKeyboardInteractive {
+ private final URIish uri;
+
+ private final CredentialsProvider provider;
+
+ private String password;
+
+ private String passphrase;
+
+ /**
+ * Wrap a CredentialsProvider to make it suitable for use with JSch.
+ *
+ * @param session
+ * the JSch session this UserInfo will support authentication on.
+ * @param credentialsProvider
+ * the provider that will perform the authentication.
+ */
+ public CredentialsProviderUserInfo(Session session,
+ CredentialsProvider credentialsProvider) {
+ this.uri = createURI(session);
+ this.provider = credentialsProvider;
+ }
+
+ private static URIish createURI(Session session) {
+ URIish uri = new URIish();
+ uri = uri.setScheme("ssh");
+ uri = uri.setUser(session.getUserName());
+ uri = uri.setHost(session.getHost());
+ uri = uri.setPort(session.getPort());
+ return uri;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public String getPassphrase() {
+ return passphrase;
+ }
+
+ public boolean promptPassphrase(String msg) {
+ CredentialItem.StringType v = newPrompt(msg);
+ if (provider.get(uri, v)) {
+ passphrase = v.getValue();
+ return true;
+ } else {
+ passphrase = null;
+ return false;
+ }
+ }
+
+ public boolean promptPassword(String msg) {
+ CredentialItem.StringType v = newPrompt(msg);
+ if (provider.get(uri, v)) {
+ password = v.getValue();
+ return true;
+ } else {
+ password = null;
+ return false;
+ }
+ }
+
+ private CredentialItem.StringType newPrompt(String msg) {
+ return new CredentialItem.StringType(msg, true);
+ }
+
+ public boolean promptYesNo(String msg) {
+ CredentialItem.YesNoType v = new CredentialItem.YesNoType(msg);
+ return provider.get(uri, v) && v.getValue();
+ }
+
+ public void showMessage(String msg) {
+ provider.get(uri, new CredentialItem.InformationalMessage(msg));
+ }
+
+ public String[] promptKeyboardInteractive(String destination, String name,
+ String instruction, String[] prompt, boolean[] echo) {
+ CredentialItem.StringType[] v = new CredentialItem.StringType[prompt.length];
+ for (int i = 0; i < prompt.length; i++)
+ v[i] = new CredentialItem.StringType(prompt[i], !echo[i]);
+
+ List<CredentialItem> items = new ArrayList<CredentialItem>();
+ if (instruction != null && instruction.length() > 0)
+ items.add(new CredentialItem.InformationalMessage(instruction));
+ items.addAll(Arrays.asList(v));
+
+ if (!provider.get(uri, items))
+ return null; // cancel
+
+ String[] result = new String[v.length];
+ for (int i = 0; i < v.length; i++)
+ result[i] = v[i].getValue();
+ return result;
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java
index 5a559abf18..926661667e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/HttpAuthMethod.java
@@ -85,9 +85,9 @@ abstract class HttpAuthMethod {
return NONE;
String type = hdr.substring(0, sp);
- if (Basic.NAME.equals(type))
+ if (Basic.NAME.equalsIgnoreCase(type))
return new Basic();
- else if (Digest.NAME.equals(type))
+ else if (Digest.NAME.equalsIgnoreCase(type))
return new Digest(hdr.substring(sp + 1));
else
return NONE;
@@ -98,9 +98,37 @@ abstract class HttpAuthMethod {
*
* @param uri
* the URI used to create the connection.
+ * @param credentialsProvider
+ * the credentials provider, or null. If provided,
+ * {@link URIish#getPass() credentials in the URI} are ignored.
+ *
+ * @return true if the authentication method is able to provide
+ * authorization for the given URI
*/
- void authorize(URIish uri) {
- authorize(uri.getUser(), uri.getPass());
+ boolean authorize(URIish uri, CredentialsProvider credentialsProvider) {
+ String username;
+ String password;
+
+ if (credentialsProvider != null) {
+ CredentialItem.Username u = new CredentialItem.Username();
+ CredentialItem.Password p = new CredentialItem.Password();
+
+ if (credentialsProvider.supports(u, p)
+ && credentialsProvider.get(uri, u, p)) {
+ username = u.getValue();
+ password = new String(p.getValue());
+ p.clear();
+ } else
+ return false;
+ } else {
+ username = uri.getUser();
+ password = uri.getPass();
+ }
+ if (username != null) {
+ authorize(username, password);
+ return true;
+ }
+ return false;
}
/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java
index 3821d696ed..d3264d5f23 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineIn.java
@@ -57,7 +57,8 @@ import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.RawParseUtils;
class PacketLineIn {
- static final String END = new String("") /* must not string pool */;
+ /* must not string pool */
+ static final String END = new StringBuilder(0).toString();
static enum AckNackResult {
/** NAK */
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshConfigSessionFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshConfigSessionFactory.java
index daa6f4ca2f..99e7b83335 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshConfigSessionFactory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshConfigSessionFactory.java
@@ -83,7 +83,8 @@ public abstract class SshConfigSessionFactory extends SshSessionFactory {
@Override
public synchronized Session getSession(String user, String pass,
- String host, int port, FS fs) throws JSchException {
+ String host, int port, CredentialsProvider credentialsProvider,
+ FS fs) throws JSchException {
if (config == null)
config = OpenSshConfig.get(fs);
@@ -105,6 +106,11 @@ public abstract class SshConfigSessionFactory extends SshSessionFactory {
final String pauth = hc.getPreferredAuthentications();
if (pauth != null)
session.setConfig("PreferredAuthentications", pauth);
+ if (credentialsProvider != null
+ && (!hc.isBatchMode() || !credentialsProvider.isInteractive())) {
+ session.setUserInfo(new CredentialsProviderUserInfo(session,
+ credentialsProvider));
+ }
configure(hc, session);
return session;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshSessionFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshSessionFactory.java
index d10010fcf6..34aa3dbd24 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshSessionFactory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshSessionFactory.java
@@ -111,6 +111,8 @@ public abstract class SshSessionFactory {
* @param port
* port number the server is listening for connections on. May be <=
* 0 to indicate the IANA registered port of 22 should be used.
+ * @param credentialsProvider
+ * provider to support authentication, may be null.
* @param fs
* the file system abstraction which will be necessary to
* perform certain file system operations.
@@ -119,14 +121,16 @@ public abstract class SshSessionFactory {
* the session could not be created.
*/
public abstract Session getSession(String user, String pass, String host,
- int port, FS fs) throws JSchException;
+ int port, CredentialsProvider credentialsProvider, FS fs)
+ throws JSchException;
/**
* Close (or recycle) a session to a host.
*
* @param session
* a session previously obtained from this factory's
- * {@link #getSession(String,String, String, int, FS)} method.s
+ * {@link #getSession(String,String, String, int, CredentialsProvider, FS)}
+ * method.
*/
public void releaseSession(final Session session) {
if (session.isConnected())
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshTransport.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshTransport.java
index f642ac1ea8..81d233f1ed 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshTransport.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshTransport.java
@@ -128,7 +128,8 @@ public abstract class SshTransport extends TcpTransport {
final String host = uri.getHost();
final int port = uri.getPort();
try {
- sock = sch.getSession(user, pass, host, port, local.getFS());
+ sock = sch.getSession(user, pass, host, port,
+ getCredentialsProvider(), local.getFS());
if (!sock.isConnected())
sock.connect(tms);
} catch (JSchException je) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
index 500cf0cff5..69eea0c223 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
@@ -558,6 +558,9 @@ public abstract class Transport {
/** Pack configuration used by this transport to make pack file. */
private PackConfig packConfig;
+ /** Assists with authentication the connection. */
+ private CredentialsProvider credentialsProvider;
+
/**
* Create a new transport instance.
*
@@ -574,6 +577,7 @@ public abstract class Transport {
this.local = local;
this.uri = uri;
this.checkFetchedObjects = tc.isFsckObjects();
+ this.credentialsProvider = CredentialsProvider.getDefault();
}
/**
@@ -822,6 +826,26 @@ public abstract class Transport {
}
/**
+ * A credentials provider to assist with authentication connections..
+ *
+ * @param credentialsProvider
+ * the credentials provider, or null if there is none
+ */
+ public void setCredentialsProvider(CredentialsProvider credentialsProvider) {
+ this.credentialsProvider = credentialsProvider;
+ }
+
+ /**
+ * The configured credentials provider.
+ *
+ * @return the credentials provider, or null if no credentials provider is
+ * associated with this transport.
+ */
+ public CredentialsProvider getCredentialsProvider() {
+ return credentialsProvider;
+ }
+
+ /**
* Fetch objects and refs from the remote repository to the local one.
* <p>
* This is a utility function providing standard fetch behavior. Local
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java
index 39dedc6a66..9eb1d2db5f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java
@@ -367,10 +367,12 @@ public class TransportHttp extends HttpTransport implements WalkTransport,
if (authMethod == HttpAuthMethod.NONE)
throw new TransportException(uri, MessageFormat.format(
JGitText.get().authenticationNotSupported, uri));
- if (1 < authAttempts || uri.getUser() == null)
+ if (1 < authAttempts
+ || !authMethod.authorize(uri,
+ getCredentialsProvider())) {
throw new TransportException(uri,
JGitText.get().notAuthorized);
- authMethod.authorize(uri);
+ }
authAttempts++;
continue;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java
index 94f4a67d58..bc24516a65 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java
@@ -155,7 +155,7 @@ public class URIish implements Serializable {
/**
* A pattern matching a SCP URI's of the form user@host:path/to/repo.git
*/
- private static final Pattern SCP_URI = Pattern.compile("^" //
+ private static final Pattern RELATIVE_SCP_URI = Pattern.compile("^" //
+ OPT_USER_PWD_P //
+ HOST_P //
+ ":(" //
@@ -163,6 +163,16 @@ public class URIish implements Serializable {
+ RELATIVE_PATH_P //
+ ")$");
+ /**
+ * A pattern matching a SCP URI's of the form user@host:/path/to/repo.git
+ */
+ private static final Pattern ABSOLUTE_SCP_URI = Pattern.compile("^" //
+ + OPT_USER_PWD_P //
+ + "([^/:]{2,})" //
+ + ":(" //
+ + "/" + RELATIVE_PATH_P //
+ + ")$");
+
private String scheme;
private String path;
@@ -200,19 +210,27 @@ public class URIish implements Serializable {
n2e(matcher.group(6)) + n2e(matcher.group(7)),
scheme);
} else {
- matcher = SCP_URI.matcher(s);
+ matcher = RELATIVE_SCP_URI.matcher(s);
if (matcher.matches()) {
user = matcher.group(1);
pass = matcher.group(2);
host = matcher.group(3);
path = matcher.group(4);
} else {
- matcher = LOCAL_FILE.matcher(s);
+ matcher = ABSOLUTE_SCP_URI.matcher(s);
if (matcher.matches()) {
- path = matcher.group(1);
- } else
- throw new URISyntaxException(s,
- JGitText.get().cannotParseGitURIish);
+ user = matcher.group(1);
+ pass = matcher.group(2);
+ host = matcher.group(3);
+ path = matcher.group(4);
+ } else {
+ matcher = LOCAL_FILE.matcher(s);
+ if (matcher.matches()) {
+ path = matcher.group(1);
+ } else
+ throw new URISyntaxException(s,
+ JGitText.get().cannotParseGitURIish);
+ }
}
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UsernamePasswordCredentialsProvider.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UsernamePasswordCredentialsProvider.java
new file mode 100644
index 0000000000..235e4b4b97
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UsernamePasswordCredentialsProvider.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2010, Google Inc.
+ * 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.transport;
+
+import java.util.Arrays;
+
+import org.eclipse.jgit.errors.UnsupportedCredentialItem;
+
+/**
+ * Simple {@link CredentialsProvider} that always uses the same information.
+ */
+public class UsernamePasswordCredentialsProvider extends CredentialsProvider {
+ private String username;
+
+ private char[] password;
+
+ /**
+ * Initialize the provider with a single username and password.
+ *
+ * @param username
+ * @param password
+ */
+ public UsernamePasswordCredentialsProvider(String username, String password) {
+ this(username, password.toCharArray());
+ }
+
+ /**
+ * Initialize the provider with a single username and password.
+ *
+ * @param username
+ * @param password
+ */
+ public UsernamePasswordCredentialsProvider(String username, char[] password) {
+ this.username = username;
+ this.password = password;
+ }
+
+ @Override
+ public boolean isInteractive() {
+ return false;
+ }
+
+ @Override
+ public boolean supports(CredentialItem... items) {
+ for (CredentialItem i : items) {
+ if (i instanceof CredentialItem.Username)
+ continue;
+
+ else if (i instanceof CredentialItem.Password)
+ continue;
+
+ else
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean get(URIish uri, CredentialItem... items)
+ throws UnsupportedCredentialItem {
+ for (CredentialItem i : items) {
+ if (i instanceof CredentialItem.Username)
+ ((CredentialItem.Username) i).setValue(username);
+
+ else if (i instanceof CredentialItem.Password)
+ ((CredentialItem.Password) i).setValue(password);
+
+ else
+ throw new UnsupportedCredentialItem(uri, i.getPromptText());
+ }
+ return true;
+ }
+
+ /** Destroy the saved username and password.. */
+ public void clear() {
+ username = null;
+
+ if (password != null) {
+ Arrays.fill(password, (char) 0);
+ password = null;
+ }
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java
index 119c041570..3759a12820 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/StringUtils.java
@@ -44,6 +44,7 @@
package org.eclipse.jgit.util;
import java.text.MessageFormat;
+import java.util.Collection;
import org.eclipse.jgit.JGitText;
@@ -158,6 +159,49 @@ public final class StringUtils {
}
}
+ /**
+ * Join a collection of Strings together using the specified separator.
+ *
+ * @param parts
+ * Strings to join
+ * @param separator
+ * used to join
+ * @return a String with all the joined parts
+ */
+ public static String join(Collection<String> parts, String separator) {
+ return StringUtils.join(parts, separator, separator);
+ }
+
+ /**
+ * Join a collection of Strings together using the specified separator and a
+ * lastSeparator which is used for joining the second last and the last
+ * part.
+ *
+ * @param parts
+ * Strings to join
+ * @param separator
+ * separator used to join all but the two last elements
+ * @param lastSeparator
+ * separator to use for joining the last two elements
+ * @return a String with all the joined parts
+ */
+ public static String join(Collection<String> parts, String separator,
+ String lastSeparator) {
+ StringBuilder sb = new StringBuilder();
+ int i = 0;
+ int lastIndex = parts.size() - 1;
+ for (String part : parts) {
+ sb.append(part);
+ if (i == lastIndex - 1) {
+ sb.append(lastSeparator);
+ } else if (i != lastIndex) {
+ sb.append(separator);
+ }
+ i++;
+ }
+ return sb.toString();
+ }
+
private StringUtils() {
// Do not create instances
}