Merge "Fix null ref exception in DirCacheCheckout"
diff --git a/org.eclipse.jgit.console/META-INF/MANIFEST.MF b/org.eclipse.jgit.console/META-INF/MANIFEST.MF
index a29b348..9607bdc 100644
--- a/org.eclipse.jgit.console/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.console/META-INF/MANIFEST.MF
@@ -7,7 +7,8 @@
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 0000000..f8f8ff9
--- /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 b11078d..0000000
--- 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 06a4eb6..92584cb 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.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.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 void testListRemote_Dumb_NeedsAuth() throws Exception {
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 void testListRemote_Dumb_NeedsAuth() throws Exception {
}
}
+ 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 void testListRemote_Smart_UploadPackNeedsAuth() throws Exception {
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/src/org/eclipse/jgit/pgm/Main.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java
index ca3960e..62ffd8d 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.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 @@ protected void run(final String[] argv) {
try {
if (!installConsole()) {
AwtAuthenticator.install();
- AwtSshSessionFactory.install();
+ AwtCredentialsProvider.install();
}
configureHttpProxy();
execute(argv);
@@ -218,7 +218,7 @@ protected Repository openGitDir(String gitdir) throws IOException {
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.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
index 8d85084..0a87fd3 100644
--- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
@@ -26,6 +26,7 @@
org.eclipse.jgit.lib;version="[0.10.0,0.11.0)",
org.eclipse.jgit.merge;version="[0.10.0,0.11.0)",
org.eclipse.jgit.nls;version="[0.10.0,0.11.0)",
+ org.eclipse.jgit.notes;version="[0.10.0,0.11.0)",
org.eclipse.jgit.patch;version="[0.10.0,0.11.0)",
org.eclipse.jgit.pgm;version="[0.10.0,0.11.0)",
org.eclipse.jgit.revplot;version="[0.10.0,0.11.0)",
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0001_ObjectId.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdTest.java
similarity index 76%
rename from org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0001_ObjectId.java
rename to org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdTest.java
index 03176cb..e5faff1 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0001_ObjectId.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdTest.java
@@ -47,7 +47,7 @@
import junit.framework.TestCase;
-public class T0001_ObjectId extends TestCase {
+public class ObjectIdTest extends TestCase {
public void test001_toString() {
final String x = "def4c620bc3713bb1bb26b808ec9312548e73946";
final ObjectId oid = ObjectId.fromString(x);
@@ -108,4 +108,47 @@ public void test011_toString() {
final ObjectId oid = ObjectId.fromString(x);
assertEquals(x.toLowerCase(), oid.name());
}
+
+ public void testGetByte() {
+ byte[] raw = new byte[20];
+ for (int i = 0; i < 20; i++)
+ raw[i] = (byte) (0xa0 + i);
+ ObjectId id = ObjectId.fromRaw(raw);
+
+ assertEquals(raw[0] & 0xff, id.getFirstByte());
+ assertEquals(raw[0] & 0xff, id.getByte(0));
+ assertEquals(raw[1] & 0xff, id.getByte(1));
+
+ for (int i = 2; i < 20; i++)
+ assertEquals("index " + i, raw[i] & 0xff, id.getByte(i));
+ }
+
+ public void testSetByte() {
+ byte[] exp = new byte[20];
+ for (int i = 0; i < 20; i++)
+ exp[i] = (byte) (0xa0 + i);
+
+ MutableObjectId id = new MutableObjectId();
+ id.fromRaw(exp);
+ assertEquals(ObjectId.fromRaw(exp).name(), id.name());
+
+ id.setByte(0, 0x10);
+ assertEquals(0x10, id.getByte(0));
+ exp[0] = 0x10;
+ assertEquals(ObjectId.fromRaw(exp).name(), id.name());
+
+ for (int p = 1; p < 20; p++) {
+ id.setByte(p, 0x10 + p);
+ assertEquals(0x10 + p, id.getByte(p));
+ exp[p] = (byte) (0x10 + p);
+ assertEquals(ObjectId.fromRaw(exp).name(), id.name());
+ }
+
+ for (int p = 0; p < 20; p++) {
+ id.setByte(p, 0x80 + p);
+ assertEquals(0x80 + p, id.getByte(p));
+ exp[p] = (byte) (0x80 + p);
+ assertEquals(ObjectId.fromRaw(exp).name(), id.name());
+ }
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/notes/NoteMapTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/notes/NoteMapTest.java
new file mode 100644
index 0000000..786f1b9
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/notes/NoteMapTest.java
@@ -0,0 +1,201 @@
+/*
+ * 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.notes;
+
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.RepositoryTestCase;
+import org.eclipse.jgit.revwalk.RevBlob;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.util.RawParseUtils;
+
+public class NoteMapTest extends RepositoryTestCase {
+ private TestRepository<Repository> tr;
+
+ private ObjectReader reader;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ tr = new TestRepository<Repository>(db);
+ reader = db.newObjectReader();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ reader.release();
+ super.tearDown();
+ }
+
+ public void testReadFlatTwoNotes() throws Exception {
+ RevBlob a = tr.blob("a");
+ RevBlob b = tr.blob("b");
+ RevBlob data1 = tr.blob("data1");
+ RevBlob data2 = tr.blob("data2");
+
+ RevCommit r = tr.commit() //
+ .add(a.name(), data1) //
+ .add(b.name(), data2) //
+ .create();
+ tr.parseBody(r);
+
+ NoteMap map = NoteMap.read(reader, r);
+ assertNotNull("have map", map);
+
+ assertTrue("has note for a", map.contains(a));
+ assertTrue("has note for b", map.contains(b));
+ assertEquals(data1, map.get(a));
+ assertEquals(data2, map.get(b));
+
+ assertFalse("no note for data1", map.contains(data1));
+ assertNull("no note for data1", map.get(data1));
+ }
+
+ public void testReadFanout2_38() throws Exception {
+ RevBlob a = tr.blob("a");
+ RevBlob b = tr.blob("b");
+ RevBlob data1 = tr.blob("data1");
+ RevBlob data2 = tr.blob("data2");
+
+ RevCommit r = tr.commit() //
+ .add(fanout(2, a.name()), data1) //
+ .add(fanout(2, b.name()), data2) //
+ .create();
+ tr.parseBody(r);
+
+ NoteMap map = NoteMap.read(reader, r);
+ assertNotNull("have map", map);
+
+ assertTrue("has note for a", map.contains(a));
+ assertTrue("has note for b", map.contains(b));
+ assertEquals(data1, map.get(a));
+ assertEquals(data2, map.get(b));
+
+ assertFalse("no note for data1", map.contains(data1));
+ assertNull("no note for data1", map.get(data1));
+ }
+
+ public void testReadFanout2_2_36() throws Exception {
+ RevBlob a = tr.blob("a");
+ RevBlob b = tr.blob("b");
+ RevBlob data1 = tr.blob("data1");
+ RevBlob data2 = tr.blob("data2");
+
+ RevCommit r = tr.commit() //
+ .add(fanout(4, a.name()), data1) //
+ .add(fanout(4, b.name()), data2) //
+ .create();
+ tr.parseBody(r);
+
+ NoteMap map = NoteMap.read(reader, r);
+ assertNotNull("have map", map);
+
+ assertTrue("has note for a", map.contains(a));
+ assertTrue("has note for b", map.contains(b));
+ assertEquals(data1, map.get(a));
+ assertEquals(data2, map.get(b));
+
+ assertFalse("no note for data1", map.contains(data1));
+ assertNull("no note for data1", map.get(data1));
+ }
+
+ public void testReadFullyFannedOut() throws Exception {
+ RevBlob a = tr.blob("a");
+ RevBlob b = tr.blob("b");
+ RevBlob data1 = tr.blob("data1");
+ RevBlob data2 = tr.blob("data2");
+
+ RevCommit r = tr.commit() //
+ .add(fanout(38, a.name()), data1) //
+ .add(fanout(38, b.name()), data2) //
+ .create();
+ tr.parseBody(r);
+
+ NoteMap map = NoteMap.read(reader, r);
+ assertNotNull("have map", map);
+
+ assertTrue("has note for a", map.contains(a));
+ assertTrue("has note for b", map.contains(b));
+ assertEquals(data1, map.get(a));
+ assertEquals(data2, map.get(b));
+
+ assertFalse("no note for data1", map.contains(data1));
+ assertNull("no note for data1", map.get(data1));
+ }
+
+ public void testGetCachedBytes() throws Exception {
+ final String exp = "this is test data";
+ RevBlob a = tr.blob("a");
+ RevBlob data = tr.blob(exp);
+
+ RevCommit r = tr.commit() //
+ .add(a.name(), data) //
+ .create();
+ tr.parseBody(r);
+
+ NoteMap map = NoteMap.read(reader, r);
+ byte[] act = map.getCachedBytes(a, exp.length() * 4);
+ assertNotNull("has data for a", act);
+ assertEquals(exp, RawParseUtils.decode(act));
+ }
+
+ private static String fanout(int prefix, String name) {
+ StringBuilder r = new StringBuilder();
+ int i = 0;
+ for (; i < prefix && i < name.length(); i += 2) {
+ if (i != 0)
+ r.append('/');
+ r.append(name.charAt(i + 0));
+ r.append(name.charAt(i + 1));
+ }
+ if (i < name.length()) {
+ if (i != 0)
+ r.append('/');
+ r.append(name.substring(i));
+ }
+ return r.toString();
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/PackIndexV2Test.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/PackIndexV2Test.java
index 2d3ec7b..0ed336d 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/PackIndexV2Test.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/PackIndexV2Test.java
@@ -74,21 +74,21 @@ public File getFileForPackdf2982f28() {
public void testCRC32() throws MissingObjectException,
UnsupportedOperationException {
assertTrue(smallIdx.hasCRC32Support());
- assertEquals(0x00000000C2B64258l, smallIdx.findCRC32(ObjectId
+ assertEquals(0x00000000C2B64258L, smallIdx.findCRC32(ObjectId
.fromString("4b825dc642cb6eb9a060e54bf8d69288fbee4904")));
- assertEquals(0x0000000072AD57C2l, smallIdx.findCRC32(ObjectId
+ assertEquals(0x0000000072AD57C2L, smallIdx.findCRC32(ObjectId
.fromString("540a36d136cf413e4b064c2b0e0a4db60f77feab")));
- assertEquals(0x00000000FF10A479l, smallIdx.findCRC32(ObjectId
+ assertEquals(0x00000000FF10A479L, smallIdx.findCRC32(ObjectId
.fromString("5b6e7c66c276e7610d4a73c70ec1a1f7c1003259")));
- assertEquals(0x0000000034B27DDCl, smallIdx.findCRC32(ObjectId
+ assertEquals(0x0000000034B27DDCL, smallIdx.findCRC32(ObjectId
.fromString("6ff87c4664981e4397625791c8ea3bbb5f2279a3")));
- assertEquals(0x000000004743F1E4l, smallIdx.findCRC32(ObjectId
+ assertEquals(0x000000004743F1E4L, smallIdx.findCRC32(ObjectId
.fromString("82c6b885ff600be425b4ea96dee75dca255b69e7")));
- assertEquals(0x00000000640B358Bl, smallIdx.findCRC32(ObjectId
+ assertEquals(0x00000000640B358BL, smallIdx.findCRC32(ObjectId
.fromString("902d5476fa249b7abc9d84c611577a81381f0327")));
- assertEquals(0x000000002A17CB5El, smallIdx.findCRC32(ObjectId
+ assertEquals(0x000000002A17CB5EL, smallIdx.findCRC32(ObjectId
.fromString("aabf2ffaec9b497f0950352b3e582d73035c2035")));
- assertEquals(0x000000000B3B5BA6l, smallIdx.findCRC32(ObjectId
+ assertEquals(0x000000000B3B5BA6L, smallIdx.findCRC32(ObjectId
.fromString("c59759f143fb1fe21c197981df75a7ee00290799")));
}
}
diff --git a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
index a3afa67..36fbae9 100644
--- a/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ui/META-INF/MANIFEST.MF
@@ -7,7 +7,8 @@
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 0000000..0e6f78a
--- /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 f0de7ce..0000000
--- 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/META-INF/MANIFEST.MF b/org.eclipse.jgit/META-INF/MANIFEST.MF
index 9e7362f..ba09e58 100644
--- a/org.eclipse.jgit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit/META-INF/MANIFEST.MF
@@ -17,6 +17,7 @@
org.eclipse.jgit.lib;version="0.10.0",
org.eclipse.jgit.merge;version="0.10.0",
org.eclipse.jgit.nls;version="0.10.0",
+ org.eclipse.jgit.notes;version="0.10.0",
org.eclipse.jgit.patch;version="0.10.0",
org.eclipse.jgit.revplot;version="0.10.0",
org.eclipse.jgit.revwalk;version="0.10.0",
diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties
index 8af6e31..ab4ec61 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 @@
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 6a75a9e..2eb316e 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 static JGitText get() {
/***/ 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/dircache/DirCacheTree.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheTree.java
index e04b797..4d97e7c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheTree.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheTree.java
@@ -44,9 +44,9 @@
package org.eclipse.jgit.dircache;
-import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH;
+import static org.eclipse.jgit.lib.FileMode.TREE;
+import static org.eclipse.jgit.lib.TreeFormatter.entrySize;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
@@ -55,9 +55,9 @@
import org.eclipse.jgit.errors.UnmergedPathException;
import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.TreeFormatter;
import org.eclipse.jgit.util.MutableInteger;
import org.eclipse.jgit.util.RawParseUtils;
@@ -315,8 +315,8 @@ ObjectId writeTree(final DirCacheEntry[] cache, int cIdx,
throws UnmergedPathException, IOException {
if (id == null) {
final int endIdx = cIdx + entrySpan;
- final int size = computeSize(cache, cIdx, pathOffset, ow);
- final ByteArrayOutputStream out = new ByteArrayOutputStream(size);
+ final TreeFormatter fmt = new TreeFormatter(computeSize(cache,
+ cIdx, pathOffset, ow));
int childIdx = 0;
int entryIdx = cIdx;
@@ -326,27 +326,19 @@ ObjectId writeTree(final DirCacheEntry[] cache, int cIdx,
if (childIdx < childCnt) {
final DirCacheTree st = children[childIdx];
if (st.contains(ep, pathOffset, ep.length)) {
- FileMode.TREE.copyTo(out);
- out.write(' ');
- out.write(st.encodedName);
- out.write(0);
- st.id.copyRawTo(out);
-
+ fmt.append(st.encodedName, TREE, st.id);
entryIdx += st.entrySpan;
childIdx++;
continue;
}
}
- e.getFileMode().copyTo(out);
- out.write(' ');
- out.write(ep, pathOffset, ep.length - pathOffset);
- out.write(0);
- out.write(e.idBuffer(), e.idOffset(), OBJECT_ID_LENGTH);
+ fmt.append(ep, pathOffset, ep.length - pathOffset, e
+ .getFileMode(), e.idBuffer(), e.idOffset());
entryIdx++;
}
- id = ow.insert(Constants.OBJ_TREE, out.toByteArray());
+ id = fmt.insert(ow);
}
return id;
}
@@ -371,9 +363,7 @@ private int computeSize(final DirCacheEntry[] cache, int cIdx,
final int stOffset = pathOffset + st.nameLength() + 1;
st.writeTree(cache, entryIdx, stOffset, ow);
- size += FileMode.TREE.copyToLength();
- size += st.nameLength();
- size += OBJECT_ID_LENGTH + 2;
+ size += entrySize(TREE, st.nameLength());
entryIdx += st.entrySpan;
childIdx++;
@@ -381,10 +371,7 @@ private int computeSize(final DirCacheEntry[] cache, int cIdx,
}
}
- final FileMode mode = e.getFileMode();
- size += mode.copyToLength();
- size += ep.length - pathOffset;
- size += OBJECT_ID_LENGTH + 2;
+ size += entrySize(e.getFileMode(), ep.length - pathOffset);
entryIdx++;
}
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 0000000..eb09588
--- /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/AnyObjectId.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AnyObjectId.java
index 7b30cec..61cc15d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AnyObjectId.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AnyObjectId.java
@@ -97,15 +97,61 @@ public static boolean equals(final AnyObjectId firstObjectId,
int w5;
/**
- * For ObjectIdMap
+ * Get the first 8 bits of the ObjectId.
*
- * @return a discriminator usable for a fan-out style map
+ * This is a faster version of {@code getByte(0)}.
+ *
+ * @return a discriminator usable for a fan-out style map. Returned values
+ * are unsigned and thus are in the range [0,255] rather than the
+ * signed byte range of [-128, 127].
*/
public final int getFirstByte() {
return w1 >>> 24;
}
/**
+ * Get any byte from the ObjectId.
+ *
+ * Callers hard-coding {@code getByte(0)} should instead use the much faster
+ * special case variant {@link #getFirstByte()}.
+ *
+ * @param index
+ * index of the byte to obtain from the raw form of the ObjectId.
+ * Must be in range [0, {@link Constants#OBJECT_ID_LENGTH}).
+ * @return the value of the requested byte at {@code index}. Returned values
+ * are unsigned and thus are in the range [0,255] rather than the
+ * signed byte range of [-128, 127].
+ * @throws ArrayIndexOutOfBoundsException
+ * {@code index} is less than 0, equal to
+ * {@link Constants#OBJECT_ID_LENGTH}, or greater than
+ * {@link Constants#OBJECT_ID_LENGTH}.
+ */
+ public final int getByte(int index) {
+ int w;
+ switch (index >> 2) {
+ case 0:
+ w = w1;
+ break;
+ case 1:
+ w = w2;
+ break;
+ case 2:
+ w = w3;
+ break;
+ case 3:
+ w = w4;
+ break;
+ case 4:
+ w = w5;
+ break;
+ default:
+ throw new ArrayIndexOutOfBoundsException(index);
+ }
+
+ return (w >>> (8 * (3 - (index & 3)))) & 0xff;
+ }
+
+ /**
* Compare this ObjectId to another and obtain a sort ordering.
*
* @param other
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/FileMode.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/FileMode.java
index 43e4dd9..f295f5b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/FileMode.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/FileMode.java
@@ -223,6 +223,23 @@ public void copyTo(final OutputStream os) throws IOException {
}
/**
+ * Copy this mode as a sequence of octal US-ASCII bytes.
+ *
+ * The mode is copied as a sequence of octal digits using the US-ASCII
+ * character encoding. The sequence does not use a leading '0' prefix to
+ * indicate octal notation. This method is suitable for generation of a mode
+ * string within a GIT tree object.
+ *
+ * @param buf
+ * buffer to copy the mode to.
+ * @param ptr
+ * position within {@code buf} for first digit.
+ */
+ public void copyTo(byte[] buf, int ptr) {
+ System.arraycopy(octalBytes, 0, buf, ptr, octalBytes.length);
+ }
+
+ /**
* @return the number of bytes written by {@link #copyTo(OutputStream)}.
*/
public int copyToLength() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/MutableObjectId.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/MutableObjectId.java
index 26e83d4..7d7dfc2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/MutableObjectId.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/MutableObjectId.java
@@ -74,6 +74,60 @@ public MutableObjectId() {
fromObjectId(src);
}
+ /**
+ * Set any byte in the id.
+ *
+ * @param index
+ * index of the byte to set in the raw form of the ObjectId. Must
+ * be in range [0, {@link Constants#OBJECT_ID_LENGTH}).
+ * @param value
+ * the value of the specified byte at {@code index}. Values are
+ * unsigned and thus are in the range [0,255] rather than the
+ * signed byte range of [-128, 127].
+ * @throws ArrayIndexOutOfBoundsException
+ * {@code index} is less than 0, equal to
+ * {@link Constants#OBJECT_ID_LENGTH}, or greater than
+ * {@link Constants#OBJECT_ID_LENGTH}.
+ */
+ public void setByte(int index, int value) {
+ switch (index >> 2) {
+ case 0:
+ w1 = set(w1, index & 3, value);
+ break;
+ case 1:
+ w2 = set(w2, index & 3, value);
+ break;
+ case 2:
+ w3 = set(w3, index & 3, value);
+ break;
+ case 3:
+ w4 = set(w4, index & 3, value);
+ break;
+ case 4:
+ w5 = set(w5, index & 3, value);
+ break;
+ default:
+ throw new ArrayIndexOutOfBoundsException(index);
+ }
+ }
+
+ private static int set(int w, int index, int value) {
+ value &= 0xff;
+
+ switch (index) {
+ case 0:
+ return (w & 0x00ffffff) | (value << 24);
+ case 1:
+ return (w & 0xff00ffff) | (value << 16);
+ case 2:
+ return (w & 0xffff00ff) | (value << 8);
+ case 3:
+ return (w & 0xffffff00) | value;
+ default:
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ }
+
/** Make this id match {@link ObjectId#zeroId()}. */
public void clear() {
w1 = 0;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Tree.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Tree.java
index 2eb578b..06ef429 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Tree.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Tree.java
@@ -45,7 +45,6 @@
package org.eclipse.jgit.lib;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.text.MessageFormat;
@@ -614,20 +613,16 @@ else if (FileMode.GITLINK.equals(mode))
* the tree cannot be loaded, or its not in a writable state.
*/
public byte[] format() throws IOException {
- ByteArrayOutputStream o = new ByteArrayOutputStream();
+ TreeFormatter fmt = new TreeFormatter();
for (TreeEntry e : members()) {
ObjectId id = e.getId();
if (id == null)
throw new ObjectWritingException(MessageFormat.format(JGitText
.get().objectAtPathDoesNotHaveId, e.getFullName()));
- e.getMode().copyTo(o);
- o.write(' ');
- o.write(e.getNameUTF8());
- o.write(0);
- id.copyRawTo(o);
+ fmt.append(e.getNameUTF8(), e.getMode(), id);
}
- return o.toByteArray();
+ return fmt.toByteArray();
}
public String toString() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/TreeFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/TreeFormatter.java
new file mode 100644
index 0000000..e14e81f
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/TreeFormatter.java
@@ -0,0 +1,333 @@
+/*
+ * 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.lib;
+
+import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH;
+import static org.eclipse.jgit.lib.Constants.OBJ_TREE;
+import static org.eclipse.jgit.lib.Constants.encode;
+import static org.eclipse.jgit.lib.FileMode.GITLINK;
+import static org.eclipse.jgit.lib.FileMode.REGULAR_FILE;
+import static org.eclipse.jgit.lib.FileMode.TREE;
+
+import java.io.IOException;
+
+import org.eclipse.jgit.revwalk.RevBlob;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevTree;
+import org.eclipse.jgit.util.TemporaryBuffer;
+
+/**
+ * Mutable formatter to construct a single tree object.
+ *
+ * This formatter does not process subtrees. Callers must handle creating each
+ * subtree on their own.
+ *
+ * To maintain good performance for bulk operations, this formatter does not
+ * validate its input. Callers are responsible for ensuring the resulting tree
+ * object is correctly well formed by writing entries in the correct order.
+ */
+public class TreeFormatter {
+ /**
+ * Compute the size of a tree entry record.
+ *
+ * This method can be used to estimate the correct size of a tree prior to
+ * allocating a formatter. Getting the size correct at allocation time
+ * ensures the internal buffer is sized correctly, reducing copying.
+ *
+ * @param mode
+ * the mode the entry will have.
+ * @param nameLen
+ * the length of the name, in bytes.
+ * @return the length of the record.
+ */
+ public static int entrySize(FileMode mode, int nameLen) {
+ return mode.copyToLength() + nameLen + OBJECT_ID_LENGTH + 2;
+ }
+
+ private byte[] buf;
+
+ private int ptr;
+
+ private TemporaryBuffer.Heap overflowBuffer;
+
+ /** Create an empty formatter with a default buffer size. */
+ public TreeFormatter() {
+ this(8192);
+ }
+
+ /**
+ * Create an empty formatter with the specified buffer size.
+ *
+ * @param size
+ * estimated size of the tree, in bytes. Callers can use
+ * {@link #entrySize(FileMode, int)} to estimate the size of each
+ * entry in advance of allocating the formatter.
+ */
+ public TreeFormatter(int size) {
+ buf = new byte[size];
+ }
+
+ /**
+ * Add a link to a submodule commit, mode is {@link #GITLINK}.
+ *
+ * @param name
+ * name of the entry.
+ * @param commit
+ * the ObjectId to store in this entry.
+ */
+ public void append(String name, RevCommit commit) {
+ append(name, GITLINK, commit);
+ }
+
+ /**
+ * Add a subtree, mode is {@link #TREE}.
+ *
+ * @param name
+ * name of the entry.
+ * @param tree
+ * the ObjectId to store in this entry.
+ */
+ public void append(String name, RevTree tree) {
+ append(name, TREE, tree);
+ }
+
+ /**
+ * Add a regular file, mode is {@link #REGULAR_FILE}.
+ *
+ * @param name
+ * name of the entry.
+ * @param blob
+ * the ObjectId to store in this entry.
+ */
+ public void append(String name, RevBlob blob) {
+ append(name, REGULAR_FILE, blob);
+ }
+
+ /**
+ * Append any entry to the tree.
+ *
+ * @param name
+ * name of the entry.
+ * @param mode
+ * mode describing the treatment of {@code id}.
+ * @param id
+ * the ObjectId to store in this entry.
+ */
+ public void append(String name, FileMode mode, AnyObjectId id) {
+ append(encode(name), mode, id);
+ }
+
+ /**
+ * Append any entry to the tree.
+ *
+ * @param name
+ * name of the entry. The name should be UTF-8 encoded, but file
+ * name encoding is not a well defined concept in Git.
+ * @param mode
+ * mode describing the treatment of {@code id}.
+ * @param id
+ * the ObjectId to store in this entry.
+ */
+ public void append(byte[] name, FileMode mode, AnyObjectId id) {
+ append(name, 0, name.length, mode, id);
+ }
+
+ /**
+ * Append any entry to the tree.
+ *
+ * @param nameBuf
+ * buffer holding the name of the entry. The name should be UTF-8
+ * encoded, but file name encoding is not a well defined concept
+ * in Git.
+ * @param namePos
+ * first position within {@code nameBuf} of the name data.
+ * @param nameLen
+ * number of bytes from {@code nameBuf} to use as the name.
+ * @param mode
+ * mode describing the treatment of {@code id}.
+ * @param id
+ * the ObjectId to store in this entry.
+ */
+ public void append(byte[] nameBuf, int namePos, int nameLen, FileMode mode,
+ AnyObjectId id) {
+ if (fmtBuf(nameBuf, namePos, nameLen, mode)) {
+ id.copyRawTo(buf, ptr);
+ ptr += OBJECT_ID_LENGTH;
+
+ } else {
+ try {
+ fmtOverflowBuffer(nameBuf, namePos, nameLen, mode);
+ id.copyRawTo(overflowBuffer);
+ } catch (IOException badBuffer) {
+ // This should never occur.
+ throw new RuntimeException(badBuffer);
+ }
+ }
+ }
+
+ /**
+ * Append any entry to the tree.
+ *
+ * @param nameBuf
+ * buffer holding the name of the entry. The name should be UTF-8
+ * encoded, but file name encoding is not a well defined concept
+ * in Git.
+ * @param namePos
+ * first position within {@code nameBuf} of the name data.
+ * @param nameLen
+ * number of bytes from {@code nameBuf} to use as the name.
+ * @param mode
+ * mode describing the treatment of {@code id}.
+ * @param idBuf
+ * buffer holding the raw ObjectId of the entry.
+ * @param idPos
+ * first position within {@code idBuf} to copy the id from.
+ */
+ public void append(byte[] nameBuf, int namePos, int nameLen, FileMode mode,
+ byte[] idBuf, int idPos) {
+ if (fmtBuf(nameBuf, namePos, nameLen, mode)) {
+ System.arraycopy(idBuf, idPos, buf, ptr, OBJECT_ID_LENGTH);
+ ptr += OBJECT_ID_LENGTH;
+
+ } else {
+ try {
+ fmtOverflowBuffer(nameBuf, namePos, nameLen, mode);
+ overflowBuffer.write(idBuf, idPos, OBJECT_ID_LENGTH);
+ } catch (IOException badBuffer) {
+ // This should never occur.
+ throw new RuntimeException(badBuffer);
+ }
+ }
+ }
+
+ private boolean fmtBuf(byte[] nameBuf, int namePos, int nameLen,
+ FileMode mode) {
+ if (buf == null || buf.length < ptr + entrySize(mode, nameLen))
+ return false;
+
+ mode.copyTo(buf, ptr);
+ ptr += mode.copyToLength();
+ buf[ptr++] = ' ';
+
+ System.arraycopy(nameBuf, namePos, buf, ptr, nameLen);
+ ptr += nameLen;
+ buf[ptr++] = 0;
+ return true;
+ }
+
+ private void fmtOverflowBuffer(byte[] nameBuf, int namePos, int nameLen,
+ FileMode mode) throws IOException {
+ if (buf != null) {
+ overflowBuffer = new TemporaryBuffer.Heap(Integer.MAX_VALUE);
+ overflowBuffer.write(buf, 0, ptr);
+ buf = null;
+ }
+
+ mode.copyTo(overflowBuffer);
+ overflowBuffer.write((byte) ' ');
+ overflowBuffer.write(nameBuf, namePos, nameLen);
+ overflowBuffer.write((byte) 0);
+ }
+
+ /**
+ * Compute the current tree's ObjectId.
+ *
+ * @return computed ObjectId of the tree
+ */
+ public ObjectId getTreeId() {
+ final ObjectInserter.Formatter fmt = new ObjectInserter.Formatter();
+ if (buf != null)
+ return fmt.idFor(OBJ_TREE, buf, 0, ptr);
+
+ try {
+ final long len = overflowBuffer.length();
+ return fmt.idFor(OBJ_TREE, len, overflowBuffer.openInputStream());
+ } catch (IOException err) {
+ // This should never happen, its read failure on a byte array.
+ throw new RuntimeException(err);
+ }
+ }
+
+ /**
+ * Insert this tree and obtain its ObjectId.
+ *
+ * @param ins
+ * the inserter to store the tree.
+ * @return computed ObjectId of the tree
+ * @throws IOException
+ * the tree could not be stored.
+ */
+ public ObjectId insert(ObjectInserter ins) throws IOException {
+ if (buf != null)
+ return ins.insert(OBJ_TREE, buf, 0, ptr);
+
+ final long len = overflowBuffer.length();
+ return ins.insert(OBJ_TREE, len, overflowBuffer.openInputStream());
+ }
+
+ /**
+ * Copy this formatter's buffer into a byte array.
+ *
+ * This method is not efficient, as it needs to create a copy of the
+ * internal buffer in order to supply an array of the correct size to the
+ * caller. If the buffer is just to pass to an ObjectInserter, consider
+ * using {@link #insert(ObjectInserter)} instead.
+ *
+ * @return a copy of this formatter's buffer.
+ */
+ public byte[] toByteArray() {
+ if (buf != null) {
+ byte[] r = new byte[ptr];
+ System.arraycopy(buf, 0, r, 0, ptr);
+ return r;
+ }
+
+ try {
+ return overflowBuffer.toByteArray();
+ } catch (IOException err) {
+ // This should never happen, its read failure on a byte array.
+ throw new RuntimeException(err);
+ }
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/notes/FanoutBucket.java b/org.eclipse.jgit/src/org/eclipse/jgit/notes/FanoutBucket.java
new file mode 100644
index 0000000..85337c8
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/notes/FanoutBucket.java
@@ -0,0 +1,126 @@
+/*
+ * 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.notes;
+
+import java.io.IOException;
+
+import org.eclipse.jgit.lib.AbbreviatedObjectId;
+import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectReader;
+
+/**
+ * A note tree holding only note subtrees, each named using a 2 digit hex name.
+ *
+ * The fanout buckets/trees contain on average 256 subtrees, naming the subtrees
+ * by a slice of the ObjectId contained within them, from "00" through "ff".
+ *
+ * Each fanout bucket has a {@link #prefixLen} that defines how many digits it
+ * skips in an ObjectId before it gets to the digits matching {@link #table}.
+ *
+ * The root tree has {@code prefixLen == 0}, and thus does not skip any digits.
+ * For ObjectId "c0ffee...", the note (if it exists) will be stored within the
+ * bucket {@code table[0xc0]}.
+ *
+ * The first level tree has {@code prefixLen == 2}, and thus skips the first two
+ * digits. For the same example "c0ffee..." object, its note would be found
+ * within the {@code table[0xff]} bucket (as first 2 digits "c0" are skipped).
+ *
+ * Each subtree is loaded on-demand, reducing startup latency for reads that
+ * only need to examine a few objects. However, due to the rather uniform
+ * distribution of the SHA-1 hash that is used for ObjectIds, accessing 256
+ * objects is very likely to load all of the subtrees into memory.
+ *
+ * A FanoutBucket must be parsed from a tree object by {@link NoteParser}.
+ */
+class FanoutBucket extends InMemoryNoteBucket {
+ /**
+ * Fan-out table similar to the PackIndex structure.
+ *
+ * Notes for an object are stored within the sub-bucket that is held here as
+ * {@code table[ objectId.getByte( prefixLen / 2 ) ]}. If the slot is null
+ * there are no notes with that prefix.
+ */
+ private final NoteBucket[] table;
+
+ FanoutBucket(int prefixLen) {
+ super(prefixLen);
+ table = new NoteBucket[256];
+ }
+
+ void parseOneEntry(int cell, ObjectId id) {
+ table[cell] = new LazyNoteBucket(id);
+ }
+
+ @Override
+ ObjectId get(AnyObjectId objId, ObjectReader or) throws IOException {
+ NoteBucket b = table[cell(objId)];
+ return b != null ? b.get(objId, or) : null;
+ }
+
+ private int cell(AnyObjectId id) {
+ return id.getByte(prefixLen >> 1);
+ }
+
+ private class LazyNoteBucket extends NoteBucket {
+ private final ObjectId treeId;
+
+ LazyNoteBucket(ObjectId treeId) {
+ this.treeId = treeId;
+ }
+
+ @Override
+ ObjectId get(AnyObjectId objId, ObjectReader or) throws IOException {
+ return load(objId, or).get(objId, or);
+ }
+
+ private NoteBucket load(AnyObjectId objId, ObjectReader or)
+ throws IOException {
+ AbbreviatedObjectId p = objId.abbreviate(prefixLen + 2);
+ NoteBucket self = NoteParser.parse(p, treeId, or);
+ table[cell(objId)] = self;
+ return self;
+ }
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/notes/InMemoryNoteBucket.java b/org.eclipse.jgit/src/org/eclipse/jgit/notes/InMemoryNoteBucket.java
new file mode 100644
index 0000000..7d0df73
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/notes/InMemoryNoteBucket.java
@@ -0,0 +1,60 @@
+/*
+ * 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.notes;
+
+/** A note bucket that has been loaded into the process. */
+abstract class InMemoryNoteBucket extends NoteBucket {
+ /**
+ * Number of leading digits that leads to this bucket in the note path.
+ *
+ * This is counted in terms of hex digits, not raw bytes. Each bucket level
+ * is typically 2 higher than its parent, placing about 256 items in each
+ * level of the tree.
+ */
+ final int prefixLen;
+
+ InMemoryNoteBucket(int prefixLen) {
+ this.prefixLen = prefixLen;
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/notes/LeafBucket.java b/org.eclipse.jgit/src/org/eclipse/jgit/notes/LeafBucket.java
new file mode 100644
index 0000000..66d773a
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/notes/LeafBucket.java
@@ -0,0 +1,111 @@
+/*
+ * 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.notes;
+
+import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectReader;
+
+/**
+ * A note tree holding only notes, with no subtrees.
+ *
+ * The leaf bucket contains on average less than 256 notes, all of whom share
+ * the same leading prefix. If a notes branch has less than 256 notes, the top
+ * level tree of the branch should be a LeafBucket. Once a notes branch has more
+ * than 256 notes, the root should be a {@link FanoutBucket} and the LeafBucket
+ * will appear only as a cell of a FanoutBucket.
+ *
+ * Entries within the LeafBucket are stored sorted by ObjectId, and lookup is
+ * performed using binary search. As the entry list should contain fewer than
+ * 256 elements, the average number of compares to find an element should be
+ * less than 8 due to the O(log N) lookup behavior.
+ *
+ * A LeafBucket must be parsed from a tree object by {@link NoteParser}.
+ */
+class LeafBucket extends InMemoryNoteBucket {
+ /** All note blobs in this bucket, sorted sequentially. */
+ private Note[] notes;
+
+ /** Number of items in {@link #notes}. */
+ private int cnt;
+
+ LeafBucket(int prefixLen) {
+ super(prefixLen);
+ notes = new Note[4];
+ }
+
+ private int search(AnyObjectId objId) {
+ int low = 0;
+ int high = cnt;
+ while (low < high) {
+ int mid = (low + high) >>> 1;
+ int cmp = objId.compareTo(notes[mid]);
+ if (cmp < 0)
+ high = mid;
+ else if (cmp == 0)
+ return mid;
+ else
+ low = mid + 1;
+ }
+ return -(low + 1);
+ }
+
+ ObjectId get(AnyObjectId objId, ObjectReader or) {
+ int idx = search(objId);
+ return 0 <= idx ? notes[idx].getData() : null;
+ }
+
+ void parseOneEntry(AnyObjectId noteOn, AnyObjectId noteData) {
+ growIfFull();
+ notes[cnt++] = new Note(noteOn, noteData.copy());
+ }
+
+ private void growIfFull() {
+ if (notes.length == cnt) {
+ Note[] n = new Note[notes.length * 2];
+ System.arraycopy(notes, 0, n, 0, cnt);
+ notes = n;
+ }
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/notes/Note.java b/org.eclipse.jgit/src/org/eclipse/jgit/notes/Note.java
new file mode 100644
index 0000000..d365f9b
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/notes/Note.java
@@ -0,0 +1,78 @@
+/*
+ * 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.notes;
+
+import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.ObjectId;
+
+/** In-memory representation of a single note attached to one object. */
+class Note extends ObjectId {
+ private ObjectId data;
+
+ /**
+ * A Git note about the object referenced by {@code noteOn}.
+ *
+ * @param noteOn
+ * the object that has a note attached to it.
+ * @param noteData
+ * the actual note data contained in this note
+ */
+ Note(AnyObjectId noteOn, ObjectId noteData) {
+ super(noteOn);
+ data = noteData;
+ }
+
+ ObjectId getData() {
+ return data;
+ }
+
+ void setData(ObjectId newData) {
+ data = newData;
+ }
+
+ @Override
+ public String toString() {
+ return "Note[" + name() + " -> " + data.name() + "]";
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteBucket.java b/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteBucket.java
new file mode 100644
index 0000000..286f140
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteBucket.java
@@ -0,0 +1,61 @@
+/*
+ * 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.notes;
+
+import java.io.IOException;
+
+import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectReader;
+
+/**
+ * A tree that stores note objects.
+ *
+ * @see FanoutBucket
+ * @see LeafBucket
+ */
+abstract class NoteBucket {
+ abstract ObjectId get(AnyObjectId objId, ObjectReader reader)
+ throws IOException;
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMap.java b/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMap.java
new file mode 100644
index 0000000..d2f0727
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMap.java
@@ -0,0 +1,221 @@
+/*
+ * 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.notes;
+
+import java.io.IOException;
+
+import org.eclipse.jgit.errors.CorruptObjectException;
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.LargeObjectException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.lib.AbbreviatedObjectId;
+import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevTree;
+
+/**
+ * Index of notes from a note branch.
+ *
+ * This class is not thread-safe, and relies on an {@link ObjectReader} that it
+ * borrows/shares with the caller. The reader can be used during any call, and
+ * is not released by this class. The caller should arrange for releasing the
+ * shared {@code ObjectReader} at the proper times.
+ */
+public class NoteMap {
+ /**
+ * Load a collection of notes from a branch.
+ *
+ * @param reader
+ * reader to scan the note branch with. This reader may be
+ * retained by the NoteMap for the life of the map in order to
+ * support lazy loading of entries.
+ * @param commit
+ * the revision of the note branch to read.
+ * @return the note map read from the commit.
+ * @throws IOException
+ * the repository cannot be accessed through the reader.
+ * @throws CorruptObjectException
+ * a tree object is corrupt and cannot be read.
+ * @throws IncorrectObjectTypeException
+ * a tree object wasn't actually a tree.
+ * @throws MissingObjectException
+ * a reference tree object doesn't exist.
+ */
+ public static NoteMap read(ObjectReader reader, RevCommit commit)
+ throws MissingObjectException, IncorrectObjectTypeException,
+ CorruptObjectException, IOException {
+ return read(reader, commit.getTree());
+ }
+
+ /**
+ * Load a collection of notes from a tree.
+ *
+ * @param reader
+ * reader to scan the note branch with. This reader may be
+ * retained by the NoteMap for the life of the map in order to
+ * support lazy loading of entries.
+ * @param tree
+ * the note tree to read.
+ * @return the note map read from the tree.
+ * @throws IOException
+ * the repository cannot be accessed through the reader.
+ * @throws CorruptObjectException
+ * a tree object is corrupt and cannot be read.
+ * @throws IncorrectObjectTypeException
+ * a tree object wasn't actually a tree.
+ * @throws MissingObjectException
+ * a reference tree object doesn't exist.
+ */
+ public static NoteMap read(ObjectReader reader, RevTree tree)
+ throws MissingObjectException, IncorrectObjectTypeException,
+ CorruptObjectException, IOException {
+ return readTree(reader, tree);
+ }
+
+ /**
+ * Load a collection of notes from a tree.
+ *
+ * @param reader
+ * reader to scan the note branch with. This reader may be
+ * retained by the NoteMap for the life of the map in order to
+ * support lazy loading of entries.
+ * @param treeId
+ * the note tree to read.
+ * @return the note map read from the tree.
+ * @throws IOException
+ * the repository cannot be accessed through the reader.
+ * @throws CorruptObjectException
+ * a tree object is corrupt and cannot be read.
+ * @throws IncorrectObjectTypeException
+ * a tree object wasn't actually a tree.
+ * @throws MissingObjectException
+ * a reference tree object doesn't exist.
+ */
+ public static NoteMap readTree(ObjectReader reader, ObjectId treeId)
+ throws MissingObjectException, IncorrectObjectTypeException,
+ CorruptObjectException, IOException {
+ NoteMap map = new NoteMap(reader);
+ map.load(treeId);
+ return map;
+ }
+
+ /** Borrowed reader to access the repository. */
+ private final ObjectReader reader;
+
+ /** All of the notes that have been loaded. */
+ private InMemoryNoteBucket root;
+
+ private NoteMap(ObjectReader reader) {
+ this.reader = reader;
+ }
+
+ /**
+ * Lookup a note for a specific ObjectId.
+ *
+ * @param id
+ * the object to look for.
+ * @return the note's blob ObjectId, or null if no note exists.
+ * @throws IOException
+ * a portion of the note space is not accessible.
+ */
+ public ObjectId get(AnyObjectId id) throws IOException {
+ return root.get(id, reader);
+ }
+
+ /**
+ * Determine if a note exists for the specified ObjectId.
+ *
+ * @param id
+ * the object to look for.
+ * @return true if a note exists; false if there is no note.
+ * @throws IOException
+ * a portion of the note space is not accessible.
+ */
+ public boolean contains(AnyObjectId id) throws IOException {
+ return get(id) != null;
+ }
+
+ /**
+ * Open and return the content of an object's note.
+ *
+ * This method assumes the note is fairly small and can be accessed
+ * efficiently. Larger notes should be accessed by streaming:
+ *
+ * <pre>
+ * ObjectId dataId = thisMap.get(id);
+ * if (dataId != null)
+ * reader.open(dataId).openStream();
+ * </pre>
+ *
+ * @param id
+ * object to lookup the note of.
+ * @param sizeLimit
+ * maximum number of bytes to return. If the note data size is
+ * larger than this limit, LargeObjectException will be thrown.
+ * @return if a note is defined for {@code id}, the note content. If no note
+ * is defined, null.
+ * @throws LargeObjectException
+ * the note data is larger than {@code sizeLimit}.
+ * @throws MissingObjectException
+ * the note's blob does not exist in the repository.
+ * @throws IOException
+ * the note's blob cannot be read from the repository
+ */
+ public byte[] getCachedBytes(AnyObjectId id, int sizeLimit)
+ throws LargeObjectException, MissingObjectException, IOException {
+ ObjectId dataId = get(id);
+ if (dataId != null)
+ return reader.open(dataId).getCachedBytes(sizeLimit);
+ else
+ return null;
+ }
+
+ private void load(ObjectId rootTree) throws MissingObjectException,
+ IncorrectObjectTypeException, CorruptObjectException, IOException {
+ AbbreviatedObjectId none = AbbreviatedObjectId.fromString("");
+ root = NoteParser.parse(none, rootTree, reader);
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteParser.java
new file mode 100644
index 0000000..04e260a
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteParser.java
@@ -0,0 +1,184 @@
+/*
+ * 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.notes;
+
+import static org.eclipse.jgit.lib.Constants.OBJECT_ID_STRING_LENGTH;
+import static org.eclipse.jgit.lib.Constants.encodeASCII;
+import static org.eclipse.jgit.lib.FileMode.TREE;
+import static org.eclipse.jgit.util.RawParseUtils.parseHexInt4;
+
+import java.io.IOException;
+
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.lib.AbbreviatedObjectId;
+import org.eclipse.jgit.lib.MutableObjectId;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.treewalk.CanonicalTreeParser;
+
+/** Custom tree parser to select note bucket type and load it. */
+final class NoteParser extends CanonicalTreeParser {
+ /**
+ * Parse a tree object into a {@link NoteBucket} instance.
+ *
+ * The type of note tree is automatically detected by examining the items
+ * within the tree, and allocating the proper storage type based on the
+ * first note-like entry encountered. Since the method parses by guessing
+ * the type on the first element, malformed note trees can be read as the
+ * wrong type of tree.
+ *
+ * This method is not recursive, it parses the one tree given to it and
+ * returns the bucket. If there are subtrees for note storage, they are
+ * setup as lazy pointers that will be resolved at a later time.
+ *
+ * @param prefix
+ * common hex digits that all notes within this tree share. The
+ * root tree has {@code prefix.length() == 0}, the first-level
+ * subtrees should be {@code prefix.length()==2}, etc.
+ * @param treeId
+ * the tree to read from the repository.
+ * @param reader
+ * reader to access the tree object.
+ * @return bucket to holding the notes of the specified tree.
+ * @throws IOException
+ * {@code treeId} cannot be accessed.
+ */
+ static InMemoryNoteBucket parse(AbbreviatedObjectId prefix,
+ final ObjectId treeId, final ObjectReader reader)
+ throws IOException {
+ return new NoteParser(prefix, reader, treeId).parseTree();
+ }
+
+ private final AbbreviatedObjectId prefix;
+
+ private final int pathPadding;
+
+ private NoteParser(AbbreviatedObjectId p, ObjectReader r, ObjectId t)
+ throws IncorrectObjectTypeException, IOException {
+ super(encodeASCII(p.name()), r, t);
+ prefix = p;
+
+ // Our path buffer has a '/' that we don't want after the prefix.
+ // Drop it by shifting the path down one position.
+ pathPadding = 0 < prefix.length() ? 1 : 0;
+ if (0 < pathPadding)
+ System.arraycopy(path, 0, path, pathPadding, prefix.length());
+ }
+
+ private InMemoryNoteBucket parseTree() {
+ for (; !eof(); next(1)) {
+ if (pathLen == pathPadding + OBJECT_ID_STRING_LENGTH && isHex())
+ return parseLeafTree();
+
+ else if (getNameLength() == 2 && isHex() && isTree())
+ return parseFanoutTree();
+ }
+
+ // If we cannot determine the style used, assume its a leaf.
+ return new LeafBucket(prefix.length());
+ }
+
+ private LeafBucket parseLeafTree() {
+ final LeafBucket leaf = new LeafBucket(prefix.length());
+ final MutableObjectId idBuf = new MutableObjectId();
+
+ for (; !eof(); next(1)) {
+ if (parseObjectId(idBuf))
+ leaf.parseOneEntry(idBuf, getEntryObjectId());
+ }
+
+ return leaf;
+ }
+
+ private boolean parseObjectId(MutableObjectId id) {
+ if (pathLen == pathPadding + OBJECT_ID_STRING_LENGTH) {
+ try {
+ id.fromString(path, pathPadding);
+ return true;
+ } catch (ArrayIndexOutOfBoundsException notHex) {
+ return false;
+ }
+ }
+ return false;
+ }
+
+ private FanoutBucket parseFanoutTree() {
+ final FanoutBucket fanout = new FanoutBucket(prefix.length());
+
+ for (; !eof(); next(1)) {
+ final int cell = parseFanoutCell();
+ if (0 <= cell)
+ fanout.parseOneEntry(cell, getEntryObjectId());
+ }
+
+ return fanout;
+ }
+
+ private int parseFanoutCell() {
+ if (getNameLength() == 2 && isTree()) {
+ try {
+ return (parseHexInt4(path[pathOffset + 0]) << 4)
+ | parseHexInt4(path[pathOffset + 1]);
+ } catch (ArrayIndexOutOfBoundsException notHex) {
+ return -1;
+ }
+ } else {
+ return -1;
+ }
+ }
+
+ private boolean isTree() {
+ return TREE.equals(mode);
+ }
+
+ private boolean isHex() {
+ try {
+ for (int i = pathOffset; i < pathLen; i++)
+ parseHexInt4(path[i]);
+ return true;
+ } catch (ArrayIndexOutOfBoundsException fail) {
+ return false;
+ }
+ }
+}
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 0000000..55ce4db
--- /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 0000000..194268f
--- /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 0000000..8f259c6
--- /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 5a559ab..9266616 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 @@ static HttpAuthMethod scanResponse(HttpURLConnection conn) {
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 @@ else if (Digest.NAME.equals(type))
*
* @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/SshConfigSessionFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshConfigSessionFactory.java
index daa6f4c..99e7b83 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 synchronized Session getSession(String user, String pass,
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 d10010f..34aa3db 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 static void setInstance(final SshSessionFactory newFactory) {
* @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 static void setInstance(final SshSessionFactory newFactory) {
* 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 f642ac1..81d233f 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 @@ protected void initSession() throws TransportException {
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 500cf0c..69eea0c 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 @@ private static String findTrackingRefName(final String remoteName,
/** 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 @@ protected Transport(final Repository local, final URIish uri) {
this.local = local;
this.uri = uri;
this.checkFetchedObjects = tc.isFsckObjects();
+ this.credentialsProvider = CredentialsProvider.getDefault();
}
/**
@@ -822,6 +826,26 @@ public void setPackConfig(PackConfig pc) {
}
/**
+ * 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 39dedc6..9eb1d2d 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 @@ private HttpURLConnection connect(final String service)
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/UsernamePasswordCredentialsProvider.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UsernamePasswordCredentialsProvider.java
new file mode 100644
index 0000000..235e4b4
--- /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;
+ }
+ }
+}