Change-Id: Ieec4f51aedadf5734ae0e3f4e8713248a3c4fc52 Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>tags/v4.2.0.201601211800-r
@@ -0,0 +1,15 @@ | |||
[buildfile] | |||
includes = //tools/default.defs | |||
[java] | |||
src_roots = src, resources, tst | |||
[project] | |||
ignore = .git | |||
[cache] | |||
mode = dir | |||
[download] | |||
maven_repo = http://repo1.maven.org/maven2 | |||
in_build = true |
@@ -0,0 +1 @@ | |||
1b03b4313b91b634bd604fc3487a05f877e59dee |
@@ -1,2 +1,4 @@ | |||
/target | |||
/.project | |||
/buck-cache | |||
/buck-out |
@@ -0,0 +1,45 @@ | |||
java_library( | |||
name = 'jgit', | |||
exported_deps = ['//org.eclipse.jgit:jgit'], | |||
visibility = ['PUBLIC'], | |||
) | |||
genrule( | |||
name = 'jgit_src', | |||
cmd = 'ln -s $(location //org.eclipse.jgit:jgit_src) $OUT', | |||
out = 'jgit_src.zip', | |||
visibility = ['PUBLIC'], | |||
) | |||
java_library( | |||
name = 'jgit-servlet', | |||
exported_deps = [ | |||
':jgit', | |||
'//org.eclipse.jgit.http.server:jgit-servlet' | |||
], | |||
visibility = ['PUBLIC'], | |||
) | |||
java_library( | |||
name = 'jgit-archive', | |||
exported_deps = [ | |||
':jgit', | |||
'//org.eclipse.jgit.archive:jgit-archive' | |||
], | |||
visibility = ['PUBLIC'], | |||
) | |||
java_library( | |||
name = 'junit', | |||
exported_deps = [ | |||
':jgit', | |||
'//org.eclipse.jgit.junit:junit' | |||
], | |||
visibility = ['PUBLIC'], | |||
) | |||
genrule( | |||
name = 'jgit_bin', | |||
cmd = 'ln -s $(location //org.eclipse.jgit.pgm:jgit) $OUT', | |||
out = 'jgit_bin', | |||
) |
@@ -0,0 +1,125 @@ | |||
maven_jar( | |||
name = 'jsch', | |||
bin_sha1 = '658b682d5c817b27ae795637dfec047c63d29935', | |||
src_sha1 = '791359d94d6edcace686a56d0727ee093a2f7c33', | |||
group = 'com.jcraft', | |||
artifact = 'jsch', | |||
version = '0.1.53', | |||
) | |||
maven_jar( | |||
name = 'javaewah', | |||
bin_sha1 = 'eceaf316a8faf0e794296ebe158ae110c7d72a5a', | |||
src_sha1 = 'a50d78eb630e05439461f3130b94b3bcd1ea6f03', | |||
group = 'com.googlecode.javaewah', | |||
artifact = 'JavaEWAH', | |||
version = '0.7.9', | |||
) | |||
maven_jar( | |||
name = 'httpcomponents', | |||
bin_sha1 = '4c47155e3e6c9a41a28db36680b828ced53b8af4', | |||
src_sha1 = 'af4d76be0c46ee26b0d9d1d4a34d244a633cac84', | |||
group = 'org.apache.httpcomponents', | |||
artifact = 'httpclient', | |||
version = '4.3.6', | |||
) | |||
maven_jar( | |||
name = 'httpcore', | |||
bin_sha1 = 'f91b7a4aadc5cf486df6e4634748d7dd7a73f06d', | |||
src_sha1 = '1b0aa62a6a91e9fa00c16f0a4a2c874804ed3b1e', | |||
group = 'org.apache.httpcomponents', | |||
artifact = 'httpcore', | |||
version = '4.3.3', | |||
) | |||
maven_jar( | |||
name = 'commons-logging', | |||
bin_sha1 = 'f6f66e966c70a83ffbdb6f17a0919eaf7c8aca7f', | |||
src_sha1 = '28bb0405fddaf04f15058fbfbe01fe2780d7d3b6', | |||
group = 'commons-logging', | |||
artifact = 'commons-logging', | |||
version = '1.1.3', | |||
) | |||
maven_jar( | |||
name = 'slf4j-api', | |||
bin_sha1 = '0081d61b7f33ebeab314e07de0cc596f8e858d97', | |||
src_sha1 = '58d38f68d4a867d4552ae27960bb348d7eaa1297', | |||
group = 'org.slf4j', | |||
artifact = 'slf4j-api', | |||
version = '1.7.2', | |||
) | |||
maven_jar( | |||
name = 'slf4j-simple', | |||
bin_sha1 = '760055906d7353ba4f7ce1b8908bc6b2e91f39fa', | |||
src_sha1 = '09474919128b3a7fcf21a5f9c907f5251f234544', | |||
group = 'org.slf4j', | |||
artifact = 'slf4j-simple', | |||
version = '1.7.2', | |||
) | |||
maven_jar( | |||
name = 'servlet-api', | |||
bin_sha1 = '3cd63d075497751784b2fa84be59432f4905bf7c', | |||
src_sha1 = 'ab3976d4574c48d22dc1abf6a9e8bd0fdf928223', | |||
group = 'javax.servlet', | |||
artifact = 'javax.servlet-api', | |||
version = '3.1.0', | |||
) | |||
maven_jar( | |||
name = 'commons-compress', | |||
bin_sha1 = 'c7d9b580aff9e9f1998361f16578e63e5c064699', | |||
src_sha1 = '396b81bdfd0fb617178e1707ef64832215307c78', | |||
group = 'org.apache.commons', | |||
artifact = 'commons-compress', | |||
version = '1.6', | |||
) | |||
maven_jar( | |||
name = 'tukaani-xz', | |||
bin_sha1 = '66db21c8484120cb6a51b5b3ea47b6f383942bec', | |||
src_sha1 = '6396220725701d767c553902c41120d7bf38e9f5', | |||
group = 'org.tukaani', | |||
artifact = 'xz', | |||
version = '1.3', | |||
) | |||
maven_jar( | |||
name = 'args4j', | |||
bin_sha1 = '139441471327b9cc6d56436cb2a31e60eb6ed2ba', | |||
src_sha1 = '22631b78cc8f60a6918557e8cbdb33e90f63a77f', | |||
group = 'args4j', | |||
artifact = 'args4j', | |||
version = '2.0.15', | |||
) | |||
maven_jar( | |||
name = 'junit', | |||
bin_sha1 = '4e031bb61df09069aeb2bffb4019e7a5034a4ee0', | |||
src_sha1 = '28e0ad201304e4a4abf999ca0570b7cffc352c3c', | |||
group = 'junit', | |||
artifact = 'junit', | |||
version = '4.11', | |||
) | |||
maven_jar( | |||
name = 'hamcrest-library', | |||
bin_sha1 = '4785a3c21320980282f9f33d0d1264a69040538f', | |||
src_sha1 = '047a7ee46628ab7133129cd7cef1e92657bc275e', | |||
group = 'org.hamcrest', | |||
artifact = 'hamcrest-library', | |||
version = '1.3', | |||
) | |||
maven_jar( | |||
name = 'hamcrest-core', | |||
bin_sha1 = '42a25dc3219429f0e5d060061f71acb49bf010a0', | |||
src_sha1 = '1dc37250fbc78e23a65a67fbbaf71d2e9cbc3c0b', | |||
group = 'org.hamcrest', | |||
artifact = 'hamcrest-core', | |||
version = '1.3', | |||
) |
@@ -0,0 +1,56 @@ | |||
VERSION = '9.2.13.v20150730' | |||
GROUP = 'org.eclipse.jetty' | |||
maven_jar( | |||
name = 'servlet', | |||
bin_sha1 = '5ad6e38015a97ae9a60b6c2ad744ccfa9cf93a50', | |||
src_sha1 = '78fbec19321150552d91f9e079c2f2ca33222b01', | |||
group = GROUP, | |||
artifact = 'jetty-servlet', | |||
version = VERSION, | |||
) | |||
maven_jar( | |||
name = 'security', | |||
bin_sha1 = 'cc7c7f27ec4cc279253be1675d9e47e58b995943', | |||
src_sha1 = '75632ebdf8bd651faafb97106c92496db59e165d', | |||
group = GROUP, | |||
artifact = 'jetty-security', | |||
version = VERSION, | |||
) | |||
maven_jar( | |||
name = 'server', | |||
bin_sha1 = '5be7d1da0a7abffd142de3091d160717c120b6ab', | |||
src_sha1 = '203e123f83efe2a5b8a9c74854c7897fe3563302', | |||
group = GROUP, | |||
artifact = 'jetty-server', | |||
version = VERSION, | |||
) | |||
maven_jar( | |||
name = 'http', | |||
bin_sha1 = '23a745d9177ef67ef53cc46b9b70c5870082efc2', | |||
src_sha1 = '5f87f7ff2057cd4b0995bc4fffe17b2aff64c130', | |||
group = GROUP, | |||
artifact = 'jetty-http', | |||
version = VERSION, | |||
) | |||
maven_jar( | |||
name = 'io', | |||
bin_sha1 = '7a351e6a1b63dfd56b6632623f7ca2793ffb67ad', | |||
src_sha1 = 'bbd61a84b748fc295456e1c5c3070aaf40a68f62', | |||
group = GROUP, | |||
artifact = 'jetty-io', | |||
version = VERSION, | |||
) | |||
maven_jar( | |||
name = 'util', | |||
bin_sha1 = 'c101476360a7cdd0670462de04053507d5e70c97', | |||
src_sha1 = '15ceecce141971b4e0facb861b3d10120ad6ce03', | |||
group = GROUP, | |||
artifact = 'jetty-util', | |||
version = VERSION, | |||
) |
@@ -0,0 +1,13 @@ | |||
java_library( | |||
name = 'jgit-archive', | |||
srcs = glob( | |||
['src/**'], | |||
excludes = ['src/org/eclipse/jgit/archive/FormatActivator.java'], | |||
), | |||
resources = glob(['resources/**']), | |||
provided_deps = [ | |||
'//org.eclipse.jgit:jgit', | |||
'//lib:commons-compress', | |||
], | |||
visibility = ['PUBLIC'], | |||
) |
@@ -0,0 +1,12 @@ | |||
java_library( | |||
name = 'http-apache', | |||
srcs = glob(['src/**']), | |||
resources = glob(['resources/**']), | |||
deps = [ | |||
'//org.eclipse.jgit:jgit', | |||
'//lib:commons-logging', | |||
'//lib:httpcomponents', | |||
'//lib:httpcore', | |||
], | |||
visibility = ['PUBLIC'], | |||
) |
@@ -7,7 +7,8 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.7 | |||
Bundle-Localization: plugin | |||
Bundle-Vendor: %Provider-Name | |||
Bundle-ActivationPolicy: lazy | |||
Import-Package: org.apache.http;version="[4.1.0,5.0.0)", | |||
Import-Package: org.apache.commons.logging;version="[1.1.1,2.0.0)", | |||
org.apache.http;version="[4.1.0,5.0.0)", | |||
org.apache.http.client;version="[4.1.0,5.0.0)", | |||
org.apache.http.client.methods;version="[4.1.0,5.0.0)", | |||
org.apache.http.client.params;version="[4.1.0,5.0.0)", |
@@ -100,7 +100,7 @@ import org.eclipse.jgit.util.TemporaryBuffer.LocalFile; | |||
public class HttpClientConnection implements HttpConnection { | |||
HttpClient client; | |||
String urlStr; | |||
URL url; | |||
HttpUriRequest req; | |||
@@ -176,16 +176,19 @@ public class HttpClientConnection implements HttpConnection { | |||
/** | |||
* @param urlStr | |||
* @throws MalformedURLException | |||
*/ | |||
public HttpClientConnection(String urlStr) { | |||
public HttpClientConnection(String urlStr) throws MalformedURLException { | |||
this(urlStr, null); | |||
} | |||
/** | |||
* @param urlStr | |||
* @param proxy | |||
* @throws MalformedURLException | |||
*/ | |||
public HttpClientConnection(String urlStr, Proxy proxy) { | |||
public HttpClientConnection(String urlStr, Proxy proxy) | |||
throws MalformedURLException { | |||
this(urlStr, proxy, null); | |||
} | |||
@@ -193,10 +196,12 @@ public class HttpClientConnection implements HttpConnection { | |||
* @param urlStr | |||
* @param proxy | |||
* @param cl | |||
* @throws MalformedURLException | |||
*/ | |||
public HttpClientConnection(String urlStr, Proxy proxy, HttpClient cl) { | |||
public HttpClientConnection(String urlStr, Proxy proxy, HttpClient cl) | |||
throws MalformedURLException { | |||
this.client = cl; | |||
this.urlStr = urlStr; | |||
this.url = new URL(urlStr); | |||
this.proxy = proxy; | |||
} | |||
@@ -206,11 +211,7 @@ public class HttpClientConnection implements HttpConnection { | |||
} | |||
public URL getURL() { | |||
try { | |||
return new URL(urlStr); | |||
} catch (MalformedURLException e) { | |||
return null; | |||
} | |||
return url; | |||
} | |||
public String getResponseMessage() throws IOException { | |||
@@ -250,11 +251,11 @@ public class HttpClientConnection implements HttpConnection { | |||
public void setRequestMethod(String method) throws ProtocolException { | |||
this.method = method; | |||
if ("GET".equalsIgnoreCase(method)) //$NON-NLS-1$ | |||
req = new HttpGet(urlStr); | |||
req = new HttpGet(url.toString()); | |||
else if ("PUT".equalsIgnoreCase(method)) //$NON-NLS-1$ | |||
req = new HttpPut(urlStr); | |||
req = new HttpPut(url.toString()); | |||
else if ("POST".equalsIgnoreCase(method)) //$NON-NLS-1$ | |||
req = new HttpPost(urlStr); | |||
req = new HttpPost(url.toString()); | |||
else { | |||
this.method = null; | |||
throw new UnsupportedOperationException(); |
@@ -0,0 +1,10 @@ | |||
java_library( | |||
name = 'jgit-servlet', | |||
srcs = glob(['src/**']), | |||
resources = glob(['resources/**']), | |||
provided_deps = [ | |||
'//org.eclipse.jgit:jgit', | |||
'//lib:servlet-api', | |||
], | |||
visibility = ['PUBLIC'], | |||
) |
@@ -0,0 +1,40 @@ | |||
TESTS = glob(['tst/**/*.java']) | |||
for t in TESTS: | |||
n = t[len('tst/'):len(t)-len('.java')].replace('/', '.') | |||
java_test( | |||
name = n, | |||
labels = ['http'], | |||
srcs = [t], | |||
deps = [ | |||
':helpers', | |||
'//org.eclipse.jgit:jgit', | |||
'//org.eclipse.jgit.http.apache:http-apache', | |||
'//org.eclipse.jgit.http.server:jgit-servlet', | |||
'//org.eclipse.jgit.junit:junit', | |||
'//org.eclipse.jgit.junit.http:junit-http', | |||
'//lib:hamcrest-core', | |||
'//lib:hamcrest-library', | |||
'//lib:junit', | |||
'//lib:servlet-api', | |||
'//lib/jetty:http', | |||
'//lib/jetty:io', | |||
'//lib/jetty:server', | |||
'//lib/jetty:servlet', | |||
'//lib/jetty:security', | |||
'//lib/jetty:util', | |||
], | |||
source_under_test = ['//org.eclipse.jgit.http.server:jgit-servlet'], | |||
) | |||
java_library( | |||
name = 'helpers', | |||
srcs = glob(['src/**/*.java']), | |||
deps = [ | |||
'//org.eclipse.jgit:jgit', | |||
'//org.eclipse.jgit.http.server:jgit-servlet', | |||
'//org.eclipse.jgit.junit:junit', | |||
'//org.eclipse.jgit.junit.http:junit-http', | |||
'//lib:junit', | |||
], | |||
) |
@@ -134,6 +134,10 @@ | |||
<artifactId>maven-surefire-plugin</artifactId> | |||
<configuration> | |||
<argLine>-Djava.io.tmpdir=${project.build.directory} -Xmx300m</argLine> | |||
<includes> | |||
<include>**/*Test.java</include> | |||
<include>**/*Tests.java</include> | |||
</includes> | |||
</configuration> | |||
</plugin> | |||
</plugins> |
@@ -140,8 +140,7 @@ public class DumbClientDumbServerTest extends HttpTestCase { | |||
assertEquals("http", remoteURI.getScheme()); | |||
Map<String, Ref> map; | |||
Transport t = Transport.open(dst, remoteURI); | |||
try { | |||
try (Transport t = Transport.open(dst, remoteURI)) { | |||
// I didn't make up these public interface names, I just | |||
// approved them for inclusion into the code base. Sorry. | |||
// --spearce | |||
@@ -149,14 +148,9 @@ public class DumbClientDumbServerTest extends HttpTestCase { | |||
assertTrue("isa TransportHttp", t instanceof TransportHttp); | |||
assertTrue("isa HttpTransport", t instanceof HttpTransport); | |||
FetchConnection c = t.openFetch(); | |||
try { | |||
try (FetchConnection c = t.openFetch()) { | |||
map = c.getRefsMap(); | |||
} finally { | |||
c.close(); | |||
} | |||
} finally { | |||
t.close(); | |||
} | |||
assertNotNull("have map of refs", map); | |||
@@ -201,11 +195,8 @@ public class DumbClientDumbServerTest extends HttpTestCase { | |||
Repository dst = createBareRepository(); | |||
assertFalse(dst.hasObject(A_txt)); | |||
Transport t = Transport.open(dst, remoteURI); | |||
try { | |||
try (Transport t = Transport.open(dst, remoteURI)) { | |||
t.fetch(NullProgressMonitor.INSTANCE, mirror(master)); | |||
} finally { | |||
t.close(); | |||
} | |||
assertTrue(dst.hasObject(A_txt)); | |||
@@ -226,11 +217,8 @@ public class DumbClientDumbServerTest extends HttpTestCase { | |||
Repository dst = createBareRepository(); | |||
assertFalse(dst.hasObject(A_txt)); | |||
Transport t = Transport.open(dst, remoteURI); | |||
try { | |||
try (Transport t = Transport.open(dst, remoteURI)) { | |||
t.fetch(NullProgressMonitor.INSTANCE, mirror(master)); | |||
} finally { | |||
t.close(); | |||
} | |||
assertTrue(dst.hasObject(A_txt)); | |||
@@ -265,8 +253,7 @@ public class DumbClientDumbServerTest extends HttpTestCase { | |||
final RevCommit Q = src.commit().create(); | |||
final Repository db = src.getRepository(); | |||
Transport t = Transport.open(db, remoteURI); | |||
try { | |||
try (Transport t = Transport.open(db, remoteURI)) { | |||
try { | |||
t.push(NullProgressMonitor.INSTANCE, push(src, Q)); | |||
fail("push incorrectly completed against a dumb server"); | |||
@@ -274,8 +261,6 @@ public class DumbClientDumbServerTest extends HttpTestCase { | |||
String exp = "remote does not support smart HTTP push"; | |||
assertEquals(exp, nse.getMessage()); | |||
} | |||
} finally { | |||
t.close(); | |||
} | |||
} | |||
} |
@@ -60,6 +60,7 @@ import org.eclipse.jgit.http.server.GitServlet; | |||
import org.eclipse.jgit.http.server.resolver.DefaultReceivePackFactory; | |||
import org.eclipse.jgit.junit.TestRepository; | |||
import org.eclipse.jgit.junit.http.HttpTestCase; | |||
import org.eclipse.jgit.lib.AnyObjectId; | |||
import org.eclipse.jgit.lib.Constants; | |||
import org.eclipse.jgit.lib.NullProgressMonitor; | |||
import org.eclipse.jgit.lib.ObjectChecker; | |||
@@ -221,8 +222,9 @@ public class GitServletResponseTests extends HttpTestCase { | |||
preHook = null; | |||
oc = new ObjectChecker() { | |||
@Override | |||
public void checkCommit(byte[] raw) throws CorruptObjectException { | |||
throw new IllegalStateException(); | |||
public void checkCommit(AnyObjectId id, byte[] raw) | |||
throws CorruptObjectException { | |||
throw new CorruptObjectException("refusing all commits"); | |||
} | |||
}; | |||
@@ -157,8 +157,7 @@ public class HttpClientTests extends HttpTestCase { | |||
public void testRepositoryNotFound_Dumb() throws Exception { | |||
URIish uri = toURIish("/dumb.none/not-found"); | |||
Repository dst = createBareRepository(); | |||
Transport t = Transport.open(dst, uri); | |||
try { | |||
try (Transport t = Transport.open(dst, uri)) { | |||
try { | |||
t.openFetch(); | |||
fail("connection opened to not found repository"); | |||
@@ -167,8 +166,6 @@ public class HttpClientTests extends HttpTestCase { | |||
+ "/info/refs?service=git-upload-pack not found"; | |||
assertEquals(exp, err.getMessage()); | |||
} | |||
} finally { | |||
t.close(); | |||
} | |||
} | |||
@@ -176,8 +173,7 @@ public class HttpClientTests extends HttpTestCase { | |||
public void testRepositoryNotFound_Smart() throws Exception { | |||
URIish uri = toURIish("/smart.none/not-found"); | |||
Repository dst = createBareRepository(); | |||
Transport t = Transport.open(dst, uri); | |||
try { | |||
try (Transport t = Transport.open(dst, uri)) { | |||
try { | |||
t.openFetch(); | |||
fail("connection opened to not found repository"); | |||
@@ -186,8 +182,6 @@ public class HttpClientTests extends HttpTestCase { | |||
+ "/info/refs?service=git-upload-pack not found"; | |||
assertEquals(exp, err.getMessage()); | |||
} | |||
} finally { | |||
t.close(); | |||
} | |||
} | |||
@@ -201,16 +195,9 @@ public class HttpClientTests extends HttpTestCase { | |||
Repository dst = createBareRepository(); | |||
Ref head; | |||
Transport t = Transport.open(dst, dumbAuthNoneURI); | |||
try { | |||
FetchConnection c = t.openFetch(); | |||
try { | |||
head = c.getRef(Constants.HEAD); | |||
} finally { | |||
c.close(); | |||
} | |||
} finally { | |||
t.close(); | |||
try (Transport t = Transport.open(dst, dumbAuthNoneURI); | |||
FetchConnection c = t.openFetch()) { | |||
head = c.getRef(Constants.HEAD); | |||
} | |||
assertNotNull("has " + Constants.HEAD, head); | |||
assertEquals(Q, head.getObjectId()); | |||
@@ -225,16 +212,9 @@ public class HttpClientTests extends HttpTestCase { | |||
Repository dst = createBareRepository(); | |||
Ref head; | |||
Transport t = Transport.open(dst, dumbAuthNoneURI); | |||
try { | |||
FetchConnection c = t.openFetch(); | |||
try { | |||
head = c.getRef(Constants.HEAD); | |||
} finally { | |||
c.close(); | |||
} | |||
} finally { | |||
t.close(); | |||
try (Transport t = Transport.open(dst, dumbAuthNoneURI); | |||
FetchConnection c = t.openFetch()) { | |||
head = c.getRef(Constants.HEAD); | |||
} | |||
assertNull("has no " + Constants.HEAD, head); | |||
} | |||
@@ -249,16 +229,9 @@ public class HttpClientTests extends HttpTestCase { | |||
Repository dst = createBareRepository(); | |||
Ref head; | |||
Transport t = Transport.open(dst, smartAuthNoneURI); | |||
try { | |||
FetchConnection c = t.openFetch(); | |||
try { | |||
head = c.getRef(Constants.HEAD); | |||
} finally { | |||
c.close(); | |||
} | |||
} finally { | |||
t.close(); | |||
try (Transport t = Transport.open(dst, smartAuthNoneURI); | |||
FetchConnection c = t.openFetch()) { | |||
head = c.getRef(Constants.HEAD); | |||
} | |||
assertNotNull("has " + Constants.HEAD, head); | |||
assertEquals(Q, head.getObjectId()); | |||
@@ -268,16 +241,13 @@ public class HttpClientTests extends HttpTestCase { | |||
public void testListRemote_Smart_WithQueryParameters() throws Exception { | |||
URIish myURI = toURIish("/snone/do?r=1&p=test.git"); | |||
Repository dst = createBareRepository(); | |||
Transport t = Transport.open(dst, myURI); | |||
try { | |||
try (Transport t = Transport.open(dst, myURI)) { | |||
try { | |||
t.openFetch(); | |||
fail("test did not fail to find repository as expected"); | |||
} catch (NoRemoteRepositoryException err) { | |||
// expected | |||
} | |||
} finally { | |||
t.close(); | |||
} | |||
List<AccessEvent> requests = getRequests(); | |||
@@ -296,62 +266,52 @@ public class HttpClientTests extends HttpTestCase { | |||
@Test | |||
public void testListRemote_Dumb_NeedsAuth() throws Exception { | |||
Repository dst = createBareRepository(); | |||
Transport t = Transport.open(dst, dumbAuthBasicURI); | |||
try { | |||
try (Transport t = Transport.open(dst, dumbAuthBasicURI)) { | |||
try { | |||
t.openFetch(); | |||
fail("connection opened even info/refs needs auth basic"); | |||
} catch (TransportException err) { | |||
String exp = dumbAuthBasicURI + ": " | |||
+ JGitText.get().notAuthorized; | |||
+ JGitText.get().noCredentialsProvider; | |||
assertEquals(exp, err.getMessage()); | |||
} | |||
} finally { | |||
t.close(); | |||
} | |||
} | |||
@Test | |||
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(); | |||
try (Transport t = Transport.open(dst, dumbAuthBasicURI)) { | |||
t.setCredentialsProvider(new UsernamePasswordCredentialsProvider( | |||
AppServer.username, AppServer.password)); | |||
t.openFetch().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(); | |||
try (Transport 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()); | |||
} | |||
} | |||
} | |||
@Test | |||
public void testListRemote_Smart_UploadPackNeedsAuth() throws Exception { | |||
Repository dst = createBareRepository(); | |||
Transport t = Transport.open(dst, smartAuthBasicURI); | |||
try { | |||
try (Transport t = Transport.open(dst, smartAuthBasicURI)) { | |||
try { | |||
t.openFetch(); | |||
fail("connection opened even though service disabled"); | |||
} catch (TransportException err) { | |||
String exp = smartAuthBasicURI + ": " | |||
+ JGitText.get().notAuthorized; | |||
+ JGitText.get().noCredentialsProvider; | |||
assertEquals(exp, err.getMessage()); | |||
} | |||
} finally { | |||
t.close(); | |||
} | |||
} | |||
@@ -363,33 +323,24 @@ public class HttpClientTests extends HttpTestCase { | |||
cfg.save(); | |||
Repository dst = createBareRepository(); | |||
Transport t = Transport.open(dst, smartAuthNoneURI); | |||
try { | |||
try (Transport t = Transport.open(dst, smartAuthNoneURI)) { | |||
try { | |||
t.openFetch(); | |||
fail("connection opened even though service disabled"); | |||
} catch (TransportException err) { | |||
String exp = smartAuthNoneURI + ": Git access forbidden"; | |||
String exp = smartAuthNoneURI + ": " | |||
+ JGitText.get().serviceNotEnabledNoName; | |||
assertEquals(exp, err.getMessage()); | |||
} | |||
} finally { | |||
t.close(); | |||
} | |||
} | |||
@Test | |||
public void testListRemoteWithoutLocalRepository() throws Exception { | |||
Transport t = Transport.open(smartAuthNoneURI); | |||
try { | |||
FetchConnection c = t.openFetch(); | |||
try { | |||
Ref head = c.getRef(Constants.HEAD); | |||
assertNotNull(head); | |||
} finally { | |||
c.close(); | |||
} | |||
} finally { | |||
t.close(); | |||
try (Transport t = Transport.open(smartAuthNoneURI); | |||
FetchConnection c = t.openFetch()) { | |||
Ref head = c.getRef(Constants.HEAD); | |||
assertNotNull(head); | |||
} | |||
} | |||
} |
@@ -211,8 +211,7 @@ public class SmartClientSmartServerTest extends HttpTestCase { | |||
assertEquals("http", remoteURI.getScheme()); | |||
Map<String, Ref> map; | |||
Transport t = Transport.open(dst, remoteURI); | |||
try { | |||
try (Transport t = Transport.open(dst, remoteURI)) { | |||
// I didn't make up these public interface names, I just | |||
// approved them for inclusion into the code base. Sorry. | |||
// --spearce | |||
@@ -226,8 +225,6 @@ public class SmartClientSmartServerTest extends HttpTestCase { | |||
} finally { | |||
c.close(); | |||
} | |||
} finally { | |||
t.close(); | |||
} | |||
assertNotNull("have map of refs", map); | |||
@@ -257,8 +254,7 @@ public class SmartClientSmartServerTest extends HttpTestCase { | |||
public void testListRemote_BadName() throws IOException, URISyntaxException { | |||
Repository dst = createBareRepository(); | |||
URIish uri = new URIish(this.remoteURI.toString() + ".invalid"); | |||
Transport t = Transport.open(dst, uri); | |||
try { | |||
try (Transport t = Transport.open(dst, uri)) { | |||
try { | |||
t.openFetch(); | |||
fail("fetch connection opened"); | |||
@@ -266,8 +262,6 @@ public class SmartClientSmartServerTest extends HttpTestCase { | |||
assertEquals(uri + ": Git repository not found", | |||
notFound.getMessage()); | |||
} | |||
} finally { | |||
t.close(); | |||
} | |||
List<AccessEvent> requests = getRequests(); | |||
@@ -288,11 +282,8 @@ public class SmartClientSmartServerTest extends HttpTestCase { | |||
Repository dst = createBareRepository(); | |||
assertFalse(dst.hasObject(A_txt)); | |||
Transport t = Transport.open(dst, remoteURI); | |||
try { | |||
try (Transport t = Transport.open(dst, remoteURI)) { | |||
t.fetch(NullProgressMonitor.INSTANCE, mirror(master)); | |||
} finally { | |||
t.close(); | |||
} | |||
assertTrue(dst.hasObject(A_txt)); | |||
@@ -331,11 +322,8 @@ public class SmartClientSmartServerTest extends HttpTestCase { | |||
// Bootstrap by doing the clone. | |||
// | |||
TestRepository dst = createTestRepository(); | |||
Transport t = Transport.open(dst.getRepository(), remoteURI); | |||
try { | |||
try (Transport t = Transport.open(dst.getRepository(), remoteURI)) { | |||
t.fetch(NullProgressMonitor.INSTANCE, mirror(master)); | |||
} finally { | |||
t.close(); | |||
} | |||
assertEquals(B, dst.getRepository().exactRef(master).getObjectId()); | |||
List<AccessEvent> cloneRequests = getRequests(); | |||
@@ -352,11 +340,8 @@ public class SmartClientSmartServerTest extends HttpTestCase { | |||
// Now incrementally update. | |||
// | |||
t = Transport.open(dst.getRepository(), remoteURI); | |||
try { | |||
try (Transport t = Transport.open(dst.getRepository(), remoteURI)) { | |||
t.fetch(NullProgressMonitor.INSTANCE, mirror(master)); | |||
} finally { | |||
t.close(); | |||
} | |||
assertEquals(Z, dst.getRepository().exactRef(master).getObjectId()); | |||
@@ -394,11 +379,8 @@ public class SmartClientSmartServerTest extends HttpTestCase { | |||
// Bootstrap by doing the clone. | |||
// | |||
TestRepository dst = createTestRepository(); | |||
Transport t = Transport.open(dst.getRepository(), remoteURI); | |||
try { | |||
try (Transport t = Transport.open(dst.getRepository(), remoteURI)) { | |||
t.fetch(NullProgressMonitor.INSTANCE, mirror(master)); | |||
} finally { | |||
t.close(); | |||
} | |||
assertEquals(B, dst.getRepository().exactRef(master).getObjectId()); | |||
List<AccessEvent> cloneRequests = getRequests(); | |||
@@ -418,11 +400,8 @@ public class SmartClientSmartServerTest extends HttpTestCase { | |||
// Now incrementally update. | |||
// | |||
t = Transport.open(dst.getRepository(), remoteURI); | |||
try { | |||
try (Transport t = Transport.open(dst.getRepository(), remoteURI)) { | |||
t.fetch(NullProgressMonitor.INSTANCE, mirror(master)); | |||
} finally { | |||
t.close(); | |||
} | |||
assertEquals(Z, dst.getRepository().exactRef(master).getObjectId()); | |||
@@ -474,8 +453,7 @@ public class SmartClientSmartServerTest extends HttpTestCase { | |||
Repository dst = createBareRepository(); | |||
assertFalse(dst.hasObject(A_txt)); | |||
Transport t = Transport.open(dst, brokenURI); | |||
try { | |||
try (Transport t = Transport.open(dst, brokenURI)) { | |||
try { | |||
t.fetch(NullProgressMonitor.INSTANCE, mirror(master)); | |||
fail("fetch completed despite upload-pack being broken"); | |||
@@ -485,8 +463,6 @@ public class SmartClientSmartServerTest extends HttpTestCase { | |||
+ " received Content-Type text/plain; charset=UTF-8"; | |||
assertEquals(exp, err.getMessage()); | |||
} | |||
} finally { | |||
t.close(); | |||
} | |||
List<AccessEvent> requests = getRequests(); | |||
@@ -517,12 +493,10 @@ public class SmartClientSmartServerTest extends HttpTestCase { | |||
final RevCommit Q = src.commit().add("Q", Q_txt).create(); | |||
final Repository db = src.getRepository(); | |||
final String dstName = Constants.R_HEADS + "new.branch"; | |||
Transport t; | |||
// push anonymous shouldn't be allowed. | |||
// | |||
t = Transport.open(db, remoteURI); | |||
try { | |||
try (Transport t = Transport.open(db, remoteURI)) { | |||
final String srcExpr = Q.name(); | |||
final boolean forceUpdate = false; | |||
final String localName = null; | |||
@@ -538,8 +512,6 @@ public class SmartClientSmartServerTest extends HttpTestCase { | |||
+ JGitText.get().authenticationNotSupported; | |||
assertEquals(exp, e.getMessage()); | |||
} | |||
} finally { | |||
t.close(); | |||
} | |||
List<AccessEvent> requests = getRequests(); | |||
@@ -560,12 +532,10 @@ public class SmartClientSmartServerTest extends HttpTestCase { | |||
final RevCommit Q = src.commit().add("Q", Q_txt).create(); | |||
final Repository db = src.getRepository(); | |||
final String dstName = Constants.R_HEADS + "new.branch"; | |||
Transport t; | |||
enableReceivePack(); | |||
t = Transport.open(db, remoteURI); | |||
try { | |||
try (Transport t = Transport.open(db, remoteURI)) { | |||
final String srcExpr = Q.name(); | |||
final boolean forceUpdate = false; | |||
final String localName = null; | |||
@@ -574,8 +544,6 @@ public class SmartClientSmartServerTest extends HttpTestCase { | |||
RemoteRefUpdate u = new RemoteRefUpdate(src.getRepository(), | |||
srcExpr, dstName, forceUpdate, localName, oldId); | |||
t.push(NullProgressMonitor.INSTANCE, Collections.singleton(u)); | |||
} finally { | |||
t.close(); | |||
} | |||
assertTrue(remoteRepository.hasObject(Q_txt)); | |||
@@ -633,7 +601,6 @@ public class SmartClientSmartServerTest extends HttpTestCase { | |||
final RevCommit Q = src.commit().add("Q", Q_bin).create(); | |||
final Repository db = src.getRepository(); | |||
final String dstName = Constants.R_HEADS + "new.branch"; | |||
Transport t; | |||
enableReceivePack(); | |||
@@ -642,8 +609,7 @@ public class SmartClientSmartServerTest extends HttpTestCase { | |||
cfg.setInt("http", null, "postbuffer", 8 * 1024); | |||
cfg.save(); | |||
t = Transport.open(db, remoteURI); | |||
try { | |||
try (Transport t = Transport.open(db, remoteURI)) { | |||
final String srcExpr = Q.name(); | |||
final boolean forceUpdate = false; | |||
final String localName = null; | |||
@@ -652,8 +618,6 @@ public class SmartClientSmartServerTest extends HttpTestCase { | |||
RemoteRefUpdate u = new RemoteRefUpdate(src.getRepository(), | |||
srcExpr, dstName, forceUpdate, localName, oldId); | |||
t.push(NullProgressMonitor.INSTANCE, Collections.singleton(u)); | |||
} finally { | |||
t.close(); | |||
} | |||
assertTrue(remoteRepository.hasObject(Q_bin)); |
@@ -0,0 +1,18 @@ | |||
java_library( | |||
name = 'junit-http', | |||
srcs = glob(['src/**']), | |||
resources = glob(['resources/**']), | |||
provided_deps = [ | |||
'//org.eclipse.jgit:jgit', | |||
'//org.eclipse.jgit.http.server:jgit-servlet', | |||
'//org.eclipse.jgit.junit:junit', | |||
'//lib:junit', | |||
'//lib:servlet-api', | |||
'//lib/jetty:http', | |||
'//lib/jetty:server', | |||
'//lib/jetty:servlet', | |||
'//lib/jetty:security', | |||
'//lib/jetty:util', | |||
], | |||
visibility = ['PUBLIC'], | |||
) |
@@ -0,0 +1,10 @@ | |||
java_library( | |||
name = 'junit', | |||
srcs = glob(['src/**']), | |||
resources = glob(['resources/**']), | |||
provided_deps = [ | |||
'//org.eclipse.jgit:jgit', | |||
'//lib:junit', | |||
], | |||
visibility = ['PUBLIC'], | |||
) |
@@ -822,7 +822,7 @@ public class TestRepository<R extends Repository> { | |||
break; | |||
final byte[] bin = db.open(o, o.getType()).getCachedBytes(); | |||
oc.checkCommit(bin); | |||
oc.checkCommit(o, bin); | |||
assertHash(o, bin); | |||
} | |||
@@ -832,7 +832,7 @@ public class TestRepository<R extends Repository> { | |||
break; | |||
final byte[] bin = db.open(o, o.getType()).getCachedBytes(); | |||
oc.check(o.getType(), bin); | |||
oc.check(o, o.getType(), bin); | |||
assertHash(o, bin); | |||
} | |||
} | |||
@@ -866,7 +866,7 @@ public class TestRepository<R extends Repository> { | |||
Set<ObjectId> all = new HashSet<ObjectId>(); | |||
for (Ref r : db.getAllRefs().values()) | |||
all.add(r.getObjectId()); | |||
pw.preparePack(m, all, Collections.<ObjectId> emptySet()); | |||
pw.preparePack(m, all, PackWriter.NONE); | |||
final ObjectId name = pw.computeName(); | |||
@@ -1155,8 +1155,7 @@ public class TestRepository<R extends Repository> { | |||
return self; | |||
} | |||
private void insertChangeId(org.eclipse.jgit.lib.CommitBuilder c) | |||
throws IOException { | |||
private void insertChangeId(org.eclipse.jgit.lib.CommitBuilder c) { | |||
if (changeId == null) | |||
return; | |||
int idx = ChangeIdUtil.indexOfChangeId(message, "\n"); |
@@ -0,0 +1,38 @@ | |||
TESTS = glob(['tst/**/*.java']) | |||
for t in TESTS: | |||
n = t[len('tst/'):len(t)-len('.java')].replace('/', '.') | |||
java_test( | |||
name = n, | |||
labels = ['pgm'], | |||
srcs = [t], | |||
deps = [ | |||
':helpers', | |||
'//org.eclipse.jgit:jgit', | |||
'//org.eclipse.jgit.archive:jgit-archive', | |||
'//org.eclipse.jgit.junit:junit', | |||
'//org.eclipse.jgit.pgm:pgm', | |||
'//lib:hamcrest-core', | |||
'//lib:hamcrest-library', | |||
'//lib:javaewah', | |||
'//lib:junit', | |||
'//lib:slf4j-api', | |||
'//lib:slf4j-simple', | |||
'//lib:commons-compress', | |||
'//lib:tukaani-xz', | |||
], | |||
source_under_test = ['//org.eclipse.jgit.pgm:pgm'], | |||
vm_args = ['-Xmx256m', '-Dfile.encoding=UTF-8'], | |||
) | |||
java_library( | |||
name = 'helpers', | |||
srcs = glob(['src/**/*.java']), | |||
deps = [ | |||
'//org.eclipse.jgit:jgit', | |||
'//org.eclipse.jgit.pgm:pgm', | |||
'//org.eclipse.jgit.junit:junit', | |||
'//lib:args4j', | |||
'//lib:junit', | |||
], | |||
) |
@@ -11,6 +11,7 @@ Import-Package: org.eclipse.jgit.api;version="[4.2.0,4.3.0)", | |||
org.eclipse.jgit.api.errors;version="[4.2.0,4.3.0)", | |||
org.eclipse.jgit.diff;version="[4.2.0,4.3.0)", | |||
org.eclipse.jgit.dircache;version="[4.2.0,4.3.0)", | |||
org.eclipse.jgit.internal.storage.file;version="4.2.0", | |||
org.eclipse.jgit.junit;version="[4.2.0,4.3.0)", | |||
org.eclipse.jgit.lib;version="[4.2.0,4.3.0)", | |||
org.eclipse.jgit.merge;version="[4.2.0,4.3.0)", |
@@ -0,0 +1,30 @@ | |||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||
<launchConfiguration type="org.eclipse.jdt.junit.launchconfig"> | |||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS"> | |||
<listEntry value="/org.eclipse.jgit.pgm.test/tst"/> | |||
</listAttribute> | |||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES"> | |||
<listEntry value="2"/> | |||
</listAttribute> | |||
<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/> | |||
<mapAttribute key="org.eclipse.debug.core.environmentVariables"> | |||
<mapEntry key="LANG" value="de_DE.UTF-8"/> | |||
</mapAttribute> | |||
<listAttribute key="org.eclipse.debug.ui.favoriteGroups"> | |||
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/> | |||
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/> | |||
</listAttribute> | |||
<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=org.eclipse.jgit.pgm.test/tst"/> | |||
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/> | |||
<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/> | |||
<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/> | |||
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/> | |||
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH"> | |||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7" path="1" type="4"/> "/> | |||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="org.eclipse.jgit.pgm.test"/> </runtimeClasspathEntry> "/> | |||
</listAttribute> | |||
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/> | |||
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> | |||
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/> | |||
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.jgit.pgm.test"/> | |||
</launchConfiguration> |
@@ -46,12 +46,16 @@ import static org.junit.Assert.assertEquals; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.nio.file.Path; | |||
import java.util.ArrayList; | |||
import java.util.Arrays; | |||
import java.util.List; | |||
import org.eclipse.jgit.junit.JGitTestUtil; | |||
import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase; | |||
import org.eclipse.jgit.pgm.CLIGitCommand; | |||
import org.eclipse.jgit.pgm.CLIGitCommand.Result; | |||
import org.eclipse.jgit.pgm.TextBuiltin.TerminatedByHelpException; | |||
import org.junit.Before; | |||
public class CLIRepositoryTestCase extends LocalDiskRepositoryTestCase { | |||
@@ -69,13 +73,59 @@ public class CLIRepositoryTestCase extends LocalDiskRepositoryTestCase { | |||
trash = db.getWorkTree(); | |||
} | |||
/** | |||
* Executes specified git commands (with arguments) | |||
* | |||
* @param cmds | |||
* each string argument must be a valid git command line, e.g. | |||
* "git branch -h" | |||
* @return command output | |||
* @throws Exception | |||
*/ | |||
protected String[] executeUnchecked(String... cmds) throws Exception { | |||
List<String> result = new ArrayList<String>(cmds.length); | |||
for (String cmd : cmds) { | |||
result.addAll(CLIGitCommand.executeUnchecked(cmd, db)); | |||
} | |||
return result.toArray(new String[0]); | |||
} | |||
/** | |||
* Executes specified git commands (with arguments), throws exception and | |||
* stops execution on first command which output contains a 'fatal:' error | |||
* | |||
* @param cmds | |||
* each string argument must be a valid git command line, e.g. | |||
* "git branch -h" | |||
* @return command output | |||
* @throws Exception | |||
*/ | |||
protected String[] execute(String... cmds) throws Exception { | |||
List<String> result = new ArrayList<String>(cmds.length); | |||
for (String cmd : cmds) | |||
result.addAll(CLIGitCommand.execute(cmd, db)); | |||
for (String cmd : cmds) { | |||
Result r = CLIGitCommand.executeRaw(cmd, db); | |||
if (r.ex instanceof TerminatedByHelpException) { | |||
result.addAll(r.errLines()); | |||
} else if (r.ex != null) { | |||
throw r.ex; | |||
} | |||
result.addAll(r.outLines()); | |||
} | |||
return result.toArray(new String[0]); | |||
} | |||
/** | |||
* @param link | |||
* the path of the symbolic link to create | |||
* @param target | |||
* the target of the symbolic link | |||
* @return the path to the symbolic link | |||
* @throws Exception | |||
*/ | |||
protected Path writeLink(String link, String target) throws Exception { | |||
return JGitTestUtil.writeLink(db, link, target); | |||
} | |||
protected File writeTrashFile(final String name, final String data) | |||
throws IOException { | |||
return JGitTestUtil.writeTrashFile(db, name, data); | |||
@@ -173,15 +223,36 @@ public class CLIRepositoryTestCase extends LocalDiskRepositoryTestCase { | |||
} | |||
protected void assertArrayOfLinesEquals(String[] expected, String[] actual) { | |||
assertEquals(toText(expected), toText(actual)); | |||
assertEquals(toString(expected), toString(actual)); | |||
} | |||
public static String toString(String... lines) { | |||
return toString(Arrays.asList(lines)); | |||
} | |||
private static String toText(String[] lines) { | |||
public static String toString(List<String> lines) { | |||
StringBuilder b = new StringBuilder(); | |||
for (String s : lines) { | |||
b.append(s); | |||
b.append('\n'); | |||
// trim indentation, to simplify tests | |||
s = s.trim(); | |||
if (s != null && !s.isEmpty()) { | |||
b.append(s); | |||
b.append('\n'); | |||
} | |||
} | |||
// delete last line break to allow simpler tests with one line compare | |||
if (b.length() > 0 && b.charAt(b.length() - 1) == '\n') { | |||
b.deleteCharAt(b.length() - 1); | |||
} | |||
return b.toString(); | |||
} | |||
public static boolean contains(List<String> lines, String str) { | |||
for (String s : lines) { | |||
if (s.contains(str)) { | |||
return true; | |||
} | |||
} | |||
return false; | |||
} | |||
} |
@@ -42,71 +42,140 @@ | |||
*/ | |||
package org.eclipse.jgit.pgm; | |||
import static org.junit.Assert.assertNull; | |||
import java.io.ByteArrayOutputStream; | |||
import java.text.MessageFormat; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.io.PrintWriter; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import org.eclipse.jgit.internal.storage.file.FileRepository; | |||
import org.eclipse.jgit.lib.Repository; | |||
import org.eclipse.jgit.pgm.internal.CLIText; | |||
import org.eclipse.jgit.pgm.opt.CmdLineParser; | |||
import org.eclipse.jgit.pgm.opt.SubcommandHandler; | |||
import org.eclipse.jgit.pgm.TextBuiltin.TerminatedByHelpException; | |||
import org.eclipse.jgit.util.IO; | |||
import org.kohsuke.args4j.Argument; | |||
public class CLIGitCommand { | |||
@Argument(index = 0, metaVar = "metaVar_command", required = true, handler = SubcommandHandler.class) | |||
private TextBuiltin subcommand; | |||
public class CLIGitCommand extends Main { | |||
@Argument(index = 1, metaVar = "metaVar_arg") | |||
private List<String> arguments = new ArrayList<String>(); | |||
private final Result result; | |||
public TextBuiltin getSubcommand() { | |||
return subcommand; | |||
private final Repository db; | |||
public CLIGitCommand(Repository db) { | |||
super(); | |||
this.db = db; | |||
result = new Result(); | |||
} | |||
public List<String> getArguments() { | |||
return arguments; | |||
/** | |||
* Executes git commands (with arguments) specified on the command line. The | |||
* git repository (same for all commands) can be specified via system | |||
* property "-Dgit_work_tree=path_to_work_tree". If the property is not set, | |||
* current directory is used. | |||
* | |||
* @param args | |||
* each element in the array must be a valid git command line, | |||
* e.g. "git branch -h" | |||
* @throws Exception | |||
*/ | |||
public static void main(String[] args) throws Exception { | |||
String workDir = System.getProperty("git_work_tree"); | |||
if (workDir == null) { | |||
workDir = "."; | |||
System.out.println( | |||
"System property 'git_work_tree' not specified, using current directory: " | |||
+ new File(workDir).getAbsolutePath()); | |||
} | |||
try (Repository db = new FileRepository(workDir + "/.git")) { | |||
for (String cmd : args) { | |||
List<String> result = execute(cmd, db); | |||
for (String line : result) { | |||
System.out.println(line); | |||
} | |||
} | |||
} | |||
} | |||
public static List<String> execute(String str, Repository db) | |||
throws Exception { | |||
Result result = executeRaw(str, db); | |||
return getOutput(result); | |||
} | |||
public static Result executeRaw(String str, Repository db) | |||
throws Exception { | |||
CLIGitCommand cmd = new CLIGitCommand(db); | |||
cmd.run(str); | |||
return cmd.result; | |||
} | |||
public static List<String> executeUnchecked(String str, Repository db) | |||
throws Exception { | |||
CLIGitCommand cmd = new CLIGitCommand(db); | |||
try { | |||
cmd.run(str); | |||
return getOutput(cmd.result); | |||
} catch (Throwable e) { | |||
return cmd.result.errLines(); | |||
} | |||
} | |||
private static List<String> getOutput(Result result) { | |||
if (result.ex instanceof TerminatedByHelpException) { | |||
return result.errLines(); | |||
} | |||
return result.outLines(); | |||
} | |||
private void run(String commandLine) throws Exception { | |||
String[] argv = convertToMainArgs(commandLine); | |||
try { | |||
return IO.readLines(new String(rawExecute(str, db))); | |||
} catch (Die e) { | |||
return IO.readLines(MessageFormat.format(CLIText.get().fatalError, | |||
e.getMessage())); | |||
super.run(argv); | |||
} catch (TerminatedByHelpException e) { | |||
// this is not a failure, super called exit() on help | |||
} finally { | |||
writer.flush(); | |||
} | |||
} | |||
public static byte[] rawExecute(String str, Repository db) | |||
private static String[] convertToMainArgs(String str) | |||
throws Exception { | |||
String[] args = split(str); | |||
if (!args[0].equalsIgnoreCase("git") || args.length < 2) | |||
if (!args[0].equalsIgnoreCase("git") || args.length < 2) { | |||
throw new IllegalArgumentException( | |||
"Expected 'git <command> [<args>]', was:" + str); | |||
} | |||
String[] argv = new String[args.length - 1]; | |||
System.arraycopy(args, 1, argv, 0, args.length - 1); | |||
return argv; | |||
} | |||
CLIGitCommand bean = new CLIGitCommand(); | |||
final CmdLineParser clp = new CmdLineParser(bean); | |||
clp.parseArgument(argv); | |||
final TextBuiltin cmd = bean.getSubcommand(); | |||
ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |||
cmd.outs = baos; | |||
if (cmd.requiresRepository()) | |||
cmd.init(db, null); | |||
else | |||
cmd.init(null, null); | |||
try { | |||
cmd.execute(bean.getArguments().toArray( | |||
new String[bean.getArguments().size()])); | |||
} finally { | |||
if (cmd.outw != null) | |||
cmd.outw.flush(); | |||
@Override | |||
PrintWriter createErrorWriter() { | |||
return new PrintWriter(result.err); | |||
} | |||
void init(final TextBuiltin cmd) throws IOException { | |||
cmd.outs = result.out; | |||
cmd.errs = result.err; | |||
super.init(cmd); | |||
} | |||
@Override | |||
protected Repository openGitDir(String aGitdir) throws IOException { | |||
assertNull(aGitdir); | |||
return db; | |||
} | |||
@Override | |||
void exit(int status, Exception t) throws Exception { | |||
if (t == null) { | |||
t = new IllegalStateException(Integer.toString(status)); | |||
} | |||
return baos.toByteArray(); | |||
result.ex = t; | |||
throw t; | |||
} | |||
/** | |||
@@ -164,4 +233,36 @@ public class CLIGitCommand { | |||
return list.toArray(new String[list.size()]); | |||
} | |||
public static class Result { | |||
public final ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||
public final ByteArrayOutputStream err = new ByteArrayOutputStream(); | |||
public Exception ex; | |||
public byte[] outBytes() { | |||
return out.toByteArray(); | |||
} | |||
public byte[] errBytes() { | |||
return err.toByteArray(); | |||
} | |||
public String outString() { | |||
return out.toString(); | |||
} | |||
public List<String> outLines() { | |||
return IO.readLines(out.toString()); | |||
} | |||
public String errString() { | |||
return err.toString(); | |||
} | |||
public List<String> errLines() { | |||
return IO.readLines(err.toString()); | |||
} | |||
} | |||
} |
@@ -45,15 +45,12 @@ package org.eclipse.jgit.pgm; | |||
import static org.junit.Assert.assertArrayEquals; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertNotNull; | |||
import java.lang.Exception; | |||
import java.lang.String; | |||
import static org.junit.Assert.fail; | |||
import org.eclipse.jgit.api.Git; | |||
import org.eclipse.jgit.dircache.DirCache; | |||
import org.eclipse.jgit.lib.CLIRepositoryTestCase; | |||
import org.junit.Before; | |||
import org.junit.Ignore; | |||
import org.junit.Test; | |||
public class AddTest extends CLIRepositoryTestCase { | |||
@@ -66,14 +63,16 @@ public class AddTest extends CLIRepositoryTestCase { | |||
git = new Git(db); | |||
} | |||
@Ignore("args4j exit()s on error instead of throwing, JVM goes down") | |||
@Test | |||
public void testAddNothing() throws Exception { | |||
assertEquals("fatal: Argument \"filepattern\" is required", // | |||
execute("git add")[0]); | |||
try { | |||
execute("git add"); | |||
fail("Must die"); | |||
} catch (Die e) { | |||
// expected, requires argument | |||
} | |||
} | |||
@Ignore("args4j exit()s for --help, too") | |||
@Test | |||
public void testAddUsage() throws Exception { | |||
execute("git add --help"); |
@@ -52,17 +52,15 @@ import java.io.ByteArrayInputStream; | |||
import java.io.File; | |||
import java.io.FileInputStream; | |||
import java.io.FileOutputStream; | |||
import java.io.InputStreamReader; | |||
import java.io.IOException; | |||
import java.io.InputStreamReader; | |||
import java.io.OutputStream; | |||
import java.lang.Object; | |||
import java.lang.String; | |||
import java.util.ArrayList; | |||
import java.util.Arrays; | |||
import java.util.List; | |||
import java.util.concurrent.Callable; | |||
import java.util.concurrent.Executors; | |||
import java.util.concurrent.ExecutorService; | |||
import java.util.concurrent.Executors; | |||
import java.util.concurrent.Future; | |||
import java.util.zip.ZipEntry; | |||
import java.util.zip.ZipInputStream; | |||
@@ -71,9 +69,7 @@ import org.eclipse.jgit.api.Git; | |||
import org.eclipse.jgit.dircache.DirCache; | |||
import org.eclipse.jgit.lib.CLIRepositoryTestCase; | |||
import org.eclipse.jgit.lib.FileMode; | |||
import org.eclipse.jgit.pgm.CLIGitCommand; | |||
import org.junit.Before; | |||
import org.junit.Ignore; | |||
import org.junit.Test; | |||
public class ArchiveTest extends CLIRepositoryTestCase { | |||
@@ -89,25 +85,26 @@ public class ArchiveTest extends CLIRepositoryTestCase { | |||
emptyTree = db.resolve("HEAD^{tree}").abbreviate(12).name(); | |||
} | |||
@Ignore("Some versions of java.util.zip refuse to write an empty ZIP") | |||
@Test | |||
public void testEmptyArchive() throws Exception { | |||
byte[] result = CLIGitCommand.rawExecute( | |||
"git archive --format=zip " + emptyTree, db); | |||
byte[] result = CLIGitCommand.executeRaw( | |||
"git archive --format=zip " + emptyTree, db).outBytes(); | |||
assertArrayEquals(new String[0], listZipEntries(result)); | |||
} | |||
@Test | |||
public void testEmptyTar() throws Exception { | |||
byte[] result = CLIGitCommand.rawExecute( | |||
"git archive --format=tar " + emptyTree, db); | |||
byte[] result = CLIGitCommand.executeRaw( | |||
"git archive --format=tar " + emptyTree, db).outBytes(); | |||
assertArrayEquals(new String[0], listTarEntries(result)); | |||
} | |||
@Test | |||
public void testUnrecognizedFormat() throws Exception { | |||
String[] expect = new String[] { "fatal: Unknown archive format 'nonsense'" }; | |||
String[] actual = execute("git archive --format=nonsense " + emptyTree); | |||
String[] expect = new String[] { | |||
"fatal: Unknown archive format 'nonsense'", "" }; | |||
String[] actual = executeUnchecked( | |||
"git archive --format=nonsense " + emptyTree); | |||
assertArrayEquals(expect, actual); | |||
} | |||
@@ -120,8 +117,8 @@ public class ArchiveTest extends CLIRepositoryTestCase { | |||
git.add().addFilepattern("c").call(); | |||
git.commit().setMessage("populate toplevel").call(); | |||
byte[] result = CLIGitCommand.rawExecute( | |||
"git archive --format=zip HEAD", db); | |||
byte[] result = CLIGitCommand.executeRaw( | |||
"git archive --format=zip HEAD", db).outBytes(); | |||
assertArrayEquals(new String[] { "a", "c" }, | |||
listZipEntries(result)); | |||
} | |||
@@ -135,8 +132,8 @@ public class ArchiveTest extends CLIRepositoryTestCase { | |||
@Test | |||
public void testDefaultFormatIsTar() throws Exception { | |||
commitGreeting(); | |||
byte[] result = CLIGitCommand.rawExecute( | |||
"git archive HEAD", db); | |||
byte[] result = CLIGitCommand.executeRaw( | |||
"git archive HEAD", db).outBytes(); | |||
assertArrayEquals(new String[] { "greeting" }, | |||
listTarEntries(result)); | |||
} | |||
@@ -302,8 +299,8 @@ public class ArchiveTest extends CLIRepositoryTestCase { | |||
git.add().addFilepattern("b").call(); | |||
git.commit().setMessage("add subdir").call(); | |||
byte[] result = CLIGitCommand.rawExecute( | |||
"git archive --format=zip master", db); | |||
byte[] result = CLIGitCommand.executeRaw( | |||
"git archive --format=zip master", db).outBytes(); | |||
String[] expect = { "a", "b.c", "b0c", "b/", "b/a", "b/b", "c" }; | |||
String[] actual = listZipEntries(result); | |||
@@ -328,8 +325,8 @@ public class ArchiveTest extends CLIRepositoryTestCase { | |||
git.add().addFilepattern("b").call(); | |||
git.commit().setMessage("add subdir").call(); | |||
byte[] result = CLIGitCommand.rawExecute( | |||
"git archive --format=tar master", db); | |||
byte[] result = CLIGitCommand.executeRaw( | |||
"git archive --format=tar master", db).outBytes(); | |||
String[] expect = { "a", "b.c", "b0c", "b/", "b/a", "b/b", "c" }; | |||
String[] actual = listTarEntries(result); | |||
@@ -349,8 +346,8 @@ public class ArchiveTest extends CLIRepositoryTestCase { | |||
@Test | |||
public void testArchivePrefixOption() throws Exception { | |||
commitBazAndFooSlashBar(); | |||
byte[] result = CLIGitCommand.rawExecute( | |||
"git archive --prefix=x/ --format=zip master", db); | |||
byte[] result = CLIGitCommand.executeRaw( | |||
"git archive --prefix=x/ --format=zip master", db).outBytes(); | |||
String[] expect = { "x/baz", "x/foo/", "x/foo/bar" }; | |||
String[] actual = listZipEntries(result); | |||
@@ -362,8 +359,8 @@ public class ArchiveTest extends CLIRepositoryTestCase { | |||
@Test | |||
public void testTarPrefixOption() throws Exception { | |||
commitBazAndFooSlashBar(); | |||
byte[] result = CLIGitCommand.rawExecute( | |||
"git archive --prefix=x/ --format=tar master", db); | |||
byte[] result = CLIGitCommand.executeRaw( | |||
"git archive --prefix=x/ --format=tar master", db).outBytes(); | |||
String[] expect = { "x/baz", "x/foo/", "x/foo/bar" }; | |||
String[] actual = listTarEntries(result); | |||
@@ -381,8 +378,8 @@ public class ArchiveTest extends CLIRepositoryTestCase { | |||
@Test | |||
public void testPrefixDoesNotNormalizeDoubleSlash() throws Exception { | |||
commitFoo(); | |||
byte[] result = CLIGitCommand.rawExecute( | |||
"git archive --prefix=x// --format=zip master", db); | |||
byte[] result = CLIGitCommand.executeRaw( | |||
"git archive --prefix=x// --format=zip master", db).outBytes(); | |||
String[] expect = { "x//foo" }; | |||
assertArrayEquals(expect, listZipEntries(result)); | |||
} | |||
@@ -390,8 +387,8 @@ public class ArchiveTest extends CLIRepositoryTestCase { | |||
@Test | |||
public void testPrefixDoesNotNormalizeDoubleSlashInTar() throws Exception { | |||
commitFoo(); | |||
byte[] result = CLIGitCommand.rawExecute( | |||
"git archive --prefix=x// --format=tar master", db); | |||
byte[] result = CLIGitCommand.executeRaw( | |||
"git archive --prefix=x// --format=tar master", db).outBytes(); | |||
String[] expect = { "x//foo" }; | |||
assertArrayEquals(expect, listTarEntries(result)); | |||
} | |||
@@ -408,8 +405,8 @@ public class ArchiveTest extends CLIRepositoryTestCase { | |||
@Test | |||
public void testPrefixWithoutTrailingSlash() throws Exception { | |||
commitBazAndFooSlashBar(); | |||
byte[] result = CLIGitCommand.rawExecute( | |||
"git archive --prefix=my- --format=zip master", db); | |||
byte[] result = CLIGitCommand.executeRaw( | |||
"git archive --prefix=my- --format=zip master", db).outBytes(); | |||
String[] expect = { "my-baz", "my-foo/", "my-foo/bar" }; | |||
String[] actual = listZipEntries(result); | |||
@@ -421,8 +418,8 @@ public class ArchiveTest extends CLIRepositoryTestCase { | |||
@Test | |||
public void testTarPrefixWithoutTrailingSlash() throws Exception { | |||
commitBazAndFooSlashBar(); | |||
byte[] result = CLIGitCommand.rawExecute( | |||
"git archive --prefix=my- --format=tar master", db); | |||
byte[] result = CLIGitCommand.executeRaw( | |||
"git archive --prefix=my- --format=tar master", db).outBytes(); | |||
String[] expect = { "my-baz", "my-foo/", "my-foo/bar" }; | |||
String[] actual = listTarEntries(result); | |||
@@ -441,8 +438,8 @@ public class ArchiveTest extends CLIRepositoryTestCase { | |||
git.submoduleAdd().setURI("./.").setPath("b").call().close(); | |||
git.commit().setMessage("add submodule").call(); | |||
byte[] result = CLIGitCommand.rawExecute( | |||
"git archive --format=zip master", db); | |||
byte[] result = CLIGitCommand.executeRaw( | |||
"git archive --format=zip master", db).outBytes(); | |||
String[] expect = { ".gitmodules", "a", "b/", "c" }; | |||
String[] actual = listZipEntries(result); | |||
@@ -461,8 +458,8 @@ public class ArchiveTest extends CLIRepositoryTestCase { | |||
git.submoduleAdd().setURI("./.").setPath("b").call().close(); | |||
git.commit().setMessage("add submodule").call(); | |||
byte[] result = CLIGitCommand.rawExecute( | |||
"git archive --format=tar master", db); | |||
byte[] result = CLIGitCommand.executeRaw( | |||
"git archive --format=tar master", db).outBytes(); | |||
String[] expect = { ".gitmodules", "a", "b/", "c" }; | |||
String[] actual = listTarEntries(result); | |||
@@ -491,8 +488,8 @@ public class ArchiveTest extends CLIRepositoryTestCase { | |||
git.commit().setMessage("three files with different modes").call(); | |||
byte[] zipData = CLIGitCommand.rawExecute( | |||
"git archive --format=zip master", db); | |||
byte[] zipData = CLIGitCommand.executeRaw( | |||
"git archive --format=zip master", db).outBytes(); | |||
writeRaw("zip-with-modes.zip", zipData); | |||
assertContainsEntryWithMode("zip-with-modes.zip", "-rw-", "plain"); | |||
assertContainsEntryWithMode("zip-with-modes.zip", "-rwx", "executable"); | |||
@@ -520,8 +517,8 @@ public class ArchiveTest extends CLIRepositoryTestCase { | |||
git.commit().setMessage("three files with different modes").call(); | |||
byte[] archive = CLIGitCommand.rawExecute( | |||
"git archive --format=tar master", db); | |||
byte[] archive = CLIGitCommand.executeRaw( | |||
"git archive --format=tar master", db).outBytes(); | |||
writeRaw("with-modes.tar", archive); | |||
assertTarContainsEntry("with-modes.tar", "-rw-r--r--", "plain"); | |||
assertTarContainsEntry("with-modes.tar", "-rwxr-xr-x", "executable"); | |||
@@ -543,8 +540,8 @@ public class ArchiveTest extends CLIRepositoryTestCase { | |||
git.add().addFilepattern("1234567890").call(); | |||
git.commit().setMessage("file with long name").call(); | |||
byte[] result = CLIGitCommand.rawExecute( | |||
"git archive --format=zip HEAD", db); | |||
byte[] result = CLIGitCommand.executeRaw( | |||
"git archive --format=zip HEAD", db).outBytes(); | |||
assertArrayEquals(l.toArray(new String[l.size()]), | |||
listZipEntries(result)); | |||
} | |||
@@ -563,8 +560,8 @@ public class ArchiveTest extends CLIRepositoryTestCase { | |||
git.add().addFilepattern("1234567890").call(); | |||
git.commit().setMessage("file with long name").call(); | |||
byte[] result = CLIGitCommand.rawExecute( | |||
"git archive --format=tar HEAD", db); | |||
byte[] result = CLIGitCommand.executeRaw( | |||
"git archive --format=tar HEAD", db).outBytes(); | |||
assertArrayEquals(l.toArray(new String[l.size()]), | |||
listTarEntries(result)); | |||
} | |||
@@ -576,8 +573,8 @@ public class ArchiveTest extends CLIRepositoryTestCase { | |||
git.add().addFilepattern("xyzzy").call(); | |||
git.commit().setMessage("add file with content").call(); | |||
byte[] result = CLIGitCommand.rawExecute( | |||
"git archive --format=zip HEAD", db); | |||
byte[] result = CLIGitCommand.executeRaw( | |||
"git archive --format=zip HEAD", db).outBytes(); | |||
assertArrayEquals(new String[] { payload }, | |||
zipEntryContent(result, "xyzzy")); | |||
} | |||
@@ -589,8 +586,8 @@ public class ArchiveTest extends CLIRepositoryTestCase { | |||
git.add().addFilepattern("xyzzy").call(); | |||
git.commit().setMessage("add file with content").call(); | |||
byte[] result = CLIGitCommand.rawExecute( | |||
"git archive --format=tar HEAD", db); | |||
byte[] result = CLIGitCommand.executeRaw( | |||
"git archive --format=tar HEAD", db).outBytes(); | |||
assertArrayEquals(new String[] { payload }, | |||
tarEntryContent(result, "xyzzy")); | |||
} |
@@ -43,11 +43,17 @@ | |||
package org.eclipse.jgit.pgm; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertFalse; | |||
import static org.junit.Assert.assertTrue; | |||
import static org.junit.Assert.fail; | |||
import java.io.File; | |||
import org.eclipse.jgit.api.Git; | |||
import org.eclipse.jgit.lib.CLIRepositoryTestCase; | |||
import org.eclipse.jgit.lib.Constants; | |||
import org.eclipse.jgit.lib.RefUpdate; | |||
import org.eclipse.jgit.pgm.internal.CLIText; | |||
import org.eclipse.jgit.revwalk.RevCommit; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
@@ -62,10 +68,20 @@ public class BranchTest extends CLIRepositoryTestCase { | |||
} | |||
} | |||
@Test | |||
public void testHelpAfterDelete() throws Exception { | |||
String err = toString(executeUnchecked("git branch -d")); | |||
String help = toString(executeUnchecked("git branch -h")); | |||
String errAndHelp = toString(executeUnchecked("git branch -d -h")); | |||
assertEquals(CLIText.fatalError(CLIText.get().branchNameRequired), err); | |||
assertEquals(toString(err, help), errAndHelp); | |||
} | |||
@Test | |||
public void testList() throws Exception { | |||
assertEquals("* master", toString(execute("git branch"))); | |||
assertEquals("* master 6fd41be initial commit", | |||
execute("git branch -v")[0]); | |||
toString(execute("git branch -v"))); | |||
} | |||
@Test | |||
@@ -73,26 +89,188 @@ public class BranchTest extends CLIRepositoryTestCase { | |||
RefUpdate updateRef = db.updateRef(Constants.HEAD, true); | |||
updateRef.setNewObjectId(db.resolve("6fd41be")); | |||
updateRef.update(); | |||
assertEquals("* (no branch) 6fd41be initial commit", | |||
execute("git branch -v")[0]); | |||
assertEquals( | |||
toString("* (no branch) 6fd41be initial commit", | |||
"master 6fd41be initial commit"), | |||
toString(execute("git branch -v"))); | |||
} | |||
@Test | |||
public void testListContains() throws Exception { | |||
try (Git git = new Git(db)) { | |||
git.branchCreate().setName("initial").call(); | |||
git.branchCreate().setName("initial").call(); | |||
RevCommit second = git.commit().setMessage("second commit") | |||
.call(); | |||
assertArrayOfLinesEquals(new String[] { " initial", "* master", "" }, | |||
execute("git branch --contains 6fd41be")); | |||
assertArrayOfLinesEquals(new String[] { "* master", "" }, | |||
execute("git branch --contains " + second.name())); | |||
assertEquals(toString(" initial", "* master"), | |||
toString(execute("git branch --contains 6fd41be"))); | |||
assertEquals("* master", | |||
toString(execute("git branch --contains " + second.name()))); | |||
} | |||
} | |||
@Test | |||
public void testExistingBranch() throws Exception { | |||
assertEquals("fatal: A branch named 'master' already exists.", | |||
execute("git branch master")[0]); | |||
toString(executeUnchecked("git branch master"))); | |||
} | |||
@Test | |||
public void testRenameSingleArg() throws Exception { | |||
try { | |||
toString(execute("git branch -m")); | |||
fail("Must die"); | |||
} catch (Die e) { | |||
// expected, requires argument | |||
} | |||
String result = toString(execute("git branch -m slave")); | |||
assertEquals("", result); | |||
result = toString(execute("git branch -a")); | |||
assertEquals("* slave", result); | |||
} | |||
@Test | |||
public void testRenameTwoArgs() throws Exception { | |||
String result = toString(execute("git branch -m master slave")); | |||
assertEquals("", result); | |||
result = toString(execute("git branch -a")); | |||
assertEquals("* slave", result); | |||
} | |||
@Test | |||
public void testCreate() throws Exception { | |||
try { | |||
toString(execute("git branch a b")); | |||
fail("Must die"); | |||
} catch (Die e) { | |||
// expected, too many arguments | |||
} | |||
String result = toString(execute("git branch second")); | |||
assertEquals("", result); | |||
result = toString(execute("git branch")); | |||
assertEquals(toString("* master", "second"), result); | |||
result = toString(execute("git branch -v")); | |||
assertEquals(toString("* master 6fd41be initial commit", | |||
"second 6fd41be initial commit"), result); | |||
} | |||
@Test | |||
public void testDelete() throws Exception { | |||
try { | |||
toString(execute("git branch -d")); | |||
fail("Must die"); | |||
} catch (Die e) { | |||
// expected, requires argument | |||
} | |||
String result = toString(execute("git branch second")); | |||
assertEquals("", result); | |||
result = toString(execute("git branch -d second")); | |||
assertEquals("", result); | |||
result = toString(execute("git branch")); | |||
assertEquals("* master", result); | |||
} | |||
@Test | |||
public void testDeleteMultiple() throws Exception { | |||
String result = toString(execute("git branch second", | |||
"git branch third", "git branch fourth")); | |||
assertEquals("", result); | |||
result = toString(execute("git branch -d second third fourth")); | |||
assertEquals("", result); | |||
result = toString(execute("git branch")); | |||
assertEquals("* master", result); | |||
} | |||
@Test | |||
public void testDeleteForce() throws Exception { | |||
try { | |||
toString(execute("git branch -D")); | |||
fail("Must die"); | |||
} catch (Die e) { | |||
// expected, requires argument | |||
} | |||
String result = toString(execute("git branch second")); | |||
assertEquals("", result); | |||
result = toString(execute("git checkout second")); | |||
assertEquals("Switched to branch 'second'", result); | |||
File a = writeTrashFile("a", "a"); | |||
assertTrue(a.exists()); | |||
execute("git add a", "git commit -m 'added a'"); | |||
result = toString(execute("git checkout master")); | |||
assertEquals("Switched to branch 'master'", result); | |||
result = toString(execute("git branch")); | |||
assertEquals(toString("* master", "second"), result); | |||
try { | |||
toString(execute("git branch -d second")); | |||
fail("Must die"); | |||
} catch (Die e) { | |||
// expected, the current HEAD is on second and not merged to master | |||
} | |||
result = toString(execute("git branch -D second")); | |||
assertEquals("", result); | |||
result = toString(execute("git branch")); | |||
assertEquals("* master", result); | |||
} | |||
@Test | |||
public void testDeleteForceMultiple() throws Exception { | |||
String result = toString(execute("git branch second", | |||
"git branch third", "git branch fourth")); | |||
assertEquals("", result); | |||
result = toString(execute("git checkout second")); | |||
assertEquals("Switched to branch 'second'", result); | |||
File a = writeTrashFile("a", "a"); | |||
assertTrue(a.exists()); | |||
execute("git add a", "git commit -m 'added a'"); | |||
result = toString(execute("git checkout master")); | |||
assertEquals("Switched to branch 'master'", result); | |||
result = toString(execute("git branch")); | |||
assertEquals(toString("fourth", "* master", "second", "third"), result); | |||
try { | |||
toString(execute("git branch -d second third fourth")); | |||
fail("Must die"); | |||
} catch (Die e) { | |||
// expected, the current HEAD is on second and not merged to master | |||
} | |||
result = toString(execute("git branch")); | |||
assertEquals(toString("fourth", "* master", "second", "third"), result); | |||
result = toString(execute("git branch -D second third fourth")); | |||
assertEquals("", result); | |||
result = toString(execute("git branch")); | |||
assertEquals("* master", result); | |||
} | |||
@Test | |||
public void testCreateFromOldCommit() throws Exception { | |||
File a = writeTrashFile("a", "a"); | |||
assertTrue(a.exists()); | |||
execute("git add a", "git commit -m 'added a'"); | |||
File b = writeTrashFile("b", "b"); | |||
assertTrue(b.exists()); | |||
execute("git add b", "git commit -m 'added b'"); | |||
String result = toString(execute("git log -n 1 --reverse")); | |||
String firstCommitId = result.substring("commit ".length(), | |||
result.indexOf('\n')); | |||
result = toString(execute("git branch -f second " + firstCommitId)); | |||
assertEquals("", result); | |||
result = toString(execute("git branch")); | |||
assertEquals(toString("* master", "second"), result); | |||
result = toString(execute("git checkout second")); | |||
assertEquals("Switched to branch 'second'", result); | |||
assertFalse(b.exists()); | |||
} | |||
} |
@@ -44,9 +44,14 @@ package org.eclipse.jgit.pgm; | |||
import static org.junit.Assert.assertArrayEquals; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertFalse; | |||
import static org.junit.Assert.assertNotNull; | |||
import static org.junit.Assert.assertTrue; | |||
import java.io.File; | |||
import java.nio.file.Files; | |||
import java.nio.file.Path; | |||
import java.util.Arrays; | |||
import java.util.List; | |||
import org.eclipse.jgit.api.Git; | |||
@@ -59,7 +64,9 @@ import org.eclipse.jgit.revwalk.RevCommit; | |||
import org.eclipse.jgit.treewalk.FileTreeIterator; | |||
import org.eclipse.jgit.treewalk.FileTreeIterator.FileEntry; | |||
import org.eclipse.jgit.treewalk.TreeWalk; | |||
import org.eclipse.jgit.util.FS; | |||
import org.eclipse.jgit.util.FileUtils; | |||
import org.junit.Assume; | |||
import org.junit.Test; | |||
public class CheckoutTest extends CLIRepositoryTestCase { | |||
@@ -109,14 +116,14 @@ public class CheckoutTest extends CLIRepositoryTestCase { | |||
assertStringArrayEquals( | |||
"fatal: A branch named 'master' already exists.", | |||
execute("git checkout -b master")); | |||
executeUnchecked("git checkout -b master")); | |||
} | |||
} | |||
@Test | |||
public void testCheckoutNewBranchOnBranchToBeBorn() throws Exception { | |||
assertStringArrayEquals("fatal: You are on a branch yet to be born", | |||
execute("git checkout -b side")); | |||
executeUnchecked("git checkout -b side")); | |||
} | |||
@Test | |||
@@ -599,4 +606,34 @@ public class CheckoutTest extends CLIRepositoryTestCase { | |||
assertEquals("Hello world b", read(b)); | |||
} | |||
} | |||
@Test | |||
public void testCheckouSingleFile() throws Exception { | |||
try (Git git = new Git(db)) { | |||
File a = writeTrashFile("a", "file a"); | |||
git.add().addFilepattern(".").call(); | |||
git.commit().setMessage("commit file a").call(); | |||
writeTrashFile("a", "b"); | |||
assertEquals("b", read(a)); | |||
assertEquals("[]", Arrays.toString(execute("git checkout -- a"))); | |||
assertEquals("file a", read(a)); | |||
} | |||
} | |||
@Test | |||
public void testCheckoutLink() throws Exception { | |||
Assume.assumeTrue(FS.DETECTED.supportsSymlinks()); | |||
try (Git git = new Git(db)) { | |||
Path path = writeLink("a", "link_a"); | |||
assertTrue(Files.isSymbolicLink(path)); | |||
git.add().addFilepattern(".").call(); | |||
git.commit().setMessage("commit link a").call(); | |||
deleteTrashFile("a"); | |||
writeTrashFile("a", "Hello world a"); | |||
assertFalse(Files.isSymbolicLink(path)); | |||
assertEquals("[]", Arrays.toString(execute("git checkout -- a"))); | |||
assertEquals("link_a", FileUtils.readSymLink(path.toFile())); | |||
assertTrue(Files.isSymbolicLink(path)); | |||
} | |||
} | |||
} |
@@ -0,0 +1,100 @@ | |||
/* | |||
* Copyright (C) 2015, Andrey Loskutov <loskutov@gmx.de> | |||
* and other copyright owners as documented in the project's IP log. | |||
* | |||
* This program and the accompanying materials are made available | |||
* under the terms of the Eclipse Distribution License v1.0 which | |||
* accompanies this distribution, is reproduced below, and is | |||
* available at http://www.eclipse.org/org/documents/edl-v10.php | |||
* | |||
* All rights reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or | |||
* without modification, are permitted provided that the following | |||
* conditions are met: | |||
* | |||
* - Redistributions of source code must retain the above copyright | |||
* notice, this list of conditions and the following disclaimer. | |||
* | |||
* - Redistributions in binary form must reproduce the above | |||
* copyright notice, this list of conditions and the following | |||
* disclaimer in the documentation and/or other materials provided | |||
* with the distribution. | |||
* | |||
* - Neither the name of the Eclipse Foundation, Inc. nor the | |||
* names of its contributors may be used to endorse or promote | |||
* products derived from this software without specific prior | |||
* written permission. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND | |||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, | |||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | |||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | |||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
*/ | |||
package org.eclipse.jgit.pgm; | |||
import static org.junit.Assert.assertEquals; | |||
import org.eclipse.jgit.lib.CLIRepositoryTestCase; | |||
import org.junit.Test; | |||
public class CommitTest extends CLIRepositoryTestCase { | |||
@Test | |||
public void testCommitPath() throws Exception { | |||
writeTrashFile("a", "a"); | |||
writeTrashFile("b", "a"); | |||
String result = toString(execute("git add a")); | |||
assertEquals("", result); | |||
result = toString(execute("git status -- a")); | |||
assertEquals(toString("On branch master", "Changes to be committed:", | |||
"new file: a"), result); | |||
result = toString(execute("git status -- b")); | |||
assertEquals(toString("On branch master", "Untracked files:", "b"), | |||
result); | |||
result = toString(execute("git commit a -m 'added a'")); | |||
assertEquals( | |||
"[master 8cb3ef7e5171aaee1792df6302a5a0cd30425f7a] added a", | |||
result); | |||
result = toString(execute("git status -- a")); | |||
assertEquals("On branch master", result); | |||
result = toString(execute("git status -- b")); | |||
assertEquals(toString("On branch master", "Untracked files:", "b"), | |||
result); | |||
} | |||
@Test | |||
public void testCommitAll() throws Exception { | |||
writeTrashFile("a", "a"); | |||
writeTrashFile("b", "a"); | |||
String result = toString(execute("git add a b")); | |||
assertEquals("", result); | |||
result = toString(execute("git status -- a b")); | |||
assertEquals(toString("On branch master", "Changes to be committed:", | |||
"new file: a", "new file: b"), result); | |||
result = toString(execute("git commit -m 'added a b'")); | |||
assertEquals( | |||
"[master 3c93fa8e3a28ee26690498be78016edcb3a38c73] added a b", | |||
result); | |||
result = toString(execute("git status -- a b")); | |||
assertEquals("On branch master", result); | |||
} | |||
} |
@@ -43,9 +43,15 @@ | |||
package org.eclipse.jgit.pgm; | |||
import static org.junit.Assert.assertArrayEquals; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertFalse; | |||
import static org.junit.Assert.assertTrue; | |||
import java.util.Arrays; | |||
import org.eclipse.jgit.api.Git; | |||
import org.eclipse.jgit.lib.CLIRepositoryTestCase; | |||
import org.eclipse.jgit.pgm.internal.CLIText; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
@@ -67,17 +73,15 @@ public class DescribeTest extends CLIRepositoryTestCase { | |||
@Test | |||
public void testNoHead() throws Exception { | |||
assertArrayEquals( | |||
new String[] { "fatal: No names found, cannot describe anything." }, | |||
execute("git describe")); | |||
assertEquals(CLIText.fatalError(CLIText.get().noNamesFound), | |||
toString(executeUnchecked("git describe"))); | |||
} | |||
@Test | |||
public void testHeadNoTag() throws Exception { | |||
git.commit().setMessage("initial commit").call(); | |||
assertArrayEquals( | |||
new String[] { "fatal: No names found, cannot describe anything." }, | |||
execute("git describe")); | |||
assertEquals(CLIText.fatalError(CLIText.get().noNamesFound), | |||
toString(executeUnchecked("git describe"))); | |||
} | |||
@Test | |||
@@ -103,4 +107,22 @@ public class DescribeTest extends CLIRepositoryTestCase { | |||
assertArrayEquals(new String[] { "v1.0-0-g6fd41be", "" }, | |||
execute("git describe --long HEAD")); | |||
} | |||
@Test | |||
public void testHelpArgumentBeforeUnknown() throws Exception { | |||
String[] output = execute("git describe -h -XYZ"); | |||
String all = Arrays.toString(output); | |||
assertTrue("Unexpected help output: " + all, | |||
all.contains("jgit describe")); | |||
assertFalse("Unexpected help output: " + all, all.contains("fatal")); | |||
} | |||
@Test | |||
public void testHelpArgumentAfterUnknown() throws Exception { | |||
String[] output = executeUnchecked("git describe -XYZ -h"); | |||
String all = Arrays.toString(output); | |||
assertTrue("Unexpected help output: " + all, | |||
all.contains("jgit describe")); | |||
assertTrue("Unexpected help output: " + all, all.contains("fatal")); | |||
} | |||
} |
@@ -50,6 +50,7 @@ import java.util.Iterator; | |||
import org.eclipse.jgit.api.Git; | |||
import org.eclipse.jgit.lib.CLIRepositoryTestCase; | |||
import org.eclipse.jgit.merge.MergeStrategy; | |||
import org.eclipse.jgit.pgm.internal.CLIText; | |||
import org.eclipse.jgit.revwalk.RevCommit; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
@@ -194,8 +195,9 @@ public class MergeTest extends CLIRepositoryTestCase { | |||
@Test | |||
public void testNoFastForwardAndSquash() throws Exception { | |||
assertEquals("fatal: You cannot combine --squash with --no-ff.", | |||
execute("git merge master --no-ff --squash")[0]); | |||
assertEquals( | |||
CLIText.fatalError(CLIText.get().cannotCombineSquashWithNoff), | |||
executeUnchecked("git merge master --no-ff --squash")[0]); | |||
} | |||
@Test | |||
@@ -209,8 +211,8 @@ public class MergeTest extends CLIRepositoryTestCase { | |||
git.add().addFilepattern("file").call(); | |||
git.commit().setMessage("commit#2").call(); | |||
assertEquals("fatal: Not possible to fast-forward, aborting.", | |||
execute("git merge master --ff-only")[0]); | |||
assertEquals(CLIText.fatalError(CLIText.get().ffNotPossibleAborting), | |||
executeUnchecked("git merge master --ff-only")[0]); | |||
} | |||
@Test |
@@ -44,8 +44,11 @@ package org.eclipse.jgit.pgm; | |||
import static org.junit.Assert.assertFalse; | |||
import static org.junit.Assert.assertTrue; | |||
import static org.junit.Assert.fail; | |||
import java.io.File; | |||
import java.util.Arrays; | |||
import org.eclipse.jgit.api.Git; | |||
import org.eclipse.jgit.junit.JGitTestUtil; | |||
import org.eclipse.jgit.lib.CLIRepositoryTestCase; | |||
@@ -97,6 +100,31 @@ public class RepoTest extends CLIRepositoryTestCase { | |||
resolveRelativeUris(); | |||
} | |||
@Test | |||
public void testMissingPath() throws Exception { | |||
try { | |||
execute("git repo"); | |||
fail("Must die"); | |||
} catch (Die e) { | |||
// expected, requires argument | |||
} | |||
} | |||
/** | |||
* See bug 484951: "git repo -h" should not print unexpected values | |||
* | |||
* @throws Exception | |||
*/ | |||
@Test | |||
public void testZombieHelpArgument() throws Exception { | |||
String[] output = execute("git repo -h"); | |||
String all = Arrays.toString(output); | |||
assertTrue("Unexpected help output: " + all, | |||
all.contains("jgit repo")); | |||
assertFalse("Unexpected help output: " + all, | |||
all.contains("jgit repo VAL")); | |||
} | |||
@Test | |||
public void testAddRepoManifest() throws Exception { | |||
StringBuilder xmlContent = new StringBuilder(); |
@@ -48,6 +48,7 @@ import org.eclipse.jgit.api.Git; | |||
import org.eclipse.jgit.lib.CLIRepositoryTestCase; | |||
import org.eclipse.jgit.revwalk.RevCommit; | |||
import org.junit.Before; | |||
import org.junit.Ignore; | |||
import org.junit.Test; | |||
public class ResetTest extends CLIRepositoryTestCase { | |||
@@ -61,6 +62,20 @@ public class ResetTest extends CLIRepositoryTestCase { | |||
git = new Git(db); | |||
} | |||
@Test | |||
public void testPathOptionHelp() throws Exception { | |||
String[] result = execute("git reset -h"); | |||
assertTrue("Unexpected argument: " + result[1], | |||
result[1].endsWith("[-- path ... ...]")); | |||
} | |||
@Test | |||
public void testZombieArgument_Bug484951() throws Exception { | |||
String[] result = execute("git reset -h"); | |||
assertFalse("Unexpected argument: " + result[0], | |||
result[0].contains("[VAL ...]")); | |||
} | |||
@Test | |||
public void testResetSelf() throws Exception { | |||
RevCommit commit = git.commit().setMessage("initial commit").call(); | |||
@@ -91,15 +106,28 @@ public class ResetTest extends CLIRepositoryTestCase { | |||
@Test | |||
public void testResetPathDoubleDash() throws Exception { | |||
resetPath(true); | |||
resetPath(true, true); | |||
} | |||
@Test | |||
public void testResetPathNoDoubleDash() throws Exception { | |||
resetPath(false); | |||
resetPath(false, true); | |||
} | |||
@Test | |||
public void testResetPathDoubleDashNoRef() throws Exception { | |||
resetPath(true, false); | |||
} | |||
@Ignore("Currently we cannote recognize if a name is a commit-ish or a path, " | |||
+ "so 'git reset a' will not work if 'a' is not a branch name but a file path") | |||
@Test | |||
public void testResetPathNoDoubleDashNoRef() throws Exception { | |||
resetPath(false, false); | |||
} | |||
private void resetPath(boolean useDoubleDash) throws Exception { | |||
private void resetPath(boolean useDoubleDash, boolean supplyCommit) | |||
throws Exception { | |||
// create files a and b | |||
writeTrashFile("a", "Hello world a"); | |||
writeTrashFile("b", "Hello world b"); | |||
@@ -115,8 +143,9 @@ public class ResetTest extends CLIRepositoryTestCase { | |||
git.add().addFilepattern(".").call(); | |||
// reset only file a | |||
String cmd = String.format("git reset %s%s a", commit.getId().name(), | |||
(useDoubleDash) ? " --" : ""); | |||
String cmd = String.format("git reset %s%s a", | |||
supplyCommit ? commit.getId().name() : "", | |||
useDoubleDash ? " --" : ""); | |||
assertStringArrayEquals("", execute(cmd)); | |||
assertEquals(commit.getId(), | |||
git.getRepository().exactRef("HEAD").getObjectId()); |
@@ -44,6 +44,7 @@ package org.eclipse.jgit.pgm; | |||
import static org.eclipse.jgit.lib.Constants.MASTER; | |||
import static org.eclipse.jgit.lib.Constants.R_HEADS; | |||
import static org.junit.Assert.assertTrue; | |||
import java.io.IOException; | |||
@@ -55,6 +56,13 @@ import org.junit.Test; | |||
public class StatusTest extends CLIRepositoryTestCase { | |||
@Test | |||
public void testPathOptionHelp() throws Exception { | |||
String[] result = execute("git status -h"); | |||
assertTrue("Unexpected argument: " + result[1], | |||
result[1].endsWith("[-- path ... ...]")); | |||
} | |||
@Test | |||
public void testStatusDefault() throws Exception { | |||
executeTest("git status", false, true); |
@@ -68,6 +68,6 @@ public class TagTest extends CLIRepositoryTestCase { | |||
git.commit().setMessage("commit").call(); | |||
assertEquals("fatal: tag 'test' already exists", | |||
execute("git tag test")[0]); | |||
executeUnchecked("git tag test")[0]); | |||
} | |||
} |
@@ -0,0 +1,70 @@ | |||
include_defs('//tools/git.defs') | |||
java_library( | |||
name = 'pgm', | |||
srcs = glob(['src/**']), | |||
resources = glob(['resources/**']), | |||
deps = [ | |||
':services', | |||
'//org.eclipse.jgit:jgit', | |||
'//org.eclipse.jgit.archive:jgit-archive', | |||
'//org.eclipse.jgit.http.apache:http-apache', | |||
'//org.eclipse.jgit.ui:ui', | |||
'//lib:args4j', | |||
], | |||
visibility = ['PUBLIC'], | |||
) | |||
prebuilt_jar( | |||
name = 'services', | |||
binary_jar = ':services__jar', | |||
) | |||
genrule( | |||
name = 'services__jar', | |||
cmd = 'cd $SRCDIR ; zip -qr $OUT .', | |||
srcs = glob(['META-INF/services/*']), | |||
out = 'services.jar', | |||
) | |||
genrule( | |||
name = 'jgit', | |||
cmd = ''.join([ | |||
'mkdir $TMP/META-INF &&', | |||
'cp $(location :binary_manifest) $TMP/META-INF/MANIFEST.MF &&', | |||
'cp $(location :jgit_jar) $TMP/jgit.jar &&', | |||
'cd $TMP && zip $TMP/jgit.jar META-INF/MANIFEST.MF &&', | |||
'cat $SRCDIR/jgit.sh $TMP/jgit.jar >$OUT &&', | |||
'chmod a+x $OUT', | |||
]), | |||
srcs = ['jgit.sh'], | |||
out = 'jgit', | |||
visibility = ['PUBLIC'], | |||
) | |||
java_binary( | |||
name = 'jgit_jar', | |||
deps = [ | |||
':pgm', | |||
'//lib:slf4j-simple', | |||
'//lib:tukaani-xz', | |||
], | |||
blacklist = [ | |||
'META-INF/DEPENDENCIES', | |||
'META-INF/maven/.*', | |||
], | |||
) | |||
genrule( | |||
name = 'binary_manifest', | |||
cmd = ';'.join(['echo "%s: %s" >>$OUT' % e for e in [ | |||
('Manifest-Version', '1.0'), | |||
('Main-Class', 'org.eclipse.jgit.pgm.Main'), | |||
('Bundle-Version', git_version()), | |||
('Implementation-Title', 'JGit Command Line Interface'), | |||
('Implementation-Vendor', 'Eclipse.org - JGit'), | |||
('Implementation-Vendor-URL', 'http://www.eclipse.org/jgit/'), | |||
('Implementation-Vendor-Id', 'org.eclipse.jgit'), | |||
]] + ['echo >>$OUT']), | |||
out = 'MANIFEST.MF', | |||
) |
@@ -21,6 +21,7 @@ Import-Package: org.apache.commons.compress.archivers;version="[1.3,2.0)", | |||
org.eclipse.jgit.gitrepo;version="[4.2.0,4.3.0)", | |||
org.eclipse.jgit.internal.storage.file;version="[4.2.0,4.3.0)", | |||
org.eclipse.jgit.internal.storage.pack;version="[4.2.0,4.3.0)", | |||
org.eclipse.jgit.internal.storage.reftree;version="[4.2.0,4.3.0)", | |||
org.eclipse.jgit.lib;version="[4.2.0,4.3.0)", | |||
org.eclipse.jgit.merge;version="4.2.0", | |||
org.eclipse.jgit.nls;version="[4.2.0,4.3.0)", | |||
@@ -31,6 +32,7 @@ Import-Package: org.apache.commons.compress.archivers;version="[1.3,2.0)", | |||
org.eclipse.jgit.storage.file;version="[4.2.0,4.3.0)", | |||
org.eclipse.jgit.storage.pack;version="[4.2.0,4.3.0)", | |||
org.eclipse.jgit.transport;version="[4.2.0,4.3.0)", | |||
org.eclipse.jgit.transport.http.apache;version="[4.2.0,4.3.0)", | |||
org.eclipse.jgit.transport.resolver;version="[4.2.0,4.3.0)", | |||
org.eclipse.jgit.treewalk;version="[4.2.0,4.3.0)", | |||
org.eclipse.jgit.treewalk.filter;version="[4.2.0,4.3.0)", |
@@ -41,6 +41,7 @@ org.eclipse.jgit.pgm.debug.DiffAlgorithms | |||
org.eclipse.jgit.pgm.debug.MakeCacheTree | |||
org.eclipse.jgit.pgm.debug.ReadDirCache | |||
org.eclipse.jgit.pgm.debug.RebuildCommitGraph | |||
org.eclipse.jgit.pgm.debug.RebuildRefTree | |||
org.eclipse.jgit.pgm.debug.ShowCacheTree | |||
org.eclipse.jgit.pgm.debug.ShowCommands | |||
org.eclipse.jgit.pgm.debug.ShowDirCache |
@@ -94,6 +94,17 @@ | |||
<version>${project.version}</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.eclipse.jgit</groupId> | |||
<artifactId>org.eclipse.jgit.http.apache</artifactId> | |||
<version>${project.version}</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.apache.httpcomponents</groupId> | |||
<artifactId>httpclient</artifactId> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.slf4j</groupId> | |||
<artifactId>slf4j-api</artifactId> |
@@ -20,6 +20,7 @@ branchAlreadyExists=A branch named ''{0}'' already exists. | |||
branchCreatedFrom=branch: Created from {0} | |||
branchDetachedHEAD=detached HEAD | |||
branchIsNotAnAncestorOfYourCurrentHEAD=The branch ''{0}'' is not an ancestor of your current HEAD.\nIf you are sure you want to delete it, run ''jgit branch -D {0}''. | |||
branchNameRequired=branch name required | |||
branchNotFound=branch ''{0}'' not found. | |||
cacheTreePathInfo="{0}": {1} entries, {2} children | |||
cannotBeRenamed={0} cannot be renamed | |||
@@ -89,7 +90,9 @@ metaVar_author=AUTHOR | |||
metaVar_base=base | |||
metaVar_blameL=START,END | |||
metaVar_blameReverse=START..END | |||
metaVar_branchAndStartPoint=branch [start-name] | |||
metaVar_branchName=branch | |||
metaVar_branchNames=branch ... | |||
metaVar_bucket=BUCKET | |||
metaVar_command=command | |||
metaVar_commandDetail=DETAIL | |||
@@ -109,6 +112,7 @@ metaVar_message=message | |||
metaVar_n=n | |||
metaVar_name=name | |||
metaVar_object=object | |||
metaVar_oldNewBranchNames=[oldbranch] newbranch | |||
metaVar_op=OP | |||
metaVar_pass=PASS | |||
metaVar_path=path | |||
@@ -125,6 +129,7 @@ metaVar_treeish=tree-ish | |||
metaVar_uriish=uri-ish | |||
metaVar_url=URL | |||
metaVar_user=USER | |||
metaVar_values=value ... | |||
metaVar_version=VERSION | |||
mostCommonlyUsedCommandsAre=The most commonly used commands are: | |||
needApprovalToDestroyCurrentRepository=Need approval to destroy current repository | |||
@@ -223,6 +228,7 @@ usage_MergeBase=Find as good common ancestors as possible for a merge | |||
usage_MergesTwoDevelopmentHistories=Merges two development histories | |||
usage_ReadDirCache= Read the DirCache 100 times | |||
usage_RebuildCommitGraph=Recreate a repository from another one's commit graph | |||
usage_RebuildRefTree=Copy references into a RefTree | |||
usage_Remote=Manage set of tracked repositories | |||
usage_RepositoryToReadFrom=Repository to read from | |||
usage_RepositoryToReceiveInto=Repository to receive into | |||
@@ -337,6 +343,7 @@ usage_recordChangesToRepository=Record changes to the repository | |||
usage_recurseIntoSubtrees=recurse into subtrees | |||
usage_renameLimit=limit size of rename matrix | |||
usage_reset=Reset current HEAD to the specified state | |||
usage_resetReference=Reset to given reference name | |||
usage_resetHard=Resets the index and working tree | |||
usage_resetSoft=Resets without touching the index file nor the working tree | |||
usage_resetMixed=Resets the index but not the working tree | |||
@@ -353,6 +360,7 @@ usage_tags=fetch all tags | |||
usage_notags=do not fetch tags | |||
usage_tagMessage=tag message | |||
usage_untrackedFilesMode=show untracked files | |||
usage_updateRef=reference to update | |||
usage_updateRemoteRefsFromAnotherRepository=Update remote refs from another repository | |||
usage_useNameInsteadOfOriginToTrackUpstream=use <name> instead of 'origin' to track upstream | |||
usage_checkoutBranchAfterClone=checkout named branch instead of remotes's HEAD |
@@ -45,7 +45,6 @@ package org.eclipse.jgit.pgm; | |||
import java.io.IOException; | |||
import java.text.MessageFormat; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.LinkedHashMap; | |||
import java.util.List; | |||
@@ -65,15 +64,18 @@ import org.eclipse.jgit.lib.RefUpdate; | |||
import org.eclipse.jgit.lib.RefUpdate.Result; | |||
import org.eclipse.jgit.lib.Repository; | |||
import org.eclipse.jgit.pgm.internal.CLIText; | |||
import org.eclipse.jgit.pgm.opt.CmdLineParser; | |||
import org.eclipse.jgit.pgm.opt.OptionWithValuesListHandler; | |||
import org.eclipse.jgit.revwalk.RevWalk; | |||
import org.kohsuke.args4j.Argument; | |||
import org.kohsuke.args4j.ExampleMode; | |||
import org.kohsuke.args4j.Option; | |||
@Command(common = true, usage = "usage_listCreateOrDeleteBranches") | |||
class Branch extends TextBuiltin { | |||
private String otherBranch; | |||
private boolean createForce; | |||
private boolean rename; | |||
@Option(name = "--remote", aliases = { "-r" }, usage = "usage_actOnRemoteTrackingBranches") | |||
private boolean remote = false; | |||
@@ -83,23 +85,69 @@ class Branch extends TextBuiltin { | |||
@Option(name = "--contains", metaVar = "metaVar_commitish", usage = "usage_printOnlyBranchesThatContainTheCommit") | |||
private String containsCommitish; | |||
@Option(name = "--delete", aliases = { "-d" }, usage = "usage_deleteFullyMergedBranch") | |||
private boolean delete = false; | |||
private List<String> delete; | |||
@Option(name = "--delete-force", aliases = { "-D" }, usage = "usage_deleteBranchEvenIfNotMerged") | |||
private boolean deleteForce = false; | |||
@Option(name = "--delete", aliases = { | |||
"-d" }, metaVar = "metaVar_branchNames", usage = "usage_deleteFullyMergedBranch", handler = OptionWithValuesListHandler.class) | |||
public void delete(List<String> names) { | |||
if (names.isEmpty()) { | |||
throw die(CLIText.get().branchNameRequired); | |||
} | |||
delete = names; | |||
} | |||
@Option(name = "--create-force", aliases = { "-f" }, usage = "usage_forceCreateBranchEvenExists") | |||
private boolean createForce = false; | |||
private List<String> deleteForce; | |||
@Option(name = "-m", usage = "usage_moveRenameABranch") | |||
private boolean rename = false; | |||
@Option(name = "--delete-force", aliases = { | |||
"-D" }, metaVar = "metaVar_branchNames", usage = "usage_deleteBranchEvenIfNotMerged", handler = OptionWithValuesListHandler.class) | |||
public void deleteForce(List<String> names) { | |||
if (names.isEmpty()) { | |||
throw die(CLIText.get().branchNameRequired); | |||
} | |||
deleteForce = names; | |||
} | |||
@Option(name = "--create-force", aliases = { | |||
"-f" }, metaVar = "metaVar_branchAndStartPoint", usage = "usage_forceCreateBranchEvenExists", handler = OptionWithValuesListHandler.class) | |||
public void createForce(List<String> branchAndStartPoint) { | |||
createForce = true; | |||
if (branchAndStartPoint.isEmpty()) { | |||
throw die(CLIText.get().branchNameRequired); | |||
} | |||
if (branchAndStartPoint.size() > 2) { | |||
throw die(CLIText.get().tooManyRefsGiven); | |||
} | |||
if (branchAndStartPoint.size() == 1) { | |||
branch = branchAndStartPoint.get(0); | |||
} else { | |||
branch = branchAndStartPoint.get(0); | |||
otherBranch = branchAndStartPoint.get(1); | |||
} | |||
} | |||
@Option(name = "--move", aliases = { | |||
"-m" }, metaVar = "metaVar_oldNewBranchNames", usage = "usage_moveRenameABranch", handler = OptionWithValuesListHandler.class) | |||
public void moveRename(List<String> currentAndNew) { | |||
rename = true; | |||
if (currentAndNew.isEmpty()) { | |||
throw die(CLIText.get().branchNameRequired); | |||
} | |||
if (currentAndNew.size() > 2) { | |||
throw die(CLIText.get().tooManyRefsGiven); | |||
} | |||
if (currentAndNew.size() == 1) { | |||
branch = currentAndNew.get(0); | |||
} else { | |||
branch = currentAndNew.get(0); | |||
otherBranch = currentAndNew.get(1); | |||
} | |||
} | |||
@Option(name = "--verbose", aliases = { "-v" }, usage = "usage_beVerbose") | |||
private boolean verbose = false; | |||
@Argument | |||
private List<String> branches = new ArrayList<String>(); | |||
@Argument(metaVar = "metaVar_name") | |||
private String branch; | |||
private final Map<String, Ref> printRefs = new LinkedHashMap<String, Ref>(); | |||
@@ -110,30 +158,33 @@ class Branch extends TextBuiltin { | |||
@Override | |||
protected void run() throws Exception { | |||
if (delete || deleteForce) | |||
delete(deleteForce); | |||
else { | |||
if (branches.size() > 2) | |||
throw die(CLIText.get().tooManyRefsGiven + new CmdLineParser(this).printExample(ExampleMode.ALL)); | |||
if (delete != null || deleteForce != null) { | |||
if (delete != null) { | |||
delete(delete, false); | |||
} | |||
if (deleteForce != null) { | |||
delete(deleteForce, true); | |||
} | |||
} else { | |||
if (rename) { | |||
String src, dst; | |||
if (branches.size() == 1) { | |||
if (otherBranch == null) { | |||
final Ref head = db.getRef(Constants.HEAD); | |||
if (head != null && head.isSymbolic()) | |||
if (head != null && head.isSymbolic()) { | |||
src = head.getLeaf().getName(); | |||
else | |||
} else { | |||
throw die(CLIText.get().cannotRenameDetachedHEAD); | |||
dst = branches.get(0); | |||
} | |||
dst = branch; | |||
} else { | |||
src = branches.get(0); | |||
src = branch; | |||
final Ref old = db.getRef(src); | |||
if (old == null) | |||
throw die(MessageFormat.format(CLIText.get().doesNotExist, src)); | |||
if (!old.getName().startsWith(Constants.R_HEADS)) | |||
throw die(MessageFormat.format(CLIText.get().notABranch, src)); | |||
src = old.getName(); | |||
dst = branches.get(1); | |||
dst = otherBranch; | |||
} | |||
if (!dst.startsWith(Constants.R_HEADS)) | |||
@@ -145,13 +196,14 @@ class Branch extends TextBuiltin { | |||
if (r.rename() != Result.RENAMED) | |||
throw die(MessageFormat.format(CLIText.get().cannotBeRenamed, src)); | |||
} else if (branches.size() > 0) { | |||
String newHead = branches.get(0); | |||
} else if (createForce || branch != null) { | |||
String newHead = branch; | |||
String startBranch; | |||
if (branches.size() == 2) | |||
startBranch = branches.get(1); | |||
else | |||
if (createForce) { | |||
startBranch = otherBranch; | |||
} else { | |||
startBranch = Constants.HEAD; | |||
} | |||
Ref startRef = db.getRef(startBranch); | |||
ObjectId startAt = db.resolve(startBranch + "^0"); //$NON-NLS-1$ | |||
if (startRef != null) { | |||
@@ -164,22 +216,27 @@ class Branch extends TextBuiltin { | |||
} | |||
startBranch = Repository.shortenRefName(startBranch); | |||
String newRefName = newHead; | |||
if (!newRefName.startsWith(Constants.R_HEADS)) | |||
if (!newRefName.startsWith(Constants.R_HEADS)) { | |||
newRefName = Constants.R_HEADS + newRefName; | |||
if (!Repository.isValidRefName(newRefName)) | |||
} | |||
if (!Repository.isValidRefName(newRefName)) { | |||
throw die(MessageFormat.format(CLIText.get().notAValidRefName, newRefName)); | |||
if (!createForce && db.resolve(newRefName) != null) | |||
} | |||
if (!createForce && db.resolve(newRefName) != null) { | |||
throw die(MessageFormat.format(CLIText.get().branchAlreadyExists, newHead)); | |||
} | |||
RefUpdate updateRef = db.updateRef(newRefName); | |||
updateRef.setNewObjectId(startAt); | |||
updateRef.setForceUpdate(createForce); | |||
updateRef.setRefLogMessage(MessageFormat.format(CLIText.get().branchCreatedFrom, startBranch), false); | |||
Result update = updateRef.update(); | |||
if (update == Result.REJECTED) | |||
if (update == Result.REJECTED) { | |||
throw die(MessageFormat.format(CLIText.get().couldNotCreateBranch, newHead, update.toString())); | |||
} | |||
} else { | |||
if (verbose) | |||
if (verbose) { | |||
rw = new RevWalk(db); | |||
} | |||
list(); | |||
} | |||
} | |||
@@ -249,7 +306,8 @@ class Branch extends TextBuiltin { | |||
outw.println(); | |||
} | |||
private void delete(boolean force) throws IOException { | |||
private void delete(List<String> branches, boolean force) | |||
throws IOException { | |||
String current = db.getBranch(); | |||
ObjectId head = db.resolve(Constants.HEAD); | |||
for (String branch : branches) { |
@@ -60,7 +60,7 @@ import org.eclipse.jgit.lib.Repository; | |||
import org.eclipse.jgit.pgm.internal.CLIText; | |||
import org.kohsuke.args4j.Argument; | |||
import org.kohsuke.args4j.Option; | |||
import org.kohsuke.args4j.spi.StopOptionHandler; | |||
import org.kohsuke.args4j.spi.RestOfArgumentsHandler; | |||
@Command(common = true, usage = "usage_checkout") | |||
class Checkout extends TextBuiltin { | |||
@@ -74,11 +74,10 @@ class Checkout extends TextBuiltin { | |||
@Option(name = "--orphan", usage = "usage_orphan") | |||
private boolean orphan = false; | |||
@Argument(required = true, index = 0, metaVar = "metaVar_name", usage = "usage_checkout") | |||
@Argument(required = false, index = 0, metaVar = "metaVar_name", usage = "usage_checkout") | |||
private String name; | |||
@Argument(index = 1) | |||
@Option(name = "--", metaVar = "metaVar_paths", multiValued = true, handler = StopOptionHandler.class) | |||
@Option(name = "--", metaVar = "metaVar_paths", multiValued = true, handler = RestOfArgumentsHandler.class) | |||
private List<String> paths = new ArrayList<String>(); | |||
@Override |
@@ -50,6 +50,7 @@ import org.eclipse.jgit.api.CloneCommand; | |||
import org.eclipse.jgit.api.Git; | |||
import org.eclipse.jgit.api.errors.InvalidRemoteException; | |||
import org.eclipse.jgit.lib.Constants; | |||
import org.eclipse.jgit.lib.TextProgressMonitor; | |||
import org.eclipse.jgit.pgm.internal.CLIText; | |||
import org.eclipse.jgit.transport.URIish; | |||
import org.eclipse.jgit.util.SystemReader; | |||
@@ -70,6 +71,9 @@ class Clone extends AbstractFetchCommand { | |||
@Option(name = "--bare", usage = "usage_bareClone") | |||
private boolean isBare; | |||
@Option(name = "--quiet", usage = "usage_quiet") | |||
private Boolean quiet; | |||
@Argument(index = 0, required = true, metaVar = "metaVar_uriish") | |||
private String sourceUri; | |||
@@ -109,10 +113,16 @@ class Clone extends AbstractFetchCommand { | |||
command.setGitDir(gitdir == null ? null : new File(gitdir)); | |||
command.setDirectory(localNameF); | |||
outw.println(MessageFormat.format(CLIText.get().cloningInto, localName)); | |||
boolean msgs = quiet == null || !quiet.booleanValue(); | |||
if (msgs) { | |||
command.setProgressMonitor(new TextProgressMonitor(errw)); | |||
outw.println(MessageFormat.format( | |||
CLIText.get().cloningInto, localName)); | |||
outw.flush(); | |||
} | |||
try { | |||
db = command.call().getRepository(); | |||
if (db.resolve(Constants.HEAD) == null) | |||
if (msgs && db.resolve(Constants.HEAD) == null) | |||
outw.println(CLIText.get().clonedEmptyRepository); | |||
} catch (InvalidRemoteException e) { | |||
throw die(MessageFormat.format(CLIText.get().doesNotExist, | |||
@@ -121,8 +131,9 @@ class Clone extends AbstractFetchCommand { | |||
if (db != null) | |||
db.close(); | |||
} | |||
outw.println(); | |||
outw.flush(); | |||
if (msgs) { | |||
outw.println(); | |||
outw.flush(); | |||
} | |||
} | |||
} |
@@ -86,6 +86,21 @@ public class Die extends RuntimeException { | |||
* @since 3.4 | |||
*/ | |||
public Die(boolean aborted) { | |||
this(aborted, null); | |||
} | |||
/** | |||
* Construct a new exception reflecting the fact that the command execution | |||
* has been aborted before running. | |||
* | |||
* @param aborted | |||
* boolean indicating the fact the execution has been aborted | |||
* @param cause | |||
* can be null | |||
* @since 4.2 | |||
*/ | |||
public Die(boolean aborted, final Throwable cause) { | |||
super(cause != null ? cause.getMessage() : null, cause); | |||
this.aborted = aborted; | |||
} | |||
@@ -62,6 +62,8 @@ import org.eclipse.jgit.lib.RepositoryBuilder; | |||
import org.eclipse.jgit.pgm.internal.CLIText; | |||
import org.eclipse.jgit.pgm.opt.CmdLineParser; | |||
import org.eclipse.jgit.pgm.opt.SubcommandHandler; | |||
import org.eclipse.jgit.transport.HttpTransport; | |||
import org.eclipse.jgit.transport.http.apache.HttpClientConnectionFactory; | |||
import org.eclipse.jgit.util.CachedAuthenticator; | |||
import org.kohsuke.args4j.Argument; | |||
import org.kohsuke.args4j.CmdLineException; | |||
@@ -88,13 +90,23 @@ public class Main { | |||
@Argument(index = 1, metaVar = "metaVar_arg") | |||
private List<String> arguments = new ArrayList<String>(); | |||
PrintWriter writer; | |||
/** | |||
* | |||
*/ | |||
public Main() { | |||
HttpTransport.setConnectionFactory(new HttpClientConnectionFactory()); | |||
} | |||
/** | |||
* Execute the command line. | |||
* | |||
* @param argv | |||
* arguments. | |||
* @throws Exception | |||
*/ | |||
public static void main(final String[] argv) { | |||
public static void main(final String[] argv) throws Exception { | |||
new Main().run(argv); | |||
} | |||
@@ -113,8 +125,10 @@ public class Main { | |||
* | |||
* @param argv | |||
* arguments. | |||
* @throws Exception | |||
*/ | |||
protected void run(final String[] argv) { | |||
protected void run(final String[] argv) throws Exception { | |||
writer = createErrorWriter(); | |||
try { | |||
if (!installConsole()) { | |||
AwtAuthenticator.install(); | |||
@@ -123,12 +137,14 @@ public class Main { | |||
configureHttpProxy(); | |||
execute(argv); | |||
} catch (Die err) { | |||
if (err.isAborted()) | |||
System.exit(1); | |||
System.err.println(MessageFormat.format(CLIText.get().fatalError, err.getMessage())); | |||
if (showStackTrace) | |||
err.printStackTrace(); | |||
System.exit(128); | |||
if (err.isAborted()) { | |||
exit(1, err); | |||
} | |||
writer.println(CLIText.fatalError(err.getMessage())); | |||
if (showStackTrace) { | |||
err.printStackTrace(writer); | |||
} | |||
exit(128, err); | |||
} catch (Exception err) { | |||
// Try to detect errno == EPIPE and exit normally if that happens | |||
// There may be issues with operating system versions and locale, | |||
@@ -136,46 +152,54 @@ public class Main { | |||
// under other circumstances. | |||
if (err.getClass() == IOException.class) { | |||
// Linux, OS X | |||
if (err.getMessage().equals("Broken pipe")) //$NON-NLS-1$ | |||
System.exit(0); | |||
if (err.getMessage().equals("Broken pipe")) { //$NON-NLS-1$ | |||
exit(0, err); | |||
} | |||
// Windows | |||
if (err.getMessage().equals("The pipe is being closed")) //$NON-NLS-1$ | |||
System.exit(0); | |||
if (err.getMessage().equals("The pipe is being closed")) { //$NON-NLS-1$ | |||
exit(0, err); | |||
} | |||
} | |||
if (!showStackTrace && err.getCause() != null | |||
&& err instanceof TransportException) | |||
System.err.println(MessageFormat.format(CLIText.get().fatalError, err.getCause().getMessage())); | |||
&& err instanceof TransportException) { | |||
writer.println(CLIText.fatalError(err.getCause().getMessage())); | |||
} | |||
if (err.getClass().getName().startsWith("org.eclipse.jgit.errors.")) { //$NON-NLS-1$ | |||
System.err.println(MessageFormat.format(CLIText.get().fatalError, err.getMessage())); | |||
if (showStackTrace) | |||
writer.println(CLIText.fatalError(err.getMessage())); | |||
if (showStackTrace) { | |||
err.printStackTrace(); | |||
System.exit(128); | |||
} | |||
exit(128, err); | |||
} | |||
err.printStackTrace(); | |||
System.exit(1); | |||
exit(1, err); | |||
} | |||
if (System.out.checkError()) { | |||
System.err.println(CLIText.get().unknownIoErrorStdout); | |||
System.exit(1); | |||
writer.println(CLIText.get().unknownIoErrorStdout); | |||
exit(1, null); | |||
} | |||
if (System.err.checkError()) { | |||
if (writer.checkError()) { | |||
// No idea how to present an error here, most likely disk full or | |||
// broken pipe | |||
System.exit(1); | |||
exit(1, null); | |||
} | |||
} | |||
PrintWriter createErrorWriter() { | |||
return new PrintWriter(System.err); | |||
} | |||
private void execute(final String[] argv) throws Exception { | |||
final CmdLineParser clp = new CmdLineParser(this); | |||
PrintWriter writer = new PrintWriter(System.err); | |||
final CmdLineParser clp = new SubcommandLineParser(this); | |||
try { | |||
clp.parseArgument(argv); | |||
} catch (CmdLineException err) { | |||
if (argv.length > 0 && !help && !version) { | |||
writer.println(MessageFormat.format(CLIText.get().fatalError, err.getMessage())); | |||
writer.println(CLIText.fatalError(err.getMessage())); | |||
writer.flush(); | |||
System.exit(1); | |||
exit(1, err); | |||
} | |||
} | |||
@@ -191,22 +215,24 @@ public class Main { | |||
writer.println(CLIText.get().mostCommonlyUsedCommandsAre); | |||
final CommandRef[] common = CommandCatalog.common(); | |||
int width = 0; | |||
for (final CommandRef c : common) | |||
for (final CommandRef c : common) { | |||
width = Math.max(width, c.getName().length()); | |||
} | |||
width += 2; | |||
for (final CommandRef c : common) { | |||
writer.print(' '); | |||
writer.print(c.getName()); | |||
for (int i = c.getName().length(); i < width; i++) | |||
for (int i = c.getName().length(); i < width; i++) { | |||
writer.print(' '); | |||
} | |||
writer.print(CLIText.get().resourceBundle().getString(c.getUsage())); | |||
writer.println(); | |||
} | |||
writer.println(); | |||
} | |||
writer.flush(); | |||
System.exit(1); | |||
exit(1, null); | |||
} | |||
if (version) { | |||
@@ -215,20 +241,38 @@ public class Main { | |||
} | |||
final TextBuiltin cmd = subcommand; | |||
if (cmd.requiresRepository()) | |||
cmd.init(openGitDir(gitdir), null); | |||
else | |||
cmd.init(null, gitdir); | |||
init(cmd); | |||
try { | |||
cmd.execute(arguments.toArray(new String[arguments.size()])); | |||
} finally { | |||
if (cmd.outw != null) | |||
if (cmd.outw != null) { | |||
cmd.outw.flush(); | |||
if (cmd.errw != null) | |||
} | |||
if (cmd.errw != null) { | |||
cmd.errw.flush(); | |||
} | |||
} | |||
} | |||
void init(final TextBuiltin cmd) throws IOException { | |||
if (cmd.requiresRepository()) { | |||
cmd.init(openGitDir(gitdir), null); | |||
} else { | |||
cmd.init(null, gitdir); | |||
} | |||
} | |||
/** | |||
* @param status | |||
* @param t | |||
* can be {@code null} | |||
* @throws Exception | |||
*/ | |||
void exit(int status, Exception t) throws Exception { | |||
writer.flush(); | |||
System.exit(status); | |||
} | |||
/** | |||
* Evaluate the {@code --git-dir} option and open the repository. | |||
* | |||
@@ -278,7 +322,7 @@ public class Main { | |||
throws IllegalAccessException, InvocationTargetException, | |||
NoSuchMethodException, ClassNotFoundException { | |||
try { | |||
Class.forName(name).getMethod("install").invoke(null); //$NON-NLS-1$ | |||
Class.forName(name).getMethod("install").invoke(null); //$NON-NLS-1$ | |||
} catch (InvocationTargetException e) { | |||
if (e.getCause() instanceof RuntimeException) | |||
throw (RuntimeException) e.getCause(); | |||
@@ -332,4 +376,19 @@ public class Main { | |||
} | |||
} | |||
} | |||
/** | |||
* Parser for subcommands which doesn't stop parsing on help options and so | |||
* proceeds all specified options | |||
*/ | |||
static class SubcommandLineParser extends CmdLineParser { | |||
public SubcommandLineParser(Object bean) { | |||
super(bean); | |||
} | |||
@Override | |||
protected boolean containsHelp(String... args) { | |||
return false; | |||
} | |||
} | |||
} |
@@ -148,9 +148,12 @@ class Merge extends TextBuiltin { | |||
break; | |||
case FAST_FORWARD: | |||
ObjectId oldHeadId = oldHead.getObjectId(); | |||
outw.println(MessageFormat.format(CLIText.get().updating, oldHeadId | |||
.abbreviate(7).name(), result.getNewHead().abbreviate(7) | |||
.name())); | |||
if (oldHeadId != null) { | |||
String oldId = oldHeadId.abbreviate(7).name(); | |||
String newId = result.getNewHead().abbreviate(7).name(); | |||
outw.println(MessageFormat.format(CLIText.get().updating, oldId, | |||
newId)); | |||
} | |||
outw.println(result.getMergeStatus().toString()); | |||
break; | |||
case CHECKOUT_CONFLICT: |
@@ -144,7 +144,7 @@ class Remote extends TextBuiltin { | |||
} | |||
@Override | |||
public void printUsageAndExit(final String message, final CmdLineParser clp) | |||
public void printUsage(final String message, final CmdLineParser clp) | |||
throws IOException { | |||
errw.println(message); | |||
errw.println("jgit remote [--verbose (-v)] [--help (-h)]"); //$NON-NLS-1$ | |||
@@ -160,7 +160,6 @@ class Remote extends TextBuiltin { | |||
errw.println(); | |||
errw.flush(); | |||
throw die(true); | |||
} | |||
private void print(List<RemoteConfig> remotes) throws IOException { |
@@ -55,7 +55,7 @@ class Repo extends TextBuiltin { | |||
@Option(name = "--groups", aliases = { "-g" }, usage = "usage_groups") | |||
private String groups = "default"; //$NON-NLS-1$ | |||
@Argument(required = true, usage = "usage_pathToXml") | |||
@Argument(required = true, metaVar = "metaVar_path", usage = "usage_pathToXml") | |||
private String path; | |||
@Option(name = "--record-remote-branch", usage = "usage_branches") |
@@ -51,7 +51,7 @@ import org.eclipse.jgit.api.ResetCommand; | |||
import org.eclipse.jgit.api.ResetCommand.ResetType; | |||
import org.kohsuke.args4j.Argument; | |||
import org.kohsuke.args4j.Option; | |||
import org.kohsuke.args4j.spi.StopOptionHandler; | |||
import org.kohsuke.args4j.spi.RestOfArgumentsHandler; | |||
@Command(common = true, usage = "usage_reset") | |||
class Reset extends TextBuiltin { | |||
@@ -65,12 +65,12 @@ class Reset extends TextBuiltin { | |||
@Option(name = "--hard", usage = "usage_resetHard") | |||
private boolean hard = false; | |||
@Argument(required = true, index = 0, metaVar = "metaVar_name", usage = "usage_reset") | |||
@Argument(required = false, index = 0, metaVar = "metaVar_commitish", usage = "usage_resetReference") | |||
private String commit; | |||
@Argument(index = 1) | |||
@Option(name = "--", metaVar = "metaVar_paths", multiValued = true, handler = StopOptionHandler.class) | |||
private List<String> paths = new ArrayList<String>(); | |||
@Argument(required = false, index = 1, metaVar = "metaVar_paths") | |||
@Option(name = "--", metaVar = "metaVar_paths", multiValued = true, handler = RestOfArgumentsHandler.class) | |||
private List<String> paths = new ArrayList<>(); | |||
@Override | |||
protected void run() throws Exception { |
@@ -75,7 +75,13 @@ class RevParse extends TextBuiltin { | |||
if (all) { | |||
Map<String, Ref> allRefs = db.getRefDatabase().getRefs(ALL); | |||
for (final Ref r : allRefs.values()) { | |||
outw.println(r.getObjectId().name()); | |||
ObjectId objectId = r.getObjectId(); | |||
// getRefs skips dangling symrefs, so objectId should never be | |||
// null. | |||
if (objectId == null) { | |||
throw new NullPointerException(); | |||
} | |||
outw.println(objectId.name()); | |||
} | |||
} else { | |||
if (verify && commits.size() > 1) { |
@@ -59,8 +59,9 @@ import org.eclipse.jgit.lib.IndexDiff.StageState; | |||
import org.eclipse.jgit.lib.Ref; | |||
import org.eclipse.jgit.lib.Repository; | |||
import org.eclipse.jgit.pgm.internal.CLIText; | |||
import org.kohsuke.args4j.Argument; | |||
import org.kohsuke.args4j.Option; | |||
import org.kohsuke.args4j.spi.RestOfArgumentsHandler; | |||
import org.eclipse.jgit.pgm.opt.UntrackedFilesHandler; | |||
/** | |||
@@ -83,7 +84,8 @@ class Status extends TextBuiltin { | |||
@Option(name = "--untracked-files", aliases = { "-u", "-uno", "-uall" }, usage = "usage_untrackedFilesMode", handler = UntrackedFilesHandler.class) | |||
protected String untrackedFilesMode = "all"; // default value //$NON-NLS-1$ | |||
@Option(name = "--", metaVar = "metaVar_path", multiValued = true) | |||
@Argument(required = false, index = 0, metaVar = "metaVar_paths") | |||
@Option(name = "--", metaVar = "metaVar_paths", multiValued = true, handler = RestOfArgumentsHandler.class) | |||
protected List<String> filterPaths; | |||
@Override |
@@ -212,17 +212,20 @@ public abstract class TextBuiltin { | |||
*/ | |||
protected void parseArguments(final String[] args) throws IOException { | |||
final CmdLineParser clp = new CmdLineParser(this); | |||
help = containsHelp(args); | |||
try { | |||
clp.parseArgument(args); | |||
} catch (CmdLineException err) { | |||
if (!help) { | |||
this.errw.println(MessageFormat.format(CLIText.get().fatalError, err.getMessage())); | |||
throw die(true); | |||
this.errw.println(CLIText.fatalError(err.getMessage())); | |||
if (help) { | |||
printUsage("", clp); //$NON-NLS-1$ | |||
} | |||
throw die(true, err); | |||
} | |||
if (help) { | |||
printUsageAndExit(clp); | |||
printUsage("", clp); //$NON-NLS-1$ | |||
throw new TerminatedByHelpException(); | |||
} | |||
argWalk = clp.getRevWalkGently(); | |||
@@ -246,6 +249,20 @@ public abstract class TextBuiltin { | |||
* @throws IOException | |||
*/ | |||
public void printUsageAndExit(final String message, final CmdLineParser clp) throws IOException { | |||
printUsage(message, clp); | |||
throw die(true); | |||
} | |||
/** | |||
* @param message | |||
* non null | |||
* @param clp | |||
* parser used to print options | |||
* @throws IOException | |||
* @since 4.2 | |||
*/ | |||
protected void printUsage(final String message, final CmdLineParser clp) | |||
throws IOException { | |||
errw.println(message); | |||
errw.print("jgit "); //$NON-NLS-1$ | |||
errw.print(commandName); | |||
@@ -257,12 +274,19 @@ public abstract class TextBuiltin { | |||
errw.println(); | |||
errw.flush(); | |||
throw die(true); | |||
} | |||
/** | |||
* @return the resource bundle that will be passed to args4j for purpose | |||
* of string localization | |||
* @return error writer, typically this is standard error. | |||
* @since 4.2 | |||
*/ | |||
public ThrowingPrintWriter getErrorWriter() { | |||
return errw; | |||
} | |||
/** | |||
* @return the resource bundle that will be passed to args4j for purpose of | |||
* string localization | |||
*/ | |||
protected ResourceBundle getResourceBundle() { | |||
return CLIText.get().resourceBundle(); | |||
@@ -324,6 +348,19 @@ public abstract class TextBuiltin { | |||
return new Die(aborted); | |||
} | |||
/** | |||
* @param aborted | |||
* boolean indicating that the execution has been aborted before | |||
* running | |||
* @param cause | |||
* why the command has failed. | |||
* @return a runtime exception the caller is expected to throw | |||
* @since 4.2 | |||
*/ | |||
protected static Die die(boolean aborted, final Throwable cause) { | |||
return new Die(aborted, cause); | |||
} | |||
String abbreviateRef(String dst, boolean abbreviateRemote) { | |||
if (dst.startsWith(R_HEADS)) | |||
dst = dst.substring(R_HEADS.length()); | |||
@@ -333,4 +370,36 @@ public abstract class TextBuiltin { | |||
dst = dst.substring(R_REMOTES.length()); | |||
return dst; | |||
} | |||
/** | |||
* @param args | |||
* non null | |||
* @return true if the given array contains help option | |||
* @since 4.2 | |||
*/ | |||
public static boolean containsHelp(String[] args) { | |||
for (String str : args) { | |||
if (str.equals("-h") || str.equals("--help")) { //$NON-NLS-1$ //$NON-NLS-2$ | |||
return true; | |||
} | |||
} | |||
return false; | |||
} | |||
/** | |||
* Exception thrown by {@link TextBuiltin} if it proceeds 'help' option | |||
* | |||
* @since 4.2 | |||
*/ | |||
public static class TerminatedByHelpException extends Die { | |||
private static final long serialVersionUID = 1L; | |||
/** | |||
* Default constructor | |||
*/ | |||
public TerminatedByHelpException() { | |||
super(true); | |||
} | |||
} | |||
} |
@@ -0,0 +1,145 @@ | |||
/* | |||
* Copyright (C) 2015, 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.pgm.debug; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import java.util.Map; | |||
import org.eclipse.jgit.internal.storage.reftree.RefTree; | |||
import org.eclipse.jgit.internal.storage.reftree.RefTreeDatabase; | |||
import org.eclipse.jgit.lib.CommitBuilder; | |||
import org.eclipse.jgit.lib.ObjectId; | |||
import org.eclipse.jgit.lib.ObjectInserter; | |||
import org.eclipse.jgit.lib.ObjectReader; | |||
import org.eclipse.jgit.lib.PersonIdent; | |||
import org.eclipse.jgit.lib.Ref; | |||
import org.eclipse.jgit.lib.RefDatabase; | |||
import org.eclipse.jgit.lib.RefUpdate; | |||
import org.eclipse.jgit.pgm.Command; | |||
import org.eclipse.jgit.pgm.TextBuiltin; | |||
import org.eclipse.jgit.revwalk.RevWalk; | |||
@Command(usage = "usage_RebuildRefTree") | |||
class RebuildRefTree extends TextBuiltin { | |||
private String txnNamespace; | |||
private String txnCommitted; | |||
@Override | |||
protected void run() throws Exception { | |||
try (ObjectReader reader = db.newObjectReader(); | |||
RevWalk rw = new RevWalk(reader); | |||
ObjectInserter inserter = db.newObjectInserter()) { | |||
RefDatabase refDb = db.getRefDatabase(); | |||
if (refDb instanceof RefTreeDatabase) { | |||
RefTreeDatabase d = (RefTreeDatabase) refDb; | |||
refDb = d.getBootstrap(); | |||
txnNamespace = d.getTxnNamespace(); | |||
txnCommitted = d.getTxnCommitted(); | |||
} else { | |||
RefTreeDatabase d = new RefTreeDatabase(db, refDb); | |||
txnNamespace = d.getTxnNamespace(); | |||
txnCommitted = d.getTxnCommitted(); | |||
} | |||
errw.format("Rebuilding %s from %s", //$NON-NLS-1$ | |||
txnCommitted, refDb.getClass().getSimpleName()); | |||
errw.println(); | |||
errw.flush(); | |||
CommitBuilder b = new CommitBuilder(); | |||
Ref ref = refDb.exactRef(txnCommitted); | |||
RefUpdate update = refDb.newUpdate(txnCommitted, true); | |||
ObjectId oldTreeId; | |||
if (ref != null && ref.getObjectId() != null) { | |||
ObjectId oldId = ref.getObjectId(); | |||
update.setExpectedOldObjectId(oldId); | |||
b.setParentId(oldId); | |||
oldTreeId = rw.parseCommit(oldId).getTree(); | |||
} else { | |||
update.setExpectedOldObjectId(ObjectId.zeroId()); | |||
oldTreeId = ObjectId.zeroId(); | |||
} | |||
RefTree tree = rebuild(refDb.getRefs(RefDatabase.ALL)); | |||
b.setTreeId(tree.writeTree(inserter)); | |||
b.setAuthor(new PersonIdent(db)); | |||
b.setCommitter(b.getAuthor()); | |||
if (b.getTreeId().equals(oldTreeId)) { | |||
return; | |||
} | |||
update.setNewObjectId(inserter.insert(b)); | |||
inserter.flush(); | |||
RefUpdate.Result result = update.update(rw); | |||
switch (result) { | |||
case NEW: | |||
case FAST_FORWARD: | |||
break; | |||
default: | |||
throw die(String.format("%s: %s", update.getName(), result)); //$NON-NLS-1$ | |||
} | |||
} | |||
} | |||
private RefTree rebuild(Map<String, Ref> refMap) { | |||
RefTree tree = RefTree.newEmptyTree(); | |||
List<org.eclipse.jgit.internal.storage.reftree.Command> cmds | |||
= new ArrayList<>(); | |||
for (Ref r : refMap.values()) { | |||
if (r.getName().equals(txnCommitted) | |||
|| r.getName().startsWith(txnNamespace)) { | |||
continue; | |||
} | |||
cmds.add(new org.eclipse.jgit.internal.storage.reftree.Command( | |||
null, | |||
db.peel(r))); | |||
} | |||
tree.apply(cmds); | |||
return tree; | |||
} | |||
} |
@@ -74,6 +74,19 @@ public class CLIText extends TranslationBundle { | |||
return MessageFormat.format(get().lineFormat, line); | |||
} | |||
/** | |||
* Format the given argument as fatal error using the format defined by | |||
* {@link #fatalError} ("fatal: " by default). | |||
* | |||
* @param message | |||
* the message to format | |||
* @return the formatted line | |||
* @since 4.2 | |||
*/ | |||
public static String fatalError(String message) { | |||
return MessageFormat.format(get().fatalError, message); | |||
} | |||
// @formatter:off | |||
/***/ public String alreadyOnBranch; | |||
/***/ public String alreadyUpToDate; | |||
@@ -85,6 +98,7 @@ public class CLIText extends TranslationBundle { | |||
/***/ public String branchCreatedFrom; | |||
/***/ public String branchDetachedHEAD; | |||
/***/ public String branchIsNotAnAncestorOfYourCurrentHEAD; | |||
/***/ public String branchNameRequired; | |||
/***/ public String branchNotFound; | |||
/***/ public String cacheTreePathInfo; | |||
/***/ public String configFileNotFound; | |||
@@ -184,6 +198,7 @@ public class CLIText extends TranslationBundle { | |||
/***/ public String metaVar_uriish; | |||
/***/ public String metaVar_url; | |||
/***/ public String metaVar_user; | |||
/***/ public String metaVar_values; | |||
/***/ public String metaVar_version; | |||
/***/ public String mostCommonlyUsedCommandsAre; | |||
/***/ public String needApprovalToDestroyCurrentRepository; |
@@ -43,19 +43,18 @@ | |||
package org.eclipse.jgit.pgm.opt; | |||
import java.io.IOException; | |||
import java.io.Writer; | |||
import java.lang.reflect.Field; | |||
import java.util.ArrayList; | |||
import java.util.Collections; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.ResourceBundle; | |||
import org.kohsuke.args4j.Argument; | |||
import org.kohsuke.args4j.CmdLineException; | |||
import org.kohsuke.args4j.IllegalAnnotationError; | |||
import org.kohsuke.args4j.NamedOptionDef; | |||
import org.kohsuke.args4j.Option; | |||
import org.kohsuke.args4j.OptionDef; | |||
import org.kohsuke.args4j.spi.OptionHandler; | |||
import org.kohsuke.args4j.spi.Setter; | |||
import org.eclipse.jgit.lib.ObjectId; | |||
import org.eclipse.jgit.lib.Repository; | |||
import org.eclipse.jgit.pgm.Die; | |||
import org.eclipse.jgit.pgm.TextBuiltin; | |||
import org.eclipse.jgit.pgm.internal.CLIText; | |||
import org.eclipse.jgit.revwalk.RevCommit; | |||
@@ -63,6 +62,15 @@ import org.eclipse.jgit.revwalk.RevTree; | |||
import org.eclipse.jgit.revwalk.RevWalk; | |||
import org.eclipse.jgit.transport.RefSpec; | |||
import org.eclipse.jgit.treewalk.AbstractTreeIterator; | |||
import org.kohsuke.args4j.Argument; | |||
import org.kohsuke.args4j.CmdLineException; | |||
import org.kohsuke.args4j.IllegalAnnotationError; | |||
import org.kohsuke.args4j.NamedOptionDef; | |||
import org.kohsuke.args4j.Option; | |||
import org.kohsuke.args4j.OptionDef; | |||
import org.kohsuke.args4j.spi.OptionHandler; | |||
import org.kohsuke.args4j.spi.RestOfArgumentsHandler; | |||
import org.kohsuke.args4j.spi.Setter; | |||
/** | |||
* Extended command line parser which handles --foo=value arguments. | |||
@@ -80,12 +88,17 @@ public class CmdLineParser extends org.kohsuke.args4j.CmdLineParser { | |||
registerHandler(RefSpec.class, RefSpecHandler.class); | |||
registerHandler(RevCommit.class, RevCommitHandler.class); | |||
registerHandler(RevTree.class, RevTreeHandler.class); | |||
registerHandler(List.class, OptionWithValuesListHandler.class); | |||
} | |||
private final Repository db; | |||
private RevWalk walk; | |||
private boolean seenHelp; | |||
private TextBuiltin cmd; | |||
/** | |||
* Creates a new command line owner that parses arguments/options and set | |||
* them into the given object. | |||
@@ -117,8 +130,12 @@ public class CmdLineParser extends org.kohsuke.args4j.CmdLineParser { | |||
*/ | |||
public CmdLineParser(final Object bean, Repository repo) { | |||
super(bean); | |||
if (repo == null && bean instanceof TextBuiltin) | |||
repo = ((TextBuiltin) bean).getRepository(); | |||
if (bean instanceof TextBuiltin) { | |||
cmd = (TextBuiltin) bean; | |||
} | |||
if (repo == null && cmd != null) { | |||
repo = cmd.getRepository(); | |||
} | |||
this.db = repo; | |||
} | |||
@@ -143,9 +160,75 @@ public class CmdLineParser extends org.kohsuke.args4j.CmdLineParser { | |||
} | |||
tmp.add(str); | |||
if (containsHelp(args)) { | |||
// suppress exceptions on required parameters if help is present | |||
seenHelp = true; | |||
// stop argument parsing here | |||
break; | |||
} | |||
} | |||
List<OptionHandler> backup = null; | |||
if (seenHelp) { | |||
backup = unsetRequiredOptions(); | |||
} | |||
super.parseArgument(tmp.toArray(new String[tmp.size()])); | |||
try { | |||
super.parseArgument(tmp.toArray(new String[tmp.size()])); | |||
} catch (Die e) { | |||
if (!seenHelp) { | |||
throw e; | |||
} | |||
printToErrorWriter(CLIText.fatalError(e.getMessage())); | |||
} finally { | |||
// reset "required" options to defaults for correct command printout | |||
if (backup != null && !backup.isEmpty()) { | |||
restoreRequiredOptions(backup); | |||
} | |||
seenHelp = false; | |||
} | |||
} | |||
private void printToErrorWriter(String error) { | |||
if (cmd == null) { | |||
System.err.println(error); | |||
} else { | |||
try { | |||
cmd.getErrorWriter().println(error); | |||
} catch (IOException e1) { | |||
System.err.println(error); | |||
} | |||
} | |||
} | |||
private List<OptionHandler> unsetRequiredOptions() { | |||
List<OptionHandler> options = getOptions(); | |||
List<OptionHandler> backup = new ArrayList<>(options); | |||
for (Iterator<OptionHandler> iterator = options.iterator(); iterator | |||
.hasNext();) { | |||
OptionHandler handler = iterator.next(); | |||
if (handler.option instanceof NamedOptionDef | |||
&& handler.option.required()) { | |||
iterator.remove(); | |||
} | |||
} | |||
return backup; | |||
} | |||
private void restoreRequiredOptions(List<OptionHandler> backup) { | |||
List<OptionHandler> options = getOptions(); | |||
options.clear(); | |||
options.addAll(backup); | |||
} | |||
/** | |||
* @param args | |||
* non null | |||
* @return true if the given array contains help option | |||
* @since 4.2 | |||
*/ | |||
protected boolean containsHelp(final String... args) { | |||
return TextBuiltin.containsHelp(args); | |||
} | |||
/** | |||
@@ -181,7 +264,7 @@ public class CmdLineParser extends org.kohsuke.args4j.CmdLineParser { | |||
return walk; | |||
} | |||
static class MyOptionDef extends OptionDef { | |||
class MyOptionDef extends OptionDef { | |||
public MyOptionDef(OptionDef o) { | |||
super(o.usage(), o.metaVar(), o.required(), o.handler(), o | |||
@@ -201,6 +284,11 @@ public class CmdLineParser extends org.kohsuke.args4j.CmdLineParser { | |||
return metaVar(); | |||
} | |||
} | |||
@Override | |||
public boolean required() { | |||
return seenHelp ? false : super.required(); | |||
} | |||
} | |||
@Override | |||
@@ -211,4 +299,55 @@ public class CmdLineParser extends org.kohsuke.args4j.CmdLineParser { | |||
return super.createOptionHandler(new MyOptionDef(o), setter); | |||
} | |||
@SuppressWarnings("unchecked") | |||
private List<OptionHandler> getOptions() { | |||
List<OptionHandler> options = null; | |||
try { | |||
Field field = org.kohsuke.args4j.CmdLineParser.class | |||
.getDeclaredField("options"); //$NON-NLS-1$ | |||
field.setAccessible(true); | |||
options = (List<OptionHandler>) field.get(this); | |||
} catch (NoSuchFieldException | SecurityException | |||
| IllegalArgumentException | IllegalAccessException e) { | |||
// ignore | |||
} | |||
if (options == null) { | |||
return Collections.emptyList(); | |||
} | |||
return options; | |||
} | |||
@Override | |||
public void printSingleLineUsage(Writer w, ResourceBundle rb) { | |||
List<OptionHandler> options = getOptions(); | |||
if (options.isEmpty()) { | |||
super.printSingleLineUsage(w, rb); | |||
return; | |||
} | |||
List<OptionHandler> backup = new ArrayList<>(options); | |||
boolean changed = sortRestOfArgumentsHandlerToTheEnd(options); | |||
try { | |||
super.printSingleLineUsage(w, rb); | |||
} finally { | |||
if (changed) { | |||
options.clear(); | |||
options.addAll(backup); | |||
} | |||
} | |||
} | |||
private boolean sortRestOfArgumentsHandlerToTheEnd( | |||
List<OptionHandler> options) { | |||
for (int i = 0; i < options.size(); i++) { | |||
OptionHandler handler = options.get(i); | |||
if (handler instanceof RestOfArgumentsHandler | |||
|| handler instanceof PathTreeFilterHandler) { | |||
options.remove(i); | |||
options.add(handler); | |||
return true; | |||
} | |||
} | |||
return false; | |||
} | |||
} |
@@ -0,0 +1,52 @@ | |||
package org.eclipse.jgit.pgm.opt; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import org.eclipse.jgit.pgm.internal.CLIText; | |||
import org.kohsuke.args4j.CmdLineException; | |||
import org.kohsuke.args4j.CmdLineParser; | |||
import org.kohsuke.args4j.OptionDef; | |||
import org.kohsuke.args4j.spi.OptionHandler; | |||
import org.kohsuke.args4j.spi.Parameters; | |||
import org.kohsuke.args4j.spi.Setter; | |||
/** | |||
* Handler which allows to parse option with few values | |||
* | |||
* @since 4.2 | |||
*/ | |||
public class OptionWithValuesListHandler extends OptionHandler<List<?>> { | |||
/** | |||
* @param parser | |||
* @param option | |||
* @param setter | |||
*/ | |||
public OptionWithValuesListHandler(CmdLineParser parser, | |||
OptionDef option, Setter<List<?>> setter) { | |||
super(parser, option, setter); | |||
} | |||
@Override | |||
public int parseArguments(Parameters params) throws CmdLineException { | |||
final List<String> list = new ArrayList<>(); | |||
for (int idx = 0; idx < params.size(); idx++) { | |||
final String p; | |||
try { | |||
p = params.getParameter(idx); | |||
} catch (CmdLineException cle) { | |||
break; | |||
} | |||
list.add(p); | |||
} | |||
setter.addValue(list); | |||
return list.size(); | |||
} | |||
@Override | |||
public String getDefaultMetaVariable() { | |||
return CLIText.get().metaVar_values; | |||
} | |||
} |
@@ -0,0 +1,95 @@ | |||
PKG = 'tst/org/eclipse/jgit/' | |||
HELPERS = glob(['src/**/*.java']) + [PKG + c for c in [ | |||
'api/AbstractRemoteCommandTest.java', | |||
'diff/AbstractDiffTestCase.java', | |||
'internal/storage/file/GcTestCase.java', | |||
'internal/storage/file/PackIndexTestCase.java', | |||
'internal/storage/file/XInputStream.java', | |||
'nls/GermanTranslatedBundle.java', | |||
'nls/MissingPropertyBundle.java', | |||
'nls/NoPropertiesBundle.java', | |||
'nls/NonTranslatedBundle.java', | |||
'revwalk/RevQueueTestCase.java', | |||
'revwalk/RevWalkTestCase.java', | |||
'transport/SpiTransport.java', | |||
'treewalk/FileTreeIteratorWithTimeControl.java', | |||
'treewalk/filter/AlwaysCloneTreeFilter.java', | |||
'test/resources/SampleDataRepositoryTestCase.java', | |||
'util/CPUTimeStopWatch.java', | |||
'util/io/Strings.java', | |||
]] | |||
DATA = [ | |||
PKG + 'lib/empty.gitindex.dat', | |||
PKG + 'lib/sorttest.gitindex.dat', | |||
] | |||
TESTS = glob( | |||
['tst/**/*.java'], | |||
excludes = HELPERS + DATA, | |||
) | |||
DEPS = { | |||
PKG + 'nls/RootLocaleTest.java': [ | |||
'//org.eclipse.jgit.pgm:pgm', | |||
'//org.eclipse.jgit.ui:ui', | |||
], | |||
} | |||
for src in TESTS: | |||
name = src[len('tst/'):len(src)-len('.java')].replace('/', '.') | |||
labels = [] | |||
if name.startswith('org.eclipse.jgit.'): | |||
l = name[len('org.eclipse.jgit.'):] | |||
if l.startswith('internal.storage.'): | |||
l = l[len('internal.storage.'):] | |||
i = l.find('.') | |||
if i > 0: | |||
labels.append(l[:i]) | |||
else: | |||
labels.append(i) | |||
if 'lib' not in labels: | |||
labels.append('lib') | |||
java_test( | |||
name = name, | |||
labels = labels, | |||
srcs = [src], | |||
deps = [ | |||
':helpers', | |||
':tst_rsrc', | |||
'//org.eclipse.jgit:jgit', | |||
'//org.eclipse.jgit.junit:junit', | |||
'//lib:hamcrest-core', | |||
'//lib:hamcrest-library', | |||
'//lib:javaewah', | |||
'//lib:junit', | |||
'//lib:slf4j-api', | |||
'//lib:slf4j-simple', | |||
] + DEPS.get(src, []), | |||
source_under_test = ['//org.eclipse.jgit:jgit'], | |||
vm_args = ['-Xmx256m', '-Dfile.encoding=UTF-8'], | |||
) | |||
java_library( | |||
name = 'helpers', | |||
srcs = HELPERS, | |||
resources = DATA, | |||
deps = [ | |||
'//org.eclipse.jgit:jgit', | |||
'//org.eclipse.jgit.junit:junit', | |||
'//lib:junit', | |||
], | |||
) | |||
prebuilt_jar( | |||
name = 'tst_rsrc', | |||
binary_jar = ':tst_rsrc_jar', | |||
) | |||
genrule( | |||
name = 'tst_rsrc_jar', | |||
cmd = 'cd $SRCDIR/tst-rsrc ; zip -qr $OUT .', | |||
srcs = glob(['tst-rsrc/**']), | |||
out = 'tst_rsrc.jar', | |||
) |
@@ -26,6 +26,7 @@ Import-Package: com.googlecode.javaewah;version="[0.7.9,0.8.0)", | |||
org.eclipse.jgit.internal.storage.dfs;version="[4.2.0,4.3.0)", | |||
org.eclipse.jgit.internal.storage.file;version="[4.2.0,4.3.0)", | |||
org.eclipse.jgit.internal.storage.pack;version="[4.2.0,4.3.0)", | |||
org.eclipse.jgit.internal.storage.reftree;version="[4.2.0,4.3.0)", | |||
org.eclipse.jgit.junit;version="[4.2.0,4.3.0)", | |||
org.eclipse.jgit.lib;version="[4.2.0,4.3.0)", | |||
org.eclipse.jgit.merge;version="[4.2.0,4.3.0)", |
@@ -0,0 +1,31 @@ | |||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||
<launchConfiguration type="org.eclipse.jdt.junit.launchconfig"> | |||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS"> | |||
<listEntry value="/org.eclipse.jgit.test/tst"/> | |||
</listAttribute> | |||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES"> | |||
<listEntry value="2"/> | |||
</listAttribute> | |||
<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/> | |||
<mapAttribute key="org.eclipse.debug.core.environmentVariables"> | |||
<mapEntry key="LANG" value="de_DE.UTF-8"/> | |||
</mapAttribute> | |||
<listAttribute key="org.eclipse.debug.ui.favoriteGroups"> | |||
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/> | |||
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/> | |||
</listAttribute> | |||
<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=org.eclipse.jgit.test/tst"/> | |||
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/> | |||
<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/> | |||
<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/> | |||
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/> | |||
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH"> | |||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6" path="1" type="4"/> "/> | |||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="org.eclipse.jgit.test"/> </runtimeClasspathEntry> "/> | |||
</listAttribute> | |||
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/> | |||
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> | |||
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/> | |||
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.jgit.test"/> | |||
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx256m"/> | |||
</launchConfiguration> |
@@ -43,6 +43,7 @@ | |||
*/ | |||
package org.eclipse.jgit.api; | |||
import static org.eclipse.jgit.util.FileUtils.RECURSIVE; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertNotNull; | |||
import static org.junit.Assert.assertTrue; | |||
@@ -797,13 +798,108 @@ public class AddCommandTest extends RepositoryTestCase { | |||
assertEquals("[a.txt, mode:100644, content:more content," | |||
+ " assume-unchanged:false][b.txt, mode:100644," | |||
+ "" + "" | |||
+ " content:content, assume-unchanged:true]", | |||
indexState(CONTENT | |||
| ASSUME_UNCHANGED)); | |||
} | |||
} | |||
@Test | |||
public void testReplaceFileWithDirectory() | |||
throws IOException, NoFilepatternException, GitAPIException { | |||
try (Git git = new Git(db)) { | |||
writeTrashFile("df", "before replacement"); | |||
git.add().addFilepattern("df").call(); | |||
assertEquals("[df, mode:100644, content:before replacement]", | |||
indexState(CONTENT)); | |||
FileUtils.delete(new File(db.getWorkTree(), "df")); | |||
writeTrashFile("df/f", "after replacement"); | |||
git.add().addFilepattern("df").call(); | |||
assertEquals("[df/f, mode:100644, content:after replacement]", | |||
indexState(CONTENT)); | |||
} | |||
} | |||
@Test | |||
public void testReplaceDirectoryWithFile() | |||
throws IOException, NoFilepatternException, GitAPIException { | |||
try (Git git = new Git(db)) { | |||
writeTrashFile("df/f", "before replacement"); | |||
git.add().addFilepattern("df").call(); | |||
assertEquals("[df/f, mode:100644, content:before replacement]", | |||
indexState(CONTENT)); | |||
FileUtils.delete(new File(db.getWorkTree(), "df"), RECURSIVE); | |||
writeTrashFile("df", "after replacement"); | |||
git.add().addFilepattern("df").call(); | |||
assertEquals("[df, mode:100644, content:after replacement]", | |||
indexState(CONTENT)); | |||
} | |||
} | |||
@Test | |||
public void testReplaceFileByPartOfDirectory() | |||
throws IOException, NoFilepatternException, GitAPIException { | |||
try (Git git = new Git(db)) { | |||
writeTrashFile("src/main", "df", "before replacement"); | |||
writeTrashFile("src/main", "z", "z"); | |||
writeTrashFile("z", "z2"); | |||
git.add().addFilepattern("src/main/df") | |||
.addFilepattern("src/main/z") | |||
.addFilepattern("z") | |||
.call(); | |||
assertEquals( | |||
"[src/main/df, mode:100644, content:before replacement]" + | |||
"[src/main/z, mode:100644, content:z]" + | |||
"[z, mode:100644, content:z2]", | |||
indexState(CONTENT)); | |||
FileUtils.delete(new File(db.getWorkTree(), "src/main/df")); | |||
writeTrashFile("src/main/df", "a", "after replacement"); | |||
writeTrashFile("src/main/df", "b", "unrelated file"); | |||
git.add().addFilepattern("src/main/df/a").call(); | |||
assertEquals( | |||
"[src/main/df/a, mode:100644, content:after replacement]" + | |||
"[src/main/z, mode:100644, content:z]" + | |||
"[z, mode:100644, content:z2]", | |||
indexState(CONTENT)); | |||
} | |||
} | |||
@Test | |||
public void testReplaceDirectoryConflictsWithFile() | |||
throws IOException, NoFilepatternException, GitAPIException { | |||
DirCache dc = db.lockDirCache(); | |||
try (ObjectInserter oi = db.newObjectInserter()) { | |||
DirCacheBuilder builder = dc.builder(); | |||
File f = writeTrashFile("a", "df", "content"); | |||
addEntryToBuilder("a", f, oi, builder, 1); | |||
f = writeTrashFile("a", "df", "other content"); | |||
addEntryToBuilder("a/df", f, oi, builder, 3); | |||
f = writeTrashFile("a", "df", "our content"); | |||
addEntryToBuilder("a/df", f, oi, builder, 2); | |||
f = writeTrashFile("z", "z"); | |||
addEntryToBuilder("z", f, oi, builder, 0); | |||
builder.commit(); | |||
} | |||
assertEquals( | |||
"[a, mode:100644, stage:1, content:content]" + | |||
"[a/df, mode:100644, stage:2, content:our content]" + | |||
"[a/df, mode:100644, stage:3, content:other content]" + | |||
"[z, mode:100644, content:z]", | |||
indexState(CONTENT)); | |||
try (Git git = new Git(db)) { | |||
FileUtils.delete(new File(db.getWorkTree(), "a"), RECURSIVE); | |||
writeTrashFile("a", "merged"); | |||
git.add().addFilepattern("a").call(); | |||
assertEquals("[a, mode:100644, content:merged]" + | |||
"[z, mode:100644, content:z]", | |||
indexState(CONTENT)); | |||
} | |||
} | |||
@Test | |||
public void testExecutableRetention() throws Exception { | |||
StoredConfig config = db.getConfig(); |
@@ -46,12 +46,15 @@ import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertNotNull; | |||
import static org.junit.Assert.assertNull; | |||
import static org.junit.Assert.assertTrue; | |||
import static org.junit.Assert.assertNotEquals; | |||
import static org.junit.Assert.fail; | |||
import java.io.File; | |||
import java.util.Date; | |||
import java.util.List; | |||
import java.util.TimeZone; | |||
import org.eclipse.jgit.api.errors.EmtpyCommitException; | |||
import org.eclipse.jgit.api.errors.WrongRepositoryStateException; | |||
import org.eclipse.jgit.diff.DiffEntry; | |||
import org.eclipse.jgit.dircache.DirCache; | |||
@@ -476,6 +479,34 @@ public class CommitCommandTest extends RepositoryTestCase { | |||
assertEquals("newauthor@example.org", amendedAuthor.getEmailAddress()); | |||
} | |||
@Test | |||
public void commitEmptyCommits() throws Exception { | |||
try (Git git = new Git(db)) { | |||
writeTrashFile("file1", "file1"); | |||
git.add().addFilepattern("file1").call(); | |||
RevCommit initial = git.commit().setMessage("initial commit") | |||
.call(); | |||
RevCommit emptyFollowUp = git.commit() | |||
.setAuthor("New Author", "newauthor@example.org") | |||
.setMessage("no change").call(); | |||
assertNotEquals(initial.getId(), emptyFollowUp.getId()); | |||
assertEquals(initial.getTree().getId(), | |||
emptyFollowUp.getTree().getId()); | |||
try { | |||
git.commit().setAuthor("New Author", "newauthor@example.org") | |||
.setMessage("again no change").setAllowEmpty(false) | |||
.call(); | |||
fail("Didn't get the expected EmtpyCommitException"); | |||
} catch (EmtpyCommitException e) { | |||
// expect this exception | |||
} | |||
} | |||
} | |||
@Test | |||
public void commitOnlyShouldCommitUnmergedPathAndNotAffectOthers() | |||
throws Exception { |
@@ -43,10 +43,12 @@ | |||
package org.eclipse.jgit.api; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertFalse; | |||
import static org.junit.Assert.assertTrue; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.nio.file.Path; | |||
import org.eclipse.jgit.api.CheckoutCommand.Stage; | |||
import org.eclipse.jgit.api.errors.JGitInternalException; | |||
@@ -59,6 +61,9 @@ import org.eclipse.jgit.lib.ObjectReader; | |||
import org.eclipse.jgit.lib.RepositoryState; | |||
import org.eclipse.jgit.lib.StoredConfig; | |||
import org.eclipse.jgit.revwalk.RevCommit; | |||
import org.eclipse.jgit.util.FS; | |||
import org.eclipse.jgit.util.FileUtils; | |||
import org.junit.Assume; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
@@ -73,6 +78,8 @@ public class PathCheckoutCommandTest extends RepositoryTestCase { | |||
private static final String FILE3 = "Test3.txt"; | |||
private static final String LINK = "link"; | |||
Git git; | |||
RevCommit initialCommit; | |||
@@ -98,6 +105,64 @@ public class PathCheckoutCommandTest extends RepositoryTestCase { | |||
git.commit().setMessage("Third commit").call(); | |||
} | |||
@Test | |||
public void testUpdateSymLink() throws Exception { | |||
Assume.assumeTrue(FS.DETECTED.supportsSymlinks()); | |||
Path path = writeLink(LINK, FILE1); | |||
git.add().addFilepattern(LINK).call(); | |||
git.commit().setMessage("Added link").call(); | |||
assertEquals("3", read(path.toFile())); | |||
writeLink(LINK, FILE2); | |||
assertEquals("c", read(path.toFile())); | |||
CheckoutCommand co = git.checkout(); | |||
co.addPath(LINK).call(); | |||
assertEquals("3", read(path.toFile())); | |||
} | |||
@Test | |||
public void testUpdateBrokenSymLinkToDirectory() throws Exception { | |||
Assume.assumeTrue(FS.DETECTED.supportsSymlinks()); | |||
Path path = writeLink(LINK, "f"); | |||
git.add().addFilepattern(LINK).call(); | |||
git.commit().setMessage("Added link").call(); | |||
assertEquals("f", FileUtils.readSymLink(path.toFile())); | |||
assertTrue(path.toFile().exists()); | |||
writeLink(LINK, "link_to_nowhere"); | |||
assertFalse(path.toFile().exists()); | |||
assertEquals("link_to_nowhere", FileUtils.readSymLink(path.toFile())); | |||
CheckoutCommand co = git.checkout(); | |||
co.addPath(LINK).call(); | |||
assertEquals("f", FileUtils.readSymLink(path.toFile())); | |||
} | |||
@Test | |||
public void testUpdateBrokenSymLink() throws Exception { | |||
Assume.assumeTrue(FS.DETECTED.supportsSymlinks()); | |||
Path path = writeLink(LINK, FILE1); | |||
git.add().addFilepattern(LINK).call(); | |||
git.commit().setMessage("Added link").call(); | |||
assertEquals("3", read(path.toFile())); | |||
assertEquals(FILE1, FileUtils.readSymLink(path.toFile())); | |||
writeLink(LINK, "link_to_nowhere"); | |||
assertFalse(path.toFile().exists()); | |||
assertEquals("link_to_nowhere", FileUtils.readSymLink(path.toFile())); | |||
CheckoutCommand co = git.checkout(); | |||
co.addPath(LINK).call(); | |||
assertEquals("3", read(path.toFile())); | |||
} | |||
@Test | |||
public void testUpdateWorkingDirectory() throws Exception { | |||
CheckoutCommand co = git.checkout(); |
@@ -65,6 +65,7 @@ import org.eclipse.jgit.junit.RepositoryTestCase; | |||
import org.eclipse.jgit.lib.Constants; | |||
import org.eclipse.jgit.lib.FileMode; | |||
import org.eclipse.jgit.lib.ObjectId; | |||
import org.eclipse.jgit.lib.Ref; | |||
import org.eclipse.jgit.revwalk.RevCommit; | |||
import org.eclipse.jgit.revwalk.RevWalk; | |||
import org.eclipse.jgit.treewalk.TreeWalk; | |||
@@ -139,8 +140,8 @@ public class ResetCommandTest extends RepositoryTestCase { | |||
AmbiguousObjectException, IOException, GitAPIException { | |||
setupRepository(); | |||
ObjectId prevHead = db.resolve(Constants.HEAD); | |||
git.reset().setMode(ResetType.HARD).setRef(initialCommit.getName()) | |||
.call(); | |||
assertSameAsHead(git.reset().setMode(ResetType.HARD) | |||
.setRef(initialCommit.getName()).call()); | |||
// check if HEAD points to initial commit now | |||
ObjectId head = db.resolve(Constants.HEAD); | |||
assertEquals(initialCommit, head); | |||
@@ -176,8 +177,8 @@ public class ResetCommandTest extends RepositoryTestCase { | |||
AmbiguousObjectException, IOException, GitAPIException { | |||
setupRepository(); | |||
ObjectId prevHead = db.resolve(Constants.HEAD); | |||
git.reset().setMode(ResetType.SOFT).setRef(initialCommit.getName()) | |||
.call(); | |||
assertSameAsHead(git.reset().setMode(ResetType.SOFT) | |||
.setRef(initialCommit.getName()).call()); | |||
// check if HEAD points to initial commit now | |||
ObjectId head = db.resolve(Constants.HEAD); | |||
assertEquals(initialCommit, head); | |||
@@ -197,8 +198,8 @@ public class ResetCommandTest extends RepositoryTestCase { | |||
AmbiguousObjectException, IOException, GitAPIException { | |||
setupRepository(); | |||
ObjectId prevHead = db.resolve(Constants.HEAD); | |||
git.reset().setMode(ResetType.MIXED).setRef(initialCommit.getName()) | |||
.call(); | |||
assertSameAsHead(git.reset().setMode(ResetType.MIXED) | |||
.setRef(initialCommit.getName()).call()); | |||
// check if HEAD points to initial commit now | |||
ObjectId head = db.resolve(Constants.HEAD); | |||
assertEquals(initialCommit, head); | |||
@@ -241,7 +242,8 @@ public class ResetCommandTest extends RepositoryTestCase { | |||
assertTrue(bEntry.getLength() > 0); | |||
assertTrue(bEntry.getLastModified() > 0); | |||
git.reset().setMode(ResetType.MIXED).setRef(commit2.getName()).call(); | |||
assertSameAsHead(git.reset().setMode(ResetType.MIXED) | |||
.setRef(commit2.getName()).call()); | |||
cache = db.readDirCache(); | |||
@@ -280,7 +282,7 @@ public class ResetCommandTest extends RepositoryTestCase { | |||
+ "[a.txt, mode:100644, stage:3]", | |||
indexState(0)); | |||
git.reset().setMode(ResetType.MIXED).call(); | |||
assertSameAsHead(git.reset().setMode(ResetType.MIXED).call()); | |||
assertEquals("[a.txt, mode:100644]" + "[b.txt, mode:100644]", | |||
indexState(0)); | |||
@@ -298,8 +300,8 @@ public class ResetCommandTest extends RepositoryTestCase { | |||
// 'a.txt' has already been modified in setupRepository | |||
// 'notAddedToIndex.txt' has been added to repository | |||
git.reset().addPath(indexFile.getName()) | |||
.addPath(untrackedFile.getName()).call(); | |||
assertSameAsHead(git.reset().addPath(indexFile.getName()) | |||
.addPath(untrackedFile.getName()).call()); | |||
DirCacheEntry postReset = DirCache.read(db.getIndexFile(), db.getFS()) | |||
.getEntry(indexFile.getName()); | |||
@@ -329,7 +331,7 @@ public class ResetCommandTest extends RepositoryTestCase { | |||
git.add().addFilepattern(untrackedFile.getName()).call(); | |||
// 'dir/b.txt' has already been modified in setupRepository | |||
git.reset().addPath("dir").call(); | |||
assertSameAsHead(git.reset().addPath("dir").call()); | |||
DirCacheEntry postReset = DirCache.read(db.getIndexFile(), db.getFS()) | |||
.getEntry("dir/b.txt"); | |||
@@ -358,9 +360,9 @@ public class ResetCommandTest extends RepositoryTestCase { | |||
// 'a.txt' has already been modified in setupRepository | |||
// 'notAddedToIndex.txt' has been added to repository | |||
// reset to the inital commit | |||
git.reset().setRef(initialCommit.getName()) | |||
.addPath(indexFile.getName()) | |||
.addPath(untrackedFile.getName()).call(); | |||
assertSameAsHead(git.reset().setRef(initialCommit.getName()) | |||
.addPath(indexFile.getName()).addPath(untrackedFile.getName()) | |||
.call()); | |||
// check that HEAD hasn't moved | |||
ObjectId head = db.resolve(Constants.HEAD); | |||
@@ -397,7 +399,7 @@ public class ResetCommandTest extends RepositoryTestCase { | |||
+ "[b.txt, mode:100644]", | |||
indexState(0)); | |||
git.reset().addPath(file).call(); | |||
assertSameAsHead(git.reset().addPath(file).call()); | |||
assertEquals("[a.txt, mode:100644]" + "[b.txt, mode:100644]", | |||
indexState(0)); | |||
@@ -409,7 +411,7 @@ public class ResetCommandTest extends RepositoryTestCase { | |||
writeTrashFile("a.txt", "content"); | |||
git.add().addFilepattern("a.txt").call(); | |||
// Should assume an empty tree, like in C Git 1.8.2 | |||
git.reset().addPath("a.txt").call(); | |||
assertSameAsHead(git.reset().addPath("a.txt").call()); | |||
DirCache cache = db.readDirCache(); | |||
DirCacheEntry aEntry = cache.getEntry("a.txt"); | |||
@@ -421,7 +423,8 @@ public class ResetCommandTest extends RepositoryTestCase { | |||
git = new Git(db); | |||
writeTrashFile("a.txt", "content"); | |||
git.add().addFilepattern("a.txt").call(); | |||
git.reset().setRef("doesnotexist").addPath("a.txt").call(); | |||
assertSameAsHead( | |||
git.reset().setRef("doesnotexist").addPath("a.txt").call()); | |||
} | |||
@Test | |||
@@ -431,7 +434,7 @@ public class ResetCommandTest extends RepositoryTestCase { | |||
git.add().addFilepattern("a.txt").call(); | |||
writeTrashFile("a.txt", "modified"); | |||
// should use default mode MIXED | |||
git.reset().call(); | |||
assertSameAsHead(git.reset().call()); | |||
DirCache cache = db.readDirCache(); | |||
DirCacheEntry aEntry = cache.getEntry("a.txt"); | |||
@@ -452,7 +455,7 @@ public class ResetCommandTest extends RepositoryTestCase { | |||
git.add().addFilepattern(untrackedFile.getName()).call(); | |||
git.reset().setRef(tagName).setMode(HARD).call(); | |||
assertSameAsHead(git.reset().setRef(tagName).setMode(HARD).call()); | |||
ObjectId head = db.resolve(Constants.HEAD); | |||
assertEquals(secondCommit, head); | |||
@@ -486,7 +489,8 @@ public class ResetCommandTest extends RepositoryTestCase { | |||
result.getMergeStatus()); | |||
assertNotNull(db.readSquashCommitMsg()); | |||
g.reset().setMode(ResetType.HARD).setRef(first.getName()).call(); | |||
assertSameAsHead(g.reset().setMode(ResetType.HARD) | |||
.setRef(first.getName()).call()); | |||
assertNull(db.readSquashCommitMsg()); | |||
} | |||
@@ -497,7 +501,7 @@ public class ResetCommandTest extends RepositoryTestCase { | |||
File fileA = writeTrashFile("a.txt", "content"); | |||
git.add().addFilepattern("a.txt").call(); | |||
// Should assume an empty tree, like in C Git 1.8.2 | |||
git.reset().setMode(ResetType.HARD).call(); | |||
assertSameAsHead(git.reset().setMode(ResetType.HARD).call()); | |||
DirCache cache = db.readDirCache(); | |||
DirCacheEntry aEntry = cache.getEntry("a.txt"); | |||
@@ -558,4 +562,14 @@ public class ResetCommandTest extends RepositoryTestCase { | |||
return dc.getEntry(path) != null; | |||
} | |||
/** | |||
* Asserts that a certain ref is similar to repos HEAD. | |||
* @param ref | |||
* @throws IOException | |||
*/ | |||
private void assertSameAsHead(Ref ref) throws IOException { | |||
Ref headRef = db.getRef(Constants.HEAD); | |||
assertEquals(headRef.getName(), ref.getName()); | |||
assertEquals(headRef.getObjectId(), ref.getObjectId()); | |||
} | |||
} |
@@ -43,11 +43,13 @@ | |||
package org.eclipse.jgit.dircache; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.fail; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit; | |||
import org.eclipse.jgit.errors.DirCacheNameConflictException; | |||
import org.eclipse.jgit.lib.FileMode; | |||
import org.eclipse.jgit.lib.ObjectId; | |||
import org.junit.Test; | |||
@@ -154,6 +156,125 @@ public class DirCachePathEditTest { | |||
assertEquals(DirCacheEntry.STAGE_3, entries.get(2).getStage()); | |||
} | |||
@Test | |||
public void testFileReplacesTree() throws Exception { | |||
DirCache dc = DirCache.newInCore(); | |||
DirCacheEditor editor = dc.editor(); | |||
editor.add(new AddEdit("a")); | |||
editor.add(new AddEdit("b/c")); | |||
editor.add(new AddEdit("b/d")); | |||
editor.add(new AddEdit("e")); | |||
editor.finish(); | |||
editor = dc.editor(); | |||
editor.add(new AddEdit("b")); | |||
editor.finish(); | |||
assertEquals(3, dc.getEntryCount()); | |||
assertEquals("a", dc.getEntry(0).getPathString()); | |||
assertEquals("b", dc.getEntry(1).getPathString()); | |||
assertEquals("e", dc.getEntry(2).getPathString()); | |||
dc.clear(); | |||
editor = dc.editor(); | |||
editor.add(new AddEdit("A.c")); | |||
editor.add(new AddEdit("A/c")); | |||
editor.add(new AddEdit("A0c")); | |||
editor.finish(); | |||
editor = dc.editor(); | |||
editor.add(new AddEdit("A")); | |||
editor.finish(); | |||
assertEquals(3, dc.getEntryCount()); | |||
assertEquals("A", dc.getEntry(0).getPathString()); | |||
assertEquals("A.c", dc.getEntry(1).getPathString()); | |||
assertEquals("A0c", dc.getEntry(2).getPathString()); | |||
} | |||
@Test | |||
public void testTreeReplacesFile() throws Exception { | |||
DirCache dc = DirCache.newInCore(); | |||
DirCacheEditor editor = dc.editor(); | |||
editor.add(new AddEdit("a")); | |||
editor.add(new AddEdit("ab")); | |||
editor.add(new AddEdit("b")); | |||
editor.add(new AddEdit("e")); | |||
editor.finish(); | |||
editor = dc.editor(); | |||
editor.add(new AddEdit("b/c/d/f")); | |||
editor.add(new AddEdit("b/g/h/i")); | |||
editor.finish(); | |||
assertEquals(5, dc.getEntryCount()); | |||
assertEquals("a", dc.getEntry(0).getPathString()); | |||
assertEquals("ab", dc.getEntry(1).getPathString()); | |||
assertEquals("b/c/d/f", dc.getEntry(2).getPathString()); | |||
assertEquals("b/g/h/i", dc.getEntry(3).getPathString()); | |||
assertEquals("e", dc.getEntry(4).getPathString()); | |||
} | |||
@Test | |||
public void testDuplicateFiles() throws Exception { | |||
DirCache dc = DirCache.newInCore(); | |||
DirCacheEditor editor = dc.editor(); | |||
editor.add(new AddEdit("a")); | |||
editor.add(new AddEdit("a")); | |||
try { | |||
editor.finish(); | |||
fail("Expected DirCacheNameConflictException to be thrown"); | |||
} catch (DirCacheNameConflictException e) { | |||
assertEquals("a a", e.getMessage()); | |||
assertEquals("a", e.getPath1()); | |||
assertEquals("a", e.getPath2()); | |||
} | |||
} | |||
@Test | |||
public void testFileOverlapsTree() throws Exception { | |||
DirCache dc = DirCache.newInCore(); | |||
DirCacheEditor editor = dc.editor(); | |||
editor.add(new AddEdit("a")); | |||
editor.add(new AddEdit("a/b").setReplace(false)); | |||
try { | |||
editor.finish(); | |||
fail("Expected DirCacheNameConflictException to be thrown"); | |||
} catch (DirCacheNameConflictException e) { | |||
assertEquals("a a/b", e.getMessage()); | |||
assertEquals("a", e.getPath1()); | |||
assertEquals("a/b", e.getPath2()); | |||
} | |||
editor = dc.editor(); | |||
editor.add(new AddEdit("A.c")); | |||
editor.add(new AddEdit("A/c").setReplace(false)); | |||
editor.add(new AddEdit("A0c")); | |||
editor.add(new AddEdit("A")); | |||
try { | |||
editor.finish(); | |||
fail("Expected DirCacheNameConflictException to be thrown"); | |||
} catch (DirCacheNameConflictException e) { | |||
assertEquals("A A/c", e.getMessage()); | |||
assertEquals("A", e.getPath1()); | |||
assertEquals("A/c", e.getPath2()); | |||
} | |||
editor = dc.editor(); | |||
editor.add(new AddEdit("A.c")); | |||
editor.add(new AddEdit("A/b/c/d").setReplace(false)); | |||
editor.add(new AddEdit("A/b/c")); | |||
editor.add(new AddEdit("A0c")); | |||
try { | |||
editor.finish(); | |||
fail("Expected DirCacheNameConflictException to be thrown"); | |||
} catch (DirCacheNameConflictException e) { | |||
assertEquals("A/b/c A/b/c/d", e.getMessage()); | |||
assertEquals("A/b/c", e.getPath1()); | |||
assertEquals("A/b/c/d", e.getPath2()); | |||
} | |||
} | |||
private static DirCacheEntry createEntry(String path, int stage) { | |||
DirCacheEntry entry = new DirCacheEntry(path, stage); | |||
entry.setFileMode(FileMode.REGULAR_FILE); |
@@ -409,6 +409,7 @@ public class RepoCommandTest extends RepositoryTestCase { | |||
.append("<project path=\"foo\" name=\"").append(defaultUri) | |||
.append("\" revision=\"").append(BRANCH).append("\" >") | |||
.append("<copyfile src=\"hello.txt\" dest=\"Hello\" />") | |||
.append("<copyfile src=\"hello.txt\" dest=\"foo/Hello\" />") | |||
.append("</project>").append("</manifest>"); | |||
JGitTestUtil.writeTrashFile(tempDb, "manifest.xml", | |||
xmlContent.toString()); | |||
@@ -423,8 +424,12 @@ public class RepoCommandTest extends RepositoryTestCase { | |||
.getRepository(); | |||
// The Hello file should exist | |||
File hello = new File(localDb.getWorkTree(), "Hello"); | |||
localDb.close(); | |||
assertTrue("The Hello file should exist", hello.exists()); | |||
// The foo/Hello file should be skipped. | |||
File foohello = new File(localDb.getWorkTree(), "foo/Hello"); | |||
assertFalse( | |||
"The foo/Hello file should be skipped", foohello.exists()); | |||
localDb.close(); | |||
// The content of Hello file should be expected | |||
BufferedReader reader = new BufferedReader(new FileReader(hello)); | |||
String content = reader.readLine(); |
@@ -107,7 +107,7 @@ public class FileRepositoryBuilderTest extends LocalDiskRepositoryTestCase { | |||
Repository r = createWorkRepository(); | |||
StoredConfig config = r.getConfig(); | |||
config.setLong(ConfigConstants.CONFIG_CORE_SECTION, null, | |||
ConfigConstants.CONFIG_KEY_REPO_FORMAT_VERSION, 1); | |||
ConfigConstants.CONFIG_KEY_REPO_FORMAT_VERSION, 999999); | |||
config.save(); | |||
try { |
@@ -43,11 +43,13 @@ | |||
package org.eclipse.jgit.internal.storage.file; | |||
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertFalse; | |||
import static org.junit.Assert.assertNotNull; | |||
import static org.junit.Assert.assertTrue; | |||
import static org.junit.Assert.fail; | |||
import static org.eclipse.jgit.internal.storage.pack.PackWriter.NONE; | |||
import java.io.ByteArrayInputStream; | |||
import java.io.ByteArrayOutputStream; | |||
@@ -66,19 +68,19 @@ import java.util.Set; | |||
import org.eclipse.jgit.errors.MissingObjectException; | |||
import org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry; | |||
import org.eclipse.jgit.internal.storage.pack.PackWriter; | |||
import org.eclipse.jgit.internal.storage.pack.PackWriter.ObjectIdSet; | |||
import org.eclipse.jgit.junit.JGitTestUtil; | |||
import org.eclipse.jgit.junit.TestRepository; | |||
import org.eclipse.jgit.junit.TestRepository.BranchBuilder; | |||
import org.eclipse.jgit.lib.AnyObjectId; | |||
import org.eclipse.jgit.lib.NullProgressMonitor; | |||
import org.eclipse.jgit.lib.ObjectId; | |||
import org.eclipse.jgit.lib.ObjectIdSet; | |||
import org.eclipse.jgit.lib.ObjectInserter; | |||
import org.eclipse.jgit.revwalk.RevBlob; | |||
import org.eclipse.jgit.revwalk.RevCommit; | |||
import org.eclipse.jgit.revwalk.RevObject; | |||
import org.eclipse.jgit.revwalk.RevWalk; | |||
import org.eclipse.jgit.storage.pack.PackConfig; | |||
import org.eclipse.jgit.storage.pack.PackStatistics; | |||
import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase; | |||
import org.eclipse.jgit.transport.PackParser; | |||
import org.junit.After; | |||
@@ -87,9 +89,6 @@ import org.junit.Test; | |||
public class PackWriterTest extends SampleDataRepositoryTestCase { | |||
private static final Set<ObjectId> EMPTY_SET_OBJECT = Collections | |||
.<ObjectId> emptySet(); | |||
private static final List<RevObject> EMPTY_LIST_REVS = Collections | |||
.<RevObject> emptyList(); | |||
@@ -170,7 +169,7 @@ public class PackWriterTest extends SampleDataRepositoryTestCase { | |||
*/ | |||
@Test | |||
public void testWriteEmptyPack1() throws IOException { | |||
createVerifyOpenPack(EMPTY_SET_OBJECT, EMPTY_SET_OBJECT, false, false); | |||
createVerifyOpenPack(NONE, NONE, false, false); | |||
assertEquals(0, writer.getObjectCount()); | |||
assertEquals(0, pack.getObjectCount()); | |||
@@ -203,8 +202,8 @@ public class PackWriterTest extends SampleDataRepositoryTestCase { | |||
final ObjectId nonExisting = ObjectId | |||
.fromString("0000000000000000000000000000000000000001"); | |||
try { | |||
createVerifyOpenPack(EMPTY_SET_OBJECT, Collections.singleton( | |||
nonExisting), false, false); | |||
createVerifyOpenPack(NONE, Collections.singleton(nonExisting), | |||
false, false); | |||
fail("Should have thrown MissingObjectException"); | |||
} catch (MissingObjectException x) { | |||
// expected | |||
@@ -220,8 +219,8 @@ public class PackWriterTest extends SampleDataRepositoryTestCase { | |||
public void testIgnoreNonExistingObjects() throws IOException { | |||
final ObjectId nonExisting = ObjectId | |||
.fromString("0000000000000000000000000000000000000001"); | |||
createVerifyOpenPack(EMPTY_SET_OBJECT, Collections.singleton( | |||
nonExisting), false, true); | |||
createVerifyOpenPack(NONE, Collections.singleton(nonExisting), | |||
false, true); | |||
// shouldn't throw anything | |||
} | |||
@@ -239,8 +238,8 @@ public class PackWriterTest extends SampleDataRepositoryTestCase { | |||
final ObjectId nonExisting = ObjectId | |||
.fromString("0000000000000000000000000000000000000001"); | |||
new GC(db).gc(); | |||
createVerifyOpenPack(EMPTY_SET_OBJECT, | |||
Collections.singleton(nonExisting), false, true, true); | |||
createVerifyOpenPack(NONE, Collections.singleton(nonExisting), false, | |||
true, true); | |||
// shouldn't throw anything | |||
} | |||
@@ -437,6 +436,38 @@ public class PackWriterTest extends SampleDataRepositoryTestCase { | |||
assertTrue(sizePack4 > sizePack4Thin); | |||
} | |||
@Test | |||
public void testDeltaStatistics() throws Exception { | |||
config.setDeltaCompress(true); | |||
FileRepository repo = createBareRepository(); | |||
TestRepository<FileRepository> testRepo = new TestRepository<FileRepository>(repo); | |||
ArrayList<RevObject> blobs = new ArrayList<>(); | |||
blobs.add(testRepo.blob(genDeltableData(1000))); | |||
blobs.add(testRepo.blob(genDeltableData(1005))); | |||
try (PackWriter pw = new PackWriter(repo)) { | |||
NullProgressMonitor m = NullProgressMonitor.INSTANCE; | |||
pw.preparePack(blobs.iterator()); | |||
pw.writePack(m, m, os); | |||
PackStatistics stats = pw.getStatistics(); | |||
assertEquals(1, stats.getTotalDeltas()); | |||
assertTrue("Delta bytes not set.", | |||
stats.byObjectType(OBJ_BLOB).getDeltaBytes() > 0); | |||
} | |||
} | |||
// Generate consistent junk data for building files that delta well | |||
private String genDeltableData(int length) { | |||
assertTrue("Generated data must have a length > 0", length > 0); | |||
char[] data = {'a', 'b', 'c', '\n'}; | |||
StringBuilder builder = new StringBuilder(length); | |||
for (int i = 0; i < length; i++) { | |||
builder.append(data[i % 4]); | |||
} | |||
return builder.toString(); | |||
} | |||
@Test | |||
public void testWriteIndex() throws Exception { | |||
config.setIndexVersion(2); | |||
@@ -494,7 +525,7 @@ public class PackWriterTest extends SampleDataRepositoryTestCase { | |||
RevCommit c2 = bb.commit().add("f", contentB).create(); | |||
testRepo.getRevWalk().parseHeaders(c2); | |||
PackIndex pf2 = writePack(repo, Collections.singleton(c2), | |||
Collections.singleton(objectIdSet(pf1))); | |||
Collections.<ObjectIdSet> singleton(pf1)); | |||
assertContent( | |||
pf2, | |||
Arrays.asList(c2.getId(), c2.getTree().getId(), | |||
@@ -519,8 +550,7 @@ public class PackWriterTest extends SampleDataRepositoryTestCase { | |||
pw.setReuseDeltaCommits(false); | |||
for (ObjectIdSet idx : excludeObjects) | |||
pw.excludeObjects(idx); | |||
pw.preparePack(NullProgressMonitor.INSTANCE, want, | |||
Collections.<ObjectId> emptySet()); | |||
pw.preparePack(NullProgressMonitor.INSTANCE, want, NONE); | |||
String id = pw.computeName().getName(); | |||
File packdir = new File(repo.getObjectsDirectory(), "pack"); | |||
File packFile = new File(packdir, "pack-" + id + ".pack"); | |||
@@ -543,7 +573,7 @@ public class PackWriterTest extends SampleDataRepositoryTestCase { | |||
final HashSet<ObjectId> interestings = new HashSet<ObjectId>(); | |||
interestings.add(ObjectId | |||
.fromString("82c6b885ff600be425b4ea96dee75dca255b69e7")); | |||
createVerifyOpenPack(interestings, EMPTY_SET_OBJECT, false, false); | |||
createVerifyOpenPack(interestings, NONE, false, false); | |||
final ObjectId expectedOrder[] = new ObjectId[] { | |||
ObjectId.fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"), | |||
@@ -699,12 +729,4 @@ public class PackWriterTest extends SampleDataRepositoryTestCase { | |||
assertEquals(objectsOrder[i++].toObjectId(), me.toObjectId()); | |||
} | |||
} | |||
private static ObjectIdSet objectIdSet(final PackIndex idx) { | |||
return new ObjectIdSet() { | |||
public boolean contains(AnyObjectId objectId) { | |||
return idx.hasObject(objectId); | |||
} | |||
}; | |||
} | |||
} |
@@ -67,7 +67,6 @@ import org.eclipse.jgit.lib.AnyObjectId; | |||
import org.eclipse.jgit.lib.CommitBuilder; | |||
import org.eclipse.jgit.lib.Constants; | |||
import org.eclipse.jgit.lib.FileMode; | |||
import org.eclipse.jgit.lib.FileTreeEntry; | |||
import org.eclipse.jgit.lib.ObjectDatabase; | |||
import org.eclipse.jgit.lib.ObjectId; | |||
import org.eclipse.jgit.lib.ObjectInserter; | |||
@@ -75,7 +74,6 @@ import org.eclipse.jgit.lib.PersonIdent; | |||
import org.eclipse.jgit.lib.RefUpdate; | |||
import org.eclipse.jgit.lib.Repository; | |||
import org.eclipse.jgit.lib.TagBuilder; | |||
import org.eclipse.jgit.lib.Tree; | |||
import org.eclipse.jgit.lib.TreeFormatter; | |||
import org.eclipse.jgit.revwalk.RevCommit; | |||
import org.eclipse.jgit.revwalk.RevTag; | |||
@@ -419,29 +417,6 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase { | |||
assertEquals(c.getCommitter(), c2.getCommitterIdent()); | |||
} | |||
@Test | |||
public void test012_SubtreeExternalSorting() throws IOException { | |||
final ObjectId emptyBlob = insertEmptyBlob(); | |||
final Tree t = new Tree(db); | |||
final FileTreeEntry e0 = t.addFile("a-"); | |||
final FileTreeEntry e1 = t.addFile("a-b"); | |||
final FileTreeEntry e2 = t.addFile("a/b"); | |||
final FileTreeEntry e3 = t.addFile("a="); | |||
final FileTreeEntry e4 = t.addFile("a=b"); | |||
e0.setId(emptyBlob); | |||
e1.setId(emptyBlob); | |||
e2.setId(emptyBlob); | |||
e3.setId(emptyBlob); | |||
e4.setId(emptyBlob); | |||
final Tree a = (Tree) t.findTreeMember("a"); | |||
a.setId(insertTree(a)); | |||
assertEquals(ObjectId | |||
.fromString("b47a8f0a4190f7572e11212769090523e23eb1ea"), | |||
insertTree(t)); | |||
} | |||
@Test | |||
public void test020_createBlobTag() throws IOException { | |||
final ObjectId emptyId = insertEmptyBlob(); | |||
@@ -465,9 +440,8 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase { | |||
@Test | |||
public void test021_createTreeTag() throws IOException { | |||
final ObjectId emptyId = insertEmptyBlob(); | |||
final Tree almostEmptyTree = new Tree(db); | |||
almostEmptyTree.addEntry(new FileTreeEntry(almostEmptyTree, emptyId, | |||
"empty".getBytes(), false)); | |||
TreeFormatter almostEmptyTree = new TreeFormatter(); | |||
almostEmptyTree.append("empty", FileMode.REGULAR_FILE, emptyId); | |||
final ObjectId almostEmptyTreeId = insertTree(almostEmptyTree); | |||
final TagBuilder t = new TagBuilder(); | |||
t.setObjectId(almostEmptyTreeId, Constants.OBJ_TREE); | |||
@@ -489,9 +463,8 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase { | |||
@Test | |||
public void test022_createCommitTag() throws IOException { | |||
final ObjectId emptyId = insertEmptyBlob(); | |||
final Tree almostEmptyTree = new Tree(db); | |||
almostEmptyTree.addEntry(new FileTreeEntry(almostEmptyTree, emptyId, | |||
"empty".getBytes(), false)); | |||
TreeFormatter almostEmptyTree = new TreeFormatter(); | |||
almostEmptyTree.append("empty", FileMode.REGULAR_FILE, emptyId); | |||
final ObjectId almostEmptyTreeId = insertTree(almostEmptyTree); | |||
final CommitBuilder almostEmptyCommit = new CommitBuilder(); | |||
almostEmptyCommit.setAuthor(new PersonIdent(author, 1154236443000L, | |||
@@ -521,9 +494,8 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase { | |||
@Test | |||
public void test023_createCommitNonAnullii() throws IOException { | |||
final ObjectId emptyId = insertEmptyBlob(); | |||
final Tree almostEmptyTree = new Tree(db); | |||
almostEmptyTree.addEntry(new FileTreeEntry(almostEmptyTree, emptyId, | |||
"empty".getBytes(), false)); | |||
TreeFormatter almostEmptyTree = new TreeFormatter(); | |||
almostEmptyTree.append("empty", FileMode.REGULAR_FILE, emptyId); | |||
final ObjectId almostEmptyTreeId = insertTree(almostEmptyTree); | |||
CommitBuilder commit = new CommitBuilder(); | |||
commit.setTreeId(almostEmptyTreeId); | |||
@@ -543,9 +515,8 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase { | |||
@Test | |||
public void test024_createCommitNonAscii() throws IOException { | |||
final ObjectId emptyId = insertEmptyBlob(); | |||
final Tree almostEmptyTree = new Tree(db); | |||
almostEmptyTree.addEntry(new FileTreeEntry(almostEmptyTree, emptyId, | |||
"empty".getBytes(), false)); | |||
TreeFormatter almostEmptyTree = new TreeFormatter(); | |||
almostEmptyTree.append("empty", FileMode.REGULAR_FILE, emptyId); | |||
final ObjectId almostEmptyTreeId = insertTree(almostEmptyTree); | |||
CommitBuilder commit = new CommitBuilder(); | |||
commit.setTreeId(almostEmptyTreeId); | |||
@@ -747,14 +718,6 @@ public class T0003_BasicTest extends SampleDataRepositoryTestCase { | |||
return emptyId; | |||
} | |||
private ObjectId insertTree(Tree tree) throws IOException { | |||
try (ObjectInserter oi = db.newObjectInserter()) { | |||
ObjectId id = oi.insert(Constants.OBJ_TREE, tree.format()); | |||
oi.flush(); | |||
return id; | |||
} | |||
} | |||
private ObjectId insertTree(TreeFormatter tree) throws IOException { | |||
try (ObjectInserter oi = db.newObjectInserter()) { | |||
ObjectId id = oi.insert(tree); |
@@ -0,0 +1,685 @@ | |||
/* | |||
* Copyright (C) 2010, 2013, 2016 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.internal.storage.reftree; | |||
import static org.eclipse.jgit.lib.Constants.HEAD; | |||
import static org.eclipse.jgit.lib.Constants.R_HEADS; | |||
import static org.eclipse.jgit.lib.Constants.R_TAGS; | |||
import static org.eclipse.jgit.lib.Ref.Storage.LOOSE; | |||
import static org.eclipse.jgit.lib.Ref.Storage.PACKED; | |||
import static org.eclipse.jgit.lib.RefDatabase.ALL; | |||
import static org.eclipse.jgit.transport.ReceiveCommand.Result.LOCK_FAILURE; | |||
import static org.eclipse.jgit.transport.ReceiveCommand.Result.OK; | |||
import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_NONFASTFORWARD; | |||
import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_OTHER_REASON; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertFalse; | |||
import static org.junit.Assert.assertNotEquals; | |||
import static org.junit.Assert.assertNotNull; | |||
import static org.junit.Assert.assertNull; | |||
import static org.junit.Assert.assertSame; | |||
import static org.junit.Assert.assertTrue; | |||
import static org.junit.Assert.fail; | |||
import java.io.IOException; | |||
import java.text.MessageFormat; | |||
import java.util.Arrays; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import java.util.Map; | |||
import org.eclipse.jgit.internal.JGitText; | |||
import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription; | |||
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository; | |||
import org.eclipse.jgit.junit.TestRepository; | |||
import org.eclipse.jgit.lib.AnyObjectId; | |||
import org.eclipse.jgit.lib.BatchRefUpdate; | |||
import org.eclipse.jgit.lib.CommitBuilder; | |||
import org.eclipse.jgit.lib.NullProgressMonitor; | |||
import org.eclipse.jgit.lib.ObjectId; | |||
import org.eclipse.jgit.lib.ObjectIdRef; | |||
import org.eclipse.jgit.lib.ObjectInserter; | |||
import org.eclipse.jgit.lib.ObjectReader; | |||
import org.eclipse.jgit.lib.Ref; | |||
import org.eclipse.jgit.lib.RefDatabase; | |||
import org.eclipse.jgit.lib.RefUpdate; | |||
import org.eclipse.jgit.lib.SymbolicRef; | |||
import org.eclipse.jgit.revwalk.RevCommit; | |||
import org.eclipse.jgit.revwalk.RevTag; | |||
import org.eclipse.jgit.revwalk.RevWalk; | |||
import org.eclipse.jgit.transport.ReceiveCommand; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
public class RefTreeDatabaseTest { | |||
private InMemRefTreeRepo repo; | |||
private RefTreeDatabase refdb; | |||
private RefDatabase bootstrap; | |||
private TestRepository<InMemRefTreeRepo> testRepo; | |||
private RevCommit A; | |||
private RevCommit B; | |||
private RevTag v1_0; | |||
@Before | |||
public void setUp() throws Exception { | |||
repo = new InMemRefTreeRepo(new DfsRepositoryDescription("test")); | |||
bootstrap = refdb.getBootstrap(); | |||
testRepo = new TestRepository<>(repo); | |||
A = testRepo.commit().create(); | |||
B = testRepo.commit(testRepo.getRevWalk().parseCommit(A)); | |||
v1_0 = testRepo.tag("v1_0", B); | |||
testRepo.getRevWalk().parseBody(v1_0); | |||
} | |||
@Test | |||
public void testSupportsAtomic() { | |||
assertTrue(refdb.performsAtomicTransactions()); | |||
} | |||
@Test | |||
public void testGetRefs_EmptyDatabase() throws IOException { | |||
assertTrue("no references", refdb.getRefs(ALL).isEmpty()); | |||
assertTrue("no references", refdb.getRefs(R_HEADS).isEmpty()); | |||
assertTrue("no references", refdb.getRefs(R_TAGS).isEmpty()); | |||
} | |||
@Test | |||
public void testGetRefs_HeadOnOneBranch() throws IOException { | |||
symref(HEAD, "refs/heads/master"); | |||
update("refs/heads/master", A); | |||
Map<String, Ref> all = refdb.getRefs(ALL); | |||
assertEquals(2, all.size()); | |||
assertTrue("has HEAD", all.containsKey(HEAD)); | |||
assertTrue("has master", all.containsKey("refs/heads/master")); | |||
Ref head = all.get(HEAD); | |||
Ref master = all.get("refs/heads/master"); | |||
assertEquals(HEAD, head.getName()); | |||
assertTrue(head.isSymbolic()); | |||
assertSame(LOOSE, head.getStorage()); | |||
assertSame("uses same ref as target", master, head.getTarget()); | |||
assertEquals("refs/heads/master", master.getName()); | |||
assertFalse(master.isSymbolic()); | |||
assertSame(PACKED, master.getStorage()); | |||
assertEquals(A, master.getObjectId()); | |||
} | |||
@Test | |||
public void testGetRefs_DetachedHead() throws IOException { | |||
update(HEAD, A); | |||
Map<String, Ref> all = refdb.getRefs(ALL); | |||
assertEquals(1, all.size()); | |||
assertTrue("has HEAD", all.containsKey(HEAD)); | |||
Ref head = all.get(HEAD); | |||
assertEquals(HEAD, head.getName()); | |||
assertFalse(head.isSymbolic()); | |||
assertSame(PACKED, head.getStorage()); | |||
assertEquals(A, head.getObjectId()); | |||
} | |||
@Test | |||
public void testGetRefs_DeeplyNestedBranch() throws IOException { | |||
String name = "refs/heads/a/b/c/d/e/f/g/h/i/j/k"; | |||
update(name, A); | |||
Map<String, Ref> all = refdb.getRefs(ALL); | |||
assertEquals(1, all.size()); | |||
Ref r = all.get(name); | |||
assertEquals(name, r.getName()); | |||
assertFalse(r.isSymbolic()); | |||
assertSame(PACKED, r.getStorage()); | |||
assertEquals(A, r.getObjectId()); | |||
} | |||
@Test | |||
public void testGetRefs_HeadBranchNotBorn() throws IOException { | |||
update("refs/heads/A", A); | |||
update("refs/heads/B", B); | |||
Map<String, Ref> all = refdb.getRefs(ALL); | |||
assertEquals(2, all.size()); | |||
assertFalse("no HEAD", all.containsKey(HEAD)); | |||
Ref a = all.get("refs/heads/A"); | |||
Ref b = all.get("refs/heads/B"); | |||
assertEquals(A, a.getObjectId()); | |||
assertEquals(B, b.getObjectId()); | |||
assertEquals("refs/heads/A", a.getName()); | |||
assertEquals("refs/heads/B", b.getName()); | |||
} | |||
@Test | |||
public void testGetRefs_HeadsOnly() throws IOException { | |||
update("refs/heads/A", A); | |||
update("refs/heads/B", B); | |||
update("refs/tags/v1.0", v1_0); | |||
Map<String, Ref> heads = refdb.getRefs(R_HEADS); | |||
assertEquals(2, heads.size()); | |||
Ref a = heads.get("A"); | |||
Ref b = heads.get("B"); | |||
assertEquals("refs/heads/A", a.getName()); | |||
assertEquals("refs/heads/B", b.getName()); | |||
assertEquals(A, a.getObjectId()); | |||
assertEquals(B, b.getObjectId()); | |||
} | |||
@Test | |||
public void testGetRefs_TagsOnly() throws IOException { | |||
update("refs/heads/A", A); | |||
update("refs/heads/B", B); | |||
update("refs/tags/v1.0", v1_0); | |||
Map<String, Ref> tags = refdb.getRefs(R_TAGS); | |||
assertEquals(1, tags.size()); | |||
Ref a = tags.get("v1.0"); | |||
assertEquals("refs/tags/v1.0", a.getName()); | |||
assertEquals(v1_0, a.getObjectId()); | |||
assertTrue(a.isPeeled()); | |||
assertEquals(v1_0.getObject(), a.getPeeledObjectId()); | |||
} | |||
@Test | |||
public void testGetRefs_HeadsSymref() throws IOException { | |||
symref("refs/heads/other", "refs/heads/master"); | |||
update("refs/heads/master", A); | |||
Map<String, Ref> heads = refdb.getRefs(R_HEADS); | |||
assertEquals(2, heads.size()); | |||
Ref master = heads.get("master"); | |||
Ref other = heads.get("other"); | |||
assertEquals("refs/heads/master", master.getName()); | |||
assertEquals(A, master.getObjectId()); | |||
assertEquals("refs/heads/other", other.getName()); | |||
assertEquals(A, other.getObjectId()); | |||
assertSame(master, other.getTarget()); | |||
} | |||
@Test | |||
public void testGetRefs_InvalidPrefixes() throws IOException { | |||
update("refs/heads/A", A); | |||
assertTrue("empty refs/heads", refdb.getRefs("refs/heads").isEmpty()); | |||
assertTrue("empty objects", refdb.getRefs("objects").isEmpty()); | |||
assertTrue("empty objects/", refdb.getRefs("objects/").isEmpty()); | |||
} | |||
@Test | |||
public void testGetRefs_DiscoversNew() throws IOException { | |||
update("refs/heads/master", A); | |||
Map<String, Ref> orig = refdb.getRefs(ALL); | |||
update("refs/heads/next", B); | |||
Map<String, Ref> next = refdb.getRefs(ALL); | |||
assertEquals(1, orig.size()); | |||
assertEquals(2, next.size()); | |||
assertFalse(orig.containsKey("refs/heads/next")); | |||
assertTrue(next.containsKey("refs/heads/next")); | |||
assertEquals(A, next.get("refs/heads/master").getObjectId()); | |||
assertEquals(B, next.get("refs/heads/next").getObjectId()); | |||
} | |||
@Test | |||
public void testGetRefs_DiscoversModified() throws IOException { | |||
symref(HEAD, "refs/heads/master"); | |||
update("refs/heads/master", A); | |||
Map<String, Ref> all = refdb.getRefs(ALL); | |||
assertEquals(A, all.get(HEAD).getObjectId()); | |||
update("refs/heads/master", B); | |||
all = refdb.getRefs(ALL); | |||
assertEquals(B, all.get(HEAD).getObjectId()); | |||
assertEquals(B, refdb.exactRef(HEAD).getObjectId()); | |||
} | |||
@Test | |||
public void testGetRefs_CycleInSymbolicRef() throws IOException { | |||
symref("refs/1", "refs/2"); | |||
symref("refs/2", "refs/3"); | |||
symref("refs/3", "refs/4"); | |||
symref("refs/4", "refs/5"); | |||
symref("refs/5", "refs/end"); | |||
update("refs/end", A); | |||
Map<String, Ref> all = refdb.getRefs(ALL); | |||
Ref r = all.get("refs/1"); | |||
assertNotNull("has 1", r); | |||
assertEquals("refs/1", r.getName()); | |||
assertEquals(A, r.getObjectId()); | |||
assertTrue(r.isSymbolic()); | |||
r = r.getTarget(); | |||
assertEquals("refs/2", r.getName()); | |||
assertEquals(A, r.getObjectId()); | |||
assertTrue(r.isSymbolic()); | |||
r = r.getTarget(); | |||
assertEquals("refs/3", r.getName()); | |||
assertEquals(A, r.getObjectId()); | |||
assertTrue(r.isSymbolic()); | |||
r = r.getTarget(); | |||
assertEquals("refs/4", r.getName()); | |||
assertEquals(A, r.getObjectId()); | |||
assertTrue(r.isSymbolic()); | |||
r = r.getTarget(); | |||
assertEquals("refs/5", r.getName()); | |||
assertEquals(A, r.getObjectId()); | |||
assertTrue(r.isSymbolic()); | |||
r = r.getTarget(); | |||
assertEquals("refs/end", r.getName()); | |||
assertEquals(A, r.getObjectId()); | |||
assertFalse(r.isSymbolic()); | |||
symref("refs/5", "refs/6"); | |||
symref("refs/6", "refs/end"); | |||
all = refdb.getRefs(ALL); | |||
assertNull("mising 1 due to cycle", all.get("refs/1")); | |||
assertEquals(A, all.get("refs/2").getObjectId()); | |||
assertEquals(A, all.get("refs/3").getObjectId()); | |||
assertEquals(A, all.get("refs/4").getObjectId()); | |||
assertEquals(A, all.get("refs/5").getObjectId()); | |||
assertEquals(A, all.get("refs/6").getObjectId()); | |||
assertEquals(A, all.get("refs/end").getObjectId()); | |||
} | |||
@Test | |||
public void testGetRef_NonExistingBranchConfig() throws IOException { | |||
assertNull("find branch config", refdb.getRef("config")); | |||
assertNull("find branch config", refdb.getRef("refs/heads/config")); | |||
} | |||
@Test | |||
public void testGetRef_FindBranchConfig() throws IOException { | |||
update("refs/heads/config", A); | |||
for (String t : new String[] { "config", "refs/heads/config" }) { | |||
Ref r = refdb.getRef(t); | |||
assertNotNull("find branch config (" + t + ")", r); | |||
assertEquals("for " + t, "refs/heads/config", r.getName()); | |||
assertEquals("for " + t, A, r.getObjectId()); | |||
} | |||
} | |||
@Test | |||
public void testFirstExactRef() throws IOException { | |||
update("refs/heads/A", A); | |||
update("refs/tags/v1.0", v1_0); | |||
Ref a = refdb.firstExactRef("refs/heads/A", "refs/tags/v1.0"); | |||
Ref one = refdb.firstExactRef("refs/tags/v1.0", "refs/heads/A"); | |||
assertEquals("refs/heads/A", a.getName()); | |||
assertEquals("refs/tags/v1.0", one.getName()); | |||
assertEquals(A, a.getObjectId()); | |||
assertEquals(v1_0, one.getObjectId()); | |||
} | |||
@Test | |||
public void testExactRef_DiscoversModified() throws IOException { | |||
symref(HEAD, "refs/heads/master"); | |||
update("refs/heads/master", A); | |||
assertEquals(A, refdb.exactRef(HEAD).getObjectId()); | |||
update("refs/heads/master", B); | |||
assertEquals(B, refdb.exactRef(HEAD).getObjectId()); | |||
} | |||
@Test | |||
public void testIsNameConflicting() throws IOException { | |||
update("refs/heads/a/b", A); | |||
update("refs/heads/q", B); | |||
// new references cannot replace an existing container | |||
assertTrue(refdb.isNameConflicting("refs")); | |||
assertTrue(refdb.isNameConflicting("refs/heads")); | |||
assertTrue(refdb.isNameConflicting("refs/heads/a")); | |||
// existing reference is not conflicting | |||
assertFalse(refdb.isNameConflicting("refs/heads/a/b")); | |||
// new references are not conflicting | |||
assertFalse(refdb.isNameConflicting("refs/heads/a/d")); | |||
assertFalse(refdb.isNameConflicting("refs/heads/master")); | |||
// existing reference must not be used as a container | |||
assertTrue(refdb.isNameConflicting("refs/heads/a/b/c")); | |||
assertTrue(refdb.isNameConflicting("refs/heads/q/master")); | |||
// refs/txn/ names always conflict. | |||
assertTrue(refdb.isNameConflicting(refdb.getTxnCommitted())); | |||
assertTrue(refdb.isNameConflicting("refs/txn/foo")); | |||
} | |||
@Test | |||
public void testUpdate_RefusesRefsTxnNamespace() throws IOException { | |||
ObjectId txnId = getTxnCommitted(); | |||
RefUpdate u = refdb.newUpdate("refs/txn/tmp", false); | |||
u.setNewObjectId(B); | |||
assertEquals(RefUpdate.Result.LOCK_FAILURE, u.update()); | |||
assertEquals(txnId, getTxnCommitted()); | |||
ReceiveCommand cmd = command(null, B, "refs/txn/tmp"); | |||
BatchRefUpdate batch = refdb.newBatchUpdate(); | |||
batch.addCommand(cmd); | |||
batch.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE); | |||
assertEquals(REJECTED_OTHER_REASON, cmd.getResult()); | |||
assertEquals(MessageFormat.format(JGitText.get().invalidRefName, | |||
"refs/txn/tmp"), cmd.getMessage()); | |||
assertEquals(txnId, getTxnCommitted()); | |||
} | |||
@Test | |||
public void testUpdate_RefusesDotLockInRefName() throws IOException { | |||
ObjectId txnId = getTxnCommitted(); | |||
RefUpdate u = refdb.newUpdate("refs/heads/pu.lock", false); | |||
u.setNewObjectId(B); | |||
assertEquals(RefUpdate.Result.REJECTED, u.update()); | |||
assertEquals(txnId, getTxnCommitted()); | |||
ReceiveCommand cmd = command(null, B, "refs/heads/pu.lock"); | |||
BatchRefUpdate batch = refdb.newBatchUpdate(); | |||
batch.addCommand(cmd); | |||
batch.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE); | |||
assertEquals(REJECTED_OTHER_REASON, cmd.getResult()); | |||
assertEquals(JGitText.get().funnyRefname, cmd.getMessage()); | |||
assertEquals(txnId, getTxnCommitted()); | |||
} | |||
@Test | |||
public void testBatchRefUpdate_NonFastForwardAborts() throws IOException { | |||
update("refs/heads/master", A); | |||
update("refs/heads/masters", B); | |||
ObjectId txnId = getTxnCommitted(); | |||
List<ReceiveCommand> commands = Arrays.asList( | |||
command(A, B, "refs/heads/master"), | |||
command(B, A, "refs/heads/masters")); | |||
BatchRefUpdate batchUpdate = refdb.newBatchUpdate(); | |||
batchUpdate.addCommand(commands); | |||
batchUpdate.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE); | |||
assertEquals(txnId, getTxnCommitted()); | |||
assertEquals(REJECTED_NONFASTFORWARD, | |||
commands.get(1).getResult()); | |||
assertEquals(REJECTED_OTHER_REASON, | |||
commands.get(0).getResult()); | |||
assertEquals(JGitText.get().transactionAborted, | |||
commands.get(0).getMessage()); | |||
} | |||
@Test | |||
public void testBatchRefUpdate_ForceUpdate() throws IOException { | |||
update("refs/heads/master", A); | |||
update("refs/heads/masters", B); | |||
ObjectId txnId = getTxnCommitted(); | |||
List<ReceiveCommand> commands = Arrays.asList( | |||
command(A, B, "refs/heads/master"), | |||
command(B, A, "refs/heads/masters")); | |||
BatchRefUpdate batchUpdate = refdb.newBatchUpdate(); | |||
batchUpdate.setAllowNonFastForwards(true); | |||
batchUpdate.addCommand(commands); | |||
batchUpdate.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE); | |||
assertNotEquals(txnId, getTxnCommitted()); | |||
Map<String, Ref> refs = refdb.getRefs(ALL); | |||
assertEquals(OK, commands.get(0).getResult()); | |||
assertEquals(OK, commands.get(1).getResult()); | |||
assertEquals( | |||
"[refs/heads/master, refs/heads/masters]", | |||
refs.keySet().toString()); | |||
assertEquals(B.getId(), refs.get("refs/heads/master").getObjectId()); | |||
assertEquals(A.getId(), refs.get("refs/heads/masters").getObjectId()); | |||
} | |||
@Test | |||
public void testBatchRefUpdate_NonFastForwardDoesNotDoExpensiveMergeCheck() | |||
throws IOException { | |||
update("refs/heads/master", B); | |||
ObjectId txnId = getTxnCommitted(); | |||
List<ReceiveCommand> commands = Arrays.asList( | |||
command(B, A, "refs/heads/master")); | |||
BatchRefUpdate batchUpdate = refdb.newBatchUpdate(); | |||
batchUpdate.setAllowNonFastForwards(true); | |||
batchUpdate.addCommand(commands); | |||
batchUpdate.execute(new RevWalk(repo) { | |||
@Override | |||
public boolean isMergedInto(RevCommit base, RevCommit tip) { | |||
fail("isMergedInto() should not be called"); | |||
return false; | |||
} | |||
}, NullProgressMonitor.INSTANCE); | |||
assertNotEquals(txnId, getTxnCommitted()); | |||
Map<String, Ref> refs = refdb.getRefs(ALL); | |||
assertEquals(OK, commands.get(0).getResult()); | |||
assertEquals(A.getId(), refs.get("refs/heads/master").getObjectId()); | |||
} | |||
@Test | |||
public void testBatchRefUpdate_ConflictCausesAbort() throws IOException { | |||
update("refs/heads/master", A); | |||
update("refs/heads/masters", B); | |||
ObjectId txnId = getTxnCommitted(); | |||
List<ReceiveCommand> commands = Arrays.asList( | |||
command(A, B, "refs/heads/master"), | |||
command(null, A, "refs/heads/master/x"), | |||
command(null, A, "refs/heads")); | |||
BatchRefUpdate batchUpdate = refdb.newBatchUpdate(); | |||
batchUpdate.setAllowNonFastForwards(true); | |||
batchUpdate.addCommand(commands); | |||
batchUpdate.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE); | |||
assertEquals(txnId, getTxnCommitted()); | |||
assertEquals(LOCK_FAILURE, commands.get(0).getResult()); | |||
assertEquals(REJECTED_OTHER_REASON, commands.get(1).getResult()); | |||
assertEquals(JGitText.get().transactionAborted, | |||
commands.get(1).getMessage()); | |||
assertEquals(REJECTED_OTHER_REASON, commands.get(2).getResult()); | |||
assertEquals(JGitText.get().transactionAborted, | |||
commands.get(2).getMessage()); | |||
} | |||
@Test | |||
public void testBatchRefUpdate_NoConflictIfDeleted() throws IOException { | |||
update("refs/heads/master", A); | |||
update("refs/heads/masters", B); | |||
ObjectId txnId = getTxnCommitted(); | |||
List<ReceiveCommand> commands = Arrays.asList( | |||
command(A, B, "refs/heads/master"), | |||
command(null, A, "refs/heads/masters/x"), | |||
command(B, null, "refs/heads/masters")); | |||
BatchRefUpdate batchUpdate = refdb.newBatchUpdate(); | |||
batchUpdate.setAllowNonFastForwards(true); | |||
batchUpdate.addCommand(commands); | |||
batchUpdate.execute(new RevWalk(repo), NullProgressMonitor.INSTANCE); | |||
assertNotEquals(txnId, getTxnCommitted()); | |||
assertEquals(OK, commands.get(0).getResult()); | |||
assertEquals(OK, commands.get(1).getResult()); | |||
assertEquals(OK, commands.get(2).getResult()); | |||
Map<String, Ref> refs = refdb.getRefs(ALL); | |||
assertEquals( | |||
"[refs/heads/master, refs/heads/masters/x]", | |||
refs.keySet().toString()); | |||
assertEquals(A.getId(), refs.get("refs/heads/masters/x").getObjectId()); | |||
} | |||
private ObjectId getTxnCommitted() throws IOException { | |||
Ref r = bootstrap.exactRef(refdb.getTxnCommitted()); | |||
if (r != null && r.getObjectId() != null) { | |||
return r.getObjectId(); | |||
} | |||
return ObjectId.zeroId(); | |||
} | |||
private static ReceiveCommand command(AnyObjectId a, AnyObjectId b, | |||
String name) { | |||
return new ReceiveCommand( | |||
a != null ? a.copy() : ObjectId.zeroId(), | |||
b != null ? b.copy() : ObjectId.zeroId(), | |||
name); | |||
} | |||
private void symref(final String name, final String dst) | |||
throws IOException { | |||
commit(new Function() { | |||
@Override | |||
public boolean apply(ObjectReader reader, RefTree tree) | |||
throws IOException { | |||
Ref old = tree.exactRef(reader, name); | |||
Command n = new Command( | |||
old, | |||
new SymbolicRef( | |||
name, | |||
new ObjectIdRef.Unpeeled(Ref.Storage.NEW, dst, null))); | |||
return tree.apply(Collections.singleton(n)); | |||
} | |||
}); | |||
} | |||
private void update(final String name, final ObjectId id) | |||
throws IOException { | |||
commit(new Function() { | |||
@Override | |||
public boolean apply(ObjectReader reader, RefTree tree) | |||
throws IOException { | |||
Ref old = tree.exactRef(reader, name); | |||
Command n; | |||
try (RevWalk rw = new RevWalk(repo)) { | |||
n = new Command(old, Command.toRef(rw, id, name, true)); | |||
} | |||
return tree.apply(Collections.singleton(n)); | |||
} | |||
}); | |||
} | |||
interface Function { | |||
boolean apply(ObjectReader reader, RefTree tree) throws IOException; | |||
} | |||
private void commit(Function fun) throws IOException { | |||
try (ObjectReader reader = repo.newObjectReader(); | |||
ObjectInserter inserter = repo.newObjectInserter(); | |||
RevWalk rw = new RevWalk(reader)) { | |||
RefUpdate u = bootstrap.newUpdate(refdb.getTxnCommitted(), false); | |||
CommitBuilder cb = new CommitBuilder(); | |||
testRepo.setAuthorAndCommitter(cb); | |||
Ref ref = bootstrap.exactRef(refdb.getTxnCommitted()); | |||
RefTree tree; | |||
if (ref != null && ref.getObjectId() != null) { | |||
tree = RefTree.read(reader, rw.parseTree(ref.getObjectId())); | |||
cb.setParentId(ref.getObjectId()); | |||
u.setExpectedOldObjectId(ref.getObjectId()); | |||
} else { | |||
tree = RefTree.newEmptyTree(); | |||
u.setExpectedOldObjectId(ObjectId.zeroId()); | |||
} | |||
assertTrue(fun.apply(reader, tree)); | |||
cb.setTreeId(tree.writeTree(inserter)); | |||
u.setNewObjectId(inserter.insert(cb)); | |||
inserter.flush(); | |||
switch (u.update(rw)) { | |||
case NEW: | |||
case FAST_FORWARD: | |||
break; | |||
default: | |||
fail("Expected " + u.getName() + " to update"); | |||
} | |||
} | |||
} | |||
private class InMemRefTreeRepo extends InMemoryRepository { | |||
private final RefTreeDatabase refs; | |||
InMemRefTreeRepo(DfsRepositoryDescription repoDesc) { | |||
super(repoDesc); | |||
refs = new RefTreeDatabase(this, super.getRefDatabase(), | |||
"refs/txn/committed"); | |||
RefTreeDatabaseTest.this.refdb = refs; | |||
} | |||
public RefDatabase getRefDatabase() { | |||
return refs; | |||
} | |||
} | |||
} |
@@ -0,0 +1,303 @@ | |||
/* | |||
* Copyright (C) 2016, 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.internal.storage.reftree; | |||
import static org.eclipse.jgit.lib.Constants.HEAD; | |||
import static org.eclipse.jgit.lib.Constants.R_HEADS; | |||
import static org.eclipse.jgit.lib.Constants.R_TAGS; | |||
import static org.eclipse.jgit.lib.Ref.Storage.LOOSE; | |||
import static org.eclipse.jgit.lib.Ref.Storage.NEW; | |||
import static org.eclipse.jgit.transport.ReceiveCommand.Result.LOCK_FAILURE; | |||
import static org.eclipse.jgit.transport.ReceiveCommand.Result.NOT_ATTEMPTED; | |||
import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_OTHER_REASON; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertFalse; | |||
import static org.junit.Assert.assertNotNull; | |||
import static org.junit.Assert.assertNull; | |||
import static org.junit.Assert.assertSame; | |||
import static org.junit.Assert.assertTrue; | |||
import java.io.IOException; | |||
import java.util.Arrays; | |||
import java.util.Collections; | |||
import org.eclipse.jgit.errors.MissingObjectException; | |||
import org.eclipse.jgit.internal.JGitText; | |||
import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription; | |||
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository; | |||
import org.eclipse.jgit.junit.TestRepository; | |||
import org.eclipse.jgit.lib.ObjectId; | |||
import org.eclipse.jgit.lib.ObjectIdRef; | |||
import org.eclipse.jgit.lib.ObjectInserter; | |||
import org.eclipse.jgit.lib.ObjectReader; | |||
import org.eclipse.jgit.lib.Ref; | |||
import org.eclipse.jgit.lib.SymbolicRef; | |||
import org.eclipse.jgit.revwalk.RevBlob; | |||
import org.eclipse.jgit.revwalk.RevTag; | |||
import org.eclipse.jgit.revwalk.RevWalk; | |||
import org.eclipse.jgit.transport.ReceiveCommand; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
public class RefTreeTest { | |||
private static final String R_MASTER = R_HEADS + "master"; | |||
private InMemoryRepository repo; | |||
private TestRepository<InMemoryRepository> git; | |||
@Before | |||
public void setUp() throws IOException { | |||
repo = new InMemoryRepository(new DfsRepositoryDescription("RefTree")); | |||
git = new TestRepository<>(repo); | |||
} | |||
@Test | |||
public void testEmptyTree() throws IOException { | |||
RefTree tree = RefTree.newEmptyTree(); | |||
try (ObjectReader reader = repo.newObjectReader()) { | |||
assertNull(HEAD, tree.exactRef(reader, HEAD)); | |||
assertNull("master", tree.exactRef(reader, R_MASTER)); | |||
} | |||
} | |||
@Test | |||
public void testApplyThenReadMaster() throws Exception { | |||
RefTree tree = RefTree.newEmptyTree(); | |||
RevBlob id = git.blob("A"); | |||
Command cmd = new Command(null, ref(R_MASTER, id)); | |||
assertTrue(tree.apply(Collections.singletonList(cmd))); | |||
assertSame(NOT_ATTEMPTED, cmd.getResult()); | |||
try (ObjectReader reader = repo.newObjectReader()) { | |||
Ref m = tree.exactRef(reader, R_MASTER); | |||
assertNotNull(R_MASTER, m); | |||
assertEquals(R_MASTER, m.getName()); | |||
assertEquals(id, m.getObjectId()); | |||
assertTrue("peeled", m.isPeeled()); | |||
} | |||
} | |||
@Test | |||
public void testUpdateMaster() throws Exception { | |||
RefTree tree = RefTree.newEmptyTree(); | |||
RevBlob id1 = git.blob("A"); | |||
Command cmd1 = new Command(null, ref(R_MASTER, id1)); | |||
assertTrue(tree.apply(Collections.singletonList(cmd1))); | |||
assertSame(NOT_ATTEMPTED, cmd1.getResult()); | |||
RevBlob id2 = git.blob("B"); | |||
Command cmd2 = new Command(ref(R_MASTER, id1), ref(R_MASTER, id2)); | |||
assertTrue(tree.apply(Collections.singletonList(cmd2))); | |||
assertSame(NOT_ATTEMPTED, cmd2.getResult()); | |||
try (ObjectReader reader = repo.newObjectReader()) { | |||
Ref m = tree.exactRef(reader, R_MASTER); | |||
assertNotNull(R_MASTER, m); | |||
assertEquals(R_MASTER, m.getName()); | |||
assertEquals(id2, m.getObjectId()); | |||
assertTrue("peeled", m.isPeeled()); | |||
} | |||
} | |||
@Test | |||
public void testHeadSymref() throws Exception { | |||
RefTree tree = RefTree.newEmptyTree(); | |||
RevBlob id = git.blob("A"); | |||
Command cmd1 = new Command(null, ref(R_MASTER, id)); | |||
Command cmd2 = new Command(null, symref(HEAD, R_MASTER)); | |||
assertTrue(tree.apply(Arrays.asList(new Command[] { cmd1, cmd2 }))); | |||
assertSame(NOT_ATTEMPTED, cmd1.getResult()); | |||
assertSame(NOT_ATTEMPTED, cmd2.getResult()); | |||
try (ObjectReader reader = repo.newObjectReader()) { | |||
Ref m = tree.exactRef(reader, HEAD); | |||
assertNotNull(HEAD, m); | |||
assertEquals(HEAD, m.getName()); | |||
assertTrue("symbolic", m.isSymbolic()); | |||
assertNotNull(m.getTarget()); | |||
assertEquals(R_MASTER, m.getTarget().getName()); | |||
assertEquals(id, m.getTarget().getObjectId()); | |||
} | |||
// Writing flushes some buffers, re-read from blob. | |||
ObjectId newId = write(tree); | |||
try (ObjectReader reader = repo.newObjectReader(); | |||
RevWalk rw = new RevWalk(reader)) { | |||
tree = RefTree.read(reader, rw.parseTree(newId)); | |||
Ref m = tree.exactRef(reader, HEAD); | |||
assertEquals(R_MASTER, m.getTarget().getName()); | |||
} | |||
} | |||
@Test | |||
public void testTagIsPeeled() throws Exception { | |||
String name = "v1.0"; | |||
RefTree tree = RefTree.newEmptyTree(); | |||
RevBlob id = git.blob("A"); | |||
RevTag tag = git.tag(name, id); | |||
String ref = R_TAGS + name; | |||
Command cmd = create(ref, tag); | |||
assertTrue(tree.apply(Collections.singletonList(cmd))); | |||
assertSame(NOT_ATTEMPTED, cmd.getResult()); | |||
try (ObjectReader reader = repo.newObjectReader()) { | |||
Ref m = tree.exactRef(reader, ref); | |||
assertNotNull(ref, m); | |||
assertEquals(ref, m.getName()); | |||
assertEquals(tag, m.getObjectId()); | |||
assertTrue("peeled", m.isPeeled()); | |||
assertEquals(id, m.getPeeledObjectId()); | |||
} | |||
} | |||
@Test | |||
public void testApplyAlreadyExists() throws Exception { | |||
RefTree tree = RefTree.newEmptyTree(); | |||
RevBlob a = git.blob("A"); | |||
Command cmd = new Command(null, ref(R_MASTER, a)); | |||
assertTrue(tree.apply(Collections.singletonList(cmd))); | |||
ObjectId treeId = write(tree); | |||
RevBlob b = git.blob("B"); | |||
Command cmd1 = create(R_MASTER, b); | |||
Command cmd2 = create(R_MASTER, b); | |||
assertFalse(tree.apply(Arrays.asList(new Command[] { cmd1, cmd2 }))); | |||
assertSame(LOCK_FAILURE, cmd1.getResult()); | |||
assertSame(REJECTED_OTHER_REASON, cmd2.getResult()); | |||
assertEquals(JGitText.get().transactionAborted, cmd2.getMessage()); | |||
assertEquals(treeId, write(tree)); | |||
} | |||
@Test | |||
public void testApplyWrongOldId() throws Exception { | |||
RefTree tree = RefTree.newEmptyTree(); | |||
RevBlob a = git.blob("A"); | |||
Command cmd = new Command(null, ref(R_MASTER, a)); | |||
assertTrue(tree.apply(Collections.singletonList(cmd))); | |||
ObjectId treeId = write(tree); | |||
RevBlob b = git.blob("B"); | |||
RevBlob c = git.blob("C"); | |||
Command cmd1 = update(R_MASTER, b, c); | |||
Command cmd2 = create(R_MASTER, b); | |||
assertFalse(tree.apply(Arrays.asList(new Command[] { cmd1, cmd2 }))); | |||
assertSame(LOCK_FAILURE, cmd1.getResult()); | |||
assertSame(REJECTED_OTHER_REASON, cmd2.getResult()); | |||
assertEquals(JGitText.get().transactionAborted, cmd2.getMessage()); | |||
assertEquals(treeId, write(tree)); | |||
} | |||
@Test | |||
public void testApplyWrongOldIdButAlreadyCurrentIsNoOp() throws Exception { | |||
RefTree tree = RefTree.newEmptyTree(); | |||
RevBlob a = git.blob("A"); | |||
Command cmd = new Command(null, ref(R_MASTER, a)); | |||
assertTrue(tree.apply(Collections.singletonList(cmd))); | |||
ObjectId treeId = write(tree); | |||
RevBlob b = git.blob("B"); | |||
cmd = update(R_MASTER, b, a); | |||
assertTrue(tree.apply(Collections.singletonList(cmd))); | |||
assertEquals(treeId, write(tree)); | |||
} | |||
@Test | |||
public void testApplyCannotCreateSubdirectory() throws Exception { | |||
RefTree tree = RefTree.newEmptyTree(); | |||
RevBlob a = git.blob("A"); | |||
Command cmd = new Command(null, ref(R_MASTER, a)); | |||
assertTrue(tree.apply(Collections.singletonList(cmd))); | |||
ObjectId treeId = write(tree); | |||
RevBlob b = git.blob("B"); | |||
Command cmd1 = create(R_MASTER + "/fail", b); | |||
assertFalse(tree.apply(Collections.singletonList(cmd1))); | |||
assertSame(LOCK_FAILURE, cmd1.getResult()); | |||
assertEquals(treeId, write(tree)); | |||
} | |||
@Test | |||
public void testApplyCannotCreateParentRef() throws Exception { | |||
RefTree tree = RefTree.newEmptyTree(); | |||
RevBlob a = git.blob("A"); | |||
Command cmd = new Command(null, ref(R_MASTER, a)); | |||
assertTrue(tree.apply(Collections.singletonList(cmd))); | |||
ObjectId treeId = write(tree); | |||
RevBlob b = git.blob("B"); | |||
Command cmd1 = create("refs/heads", b); | |||
assertFalse(tree.apply(Collections.singletonList(cmd1))); | |||
assertSame(LOCK_FAILURE, cmd1.getResult()); | |||
assertEquals(treeId, write(tree)); | |||
} | |||
private static Ref ref(String name, ObjectId id) { | |||
return new ObjectIdRef.PeeledNonTag(LOOSE, name, id); | |||
} | |||
private static Ref symref(String name, String dest) { | |||
Ref d = new ObjectIdRef.PeeledNonTag(NEW, dest, null); | |||
return new SymbolicRef(name, d); | |||
} | |||
private Command create(String name, ObjectId id) | |||
throws MissingObjectException, IOException { | |||
return update(name, ObjectId.zeroId(), id); | |||
} | |||
private Command update(String name, ObjectId oldId, ObjectId newId) | |||
throws MissingObjectException, IOException { | |||
try (RevWalk rw = new RevWalk(repo)) { | |||
return new Command(rw, new ReceiveCommand(oldId, newId, name)); | |||
} | |||
} | |||
private ObjectId write(RefTree tree) throws IOException { | |||
try (ObjectInserter ins = repo.newObjectInserter()) { | |||
ObjectId id = tree.writeTree(ins); | |||
ins.flush(); | |||
return id; | |||
} | |||
} | |||
} |
@@ -1084,7 +1084,7 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { | |||
assertWorkDir(mkmap(linkName, "a", fname, "a")); | |||
Status st = git.status().call(); | |||
assertFalse(st.isClean()); | |||
assertTrue(st.isClean()); | |||
} | |||
@Test | |||
@@ -1213,9 +1213,7 @@ public class DirCacheCheckoutTest extends RepositoryTestCase { | |||
assertWorkDir(mkmap(fname, "a")); | |||
Status st = git.status().call(); | |||
assertFalse(st.isClean()); | |||
assertEquals(1, st.getAdded().size()); | |||
assertTrue(st.getAdded().contains(fname + "/dir/file1")); | |||
assertTrue(st.isClean()); | |||
} | |||
@Test |
@@ -99,8 +99,7 @@ public class IndexDiffTest extends RepositoryTestCase { | |||
public void testAdded() throws IOException { | |||
writeTrashFile("file1", "file1"); | |||
writeTrashFile("dir/subfile", "dir/subfile"); | |||
Tree tree = new Tree(db); | |||
tree.setId(insertTree(tree)); | |||
ObjectId tree = insertTree(new TreeFormatter()); | |||
DirCache index = db.lockDirCache(); | |||
DirCacheEditor editor = index.editor(); | |||
@@ -108,7 +107,7 @@ public class IndexDiffTest extends RepositoryTestCase { | |||
editor.add(add(db, trash, "dir/subfile")); | |||
editor.commit(); | |||
FileTreeIterator iterator = new FileTreeIterator(db); | |||
IndexDiff diff = new IndexDiff(db, tree.getId(), iterator); | |||
IndexDiff diff = new IndexDiff(db, tree, iterator); | |||
diff.diff(); | |||
assertEquals(2, diff.getAdded().size()); | |||
assertTrue(diff.getAdded().contains("file1")); | |||
@@ -124,18 +123,16 @@ public class IndexDiffTest extends RepositoryTestCase { | |||
writeTrashFile("file2", "file2"); | |||
writeTrashFile("dir/file3", "dir/file3"); | |||
Tree tree = new Tree(db); | |||
tree.addFile("file2"); | |||
tree.addFile("dir/file3"); | |||
assertEquals(2, tree.memberCount()); | |||
tree.findBlobMember("file2").setId(ObjectId.fromString("30d67d4672d5c05833b7192cc77a79eaafb5c7ad")); | |||
Tree tree2 = (Tree) tree.findTreeMember("dir"); | |||
tree2.findBlobMember("file3").setId(ObjectId.fromString("873fb8d667d05436d728c52b1d7a09528e6eb59b")); | |||
tree2.setId(insertTree(tree2)); | |||
tree.setId(insertTree(tree)); | |||
TreeFormatter dir = new TreeFormatter(); | |||
dir.append("file3", FileMode.REGULAR_FILE, ObjectId.fromString("873fb8d667d05436d728c52b1d7a09528e6eb59b")); | |||
TreeFormatter tree = new TreeFormatter(); | |||
tree.append("file2", FileMode.REGULAR_FILE, ObjectId.fromString("30d67d4672d5c05833b7192cc77a79eaafb5c7ad")); | |||
tree.append("dir", FileMode.TREE, insertTree(dir)); | |||
ObjectId treeId = insertTree(tree); | |||
FileTreeIterator iterator = new FileTreeIterator(db); | |||
IndexDiff diff = new IndexDiff(db, tree.getId(), iterator); | |||
IndexDiff diff = new IndexDiff(db, treeId, iterator); | |||
diff.diff(); | |||
assertEquals(2, diff.getRemoved().size()); | |||
assertTrue(diff.getRemoved().contains("file2")); | |||
@@ -157,16 +154,16 @@ public class IndexDiffTest extends RepositoryTestCase { | |||
writeTrashFile("dir/file3", "changed"); | |||
Tree tree = new Tree(db); | |||
tree.addFile("file2").setId(ObjectId.fromString("0123456789012345678901234567890123456789")); | |||
tree.addFile("dir/file3").setId(ObjectId.fromString("0123456789012345678901234567890123456789")); | |||
assertEquals(2, tree.memberCount()); | |||
TreeFormatter dir = new TreeFormatter(); | |||
dir.append("file3", FileMode.REGULAR_FILE, ObjectId.fromString("0123456789012345678901234567890123456789")); | |||
TreeFormatter tree = new TreeFormatter(); | |||
tree.append("dir", FileMode.TREE, insertTree(dir)); | |||
tree.append("file2", FileMode.REGULAR_FILE, ObjectId.fromString("0123456789012345678901234567890123456789")); | |||
ObjectId treeId = insertTree(tree); | |||
Tree tree2 = (Tree) tree.findTreeMember("dir"); | |||
tree2.setId(insertTree(tree2)); | |||
tree.setId(insertTree(tree)); | |||
FileTreeIterator iterator = new FileTreeIterator(db); | |||
IndexDiff diff = new IndexDiff(db, tree.getId(), iterator); | |||
IndexDiff diff = new IndexDiff(db, treeId, iterator); | |||
diff.diff(); | |||
assertEquals(2, diff.getChanged().size()); | |||
assertTrue(diff.getChanged().contains("file2")); | |||
@@ -314,17 +311,16 @@ public class IndexDiffTest extends RepositoryTestCase { | |||
git.add().addFilepattern("a=c").call(); | |||
git.add().addFilepattern("a=d").call(); | |||
Tree tree = new Tree(db); | |||
TreeFormatter tree = new TreeFormatter(); | |||
// got the hash id'd from the data using echo -n a.b|git hash-object -t blob --stdin | |||
tree.addFile("a.b").setId(ObjectId.fromString("f6f28df96c2b40c951164286e08be7c38ec74851")); | |||
tree.addFile("a.c").setId(ObjectId.fromString("6bc0e647512d2a0bef4f26111e484dc87df7f5ca")); | |||
tree.addFile("a=c").setId(ObjectId.fromString("06022365ddbd7fb126761319633bf73517770714")); | |||
tree.addFile("a=d").setId(ObjectId.fromString("fa6414df3da87840700e9eeb7fc261dd77ccd5c2")); | |||
tree.setId(insertTree(tree)); | |||
tree.append("a.b", FileMode.REGULAR_FILE, ObjectId.fromString("f6f28df96c2b40c951164286e08be7c38ec74851")); | |||
tree.append("a.c", FileMode.REGULAR_FILE, ObjectId.fromString("6bc0e647512d2a0bef4f26111e484dc87df7f5ca")); | |||
tree.append("a=c", FileMode.REGULAR_FILE, ObjectId.fromString("06022365ddbd7fb126761319633bf73517770714")); | |||
tree.append("a=d", FileMode.REGULAR_FILE, ObjectId.fromString("fa6414df3da87840700e9eeb7fc261dd77ccd5c2")); | |||
ObjectId treeId = insertTree(tree); | |||
FileTreeIterator iterator = new FileTreeIterator(db); | |||
IndexDiff diff = new IndexDiff(db, tree.getId(), iterator); | |||
IndexDiff diff = new IndexDiff(db, treeId, iterator); | |||
diff.diff(); | |||
assertEquals(0, diff.getChanged().size()); | |||
assertEquals(0, diff.getAdded().size()); | |||
@@ -356,24 +352,27 @@ public class IndexDiffTest extends RepositoryTestCase { | |||
.addFilepattern("a/c").addFilepattern("a=c") | |||
.addFilepattern("a=d").call(); | |||
Tree tree = new Tree(db); | |||
// got the hash id'd from the data using echo -n a.b|git hash-object -t blob --stdin | |||
tree.addFile("a.b").setId(ObjectId.fromString("f6f28df96c2b40c951164286e08be7c38ec74851")); | |||
tree.addFile("a.c").setId(ObjectId.fromString("6bc0e647512d2a0bef4f26111e484dc87df7f5ca")); | |||
tree.addFile("a/b.b/b").setId(ObjectId.fromString("8d840bd4e2f3a48ff417c8e927d94996849933fd")); | |||
tree.addFile("a/b").setId(ObjectId.fromString("db89c972fc57862eae378f45b74aca228037d415")); | |||
tree.addFile("a/c").setId(ObjectId.fromString("52ad142a008aeb39694bafff8e8f1be75ed7f007")); | |||
tree.addFile("a=c").setId(ObjectId.fromString("06022365ddbd7fb126761319633bf73517770714")); | |||
tree.addFile("a=d").setId(ObjectId.fromString("fa6414df3da87840700e9eeb7fc261dd77ccd5c2")); | |||
Tree tree3 = (Tree) tree.findTreeMember("a/b.b"); | |||
tree3.setId(insertTree(tree3)); | |||
Tree tree2 = (Tree) tree.findTreeMember("a"); | |||
tree2.setId(insertTree(tree2)); | |||
tree.setId(insertTree(tree)); | |||
TreeFormatter bb = new TreeFormatter(); | |||
bb.append("b", FileMode.REGULAR_FILE, ObjectId.fromString("8d840bd4e2f3a48ff417c8e927d94996849933fd")); | |||
TreeFormatter a = new TreeFormatter(); | |||
a.append("b", FileMode.REGULAR_FILE, ObjectId | |||
.fromString("db89c972fc57862eae378f45b74aca228037d415")); | |||
a.append("b.b", FileMode.TREE, insertTree(bb)); | |||
a.append("c", FileMode.REGULAR_FILE, ObjectId.fromString("52ad142a008aeb39694bafff8e8f1be75ed7f007")); | |||
TreeFormatter tree = new TreeFormatter(); | |||
tree.append("a.b", FileMode.REGULAR_FILE, ObjectId.fromString("f6f28df96c2b40c951164286e08be7c38ec74851")); | |||
tree.append("a.c", FileMode.REGULAR_FILE, ObjectId.fromString("6bc0e647512d2a0bef4f26111e484dc87df7f5ca")); | |||
tree.append("a", FileMode.TREE, insertTree(a)); | |||
tree.append("a=c", FileMode.REGULAR_FILE, ObjectId.fromString("06022365ddbd7fb126761319633bf73517770714")); | |||
tree.append("a=d", FileMode.REGULAR_FILE, ObjectId.fromString("fa6414df3da87840700e9eeb7fc261dd77ccd5c2")); | |||
ObjectId treeId = insertTree(tree); | |||
FileTreeIterator iterator = new FileTreeIterator(db); | |||
IndexDiff diff = new IndexDiff(db, tree.getId(), iterator); | |||
IndexDiff diff = new IndexDiff(db, treeId, iterator); | |||
diff.diff(); | |||
assertEquals(0, diff.getChanged().size()); | |||
assertEquals(0, diff.getAdded().size()); | |||
@@ -383,9 +382,9 @@ public class IndexDiffTest extends RepositoryTestCase { | |||
assertEquals(Collections.EMPTY_SET, diff.getUntrackedFolders()); | |||
} | |||
private ObjectId insertTree(Tree tree) throws IOException { | |||
private ObjectId insertTree(TreeFormatter tree) throws IOException { | |||
try (ObjectInserter oi = db.newObjectInserter()) { | |||
ObjectId id = oi.insert(Constants.OBJ_TREE, tree.format()); | |||
ObjectId id = oi.insert(tree); | |||
oi.flush(); | |||
return id; | |||
} |
@@ -1,319 +0,0 @@ | |||
/* | |||
* Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com> | |||
* Copyright (C) 2006-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.lib; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertFalse; | |||
import static org.junit.Assert.assertNotNull; | |||
import static org.junit.Assert.assertSame; | |||
import static org.junit.Assert.assertTrue; | |||
import java.io.IOException; | |||
import java.io.UnsupportedEncodingException; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase; | |||
import org.junit.Test; | |||
@SuppressWarnings("deprecation") | |||
public class T0002_TreeTest extends SampleDataRepositoryTestCase { | |||
private static final ObjectId SOME_FAKE_ID = ObjectId.fromString( | |||
"0123456789abcdef0123456789abcdef01234567"); | |||
private static int compareNamesUsingSpecialCompare(String a, String b) | |||
throws UnsupportedEncodingException { | |||
char lasta = '\0'; | |||
byte[] abytes; | |||
if (a.length() > 0 && a.charAt(a.length()-1) == '/') { | |||
lasta = '/'; | |||
a = a.substring(0, a.length() - 1); | |||
} | |||
abytes = a.getBytes("ISO-8859-1"); | |||
char lastb = '\0'; | |||
byte[] bbytes; | |||
if (b.length() > 0 && b.charAt(b.length()-1) == '/') { | |||
lastb = '/'; | |||
b = b.substring(0, b.length() - 1); | |||
} | |||
bbytes = b.getBytes("ISO-8859-1"); | |||
return Tree.compareNames(abytes, bbytes, lasta, lastb); | |||
} | |||
@Test | |||
public void test000_sort_01() throws UnsupportedEncodingException { | |||
assertEquals(0, compareNamesUsingSpecialCompare("a","a")); | |||
} | |||
@Test | |||
public void test000_sort_02() throws UnsupportedEncodingException { | |||
assertEquals(-1, compareNamesUsingSpecialCompare("a","b")); | |||
assertEquals(1, compareNamesUsingSpecialCompare("b","a")); | |||
} | |||
@Test | |||
public void test000_sort_03() throws UnsupportedEncodingException { | |||
assertEquals(1, compareNamesUsingSpecialCompare("a:","a")); | |||
assertEquals(1, compareNamesUsingSpecialCompare("a/","a")); | |||
assertEquals(-1, compareNamesUsingSpecialCompare("a","a/")); | |||
assertEquals(-1, compareNamesUsingSpecialCompare("a","a:")); | |||
assertEquals(1, compareNamesUsingSpecialCompare("a:","a/")); | |||
assertEquals(-1, compareNamesUsingSpecialCompare("a/","a:")); | |||
} | |||
@Test | |||
public void test000_sort_04() throws UnsupportedEncodingException { | |||
assertEquals(-1, compareNamesUsingSpecialCompare("a.a","a/a")); | |||
assertEquals(1, compareNamesUsingSpecialCompare("a/a","a.a")); | |||
} | |||
@Test | |||
public void test000_sort_05() throws UnsupportedEncodingException { | |||
assertEquals(-1, compareNamesUsingSpecialCompare("a.","a/")); | |||
assertEquals(1, compareNamesUsingSpecialCompare("a/","a.")); | |||
} | |||
@Test | |||
public void test001_createEmpty() throws IOException { | |||
final Tree t = new Tree(db); | |||
assertTrue("isLoaded", t.isLoaded()); | |||
assertTrue("isModified", t.isModified()); | |||
assertTrue("no parent", t.getParent() == null); | |||
assertTrue("isRoot", t.isRoot()); | |||
assertTrue("no name", t.getName() == null); | |||
assertTrue("no nameUTF8", t.getNameUTF8() == null); | |||
assertTrue("has entries array", t.members() != null); | |||
assertEquals("entries is empty", 0, t.members().length); | |||
assertEquals("full name is empty", "", t.getFullName()); | |||
assertTrue("no id", t.getId() == null); | |||
assertTrue("database is r", t.getRepository() == db); | |||
assertTrue("no foo child", t.findTreeMember("foo") == null); | |||
assertTrue("no foo child", t.findBlobMember("foo") == null); | |||
} | |||
@Test | |||
public void test002_addFile() throws IOException { | |||
final Tree t = new Tree(db); | |||
t.setId(SOME_FAKE_ID); | |||
assertTrue("has id", t.getId() != null); | |||
assertFalse("not modified", t.isModified()); | |||
final String n = "bob"; | |||
final FileTreeEntry f = t.addFile(n); | |||
assertNotNull("have file", f); | |||
assertEquals("name matches", n, f.getName()); | |||
assertEquals("name matches", f.getName(), new String(f.getNameUTF8(), | |||
"UTF-8")); | |||
assertEquals("full name matches", n, f.getFullName()); | |||
assertTrue("no id", f.getId() == null); | |||
assertTrue("is modified", t.isModified()); | |||
assertTrue("has no id", t.getId() == null); | |||
assertTrue("found bob", t.findBlobMember(f.getName()) == f); | |||
final TreeEntry[] i = t.members(); | |||
assertNotNull("members array not null", i); | |||
assertTrue("iterator is not empty", i != null && i.length > 0); | |||
assertTrue("iterator returns file", i != null && i[0] == f); | |||
assertTrue("iterator is empty", i != null && i.length == 1); | |||
} | |||
@Test | |||
public void test004_addTree() throws IOException { | |||
final Tree t = new Tree(db); | |||
t.setId(SOME_FAKE_ID); | |||
assertTrue("has id", t.getId() != null); | |||
assertFalse("not modified", t.isModified()); | |||
final String n = "bob"; | |||
final Tree f = t.addTree(n); | |||
assertNotNull("have tree", f); | |||
assertEquals("name matches", n, f.getName()); | |||
assertEquals("name matches", f.getName(), new String(f.getNameUTF8(), | |||
"UTF-8")); | |||
assertEquals("full name matches", n, f.getFullName()); | |||
assertTrue("no id", f.getId() == null); | |||
assertTrue("parent matches", f.getParent() == t); | |||
assertTrue("repository matches", f.getRepository() == db); | |||
assertTrue("isLoaded", f.isLoaded()); | |||
assertFalse("has items", f.members().length > 0); | |||
assertFalse("is root", f.isRoot()); | |||
assertTrue("parent is modified", t.isModified()); | |||
assertTrue("parent has no id", t.getId() == null); | |||
assertTrue("found bob child", t.findTreeMember(f.getName()) == f); | |||
final TreeEntry[] i = t.members(); | |||
assertTrue("iterator is not empty", i.length > 0); | |||
assertTrue("iterator returns file", i[0] == f); | |||
assertEquals("iterator is empty", 1, i.length); | |||
} | |||
@Test | |||
public void test005_addRecursiveFile() throws IOException { | |||
final Tree t = new Tree(db); | |||
final FileTreeEntry f = t.addFile("a/b/c"); | |||
assertNotNull("created f", f); | |||
assertEquals("c", f.getName()); | |||
assertEquals("b", f.getParent().getName()); | |||
assertEquals("a", f.getParent().getParent().getName()); | |||
assertTrue("t is great-grandparent", t == f.getParent().getParent() | |||
.getParent()); | |||
} | |||
@Test | |||
public void test005_addRecursiveTree() throws IOException { | |||
final Tree t = new Tree(db); | |||
final Tree f = t.addTree("a/b/c"); | |||
assertNotNull("created f", f); | |||
assertEquals("c", f.getName()); | |||
assertEquals("b", f.getParent().getName()); | |||
assertEquals("a", f.getParent().getParent().getName()); | |||
assertTrue("t is great-grandparent", t == f.getParent().getParent() | |||
.getParent()); | |||
} | |||
@Test | |||
public void test006_addDeepTree() throws IOException { | |||
final Tree t = new Tree(db); | |||
final Tree e = t.addTree("e"); | |||
assertNotNull("have e", e); | |||
assertTrue("e.parent == t", e.getParent() == t); | |||
final Tree f = t.addTree("f"); | |||
assertNotNull("have f", f); | |||
assertTrue("f.parent == t", f.getParent() == t); | |||
final Tree g = f.addTree("g"); | |||
assertNotNull("have g", g); | |||
assertTrue("g.parent == f", g.getParent() == f); | |||
final Tree h = g.addTree("h"); | |||
assertNotNull("have h", h); | |||
assertTrue("h.parent = g", h.getParent() == g); | |||
h.setId(SOME_FAKE_ID); | |||
assertTrue("h not modified", !h.isModified()); | |||
g.setId(SOME_FAKE_ID); | |||
assertTrue("g not modified", !g.isModified()); | |||
f.setId(SOME_FAKE_ID); | |||
assertTrue("f not modified", !f.isModified()); | |||
e.setId(SOME_FAKE_ID); | |||
assertTrue("e not modified", !e.isModified()); | |||
t.setId(SOME_FAKE_ID); | |||
assertTrue("t not modified.", !t.isModified()); | |||
assertEquals("full path of h ok", "f/g/h", h.getFullName()); | |||
assertTrue("Can find h", t.findTreeMember(h.getFullName()) == h); | |||
assertTrue("Can't find f/z", t.findBlobMember("f/z") == null); | |||
assertTrue("Can't find y/z", t.findBlobMember("y/z") == null); | |||
final FileTreeEntry i = h.addFile("i"); | |||
assertNotNull(i); | |||
assertEquals("full path of i ok", "f/g/h/i", i.getFullName()); | |||
assertTrue("Can find i", t.findBlobMember(i.getFullName()) == i); | |||
assertTrue("h modified", h.isModified()); | |||
assertTrue("g modified", g.isModified()); | |||
assertTrue("f modified", f.isModified()); | |||
assertTrue("e not modified", !e.isModified()); | |||
assertTrue("t modified", t.isModified()); | |||
assertTrue("h no id", h.getId() == null); | |||
assertTrue("g no id", g.getId() == null); | |||
assertTrue("f no id", f.getId() == null); | |||
assertTrue("e has id", e.getId() != null); | |||
assertTrue("t no id", t.getId() == null); | |||
} | |||
@Test | |||
public void test007_manyFileLookup() throws IOException { | |||
final Tree t = new Tree(db); | |||
final List<FileTreeEntry> files = new ArrayList<FileTreeEntry>(26 * 26); | |||
for (char level1 = 'a'; level1 <= 'z'; level1++) { | |||
for (char level2 = 'a'; level2 <= 'z'; level2++) { | |||
final String n = "." + level1 + level2 + "9"; | |||
final FileTreeEntry f = t.addFile(n); | |||
assertNotNull("File " + n + " added.", f); | |||
assertEquals(n, f.getName()); | |||
files.add(f); | |||
} | |||
} | |||
assertEquals(files.size(), t.memberCount()); | |||
final TreeEntry[] ents = t.members(); | |||
assertNotNull(ents); | |||
assertEquals(files.size(), ents.length); | |||
for (int k = 0; k < ents.length; k++) { | |||
assertTrue("File " + files.get(k).getName() | |||
+ " is at " + k + ".", files.get(k) == ents[k]); | |||
} | |||
} | |||
@Test | |||
public void test008_SubtreeInternalSorting() throws IOException { | |||
final Tree t = new Tree(db); | |||
final FileTreeEntry e0 = t.addFile("a-b"); | |||
final FileTreeEntry e1 = t.addFile("a-"); | |||
final FileTreeEntry e2 = t.addFile("a=b"); | |||
final Tree e3 = t.addTree("a"); | |||
final FileTreeEntry e4 = t.addFile("a="); | |||
final TreeEntry[] ents = t.members(); | |||
assertSame(e1, ents[0]); | |||
assertSame(e0, ents[1]); | |||
assertSame(e3, ents[2]); | |||
assertSame(e4, ents[3]); | |||
assertSame(e2, ents[4]); | |||
} | |||
@Test | |||
public void test009_SymlinkAndGitlink() throws IOException { | |||
final Tree symlinkTree = mapTree("symlink"); | |||
assertTrue("Symlink entry exists", symlinkTree.existsBlob("symlink.txt")); | |||
final Tree gitlinkTree = mapTree("gitlink"); | |||
assertTrue("Gitlink entry exists", gitlinkTree.existsBlob("submodule")); | |||
} | |||
private Tree mapTree(String name) throws IOException { | |||
ObjectId id = db.resolve(name + "^{tree}"); | |||
return new Tree(db, id, db.open(id).getCachedBytes()); | |||
} | |||
} |
@@ -47,11 +47,10 @@ import static org.junit.Assert.assertNull; | |||
import static org.junit.Assert.assertSame; | |||
import static org.junit.Assert.assertTrue; | |||
import org.eclipse.jgit.lib.Constants; | |||
import org.eclipse.jgit.lib.FileTreeEntry; | |||
import org.eclipse.jgit.lib.FileMode; | |||
import org.eclipse.jgit.lib.ObjectId; | |||
import org.eclipse.jgit.lib.ObjectInserter; | |||
import org.eclipse.jgit.lib.Tree; | |||
import org.eclipse.jgit.lib.TreeFormatter; | |||
import org.junit.Test; | |||
@SuppressWarnings("deprecation") | |||
@@ -220,28 +219,24 @@ public class ObjectWalkTest extends RevWalkTestCase { | |||
.fromString("abbbfafe3129f85747aba7bfac992af77134c607"); | |||
final RevTree tree_root, tree_A, tree_AB; | |||
final RevCommit b; | |||
{ | |||
Tree root = new Tree(db); | |||
Tree A = root.addTree("A"); | |||
FileTreeEntry B = root.addFile("B"); | |||
B.setId(bId); | |||
Tree A_A = A.addTree("A"); | |||
Tree A_B = A.addTree("B"); | |||
try (final ObjectInserter inserter = db.newObjectInserter()) { | |||
A_A.setId(inserter.insert(Constants.OBJ_TREE, A_A.format())); | |||
A_B.setId(inserter.insert(Constants.OBJ_TREE, A_B.format())); | |||
A.setId(inserter.insert(Constants.OBJ_TREE, A.format())); | |||
root.setId(inserter.insert(Constants.OBJ_TREE, root.format())); | |||
inserter.flush(); | |||
} | |||
tree_root = rw.parseTree(root.getId()); | |||
tree_A = rw.parseTree(A.getId()); | |||
tree_AB = rw.parseTree(A_A.getId()); | |||
assertSame(tree_AB, rw.parseTree(A_B.getId())); | |||
b = commit(rw.parseTree(root.getId())); | |||
try (ObjectInserter inserter = db.newObjectInserter()) { | |||
ObjectId empty = inserter.insert(new TreeFormatter()); | |||
TreeFormatter A = new TreeFormatter(); | |||
A.append("A", FileMode.TREE, empty); | |||
A.append("B", FileMode.TREE, empty); | |||
ObjectId idA = inserter.insert(A); | |||
TreeFormatter root = new TreeFormatter(); | |||
root.append("A", FileMode.TREE, idA); | |||
root.append("B", FileMode.REGULAR_FILE, bId); | |||
ObjectId idRoot = inserter.insert(root); | |||
inserter.flush(); | |||
tree_root = objw.parseTree(idRoot); | |||
tree_A = objw.parseTree(idA); | |||
tree_AB = objw.parseTree(empty); | |||
b = commit(tree_root); | |||
} | |||
markStart(b); |
@@ -43,13 +43,18 @@ | |||
package org.eclipse.jgit.revwalk; | |||
import static java.nio.charset.StandardCharsets.UTF_8; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertNotNull; | |||
import static org.junit.Assert.assertNull; | |||
import static org.junit.Assert.assertSame; | |||
import static org.junit.Assert.assertTrue; | |||
import static org.junit.Assert.fail; | |||
import java.io.ByteArrayOutputStream; | |||
import java.io.UnsupportedEncodingException; | |||
import java.nio.charset.IllegalCharsetNameException; | |||
import java.nio.charset.UnsupportedCharsetException; | |||
import java.util.TimeZone; | |||
import org.eclipse.jgit.junit.RepositoryTestCase; | |||
@@ -303,6 +308,86 @@ public class RevCommitParseTest extends RepositoryTestCase { | |||
assertEquals("\u304d\u308c\u3044\n\nHi\n", c.getFullMessage()); | |||
} | |||
@Test | |||
public void testParse_incorrectUtf8Name() throws Exception { | |||
ByteArrayOutputStream b = new ByteArrayOutputStream(); | |||
b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n" | |||
.getBytes(UTF_8)); | |||
b.write("author au <a@example.com> 1218123387 +0700\n".getBytes(UTF_8)); | |||
b.write("committer co <c@example.com> 1218123390 -0500\n" | |||
.getBytes(UTF_8)); | |||
b.write("encoding 'utf8'\n".getBytes(UTF_8)); | |||
b.write("\n".getBytes(UTF_8)); | |||
b.write("Sm\u00f6rg\u00e5sbord\n".getBytes(UTF_8)); | |||
RevCommit c = new RevCommit( | |||
id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); | |||
c.parseCanonical(new RevWalk(db), b.toByteArray()); | |||
assertEquals("'utf8'", c.getEncodingName()); | |||
assertEquals("Sm\u00f6rg\u00e5sbord\n", c.getFullMessage()); | |||
try { | |||
c.getEncoding(); | |||
fail("Expected " + IllegalCharsetNameException.class); | |||
} catch (IllegalCharsetNameException badName) { | |||
assertEquals("'utf8'", badName.getMessage()); | |||
} | |||
} | |||
@Test | |||
public void testParse_illegalEncoding() throws Exception { | |||
ByteArrayOutputStream b = new ByteArrayOutputStream(); | |||
b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes(UTF_8)); | |||
b.write("author au <a@example.com> 1218123387 +0700\n".getBytes(UTF_8)); | |||
b.write("committer co <c@example.com> 1218123390 -0500\n".getBytes(UTF_8)); | |||
b.write("encoding utf-8logoutputencoding=gbk\n".getBytes(UTF_8)); | |||
b.write("\n".getBytes(UTF_8)); | |||
b.write("message\n".getBytes(UTF_8)); | |||
RevCommit c = new RevCommit( | |||
id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); | |||
c.parseCanonical(new RevWalk(db), b.toByteArray()); | |||
assertEquals("utf-8logoutputencoding=gbk", c.getEncodingName()); | |||
assertEquals("message\n", c.getFullMessage()); | |||
assertEquals("message", c.getShortMessage()); | |||
assertTrue(c.getFooterLines().isEmpty()); | |||
assertEquals("au", c.getAuthorIdent().getName()); | |||
try { | |||
c.getEncoding(); | |||
fail("Expected " + IllegalCharsetNameException.class); | |||
} catch (IllegalCharsetNameException badName) { | |||
assertEquals("utf-8logoutputencoding=gbk", badName.getMessage()); | |||
} | |||
} | |||
@Test | |||
public void testParse_unsupportedEncoding() throws Exception { | |||
ByteArrayOutputStream b = new ByteArrayOutputStream(); | |||
b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes(UTF_8)); | |||
b.write("author au <a@example.com> 1218123387 +0700\n".getBytes(UTF_8)); | |||
b.write("committer co <c@example.com> 1218123390 -0500\n".getBytes(UTF_8)); | |||
b.write("encoding it_IT.UTF8\n".getBytes(UTF_8)); | |||
b.write("\n".getBytes(UTF_8)); | |||
b.write("message\n".getBytes(UTF_8)); | |||
RevCommit c = new RevCommit( | |||
id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); | |||
c.parseCanonical(new RevWalk(db), b.toByteArray()); | |||
assertEquals("it_IT.UTF8", c.getEncodingName()); | |||
assertEquals("message\n", c.getFullMessage()); | |||
assertEquals("message", c.getShortMessage()); | |||
assertTrue(c.getFooterLines().isEmpty()); | |||
assertEquals("au", c.getAuthorIdent().getName()); | |||
try { | |||
c.getEncoding(); | |||
fail("Expected " + UnsupportedCharsetException.class); | |||
} catch (UnsupportedCharsetException badName) { | |||
assertEquals("it_IT.UTF8", badName.getMessage()); | |||
} | |||
} | |||
@Test | |||
public void testParse_NoMessage() throws Exception { | |||
final String msg = ""; |
@@ -43,6 +43,7 @@ | |||
package org.eclipse.jgit.revwalk; | |||
import static java.nio.charset.StandardCharsets.UTF_8; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertNotNull; | |||
import static org.junit.Assert.assertNull; | |||
@@ -361,6 +362,44 @@ public class RevTagParseTest extends RepositoryTestCase { | |||
assertEquals("\u304d\u308c\u3044\n\nHi\n", c.getFullMessage()); | |||
} | |||
@Test | |||
public void testParse_illegalEncoding() throws Exception { | |||
ByteArrayOutputStream b = new ByteArrayOutputStream(); | |||
b.write("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes(UTF_8)); | |||
b.write("type tree\n".getBytes(UTF_8)); | |||
b.write("tag v1.0\n".getBytes(UTF_8)); | |||
b.write("tagger t <t@example.com> 1218123387 +0700\n".getBytes(UTF_8)); | |||
b.write("encoding utf-8logoutputencoding=gbk\n".getBytes(UTF_8)); | |||
b.write("\n".getBytes(UTF_8)); | |||
b.write("message\n".getBytes(UTF_8)); | |||
RevTag t = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); | |||
t.parseCanonical(new RevWalk(db), b.toByteArray()); | |||
assertEquals("t", t.getTaggerIdent().getName()); | |||
assertEquals("message", t.getShortMessage()); | |||
assertEquals("message\n", t.getFullMessage()); | |||
} | |||
@Test | |||
public void testParse_unsupportedEncoding() throws Exception { | |||
ByteArrayOutputStream b = new ByteArrayOutputStream(); | |||
b.write("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes(UTF_8)); | |||
b.write("type tree\n".getBytes(UTF_8)); | |||
b.write("tag v1.0\n".getBytes(UTF_8)); | |||
b.write("tagger t <t@example.com> 1218123387 +0700\n".getBytes(UTF_8)); | |||
b.write("encoding it_IT.UTF8\n".getBytes(UTF_8)); | |||
b.write("\n".getBytes(UTF_8)); | |||
b.write("message\n".getBytes(UTF_8)); | |||
RevTag t = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); | |||
t.parseCanonical(new RevWalk(db), b.toByteArray()); | |||
assertEquals("t", t.getTaggerIdent().getName()); | |||
assertEquals("message", t.getShortMessage()); | |||
assertEquals("message\n", t.getFullMessage()); | |||
} | |||
@Test | |||
public void testParse_NoMessage() throws Exception { | |||
final String msg = ""; |
@@ -112,12 +112,9 @@ public class AtomicPushTest { | |||
public void pushNonAtomic() throws Exception { | |||
PushResult r; | |||
server.setPerformsAtomicTransactions(false); | |||
Transport tn = testProtocol.open(uri, client, "server"); | |||
try { | |||
try (Transport tn = testProtocol.open(uri, client, "server")) { | |||
tn.setPushAtomic(false); | |||
r = tn.push(NullProgressMonitor.INSTANCE, commands()); | |||
} finally { | |||
tn.close(); | |||
} | |||
RemoteRefUpdate one = r.getRemoteUpdate("refs/heads/one"); | |||
@@ -131,12 +128,9 @@ public class AtomicPushTest { | |||
@Test | |||
public void pushAtomicClientGivesUpEarly() throws Exception { | |||
PushResult r; | |||
Transport tn = testProtocol.open(uri, client, "server"); | |||
try { | |||
try (Transport tn = testProtocol.open(uri, client, "server")) { | |||
tn.setPushAtomic(true); | |||
r = tn.push(NullProgressMonitor.INSTANCE, commands()); | |||
} finally { | |||
tn.close(); | |||
} | |||
RemoteRefUpdate one = r.getRemoteUpdate("refs/heads/one"); | |||
@@ -167,8 +161,7 @@ public class AtomicPushTest { | |||
ObjectId.zeroId())); | |||
server.setPerformsAtomicTransactions(false); | |||
Transport tn = testProtocol.open(uri, client, "server"); | |||
try { | |||
try (Transport tn = testProtocol.open(uri, client, "server")) { | |||
tn.setPushAtomic(true); | |||
tn.push(NullProgressMonitor.INSTANCE, cmds); | |||
fail("did not throw TransportException"); | |||
@@ -176,8 +169,6 @@ public class AtomicPushTest { | |||
assertEquals( | |||
uri + ": " + JGitText.get().atomicPushNotSupported, | |||
e.getMessage()); | |||
} finally { | |||
tn.close(); | |||
} | |||
} | |||
@@ -168,8 +168,10 @@ public class BundleWriterTest extends SampleDataRepositoryTestCase { | |||
final ByteArrayInputStream in = new ByteArrayInputStream(bundle); | |||
final RefSpec rs = new RefSpec("refs/heads/*:refs/heads/*"); | |||
final Set<RefSpec> refs = Collections.singleton(rs); | |||
return new TransportBundleStream(newRepo, uri, in).fetch( | |||
NullProgressMonitor.INSTANCE, refs); | |||
try (TransportBundleStream transport = new TransportBundleStream( | |||
newRepo, uri, in)) { | |||
return transport.fetch(NullProgressMonitor.INSTANCE, refs); | |||
} | |||
} | |||
private byte[] makeBundle(final String name, |
@@ -116,12 +116,9 @@ public class ReceivePackAdvertiseRefsHookTest extends LocalDiskRepositoryTestCas | |||
// Clone from dst into src | |||
// | |||
Transport t = Transport.open(src, uriOf(dst)); | |||
try { | |||
try (Transport t = Transport.open(src, uriOf(dst))) { | |||
t.fetch(PM, Collections.singleton(new RefSpec("+refs/*:refs/*"))); | |||
assertEquals(B, src.resolve(R_MASTER)); | |||
} finally { | |||
t.close(); | |||
} | |||
// Now put private stuff into dst. | |||
@@ -144,7 +141,8 @@ public class ReceivePackAdvertiseRefsHookTest extends LocalDiskRepositoryTestCas | |||
@Test | |||
public void testFilterHidesPrivate() throws Exception { | |||
Map<String, Ref> refs; | |||
TransportLocal t = new TransportLocal(src, uriOf(dst), dst.getDirectory()) { | |||
try (TransportLocal t = new TransportLocal(src, uriOf(dst), | |||
dst.getDirectory()) { | |||
@Override | |||
ReceivePack createReceivePack(final Repository db) { | |||
db.close(); | |||
@@ -154,16 +152,10 @@ public class ReceivePackAdvertiseRefsHookTest extends LocalDiskRepositoryTestCas | |||
rp.setAdvertiseRefsHook(new HidePrivateHook()); | |||
return rp; | |||
} | |||
}; | |||
try { | |||
PushConnection c = t.openPush(); | |||
try { | |||
}) { | |||
try (PushConnection c = t.openPush()) { | |||
refs = c.getRefsMap(); | |||
} finally { | |||
c.close(); | |||
} | |||
} finally { | |||
t.close(); | |||
} | |||
assertNotNull(refs); |
@@ -340,6 +340,41 @@ public class RefSpecTest { | |||
assertEquals("refs/heads/foo", c.getSource()); | |||
} | |||
@Test | |||
public void testWildcardAfterText1() { | |||
RefSpec a = new RefSpec("refs/heads/*/for-linus:refs/remotes/mine/*-blah"); | |||
assertTrue(a.isWildcard()); | |||
assertTrue(a.matchDestination("refs/remotes/mine/x-blah")); | |||
assertTrue(a.matchDestination("refs/remotes/mine/foo-blah")); | |||
assertTrue(a.matchDestination("refs/remotes/mine/foo/x-blah")); | |||
assertFalse(a.matchDestination("refs/remotes/origin/foo/x-blah")); | |||
RefSpec b = a.expandFromSource("refs/heads/foo/for-linus"); | |||
assertEquals("refs/remotes/mine/foo-blah", b.getDestination()); | |||
RefSpec c = a.expandFromDestination("refs/remotes/mine/foo-blah"); | |||
assertEquals("refs/heads/foo/for-linus", c.getSource()); | |||
} | |||
@Test | |||
public void testWildcardAfterText2() { | |||
RefSpec a = new RefSpec("refs/heads*/for-linus:refs/remotes/mine/*"); | |||
assertTrue(a.isWildcard()); | |||
assertTrue(a.matchSource("refs/headsx/for-linus")); | |||
assertTrue(a.matchSource("refs/headsfoo/for-linus")); | |||
assertTrue(a.matchSource("refs/headsx/foo/for-linus")); | |||
assertFalse(a.matchSource("refs/headx/for-linus")); | |||
RefSpec b = a.expandFromSource("refs/headsx/for-linus"); | |||
assertEquals("refs/remotes/mine/x", b.getDestination()); | |||
RefSpec c = a.expandFromDestination("refs/remotes/mine/x"); | |||
assertEquals("refs/headsx/for-linus", c.getSource()); | |||
RefSpec d = a.expandFromSource("refs/headsx/foo/for-linus"); | |||
assertEquals("refs/remotes/mine/x/foo", d.getDestination()); | |||
RefSpec e = a.expandFromDestination("refs/remotes/mine/x/foo"); | |||
assertEquals("refs/headsx/foo/for-linus", e.getSource()); | |||
} | |||
@Test | |||
public void testWildcardMirror() { | |||
RefSpec a = new RefSpec("*:*"); | |||
@@ -403,21 +438,6 @@ public class RefSpecTest { | |||
assertNotNull(new RefSpec("refs/heads/*:refs/heads/*/*")); | |||
} | |||
@Test(expected = IllegalArgumentException.class) | |||
public void invalidWhenWildcardAfterText() { | |||
assertNotNull(new RefSpec("refs/heads/wrong*:refs/heads/right/*")); | |||
} | |||
@Test(expected = IllegalArgumentException.class) | |||
public void invalidWhenWildcardBeforeText() { | |||
assertNotNull(new RefSpec("*wrong:right/*")); | |||
} | |||
@Test(expected = IllegalArgumentException.class) | |||
public void invalidWhenWildcardBeforeTextAtEnd() { | |||
assertNotNull(new RefSpec("refs/heads/*wrong:right/*")); | |||
} | |||
@Test(expected = IllegalArgumentException.class) | |||
public void invalidSourceDoubleSlashes() { | |||
assertNotNull(new RefSpec("refs/heads//wrong")); |
@@ -61,13 +61,10 @@ import org.eclipse.jgit.lib.ObjectId; | |||
import org.eclipse.jgit.lib.Ref; | |||
import org.eclipse.jgit.lib.Repository; | |||
import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase; | |||
import org.junit.After; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
public class TransportTest extends SampleDataRepositoryTestCase { | |||
private Transport transport; | |||
private RemoteConfig remoteConfig; | |||
@Override | |||
@@ -77,17 +74,6 @@ public class TransportTest extends SampleDataRepositoryTestCase { | |||
final Config config = db.getConfig(); | |||
remoteConfig = new RemoteConfig(config, "test"); | |||
remoteConfig.addURI(new URIish("http://everyones.loves.git/u/2")); | |||
transport = null; | |||
} | |||
@Override | |||
@After | |||
public void tearDown() throws Exception { | |||
if (transport != null) { | |||
transport.close(); | |||
transport = null; | |||
} | |||
super.tearDown(); | |||
} | |||
/** | |||
@@ -99,10 +85,11 @@ public class TransportTest extends SampleDataRepositoryTestCase { | |||
@Test | |||
public void testFindRemoteRefUpdatesNoWildcardNoTracking() | |||
throws IOException { | |||
transport = Transport.open(db, remoteConfig); | |||
final Collection<RemoteRefUpdate> result = transport | |||
.findRemoteRefUpdatesFor(Collections.nCopies(1, new RefSpec( | |||
"refs/heads/master:refs/heads/x"))); | |||
Collection<RemoteRefUpdate> result; | |||
try (Transport transport = Transport.open(db, remoteConfig)) { | |||
result = transport.findRemoteRefUpdatesFor(Collections.nCopies(1, | |||
new RefSpec("refs/heads/master:refs/heads/x"))); | |||
} | |||
assertEquals(1, result.size()); | |||
final RemoteRefUpdate rru = result.iterator().next(); | |||
@@ -122,10 +109,11 @@ public class TransportTest extends SampleDataRepositoryTestCase { | |||
@Test | |||
public void testFindRemoteRefUpdatesNoWildcardNoDestination() | |||
throws IOException { | |||
transport = Transport.open(db, remoteConfig); | |||
final Collection<RemoteRefUpdate> result = transport | |||
.findRemoteRefUpdatesFor(Collections.nCopies(1, new RefSpec( | |||
"+refs/heads/master"))); | |||
Collection<RemoteRefUpdate> result; | |||
try (Transport transport = Transport.open(db, remoteConfig)) { | |||
result = transport.findRemoteRefUpdatesFor( | |||
Collections.nCopies(1, new RefSpec("+refs/heads/master"))); | |||
} | |||
assertEquals(1, result.size()); | |||
final RemoteRefUpdate rru = result.iterator().next(); | |||
@@ -143,10 +131,11 @@ public class TransportTest extends SampleDataRepositoryTestCase { | |||
*/ | |||
@Test | |||
public void testFindRemoteRefUpdatesWildcardNoTracking() throws IOException { | |||
transport = Transport.open(db, remoteConfig); | |||
final Collection<RemoteRefUpdate> result = transport | |||
.findRemoteRefUpdatesFor(Collections.nCopies(1, new RefSpec( | |||
"+refs/heads/*:refs/heads/test/*"))); | |||
Collection<RemoteRefUpdate> result; | |||
try (Transport transport = Transport.open(db, remoteConfig)) { | |||
result = transport.findRemoteRefUpdatesFor(Collections.nCopies(1, | |||
new RefSpec("+refs/heads/*:refs/heads/test/*"))); | |||
} | |||
assertEquals(12, result.size()); | |||
boolean foundA = false; | |||
@@ -171,12 +160,14 @@ public class TransportTest extends SampleDataRepositoryTestCase { | |||
*/ | |||
@Test | |||
public void testFindRemoteRefUpdatesTwoRefSpecs() throws IOException { | |||
transport = Transport.open(db, remoteConfig); | |||
final RefSpec specA = new RefSpec("+refs/heads/a:refs/heads/b"); | |||
final RefSpec specC = new RefSpec("+refs/heads/c:refs/heads/d"); | |||
final Collection<RefSpec> specs = Arrays.asList(specA, specC); | |||
final Collection<RemoteRefUpdate> result = transport | |||
.findRemoteRefUpdatesFor(specs); | |||
Collection<RemoteRefUpdate> result; | |||
try (Transport transport = Transport.open(db, remoteConfig)) { | |||
result = transport.findRemoteRefUpdatesFor(specs); | |||
} | |||
assertEquals(2, result.size()); | |||
boolean foundA = false; | |||
@@ -202,10 +193,12 @@ public class TransportTest extends SampleDataRepositoryTestCase { | |||
public void testFindRemoteRefUpdatesTrackingRef() throws IOException { | |||
remoteConfig.addFetchRefSpec(new RefSpec( | |||
"refs/heads/*:refs/remotes/test/*")); | |||
transport = Transport.open(db, remoteConfig); | |||
final Collection<RemoteRefUpdate> result = transport | |||
.findRemoteRefUpdatesFor(Collections.nCopies(1, new RefSpec( | |||
"+refs/heads/a:refs/heads/a"))); | |||
Collection<RemoteRefUpdate> result; | |||
try (Transport transport = Transport.open(db, remoteConfig)) { | |||
result = transport.findRemoteRefUpdatesFor(Collections.nCopies(1, | |||
new RefSpec("+refs/heads/a:refs/heads/a"))); | |||
} | |||
assertEquals(1, result.size()); | |||
final TrackingRefUpdate tru = result.iterator().next() | |||
@@ -225,20 +218,18 @@ public class TransportTest extends SampleDataRepositoryTestCase { | |||
config.addURI(new URIish("../" + otherDir)); | |||
// Should not throw NoRemoteRepositoryException | |||
transport = Transport.open(db, config); | |||
Transport.open(db, config).close(); | |||
} | |||
@Test | |||
public void testLocalTransportFetchWithoutLocalRepository() | |||
throws Exception { | |||
URIish uri = new URIish("file://" + db.getWorkTree().getAbsolutePath()); | |||
transport = Transport.open(uri); | |||
FetchConnection fetchConnection = transport.openFetch(); | |||
try { | |||
Ref head = fetchConnection.getRef(Constants.HEAD); | |||
assertNotNull(head); | |||
} finally { | |||
fetchConnection.close(); | |||
try (Transport transport = Transport.open(uri)) { | |||
try (FetchConnection fetchConnection = transport.openFetch()) { | |||
Ref head = fetchConnection.getRef(Constants.HEAD); | |||
assertNotNull(head); | |||
} | |||
} | |||
} | |||
@@ -459,6 +459,48 @@ public class URIishTest { | |||
assertEquals(u, new URIish(str)); | |||
} | |||
@Test | |||
public void testSshProtoWithEmailUserAndPort() throws Exception { | |||
final String str = "ssh://user.name@email.com@example.com:33/some/p ath"; | |||
URIish u = new URIish(str); | |||
assertEquals("ssh", u.getScheme()); | |||
assertTrue(u.isRemote()); | |||
assertEquals("/some/p ath", u.getRawPath()); | |||
assertEquals("/some/p ath", u.getPath()); | |||
assertEquals("example.com", u.getHost()); | |||
assertEquals("user.name@email.com", u.getUser()); | |||
assertNull(u.getPass()); | |||
assertEquals(33, u.getPort()); | |||
assertEquals("ssh://user.name%40email.com@example.com:33/some/p ath", | |||
u.toPrivateString()); | |||
assertEquals("ssh://user.name%40email.com@example.com:33/some/p%20ath", | |||
u.toPrivateASCIIString()); | |||
assertEquals(u.setPass(null).toPrivateString(), u.toString()); | |||
assertEquals(u.setPass(null).toPrivateASCIIString(), u.toASCIIString()); | |||
assertEquals(u, new URIish(str)); | |||
} | |||
@Test | |||
public void testSshProtoWithEmailUserPassAndPort() throws Exception { | |||
final String str = "ssh://user.name@email.com:pass@wor:d@example.com:33/some/p ath"; | |||
URIish u = new URIish(str); | |||
assertEquals("ssh", u.getScheme()); | |||
assertTrue(u.isRemote()); | |||
assertEquals("/some/p ath", u.getRawPath()); | |||
assertEquals("/some/p ath", u.getPath()); | |||
assertEquals("example.com", u.getHost()); | |||
assertEquals("user.name@email.com", u.getUser()); | |||
assertEquals("pass@wor:d", u.getPass()); | |||
assertEquals(33, u.getPort()); | |||
assertEquals("ssh://user.name%40email.com:pass%40wor%3ad@example.com:33/some/p ath", | |||
u.toPrivateString()); | |||
assertEquals("ssh://user.name%40email.com:pass%40wor%3ad@example.com:33/some/p%20ath", | |||
u.toPrivateASCIIString()); | |||
assertEquals(u.setPass(null).toPrivateString(), u.toString()); | |||
assertEquals(u.setPass(null).toPrivateASCIIString(), u.toASCIIString()); | |||
assertEquals(u, new URIish(str)); | |||
} | |||
@Test | |||
public void testSshProtoWithADUserPassAndPort() throws Exception { | |||
final String str = "ssh://DOMAIN\\user:pass@example.com:33/some/p ath"; |
@@ -44,7 +44,6 @@ | |||
package org.eclipse.jgit.treewalk; | |||
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB; | |||
import static org.eclipse.jgit.lib.Constants.OBJ_TREE; | |||
import static org.eclipse.jgit.lib.Constants.encode; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertFalse; | |||
@@ -54,11 +53,10 @@ import org.eclipse.jgit.junit.RepositoryTestCase; | |||
import org.eclipse.jgit.lib.FileMode; | |||
import org.eclipse.jgit.lib.ObjectId; | |||
import org.eclipse.jgit.lib.ObjectInserter; | |||
import org.eclipse.jgit.lib.Tree; | |||
import org.eclipse.jgit.lib.TreeFormatter; | |||
import org.eclipse.jgit.treewalk.filter.TreeFilter; | |||
import org.junit.Test; | |||
@SuppressWarnings("deprecation") | |||
public class TreeWalkBasicDiffTest extends RepositoryTestCase { | |||
@Test | |||
public void testMissingSubtree_DetectFileAdded_FileModified() | |||
@@ -72,62 +70,63 @@ public class TreeWalkBasicDiffTest extends RepositoryTestCase { | |||
// Create sub-a/empty, sub-c/empty = hello. | |||
{ | |||
final Tree root = new Tree(db); | |||
TreeFormatter root = new TreeFormatter(); | |||
{ | |||
final Tree subA = root.addTree("sub-a"); | |||
subA.addFile("empty").setId(aFileId); | |||
subA.setId(inserter.insert(OBJ_TREE, subA.format())); | |||
TreeFormatter subA = new TreeFormatter(); | |||
subA.append("empty", FileMode.REGULAR_FILE, aFileId); | |||
root.append("sub-a", FileMode.TREE, inserter.insert(subA)); | |||
} | |||
{ | |||
final Tree subC = root.addTree("sub-c"); | |||
subC.addFile("empty").setId(cFileId1); | |||
subC.setId(inserter.insert(OBJ_TREE, subC.format())); | |||
TreeFormatter subC = new TreeFormatter(); | |||
subC.append("empty", FileMode.REGULAR_FILE, cFileId1); | |||
root.append("sub-c", FileMode.TREE, inserter.insert(subC)); | |||
} | |||
oldTree = inserter.insert(OBJ_TREE, root.format()); | |||
oldTree = inserter.insert(root); | |||
} | |||
// Create sub-a/empty, sub-b/empty, sub-c/empty. | |||
{ | |||
final Tree root = new Tree(db); | |||
TreeFormatter root = new TreeFormatter(); | |||
{ | |||
final Tree subA = root.addTree("sub-a"); | |||
subA.addFile("empty").setId(aFileId); | |||
subA.setId(inserter.insert(OBJ_TREE, subA.format())); | |||
TreeFormatter subA = new TreeFormatter(); | |||
subA.append("empty", FileMode.REGULAR_FILE, aFileId); | |||
root.append("sub-a", FileMode.TREE, inserter.insert(subA)); | |||
} | |||
{ | |||
final Tree subB = root.addTree("sub-b"); | |||
subB.addFile("empty").setId(bFileId); | |||
subB.setId(inserter.insert(OBJ_TREE, subB.format())); | |||
TreeFormatter subB = new TreeFormatter(); | |||
subB.append("empty", FileMode.REGULAR_FILE, bFileId); | |||
root.append("sub-b", FileMode.TREE, inserter.insert(subB)); | |||
} | |||
{ | |||
final Tree subC = root.addTree("sub-c"); | |||
subC.addFile("empty").setId(cFileId2); | |||
subC.setId(inserter.insert(OBJ_TREE, subC.format())); | |||
TreeFormatter subC = new TreeFormatter(); | |||
subC.append("empty", FileMode.REGULAR_FILE, cFileId2); | |||
root.append("sub-c", FileMode.TREE, inserter.insert(subC)); | |||
} | |||
newTree = inserter.insert(OBJ_TREE, root.format()); | |||
newTree = inserter.insert(root); | |||
} | |||
inserter.flush(); | |||
} | |||
final TreeWalk tw = new TreeWalk(db); | |||
tw.reset(oldTree, newTree); | |||
tw.setRecursive(true); | |||
tw.setFilter(TreeFilter.ANY_DIFF); | |||
try (TreeWalk tw = new TreeWalk(db)) { | |||
tw.reset(oldTree, newTree); | |||
tw.setRecursive(true); | |||
tw.setFilter(TreeFilter.ANY_DIFF); | |||
assertTrue(tw.next()); | |||
assertEquals("sub-b/empty", tw.getPathString()); | |||
assertEquals(FileMode.MISSING, tw.getFileMode(0)); | |||
assertEquals(FileMode.REGULAR_FILE, tw.getFileMode(1)); | |||
assertEquals(ObjectId.zeroId(), tw.getObjectId(0)); | |||
assertEquals(bFileId, tw.getObjectId(1)); | |||
assertTrue(tw.next()); | |||
assertEquals("sub-b/empty", tw.getPathString()); | |||
assertEquals(FileMode.MISSING, tw.getFileMode(0)); | |||
assertEquals(FileMode.REGULAR_FILE, tw.getFileMode(1)); | |||
assertEquals(ObjectId.zeroId(), tw.getObjectId(0)); | |||
assertEquals(bFileId, tw.getObjectId(1)); | |||
assertTrue(tw.next()); | |||
assertEquals("sub-c/empty", tw.getPathString()); | |||
assertEquals(FileMode.REGULAR_FILE, tw.getFileMode(0)); | |||
assertEquals(FileMode.REGULAR_FILE, tw.getFileMode(1)); | |||
assertEquals(cFileId1, tw.getObjectId(0)); | |||
assertEquals(cFileId2, tw.getObjectId(1)); | |||
assertTrue(tw.next()); | |||
assertEquals("sub-c/empty", tw.getPathString()); | |||
assertEquals(FileMode.REGULAR_FILE, tw.getFileMode(0)); | |||
assertEquals(FileMode.REGULAR_FILE, tw.getFileMode(1)); | |||
assertEquals(cFileId1, tw.getObjectId(0)); | |||
assertEquals(cFileId2, tw.getObjectId(1)); | |||
assertFalse(tw.next()); | |||
assertFalse(tw.next()); | |||
} | |||
} | |||
} |
@@ -43,11 +43,18 @@ | |||
package org.eclipse.jgit.treewalk.filter; | |||
import static org.junit.Assert.assertArrayEquals; | |||
import static org.junit.Assert.assertFalse; | |||
import static org.junit.Assert.assertTrue; | |||
import static org.junit.Assert.fail; | |||
import java.io.IOException; | |||
import java.util.ArrayList; | |||
import java.util.Arrays; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import org.eclipse.jgit.dircache.DirCache; | |||
import org.eclipse.jgit.dircache.DirCacheEditor; | |||
@@ -58,6 +65,7 @@ import org.eclipse.jgit.errors.MissingObjectException; | |||
import org.eclipse.jgit.errors.StopWalkException; | |||
import org.eclipse.jgit.lib.FileMode; | |||
import org.eclipse.jgit.lib.ObjectReader; | |||
import org.eclipse.jgit.lib.Sets; | |||
import org.eclipse.jgit.treewalk.TreeWalk; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
@@ -66,6 +74,8 @@ public class PathFilterGroupTest { | |||
private TreeFilter filter; | |||
private Map<String, TreeFilter> singles; | |||
@Before | |||
public void setup() { | |||
// @formatter:off | |||
@@ -81,64 +91,75 @@ public class PathFilterGroupTest { | |||
}; | |||
// @formatter:on | |||
filter = PathFilterGroup.createFromStrings(paths); | |||
singles = new HashMap<>(); | |||
for (String path : paths) { | |||
singles.put(path, PathFilterGroup.createFromStrings(path)); | |||
} | |||
} | |||
@Test | |||
public void testExact() throws MissingObjectException, | |||
IncorrectObjectTypeException, IOException { | |||
assertTrue(filter.include(fakeWalk("a"))); | |||
assertTrue(filter.include(fakeWalk("b/c"))); | |||
assertTrue(filter.include(fakeWalk("c/d/e"))); | |||
assertTrue(filter.include(fakeWalk("c/d/f"))); | |||
assertTrue(filter.include(fakeWalk("d/e/f/g"))); | |||
assertTrue(filter.include(fakeWalk("d/e/f/g.x"))); | |||
assertMatches(Sets.of("a"), fakeWalk("a")); | |||
assertMatches(Sets.of("b/c"), fakeWalk("b/c")); | |||
assertMatches(Sets.of("c/d/e"), fakeWalk("c/d/e")); | |||
assertMatches(Sets.of("c/d/f"), fakeWalk("c/d/f")); | |||
assertMatches(Sets.of("d/e/f/g"), fakeWalk("d/e/f/g")); | |||
assertMatches(Sets.of("d/e/f/g.x"), fakeWalk("d/e/f/g.x")); | |||
} | |||
@Test | |||
public void testNoMatchButClose() throws MissingObjectException, | |||
IncorrectObjectTypeException, IOException { | |||
assertFalse(filter.include(fakeWalk("a+"))); | |||
assertFalse(filter.include(fakeWalk("b+/c"))); | |||
assertFalse(filter.include(fakeWalk("c+/d/e"))); | |||
assertFalse(filter.include(fakeWalk("c+/d/f"))); | |||
assertFalse(filter.include(fakeWalk("c/d.a"))); | |||
assertFalse(filter.include(fakeWalk("d+/e/f/g"))); | |||
assertNoMatches(fakeWalk("a+")); | |||
assertNoMatches(fakeWalk("b+/c")); | |||
assertNoMatches(fakeWalk("c+/d/e")); | |||
assertNoMatches(fakeWalk("c+/d/f")); | |||
assertNoMatches(fakeWalk("c/d.a")); | |||
assertNoMatches(fakeWalk("d+/e/f/g")); | |||
} | |||
@Test | |||
public void testJustCommonPrefixIsNotMatch() throws MissingObjectException, | |||
IncorrectObjectTypeException, IOException { | |||
assertFalse(filter.include(fakeWalk("b/a"))); | |||
assertFalse(filter.include(fakeWalk("b/d"))); | |||
assertFalse(filter.include(fakeWalk("c/d/a"))); | |||
assertFalse(filter.include(fakeWalk("d/e/e"))); | |||
assertNoMatches(fakeWalk("b/a")); | |||
assertNoMatches(fakeWalk("b/d")); | |||
assertNoMatches(fakeWalk("c/d/a")); | |||
assertNoMatches(fakeWalk("d/e/e")); | |||
assertNoMatches(fakeWalk("d/e/f/g.y")); | |||
} | |||
@Test | |||
public void testKeyIsPrefixOfFilter() throws MissingObjectException, | |||
IncorrectObjectTypeException, IOException { | |||
assertTrue(filter.include(fakeWalk("b"))); | |||
assertTrue(filter.include(fakeWalk("c/d"))); | |||
assertTrue(filter.include(fakeWalk("c/d"))); | |||
assertTrue(filter.include(fakeWalk("c"))); | |||
assertTrue(filter.include(fakeWalk("d/e/f"))); | |||
assertTrue(filter.include(fakeWalk("d/e"))); | |||
assertTrue(filter.include(fakeWalk("d"))); | |||
assertMatches(Sets.of("b/c"), fakeWalkAtSubtree("b")); | |||
assertMatches(Sets.of("c/d/e", "c/d/f"), fakeWalkAtSubtree("c/d")); | |||
assertMatches(Sets.of("c/d/e", "c/d/f"), fakeWalkAtSubtree("c")); | |||
assertMatches(Sets.of("d/e/f/g", "d/e/f/g.x"), | |||
fakeWalkAtSubtree("d/e/f")); | |||
assertMatches(Sets.of("d/e/f/g", "d/e/f/g.x"), | |||
fakeWalkAtSubtree("d/e")); | |||
assertMatches(Sets.of("d/e/f/g", "d/e/f/g.x"), fakeWalkAtSubtree("d")); | |||
assertNoMatches(fakeWalk("b")); | |||
assertNoMatches(fakeWalk("c/d")); | |||
assertNoMatches(fakeWalk("c")); | |||
assertNoMatches(fakeWalk("d/e/f")); | |||
assertNoMatches(fakeWalk("d/e")); | |||
assertNoMatches(fakeWalk("d")); | |||
} | |||
@Test | |||
public void testFilterIsPrefixOfKey() throws MissingObjectException, | |||
IncorrectObjectTypeException, IOException { | |||
assertTrue(filter.include(fakeWalk("a/b"))); | |||
assertTrue(filter.include(fakeWalk("b/c/d"))); | |||
assertTrue(filter.include(fakeWalk("c/d/e/f"))); | |||
assertTrue(filter.include(fakeWalk("c/d/f/g"))); | |||
assertTrue(filter.include(fakeWalk("d/e/f/g/h"))); | |||
assertTrue(filter.include(fakeWalk("d/e/f/g/y"))); | |||
assertTrue(filter.include(fakeWalk("d/e/f/g.x/h"))); | |||
// listed before g/y, so can't StopWalk here, but it's not included | |||
// either | |||
assertFalse(filter.include(fakeWalk("d/e/f/g.y"))); | |||
assertMatches(Sets.of("a"), fakeWalk("a/b")); | |||
assertMatches(Sets.of("b/c"), fakeWalk("b/c/d")); | |||
assertMatches(Sets.of("c/d/e"), fakeWalk("c/d/e/f")); | |||
assertMatches(Sets.of("c/d/f"), fakeWalk("c/d/f/g")); | |||
assertMatches(Sets.of("d/e/f/g"), fakeWalk("d/e/f/g/h")); | |||
assertMatches(Sets.of("d/e/f/g"), fakeWalk("d/e/f/g/y")); | |||
assertMatches(Sets.of("d/e/f/g.x"), fakeWalk("d/e/f/g.x/h")); | |||
} | |||
@Test | |||
@@ -182,6 +203,10 @@ public class PathFilterGroupTest { | |||
// less obvious #2 due to git sorting order | |||
filter.include(fakeWalk("d/e/f/g/h.txt")); | |||
// listed before g/y, so can't StopWalk here | |||
filter.include(fakeWalk("d/e/f/g.y")); | |||
singles.get("d/e/f/g").include(fakeWalk("d/e/f/g.y")); | |||
// non-ascii | |||
try { | |||
filter.include(fakeWalk("\u00C0")); | |||
@@ -191,6 +216,44 @@ public class PathFilterGroupTest { | |||
} | |||
} | |||
private void assertNoMatches(TreeWalk tw) throws MissingObjectException, | |||
IncorrectObjectTypeException, IOException { | |||
assertMatches(Sets.<String> of(), tw); | |||
} | |||
private void assertMatches(Set<String> expect, TreeWalk tw) | |||
throws MissingObjectException, IncorrectObjectTypeException, | |||
IOException { | |||
List<String> actual = new ArrayList<>(); | |||
for (String path : singles.keySet()) { | |||
if (includes(singles.get(path), tw)) { | |||
actual.add(path); | |||
} | |||
} | |||
String[] e = expect.toArray(new String[expect.size()]); | |||
String[] a = actual.toArray(new String[actual.size()]); | |||
Arrays.sort(e); | |||
Arrays.sort(a); | |||
assertArrayEquals(e, a); | |||
if (expect.isEmpty()) { | |||
assertFalse(includes(filter, tw)); | |||
} else { | |||
assertTrue(includes(filter, tw)); | |||
} | |||
} | |||
private static boolean includes(TreeFilter f, TreeWalk tw) | |||
throws MissingObjectException, IncorrectObjectTypeException, | |||
IOException { | |||
try { | |||
return f.include(tw); | |||
} catch (StopWalkException e) { | |||
return false; | |||
} | |||
} | |||
TreeWalk fakeWalk(final String path) throws IOException { | |||
DirCache dc = DirCache.newInCore(); | |||
DirCacheEditor dce = dc.editor(); | |||
@@ -210,4 +273,25 @@ public class PathFilterGroupTest { | |||
return ret; | |||
} | |||
TreeWalk fakeWalkAtSubtree(final String path) throws IOException { | |||
DirCache dc = DirCache.newInCore(); | |||
DirCacheEditor dce = dc.editor(); | |||
dce.add(new DirCacheEditor.PathEdit(path + "/README") { | |||
public void apply(DirCacheEntry ent) { | |||
ent.setFileMode(FileMode.REGULAR_FILE); | |||
} | |||
}); | |||
dce.finish(); | |||
TreeWalk ret = new TreeWalk((ObjectReader) null); | |||
ret.addTree(new DirCacheIterator(dc)); | |||
ret.next(); | |||
while (!path.equals(ret.getPathString())) { | |||
if (ret.isSubtree()) { | |||
ret.enterSubtree(); | |||
} | |||
ret.next(); | |||
} | |||
return ret; | |||
} | |||
} |
@@ -45,7 +45,6 @@ package org.eclipse.jgit.util; | |||
import static org.junit.Assert.assertEquals; | |||
import java.io.IOException; | |||
import java.util.concurrent.TimeUnit; | |||
import org.eclipse.jgit.junit.MockSystemReader; | |||
@@ -113,7 +112,7 @@ public class ChangeIdUtilTest { | |||
} | |||
@Test | |||
public void testId() throws IOException { | |||
public void testId() { | |||
String msg = "A\nMessage\n"; | |||
ObjectId id = ChangeIdUtil.computeChangeId(treeId, parentId, p, q, msg); | |||
assertEquals("73f3751208ac92cbb76f9a26ac4a0d9d472e381b", ObjectId |
@@ -54,6 +54,7 @@ import java.util.regex.Matcher; | |||
import org.eclipse.jgit.junit.JGitTestUtil; | |||
import org.junit.After; | |||
import org.junit.Assume; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
@@ -424,18 +425,27 @@ public class FileUtilTest { | |||
@Test | |||
public void testCreateSymlink() throws IOException { | |||
FS fs = FS.DETECTED; | |||
try { | |||
fs.createSymLink(new File(trash, "x"), "y"); | |||
} catch (IOException e) { | |||
if (fs.supportsSymlinks()) | |||
fail("FS claims to support symlinks but attempt to create symlink failed"); | |||
return; | |||
} | |||
assertTrue(fs.supportsSymlinks()); | |||
// show test as ignored if the FS doesn't support symlinks | |||
Assume.assumeTrue(fs.supportsSymlinks()); | |||
fs.createSymLink(new File(trash, "x"), "y"); | |||
String target = fs.readSymLink(new File(trash, "x")); | |||
assertEquals("y", target); | |||
} | |||
@Test | |||
public void testCreateSymlinkOverrideExisting() throws IOException { | |||
FS fs = FS.DETECTED; | |||
// show test as ignored if the FS doesn't support symlinks | |||
Assume.assumeTrue(fs.supportsSymlinks()); | |||
File file = new File(trash, "x"); | |||
fs.createSymLink(file, "y"); | |||
String target = fs.readSymLink(file); | |||
assertEquals("y", target); | |||
fs.createSymLink(file, "z"); | |||
target = fs.readSymLink(file); | |||
assertEquals("z", target); | |||
} | |||
@Test | |||
public void testRelativize_doc() { | |||
// This is the javadoc example |
@@ -0,0 +1,118 @@ | |||
/* | |||
* Copyright (C) 2016, 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.util; | |||
import static org.eclipse.jgit.util.Paths.compare; | |||
import static org.eclipse.jgit.util.Paths.compareSameName; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertNull; | |||
import org.eclipse.jgit.lib.Constants; | |||
import org.eclipse.jgit.lib.FileMode; | |||
import org.junit.Test; | |||
public class PathsTest { | |||
@Test | |||
public void testStripTrailingSeparator() { | |||
assertNull(Paths.stripTrailingSeparator(null)); | |||
assertEquals("", Paths.stripTrailingSeparator("")); | |||
assertEquals("a", Paths.stripTrailingSeparator("a")); | |||
assertEquals("a/boo", Paths.stripTrailingSeparator("a/boo")); | |||
assertEquals("a/boo", Paths.stripTrailingSeparator("a/boo/")); | |||
assertEquals("a/boo", Paths.stripTrailingSeparator("a/boo//")); | |||
assertEquals("a/boo", Paths.stripTrailingSeparator("a/boo///")); | |||
} | |||
@Test | |||
public void testPathCompare() { | |||
byte[] a = Constants.encode("afoo/bar.c"); | |||
byte[] b = Constants.encode("bfoo/bar.c"); | |||
assertEquals(0, compare(a, 1, a.length, 0, b, 1, b.length, 0)); | |||
assertEquals(-1, compare(a, 0, a.length, 0, b, 0, b.length, 0)); | |||
assertEquals(1, compare(b, 0, b.length, 0, a, 0, a.length, 0)); | |||
a = Constants.encode("a"); | |||
b = Constants.encode("aa"); | |||
assertEquals(-97, compare(a, 0, a.length, 0, b, 0, b.length, 0)); | |||
assertEquals(0, compare(a, 0, a.length, 0, b, 0, 1, 0)); | |||
assertEquals(0, compare(a, 0, a.length, 0, b, 1, 2, 0)); | |||
assertEquals(0, compareSameName(a, 0, a.length, b, 1, b.length, 0)); | |||
assertEquals(0, compareSameName(a, 0, a.length, b, 0, 1, 0)); | |||
assertEquals(-50, compareSameName(a, 0, a.length, b, 0, b.length, 0)); | |||
assertEquals(97, compareSameName(b, 0, b.length, a, 0, a.length, 0)); | |||
a = Constants.encode("a"); | |||
b = Constants.encode("a"); | |||
assertEquals(0, compare( | |||
a, 0, a.length, FileMode.TREE.getBits(), | |||
b, 0, b.length, FileMode.TREE.getBits())); | |||
assertEquals(0, compare( | |||
a, 0, a.length, FileMode.REGULAR_FILE.getBits(), | |||
b, 0, b.length, FileMode.REGULAR_FILE.getBits())); | |||
assertEquals(-47, compare( | |||
a, 0, a.length, FileMode.REGULAR_FILE.getBits(), | |||
b, 0, b.length, FileMode.TREE.getBits())); | |||
assertEquals(47, compare( | |||
a, 0, a.length, FileMode.TREE.getBits(), | |||
b, 0, b.length, FileMode.REGULAR_FILE.getBits())); | |||
assertEquals(0, compareSameName( | |||
a, 0, a.length, | |||
b, 0, b.length, FileMode.TREE.getBits())); | |||
assertEquals(0, compareSameName( | |||
a, 0, a.length, | |||
b, 0, b.length, FileMode.REGULAR_FILE.getBits())); | |||
a = Constants.encode("a.c"); | |||
b = Constants.encode("a"); | |||
byte[] c = Constants.encode("a0c"); | |||
assertEquals(-1, compare( | |||
a, 0, a.length, FileMode.REGULAR_FILE.getBits(), | |||
b, 0, b.length, FileMode.TREE.getBits())); | |||
assertEquals(-1, compare( | |||
b, 0, b.length, FileMode.TREE.getBits(), | |||
c, 0, c.length, FileMode.REGULAR_FILE.getBits())); | |||
} | |||
} |
@@ -0,0 +1,7 @@ | |||
java_library( | |||
name = 'ui', | |||
srcs = glob(['src/**']), | |||
resources = glob(['resources/**']), | |||
deps = ['//org.eclipse.jgit:jgit'], | |||
visibility = ['PUBLIC'], | |||
) |
@@ -56,15 +56,20 @@ import javax.swing.JPasswordField; | |||
import javax.swing.JTextField; | |||
import org.eclipse.jgit.errors.UnsupportedCredentialItem; | |||
import org.eclipse.jgit.transport.ChainingCredentialsProvider; | |||
import org.eclipse.jgit.transport.CredentialItem; | |||
import org.eclipse.jgit.transport.CredentialsProvider; | |||
import org.eclipse.jgit.transport.NetRCCredentialsProvider; | |||
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()); | |||
final AwtCredentialsProvider c = new AwtCredentialsProvider(); | |||
CredentialsProvider cp = new ChainingCredentialsProvider( | |||
new NetRCCredentialsProvider(), c); | |||
CredentialsProvider.setDefault(cp); | |||
} | |||
@Override |
@@ -1,5 +1,45 @@ | |||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||
<component id="org.eclipse.jgit" version="2"> | |||
<resource path="META-INF/MANIFEST.MF" type="org.eclipse.jgit.lib.FileTreeEntry"> | |||
<filter id="305324134"> | |||
<message_arguments> | |||
<message_argument value="org.eclipse.jgit.lib.FileTreeEntry"/> | |||
<message_argument value="org.eclipse.jgit_4.2.0"/> | |||
</message_arguments> | |||
</filter> | |||
</resource> | |||
<resource path="META-INF/MANIFEST.MF" type="org.eclipse.jgit.lib.GitlinkTreeEntry"> | |||
<filter id="305324134"> | |||
<message_arguments> | |||
<message_argument value="org.eclipse.jgit.lib.GitlinkTreeEntry"/> | |||
<message_argument value="org.eclipse.jgit_4.2.0"/> | |||
</message_arguments> | |||
</filter> | |||
</resource> | |||
<resource path="META-INF/MANIFEST.MF" type="org.eclipse.jgit.lib.SymlinkTreeEntry"> | |||
<filter id="305324134"> | |||
<message_arguments> | |||
<message_argument value="org.eclipse.jgit.lib.SymlinkTreeEntry"/> | |||
<message_argument value="org.eclipse.jgit_4.2.0"/> | |||
</message_arguments> | |||
</filter> | |||
</resource> | |||
<resource path="META-INF/MANIFEST.MF" type="org.eclipse.jgit.lib.Tree"> | |||
<filter id="305324134"> | |||
<message_arguments> | |||
<message_argument value="org.eclipse.jgit.lib.Tree"/> | |||
<message_argument value="org.eclipse.jgit_4.2.0"/> | |||
</message_arguments> | |||
</filter> | |||
</resource> | |||
<resource path="META-INF/MANIFEST.MF" type="org.eclipse.jgit.lib.TreeEntry"> | |||
<filter id="305324134"> | |||
<message_arguments> | |||
<message_argument value="org.eclipse.jgit.lib.TreeEntry"/> | |||
<message_argument value="org.eclipse.jgit_4.2.0"/> | |||
</message_arguments> | |||
</filter> | |||
</resource> | |||
<resource path="src/org/eclipse/jgit/attributes/AttributesNode.java" type="org.eclipse.jgit.attributes.AttributesNode"> | |||
<filter comment="attributes weren't really usable in earlier versions" id="338792546"> | |||
<message_arguments> |
@@ -0,0 +1,20 @@ | |||
SRCS = glob(['src/**']) | |||
RESOURCES = glob(['resources/**']) | |||
java_library( | |||
name = 'jgit', | |||
srcs = SRCS, | |||
resources = RESOURCES, | |||
deps = [ | |||
'//lib:javaewah', | |||
'//lib:jsch', | |||
'//lib:httpcomponents', | |||
'//lib:slf4j-api', | |||
], | |||
visibility = ['PUBLIC'], | |||
) | |||
java_sources( | |||
name = 'jgit_src', | |||
srcs = SRCS + RESOURCES, | |||
) |
@@ -65,9 +65,10 @@ Export-Package: org.eclipse.jgit.annotations;version="4.2.0", | |||
org.eclipse.jgit.junit, | |||
org.eclipse.jgit.junit.http, | |||
org.eclipse.jgit.http.server, | |||
org.eclipse.jgit.java7.test, | |||
org.eclipse.jgit.pgm.test, | |||
org.eclipse.jgit.pgm", | |||
org.eclipse.jgit.internal.storage.pack;version="4.2.0";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm", | |||
org.eclipse.jgit.internal.storage.reftree;version="4.2.0";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm", | |||
org.eclipse.jgit.lib;version="4.2.0"; | |||
uses:="org.eclipse.jgit.revwalk, | |||
org.eclipse.jgit.treewalk.filter, |
@@ -99,6 +99,7 @@ cannotSquashFixupWithoutPreviousCommit=Cannot {0} without previous commit. | |||
cannotStoreObjects=cannot store objects | |||
cannotResolveUniquelyAbbrevObjectId=Could not resolve uniquely the abbreviated object ID | |||
cannotUnloadAModifiedTree=Cannot unload a modified tree. | |||
cannotUpdateUnbornBranch=Cannot update unborn branch | |||
cannotWorkWithOtherStagesThanZeroRightNow=Cannot work with other stages than zero right now. Won't write corrupt index. | |||
cannotWriteObjectsPath=Cannot write {0}/{1}: {2} | |||
canOnlyCherryPickCommitsWithOneParent=Cannot cherry-pick commit ''{0}'' because it has {1} parents, only commits with exactly one parent are supported. | |||
@@ -125,14 +126,15 @@ connectionFailed=connection failed | |||
connectionTimeOut=Connection time out: {0} | |||
contextMustBeNonNegative=context must be >= 0 | |||
corruptionDetectedReReadingAt=Corruption detected re-reading at {0} | |||
corruptObjectBadDate=bad date | |||
corruptObjectBadEmail=bad email | |||
corruptObjectBadStream=bad stream | |||
corruptObjectBadStreamCorruptHeader=bad stream, corrupt header | |||
corruptObjectBadTimezone=bad time zone | |||
corruptObjectDuplicateEntryNames=duplicate entry names | |||
corruptObjectGarbageAfterSize=garbage after size | |||
corruptObjectIncorrectLength=incorrect length | |||
corruptObjectIncorrectSorting=incorrectly sorted | |||
corruptObjectInvalidAuthor=invalid author | |||
corruptObjectInvalidCommitter=invalid committer | |||
corruptObjectInvalidEntryMode=invalid entry mode | |||
corruptObjectInvalidMode=invalid mode | |||
corruptObjectInvalidModeChar=invalid mode character | |||
@@ -151,11 +153,11 @@ corruptObjectInvalidNameNul=invalid name 'NUL' | |||
corruptObjectInvalidNamePrn=invalid name 'PRN' | |||
corruptObjectInvalidObject=invalid object | |||
corruptObjectInvalidParent=invalid parent | |||
corruptObjectInvalidTagger=invalid tagger | |||
corruptObjectInvalidTree=invalid tree | |||
corruptObjectInvalidType=invalid type | |||
corruptObjectInvalidType2=invalid type {0} | |||
corruptObjectMalformedHeader=malformed header: {0} | |||
corruptObjectMissingEmail=missing email | |||
corruptObjectNameContainsByte=name contains byte 0x%x | |||
corruptObjectNameContainsChar=name contains '%c' | |||
corruptObjectNameContainsNullByte=name contains byte 0x00 | |||
@@ -181,6 +183,7 @@ corruptObjectPackfileChecksumIncorrect=Packfile checksum incorrect. | |||
corruptObjectTruncatedInMode=truncated in mode | |||
corruptObjectTruncatedInName=truncated in name | |||
corruptObjectTruncatedInObjectId=truncated in object id | |||
corruptObjectZeroId=entry points to null SHA-1 | |||
couldNotCheckOutBecauseOfConflicts=Could not check out because of conflicts | |||
couldNotDeleteLockFileShouldNotHappen=Could not delete lock file. Should not happen | |||
couldNotDeleteTemporaryIndexFileShouldNotHappen=Could not delete temporary index file. Should not happen | |||
@@ -432,6 +435,7 @@ noXMLParserAvailable=No XML parser available. | |||
objectAtHasBadZlibStream=Object at {0} in {1} has bad zlib stream | |||
objectAtPathDoesNotHaveId=Object at path "{0}" does not have an id assigned. All object ids must be assigned prior to writing a tree. | |||
objectIsCorrupt=Object {0} is corrupt: {1} | |||
objectIsCorrupt3={0}: object {1}: {2} | |||
objectIsNotA=Object {0} is not a {1}. | |||
objectNotFound=Object {0} not found. | |||
objectNotFoundIn=Object {0} not found in {1}. | |||
@@ -595,6 +599,7 @@ transportExceptionInvalid=Invalid {0} {1}:{2} | |||
transportExceptionMissingAssumed=Missing assumed {0} | |||
transportExceptionReadRef=read {0} | |||
transportNeedsRepository=Transport needs repository | |||
transportProvidedRefWithNoObjectId=Transport provided ref {0} with no object id | |||
transportProtoAmazonS3=Amazon S3 | |||
transportProtoBundleFile=Git Bundle File | |||
transportProtoFTP=FTP |
@@ -43,6 +43,10 @@ | |||
*/ | |||
package org.eclipse.jgit.api; | |||
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB; | |||
import static org.eclipse.jgit.lib.FileMode.GITLINK; | |||
import static org.eclipse.jgit.lib.FileMode.TYPE_TREE; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.util.Collection; | |||
@@ -58,12 +62,12 @@ import org.eclipse.jgit.dircache.DirCacheBuilder; | |||
import org.eclipse.jgit.dircache.DirCacheEntry; | |||
import org.eclipse.jgit.dircache.DirCacheIterator; | |||
import org.eclipse.jgit.internal.JGitText; | |||
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.Repository; | |||
import org.eclipse.jgit.treewalk.FileTreeIterator; | |||
import org.eclipse.jgit.treewalk.TreeWalk; | |||
import org.eclipse.jgit.treewalk.NameConflictTreeWalk; | |||
import org.eclipse.jgit.treewalk.TreeWalk.OperationType; | |||
import org.eclipse.jgit.treewalk.WorkingTreeIterator; | |||
import org.eclipse.jgit.treewalk.filter.PathFilterGroup; | |||
@@ -135,15 +139,12 @@ public class AddCommand extends GitCommand<DirCache> { | |||
throw new NoFilepatternException(JGitText.get().atLeastOnePatternIsRequired); | |||
checkCallable(); | |||
DirCache dc = null; | |||
boolean addAll = false; | |||
if (filepatterns.contains(".")) //$NON-NLS-1$ | |||
addAll = true; | |||
boolean addAll = filepatterns.contains("."); //$NON-NLS-1$ | |||
try (ObjectInserter inserter = repo.newObjectInserter(); | |||
final TreeWalk tw = new TreeWalk(repo)) { | |||
NameConflictTreeWalk tw = new NameConflictTreeWalk(repo)) { | |||
tw.setOperationType(OperationType.CHECKIN_OP); | |||
dc = repo.lockDirCache(); | |||
DirCacheIterator c; | |||
DirCacheBuilder builder = dc.builder(); | |||
tw.addTree(new DirCacheBuildIterator(builder)); | |||
@@ -151,62 +152,85 @@ public class AddCommand extends GitCommand<DirCache> { | |||
workingTreeIterator = new FileTreeIterator(repo); | |||
workingTreeIterator.setDirCacheIterator(tw, 0); | |||
tw.addTree(workingTreeIterator); | |||
tw.setRecursive(true); | |||
if (!addAll) | |||
tw.setFilter(PathFilterGroup.createFromStrings(filepatterns)); | |||
String lastAddedFile = null; | |||
byte[] lastAdded = null; | |||
while (tw.next()) { | |||
String path = tw.getPathString(); | |||
DirCacheIterator c = tw.getTree(0, DirCacheIterator.class); | |||
WorkingTreeIterator f = tw.getTree(1, WorkingTreeIterator.class); | |||
if (tw.getTree(0, DirCacheIterator.class) == null && | |||
f != null && f.isEntryIgnored()) { | |||
if (c == null && f != null && f.isEntryIgnored()) { | |||
// file is not in index but is ignored, do nothing | |||
continue; | |||
} else if (c == null && update) { | |||
// Only update of existing entries was requested. | |||
continue; | |||
} | |||
DirCacheEntry entry = c != null ? c.getDirCacheEntry() : null; | |||
if (entry != null && entry.getStage() > 0 | |||
&& lastAdded != null | |||
&& lastAdded.length == tw.getPathLength() | |||
&& tw.isPathPrefix(lastAdded, lastAdded.length) == 0) { | |||
// In case of an existing merge conflict the | |||
// DirCacheBuildIterator iterates over all stages of | |||
// this path, we however want to add only one | |||
// new DirCacheEntry per path. | |||
continue; | |||
} | |||
if (tw.isSubtree() && !tw.isDirectoryFileConflict()) { | |||
tw.enterSubtree(); | |||
continue; | |||
} | |||
if (f == null) { // working tree file does not exist | |||
if (entry != null | |||
&& (!update || GITLINK == entry.getFileMode())) { | |||
builder.add(entry); | |||
} | |||
continue; | |||
} | |||
if (entry != null && entry.isAssumeValid()) { | |||
// Index entry is marked assume valid. Even though | |||
// the user specified the file to be added JGit does | |||
// not consider the file for addition. | |||
builder.add(entry); | |||
continue; | |||
} | |||
if (f.getEntryRawMode() == TYPE_TREE) { | |||
// Index entry exists and is symlink, gitlink or file, | |||
// otherwise the tree would have been entered above. | |||
// Replace the index entry by diving into tree of files. | |||
tw.enterSubtree(); | |||
continue; | |||
} | |||
byte[] path = tw.getRawPath(); | |||
if (entry == null || entry.getStage() > 0) { | |||
entry = new DirCacheEntry(path); | |||
} | |||
// In case of an existing merge conflict the | |||
// DirCacheBuildIterator iterates over all stages of | |||
// this path, we however want to add only one | |||
// new DirCacheEntry per path. | |||
else if (!(path.equals(lastAddedFile))) { | |||
if (!(update && tw.getTree(0, DirCacheIterator.class) == null)) { | |||
c = tw.getTree(0, DirCacheIterator.class); | |||
if (f != null) { // the file exists | |||
long sz = f.getEntryLength(); | |||
DirCacheEntry entry = new DirCacheEntry(path); | |||
if (c == null || c.getDirCacheEntry() == null | |||
|| !c.getDirCacheEntry().isAssumeValid()) { | |||
FileMode mode = f.getIndexFileMode(c); | |||
entry.setFileMode(mode); | |||
if (FileMode.GITLINK != mode) { | |||
entry.setLength(sz); | |||
entry.setLastModified(f | |||
.getEntryLastModified()); | |||
long contentSize = f | |||
.getEntryContentLength(); | |||
InputStream in = f.openEntryStream(); | |||
try { | |||
entry.setObjectId(inserter.insert( | |||
Constants.OBJ_BLOB, contentSize, in)); | |||
} finally { | |||
in.close(); | |||
} | |||
} else | |||
entry.setObjectId(f.getEntryObjectId()); | |||
builder.add(entry); | |||
lastAddedFile = path; | |||
} else { | |||
builder.add(c.getDirCacheEntry()); | |||
} | |||
} else if (c != null | |||
&& (!update || FileMode.GITLINK == c | |||
.getEntryFileMode())) | |||
builder.add(c.getDirCacheEntry()); | |||
FileMode mode = f.getIndexFileMode(c); | |||
entry.setFileMode(mode); | |||
if (GITLINK != mode) { | |||
entry.setLength(f.getEntryLength()); | |||
entry.setLastModified(f.getEntryLastModified()); | |||
long len = f.getEntryContentLength(); | |||
try (InputStream in = f.openEntryStream()) { | |||
ObjectId id = inserter.insert(OBJ_BLOB, len, in); | |||
entry.setObjectId(id); | |||
} | |||
} else { | |||
entry.setLength(0); | |||
entry.setLastModified(0); | |||
entry.setObjectId(f.getEntryObjectId()); | |||
} | |||
builder.add(entry); | |||
lastAdded = path; | |||
} | |||
inserter.flush(); | |||
builder.commit(); |
@@ -47,6 +47,7 @@ import java.io.FileOutputStream; | |||
import java.io.FileWriter; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.nio.file.StandardCopyOption; | |||
import java.text.MessageFormat; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
@@ -141,9 +142,13 @@ public class ApplyCommand extends GitCommand<ApplyResult> { | |||
case RENAME: | |||
f = getFile(fh.getOldPath(), false); | |||
File dest = getFile(fh.getNewPath(), false); | |||
if (!f.renameTo(dest)) | |||
try { | |||
FileUtils.rename(f, dest, | |||
StandardCopyOption.ATOMIC_MOVE); | |||
} catch (IOException e) { | |||
throw new PatchApplyException(MessageFormat.format( | |||
JGitText.get().renameFileFailed, f, dest)); | |||
JGitText.get().renameFileFailed, f, dest), e); | |||
} | |||
break; | |||
case COPY: | |||
f = getFile(fh.getOldPath(), false); |
@@ -331,9 +331,16 @@ public class CheckoutCommand extends GitCommand<Ref> { | |||
} | |||
private String getShortBranchName(Ref headRef) { | |||
if (headRef.getTarget().getName().equals(headRef.getName())) | |||
return headRef.getTarget().getObjectId().getName(); | |||
return Repository.shortenRefName(headRef.getTarget().getName()); | |||
if (headRef.isSymbolic()) { | |||
return Repository.shortenRefName(headRef.getTarget().getName()); | |||
} | |||
// Detached HEAD. Every non-symbolic ref in the ref database has an | |||
// object id, so this cannot be null. | |||
ObjectId id = headRef.getObjectId(); | |||
if (id == null) { | |||
throw new NullPointerException(); | |||
} | |||
return id.getName(); | |||
} | |||
/** |
@@ -61,6 +61,7 @@ import org.eclipse.jgit.internal.JGitText; | |||
import org.eclipse.jgit.lib.ConfigConstants; | |||
import org.eclipse.jgit.lib.Constants; | |||
import org.eclipse.jgit.lib.NullProgressMonitor; | |||
import org.eclipse.jgit.lib.ObjectId; | |||
import org.eclipse.jgit.lib.ProgressMonitor; | |||
import org.eclipse.jgit.lib.Ref; | |||
import org.eclipse.jgit.lib.RefUpdate; | |||
@@ -235,7 +236,7 @@ public class CloneCommand extends TransportCommand<CloneCommand, Git> { | |||
} | |||
if (head == null || head.getObjectId() == null) | |||
return; // throw exception? | |||
return; // TODO throw exception? | |||
if (head.getName().startsWith(Constants.R_HEADS)) { | |||
final RefUpdate newHead = clonedRepo.updateRef(Constants.HEAD); | |||
@@ -287,20 +288,24 @@ public class CloneCommand extends TransportCommand<CloneCommand, Git> { | |||
private Ref findBranchToCheckout(FetchResult result) { | |||
final Ref idHEAD = result.getAdvertisedRef(Constants.HEAD); | |||
if (idHEAD == null) | |||
ObjectId headId = idHEAD != null ? idHEAD.getObjectId() : null; | |||
if (headId == null) { | |||
return null; | |||
} | |||
Ref master = result.getAdvertisedRef(Constants.R_HEADS | |||
+ Constants.MASTER); | |||
if (master != null && master.getObjectId().equals(idHEAD.getObjectId())) | |||
ObjectId objectId = master != null ? master.getObjectId() : null; | |||
if (headId.equals(objectId)) { | |||
return master; | |||
} | |||
Ref foundBranch = null; | |||
for (final Ref r : result.getAdvertisedRefs()) { | |||
final String n = r.getName(); | |||
if (!n.startsWith(Constants.R_HEADS)) | |||
continue; | |||
if (r.getObjectId().equals(idHEAD.getObjectId())) { | |||
if (headId.equals(r.getObjectId())) { | |||
foundBranch = r; | |||
break; | |||
} |