* Re: malloc fails when dealing with huge files
From: Jeff Whiteside @ 2008-12-11 0:16 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Jonathan Blanton, git
In-Reply-To: <alpine.LFD.2.00.0812101121401.3340@localhost.localdomain>
i tried to do something like that over a year ago, having gotten the
insane idea that i wanted to version my whole harddrive. binaries
were a huge problem.
checkouts were also a problem over slow connections because there is
no git-clone --resume, so if your connection is interrupted, you're
back at square one. perhaps git-torrent will fix that.
git wasn't supposed to be file based, as much as line/code based. let
me know if you find a better alternative to git for filesystems.
it's too bad there's not a better way to keep resources tagged to a
version by a sha1, but keep source separate.
On Wed, Dec 10, 2008 at 11:32 AM, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
>
>
> On Wed, 10 Dec 2008, Jonathan Blanton wrote:
>>
>> I'm using Git for a project that contains huge (multi-gigabyte) files.
>> I need to track these files, but with some of the really big ones,
>> git-add aborts with the message "fatal: Out of memory, malloc failed".
>
> git is _really_ not designed for huge files.
>
> By design - good or bad - git does pretty much all single file operations
> with the whole file in memory as one single allocation.
>
> Now, some of that is hard to fix - or at least would generate much more
> complex code. The _particular_ case of "git add" could be fixed without
> undue pain, but it's not entirely trivial either.
>
> The main offender is probably "index_fd()" that just mmap's the whole file
> in one go and then calls write_sha1_file() which really expects it to be
> one single memory area both for the initial SHA1 create and for the
> compression and writing out of the result.
>
> Changing that to do big files in pieces would not be _too_ painful, but
> it's not just a couple of lines either.
>
> However, git performance with big files would never be wonderful, and
> things like "git diff" would still end up reading not just the whole file,
> but _both_versions_ at the same time. Marking the big files as being
> no-diff might help, though.
>
>
> Linus
> --
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* Re: [RFC/PATCH] Add support for a pdf version of the user manual
From: Junio C Hamano @ 2008-12-11 0:11 UTC (permalink / raw)
To: SLONIK.AZ; +Cc: Miklos Vajna, git
In-Reply-To: <ee2a733e0812101606m1c522541j9380b6f5d5dc7fc8@mail.gmail.com>
"Leo Razoumov" <slonik.az@gmail.com> writes:
> BTW, for those of us without dblatex, is it possible to have pdf
> manual pregenerated the same way html and man pages are pregenerated
> for official releases in the git repo?
Those of us includes myself, so...
^ permalink raw reply
* Re: [RFC/PATCH] Add support for a pdf version of the user manual
From: Leo Razoumov @ 2008-12-11 0:06 UTC (permalink / raw)
To: Miklos Vajna; +Cc: git
In-Reply-To: <1228949090-22475-1-git-send-email-vmiklos@frugalware.org>
On 12/10/08, Miklos Vajna <vmiklos@frugalware.org> wrote:
> Use dblatex in order to create a pdf version of the git user manual. No
> existing Makefile targets (including "all") are touched, so you need to
> explicitly say
>
> make pdf
> sudo make install-pdf
>
> to get user-manual.pdf created and installed.
>
Thanks a lot! Having manual in pdf forms rocks!
BTW, for those of us without dblatex, is it possible to have pdf
manual pregenerated the same way html and man pages are pregenerated
for official releases in the git repo?? I would love to have pdf (and
'info' for that matter) branch in addition to html and man branches.
--Leo--
^ permalink raw reply
* [JGIT PATCH 6/6 v2] Add ~user friendly Bourne style quoting for TransportGitSsh
From: Shawn O. Pearce @ 2008-12-10 23:59 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <1228953594-12749-2-git-send-email-spearce@spearce.org>
This mostly completes the migration of our quoting rules from the
SSH transport to our QuotedString pattern. User names may be left
alone for the shell to expand when the string is evaluated, if the
caller wants that sort of behavior in a particular context.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../util/QuotedStringBourneUserPathStyleTest.java | 130 ++++++++++++++++++++
.../spearce/jgit/transport/TransportGitSsh.java | 27 +----
.../src/org/spearce/jgit/util/QuotedString.java | 28 ++++
3 files changed, 160 insertions(+), 25 deletions(-)
create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/util/QuotedStringBourneUserPathStyleTest.java
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/util/QuotedStringBourneUserPathStyleTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/util/QuotedStringBourneUserPathStyleTest.java
new file mode 100644
index 0000000..36fb52a
--- /dev/null
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/util/QuotedStringBourneUserPathStyleTest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ *
+ * 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 Git Development Community 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.spearce.jgit.util;
+
+import static org.spearce.jgit.util.QuotedString.BOURNE_USER_PATH;
+import junit.framework.TestCase;
+
+import org.spearce.jgit.lib.Constants;
+
+public class QuotedStringBourneUserPathStyleTest extends TestCase {
+ private static void assertQuote(final String in, final String exp) {
+ final String r = BOURNE_USER_PATH.quote(in);
+ assertNotSame(in, r);
+ assertFalse(in.equals(r));
+ assertEquals('\'' + exp + '\'', r);
+ }
+
+ private static void assertDequote(final String exp, final String in) {
+ final byte[] b = Constants.encode('\'' + in + '\'');
+ final String r = BOURNE_USER_PATH.dequote(b, 0, b.length);
+ assertEquals(exp, r);
+ }
+
+ public void testQuote_Empty() {
+ assertEquals("''", BOURNE_USER_PATH.quote(""));
+ }
+
+ public void testDequote_Empty1() {
+ assertEquals("", BOURNE_USER_PATH.dequote(new byte[0], 0, 0));
+ }
+
+ public void testDequote_Empty2() {
+ assertEquals("", BOURNE_USER_PATH.dequote(new byte[] { '\'', '\'' }, 0,
+ 2));
+ }
+
+ public void testDequote_SoleSq() {
+ assertEquals("", BOURNE_USER_PATH.dequote(new byte[] { '\'' }, 0, 1));
+ }
+
+ public void testQuote_BareA() {
+ assertQuote("a", "a");
+ }
+
+ public void testDequote_BareA() {
+ final String in = "a";
+ final byte[] b = Constants.encode(in);
+ assertEquals(in, BOURNE_USER_PATH.dequote(b, 0, b.length));
+ }
+
+ public void testDequote_BareABCZ_OnlyBC() {
+ final String in = "abcz";
+ final byte[] b = Constants.encode(in);
+ final int p = in.indexOf('b');
+ assertEquals("bc", BOURNE_USER_PATH.dequote(b, p, p + 2));
+ }
+
+ public void testDequote_LoneBackslash() {
+ assertDequote("\\", "\\");
+ }
+
+ public void testQuote_NamedEscapes() {
+ assertQuote("'", "'\\''");
+ assertQuote("!", "'\\!'");
+
+ assertQuote("a'b", "a'\\''b");
+ assertQuote("a!b", "a'\\!'b");
+ }
+
+ public void testDequote_NamedEscapes() {
+ assertDequote("'", "'\\''");
+ assertDequote("!", "'\\!'");
+
+ assertDequote("a'b", "a'\\''b");
+ assertDequote("a!b", "a'\\!'b");
+ }
+
+ public void testQuote_User() {
+ assertEquals("~foo/", BOURNE_USER_PATH.quote("~foo"));
+ assertEquals("~foo/", BOURNE_USER_PATH.quote("~foo/"));
+ assertEquals("~/", BOURNE_USER_PATH.quote("~/"));
+
+ assertEquals("~foo/'a'", BOURNE_USER_PATH.quote("~foo/a"));
+ assertEquals("~/'a'", BOURNE_USER_PATH.quote("~/a"));
+ }
+
+ public void testDequote_User() {
+ assertEquals("~foo", BOURNE_USER_PATH.dequote("~foo"));
+ assertEquals("~foo/", BOURNE_USER_PATH.dequote("~foo/"));
+ assertEquals("~/", BOURNE_USER_PATH.dequote("~/"));
+
+ assertEquals("~foo/a", BOURNE_USER_PATH.dequote("~foo/'a'"));
+ assertEquals("~/a", BOURNE_USER_PATH.dequote("~/'a'"));
+ }
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java
index e3f5ae8..d4bf466 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java
@@ -131,31 +131,8 @@ private static void sqAlways(final StringBuilder cmd, final String val) {
}
private static void sq(final StringBuilder cmd, final String val) {
- int i = 0;
-
- if (val.length() == 0)
- return;
- if (val.matches("^~[A-Za-z0-9_-]+$")) {
- // If the string is just "~user" we can assume they
- // mean "~user/" and evaluate it within the shell.
- //
- cmd.append(val);
- cmd.append('/');
- return;
- }
-
- if (val.matches("^~[A-Za-z0-9_-]*/.*$")) {
- // If the string is of "~/path" or "~user/path"
- // we must not escape ~/ or ~user/ from the shell
- // as we need that portion to be evaluated.
- //
- i = val.indexOf('/') + 1;
- cmd.append(val.substring(0, i));
- if (i == val.length())
- return;
- }
-
- cmd.append(QuotedString.BOURNE.quote(val.substring(i)));
+ if (val.length() > 0)
+ cmd.append(QuotedString.BOURNE.quote(val));
}
private void initSession() throws TransportException {
diff --git a/org.spearce.jgit/src/org/spearce/jgit/util/QuotedString.java b/org.spearce.jgit/src/org/spearce/jgit/util/QuotedString.java
index 82ce716..60c4195 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/util/QuotedString.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/util/QuotedString.java
@@ -55,6 +55,9 @@
*/
public static final BourneStyle BOURNE = new BourneStyle();
+ /** Bourne style, but permits <code>~user</code> at the start of the string. */
+ public static final BourneUserPathStyle BOURNE_USER_PATH = new BourneUserPathStyle();
+
/**
* Quote an input string by the quoting rules.
* <p>
@@ -174,6 +177,31 @@ public String dequote(final byte[] in, int ip, final int ie) {
}
}
+ /** Bourne style, but permits <code>~user</code> at the start of the string. */
+ public static class BourneUserPathStyle extends BourneStyle {
+ @Override
+ public String quote(final String in) {
+ if (in.matches("^~[A-Za-z0-9_-]+$")) {
+ // If the string is just "~user" we can assume they
+ // mean "~user/".
+ //
+ return in + "/";
+ }
+
+ if (in.matches("^~[A-Za-z0-9_-]*/.*$")) {
+ // If the string is of "~/path" or "~user/path"
+ // we must not escape ~/ or ~user/ from the shell.
+ //
+ final int i = in.indexOf('/') + 1;
+ if (i == in.length())
+ return in;
+ return in.substring(0, i) + super.quote(in.substring(i));
+ }
+
+ return super.quote(in);
+ }
+ }
+
/** Quoting style that obeys the rules Git applies to file names */
public static final class GitPathStyle extends QuotedString {
private static final byte[] quote;
--
1.6.1.rc2.299.gead4c
^ permalink raw reply related
* [JGIT PATCH 5/6 v2] Add Bourne style quoting for TransportGitSsh
From: Shawn O. Pearce @ 2008-12-10 23:59 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <1228953594-12749-1-git-send-email-spearce@spearce.org>
Now that we have a nice QuotedString abstraction we can port our
string quoting logic from being private within the SSH transport
code to being available in the rest of the library.
Currently we only support the super-restrictive quoting style used
for the repository path name argument over SSH. We don't support the
"minimal" style used to invoke the command name, nor do we support
the ~user/ style format, which cannot be quoted.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../jgit/util/QuotedStringBourneStyleTest.java | 111 ++++++++++++++++++++
.../spearce/jgit/transport/TransportGitSsh.java | 13 +--
.../src/org/spearce/jgit/util/QuotedString.java | 66 ++++++++++++
3 files changed, 179 insertions(+), 11 deletions(-)
create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/util/QuotedStringBourneStyleTest.java
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/util/QuotedStringBourneStyleTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/util/QuotedStringBourneStyleTest.java
new file mode 100644
index 0000000..86d46fe
--- /dev/null
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/util/QuotedStringBourneStyleTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ *
+ * 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 Git Development Community 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.spearce.jgit.util;
+
+import static org.spearce.jgit.util.QuotedString.BOURNE;
+import junit.framework.TestCase;
+
+import org.spearce.jgit.lib.Constants;
+
+public class QuotedStringBourneStyleTest extends TestCase {
+ private static void assertQuote(final String in, final String exp) {
+ final String r = BOURNE.quote(in);
+ assertNotSame(in, r);
+ assertFalse(in.equals(r));
+ assertEquals('\'' + exp + '\'', r);
+ }
+
+ private static void assertDequote(final String exp, final String in) {
+ final byte[] b = Constants.encode('\'' + in + '\'');
+ final String r = BOURNE.dequote(b, 0, b.length);
+ assertEquals(exp, r);
+ }
+
+ public void testQuote_Empty() {
+ assertEquals("''", BOURNE.quote(""));
+ }
+
+ public void testDequote_Empty1() {
+ assertEquals("", BOURNE.dequote(new byte[0], 0, 0));
+ }
+
+ public void testDequote_Empty2() {
+ assertEquals("", BOURNE.dequote(new byte[] { '\'', '\'' }, 0, 2));
+ }
+
+ public void testDequote_SoleSq() {
+ assertEquals("", BOURNE.dequote(new byte[] { '\'' }, 0, 1));
+ }
+
+ public void testQuote_BareA() {
+ assertQuote("a", "a");
+ }
+
+ public void testDequote_BareA() {
+ final String in = "a";
+ final byte[] b = Constants.encode(in);
+ assertEquals(in, BOURNE.dequote(b, 0, b.length));
+ }
+
+ public void testDequote_BareABCZ_OnlyBC() {
+ final String in = "abcz";
+ final byte[] b = Constants.encode(in);
+ final int p = in.indexOf('b');
+ assertEquals("bc", BOURNE.dequote(b, p, p + 2));
+ }
+
+ public void testDequote_LoneBackslash() {
+ assertDequote("\\", "\\");
+ }
+
+ public void testQuote_NamedEscapes() {
+ assertQuote("'", "'\\''");
+ assertQuote("!", "'\\!'");
+
+ assertQuote("a'b", "a'\\''b");
+ assertQuote("a!b", "a'\\!'b");
+ }
+
+ public void testDequote_NamedEscapes() {
+ assertDequote("'", "'\\''");
+ assertDequote("!", "'\\!'");
+
+ assertDequote("a'b", "a'\\''b");
+ assertDequote("a!b", "a'\\!'b");
+ }
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java
index 3f2cd37..e3f5ae8 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java
@@ -47,6 +47,7 @@
import org.spearce.jgit.errors.NoRemoteRepositoryException;
import org.spearce.jgit.errors.TransportException;
import org.spearce.jgit.lib.Repository;
+import org.spearce.jgit.util.QuotedString;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSchException;
@@ -154,17 +155,7 @@ private static void sq(final StringBuilder cmd, final String val) {
return;
}
- cmd.append('\'');
- for (; i < val.length(); i++) {
- final char c = val.charAt(i);
- if (c == '\'')
- cmd.append("'\\''");
- else if (c == '!')
- cmd.append("'\\!'");
- else
- cmd.append(c);
- }
- cmd.append('\'');
+ cmd.append(QuotedString.BOURNE.quote(val.substring(i)));
}
private void initSession() throws TransportException {
diff --git a/org.spearce.jgit/src/org/spearce/jgit/util/QuotedString.java b/org.spearce.jgit/src/org/spearce/jgit/util/QuotedString.java
index 279b713..82ce716 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/util/QuotedString.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/util/QuotedString.java
@@ -47,6 +47,15 @@
public static final GitPathStyle GIT_PATH = new GitPathStyle();
/**
+ * Quoting style used by the Bourne shell.
+ * <p>
+ * Quotes are unconditionally inserted during {@link #quote(String)}. This
+ * protects shell meta-characters like <code>$</code> or <code>~</code> from
+ * being recognized as special.
+ */
+ public static final BourneStyle BOURNE = new BourneStyle();
+
+ /**
* Quote an input string by the quoting rules.
* <p>
* If the input string does not require any quoting, the same String
@@ -108,6 +117,63 @@ public String dequote(final String in) {
*/
public abstract String dequote(byte[] in, int offset, int end);
+ /**
+ * Quoting style used by the Bourne shell.
+ * <p>
+ * Quotes are unconditionally inserted during {@link #quote(String)}. This
+ * protects shell meta-characters like <code>$</code> or <code>~</code> from
+ * being recognized as special.
+ */
+ public static class BourneStyle extends QuotedString {
+ @Override
+ public String quote(final String in) {
+ final StringBuilder r = new StringBuilder();
+ r.append('\'');
+ int start = 0, i = 0;
+ for (; i < in.length(); i++) {
+ switch (in.charAt(i)) {
+ case '\'':
+ case '!':
+ r.append(in, start, i);
+ r.append('\'');
+ r.append('\\');
+ r.append(in.charAt(i));
+ r.append('\'');
+ start = i + 1;
+ break;
+ }
+ }
+ r.append(in, start, i);
+ r.append('\'');
+ return r.toString();
+ }
+
+ @Override
+ public String dequote(final byte[] in, int ip, final int ie) {
+ boolean inquote = false;
+ final byte[] r = new byte[ie - ip];
+ int rPtr = 0;
+ while (ip < ie) {
+ final byte b = in[ip++];
+ switch (b) {
+ case '\'':
+ inquote = !inquote;
+ continue;
+ case '\\':
+ if (inquote || ip == ie)
+ r[rPtr++] = b; // literal within a quote
+ else
+ r[rPtr++] = in[ip++];
+ continue;
+ default:
+ r[rPtr++] = b;
+ continue;
+ }
+ }
+ return RawParseUtils.decode(Constants.CHARSET, r, 0, rPtr);
+ }
+ }
+
/** Quoting style that obeys the rules Git applies to file names */
public static final class GitPathStyle extends QuotedString {
private static final byte[] quote;
--
1.6.1.rc2.299.gead4c
^ permalink raw reply related
* [JGIT PATCH 4/6 v2] Add QuotedString class to handle Git path style quoting rules
From: Shawn O. Pearce @ 2008-12-10 23:59 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
Git patch files can contain file names which are quoted using the
roughly the C language quoting rules. In order to correctly create
or parse these files we must implement a quoting style that matches
those specific rules.
QuotedString itself is an abstract API so callers can be passed a
quoting style based on the context of where their output will be
used, and multiple styles could be supported. This may be useful
if jgit ever grows a "git for-each-ref" style of output where Perl,
Python, Tcl and Bourne style quoting might be necessary.
References through the singleton QuotedString.GIT_PATH should be
able to bypass the virtual function table, as the specific type is
mentioned in the field declaration and that type is final. A good
JIT should be able to remove the abstraction costs when the caller
has hardcoded the quoting style.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../jgit/util/QuotedStringGitPathStyleTest.java | 144 +++++++++++
.../src/org/spearce/jgit/util/QuotedString.java | 268 ++++++++++++++++++++
2 files changed, 412 insertions(+), 0 deletions(-)
create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/util/QuotedStringGitPathStyleTest.java
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/util/QuotedString.java
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/util/QuotedStringGitPathStyleTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/util/QuotedStringGitPathStyleTest.java
new file mode 100644
index 0000000..ed9eaac
--- /dev/null
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/util/QuotedStringGitPathStyleTest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ *
+ * 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 Git Development Community 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.spearce.jgit.util;
+
+import static org.spearce.jgit.util.QuotedString.GIT_PATH;
+import junit.framework.TestCase;
+
+import org.spearce.jgit.lib.Constants;
+
+public class QuotedStringGitPathStyleTest extends TestCase {
+ private static void assertQuote(final String in, final String exp) {
+ final String r = GIT_PATH.quote(in);
+ assertNotSame(in, r);
+ assertFalse(in.equals(r));
+ assertEquals('"' + exp + '"', r);
+ }
+
+ private static void assertDequote(final String exp, final String in) {
+ final byte[] b = Constants.encode('"' + in + '"');
+ final String r = GIT_PATH.dequote(b, 0, b.length);
+ assertEquals(exp, r);
+ }
+
+ public void testQuote_Empty() {
+ assertEquals("\"\"", GIT_PATH.quote(""));
+ }
+
+ public void testDequote_Empty1() {
+ assertEquals("", GIT_PATH.dequote(new byte[0], 0, 0));
+ }
+
+ public void testDequote_Empty2() {
+ assertEquals("", GIT_PATH.dequote(new byte[] { '"', '"' }, 0, 2));
+ }
+
+ public void testDequote_SoleDq() {
+ assertEquals("\"", GIT_PATH.dequote(new byte[] { '"' }, 0, 1));
+ }
+
+ public void testQuote_BareA() {
+ final String in = "a";
+ assertSame(in, GIT_PATH.quote(in));
+ }
+
+ public void testDequote_BareA() {
+ final String in = "a";
+ final byte[] b = Constants.encode(in);
+ assertEquals(in, GIT_PATH.dequote(b, 0, b.length));
+ }
+
+ public void testDequote_BareABCZ_OnlyBC() {
+ final String in = "abcz";
+ final byte[] b = Constants.encode(in);
+ final int p = in.indexOf('b');
+ assertEquals("bc", GIT_PATH.dequote(b, p, p + 2));
+ }
+
+ public void testDequote_LoneBackslash() {
+ assertDequote("\\", "\\");
+ }
+
+ public void testQuote_NamedEscapes() {
+ assertQuote("\u0007", "\\a");
+ assertQuote("\b", "\\b");
+ assertQuote("\f", "\\f");
+ assertQuote("\n", "\\n");
+ assertQuote("\r", "\\r");
+ assertQuote("\t", "\\t");
+ assertQuote("\u000B", "\\v");
+ assertQuote("\\", "\\\\");
+ assertQuote("\"", "\\\"");
+ }
+
+ public void testDequote_NamedEscapes() {
+ assertDequote("\u0007", "\\a");
+ assertDequote("\b", "\\b");
+ assertDequote("\f", "\\f");
+ assertDequote("\n", "\\n");
+ assertDequote("\r", "\\r");
+ assertDequote("\t", "\\t");
+ assertDequote("\u000B", "\\v");
+ assertDequote("\\", "\\\\");
+ assertDequote("\"", "\\\"");
+ }
+
+ public void testDequote_OctalAll() {
+ for (int i = 0; i < 256; i++) {
+ String s = Integer.toOctalString(i);
+ while (s.length() < 3) {
+ s = "0" + s;
+ }
+ assertDequote("" + (char) i, "\\" + s);
+ }
+ }
+
+ public void testQuote_OctalAll() {
+ assertQuote("\1", "\\001");
+ assertQuote("~", "\\176");
+ assertQuote("\u00ff", "\\303\\277"); // \u00ff in UTF-8
+ }
+
+ public void testDequote_UnknownEscapeQ() {
+ assertDequote("\\q", "\\q");
+ }
+
+ public void testDequote_FooTabBar() {
+ assertDequote("foo\tbar", "foo\\tbar");
+ }
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/util/QuotedString.java b/org.spearce.jgit/src/org/spearce/jgit/util/QuotedString.java
new file mode 100644
index 0000000..279b713
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/util/QuotedString.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ *
+ * 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 Git Development Community 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.spearce.jgit.util;
+
+import java.util.Arrays;
+
+import org.spearce.jgit.lib.Constants;
+
+/** Utility functions related to quoted string handling. */
+public abstract class QuotedString {
+ /** Quoting style that obeys the rules Git applies to file names */
+ public static final GitPathStyle GIT_PATH = new GitPathStyle();
+
+ /**
+ * Quote an input string by the quoting rules.
+ * <p>
+ * If the input string does not require any quoting, the same String
+ * reference is returned to the caller.
+ * <p>
+ * Otherwise a quoted string is returned, including the opening and closing
+ * quotation marks at the start and end of the string. If the style does not
+ * permit raw Unicode characters then the string will first be encoded in
+ * UTF-8, with unprintable sequences possibly escaped by the rules.
+ *
+ * @param in
+ * any non-null Unicode string.
+ * @return a quoted string. See above for details.
+ */
+ public abstract String quote(String in);
+
+ /**
+ * Clean a previously quoted input, decoding the result via UTF-8.
+ * <p>
+ * This method must match quote such that:
+ *
+ * <pre>
+ * a.equals(dequote(quote(a)));
+ * </pre>
+ *
+ * is true for any <code>a</code>.
+ *
+ * @param in
+ * a Unicode string to remove quoting from.
+ * @return the cleaned string.
+ * @see #dequote(byte[], int, int)
+ */
+ public String dequote(final String in) {
+ final byte[] b = Constants.encode(in);
+ return dequote(b, 0, b.length);
+ }
+
+ /**
+ * Decode a previously quoted input, scanning a UTF-8 encoded buffer.
+ * <p>
+ * This method must match quote such that:
+ *
+ * <pre>
+ * a.equals(dequote(Constants.encode(quote(a))));
+ * </pre>
+ *
+ * is true for any <code>a</code>.
+ * <p>
+ * This method removes any opening/closing quotation marks added by
+ * {@link #quote(String)}.
+ *
+ * @param in
+ * the input buffer to parse.
+ * @param offset
+ * first position within <code>in</code> to scan.
+ * @param end
+ * one position past in <code>in</code> to scan.
+ * @return the cleaned string.
+ */
+ public abstract String dequote(byte[] in, int offset, int end);
+
+ /** Quoting style that obeys the rules Git applies to file names */
+ public static final class GitPathStyle extends QuotedString {
+ private static final byte[] quote;
+ static {
+ quote = new byte[128];
+ Arrays.fill(quote, (byte) -1);
+
+ for (int i = '0'; i <= '9'; i++)
+ quote[i] = 0;
+ for (int i = 'a'; i <= 'z'; i++)
+ quote[i] = 0;
+ for (int i = 'A'; i <= 'Z'; i++)
+ quote[i] = 0;
+ quote[' '] = 0;
+ quote['+'] = 0;
+ quote[','] = 0;
+ quote['-'] = 0;
+ quote['.'] = 0;
+ quote['/'] = 0;
+ quote['='] = 0;
+ quote['_'] = 0;
+ quote['^'] = 0;
+
+ quote['\u0007'] = 'a';
+ quote['\b'] = 'b';
+ quote['\f'] = 'f';
+ quote['\n'] = 'n';
+ quote['\r'] = 'r';
+ quote['\t'] = 't';
+ quote['\u000B'] = 'v';
+ quote['\\'] = '\\';
+ quote['"'] = '"';
+ }
+
+ @Override
+ public String quote(final String instr) {
+ if (instr.length() == 0)
+ return "\"\"";
+ boolean reuse = true;
+ final byte[] in = Constants.encode(instr);
+ final StringBuilder r = new StringBuilder(2 + in.length);
+ r.append('"');
+ for (int i = 0; i < in.length; i++) {
+ final int c = in[i] & 0xff;
+ if (c < quote.length) {
+ final byte style = quote[c];
+ if (style == 0) {
+ r.append((char) c);
+ continue;
+ }
+ if (style > 0) {
+ reuse = false;
+ r.append('\\');
+ r.append((char) style);
+ continue;
+ }
+ }
+
+ reuse = false;
+ r.append('\\');
+ r.append((char) (((c >> 6) & 03) + '0'));
+ r.append((char) (((c >> 3) & 07) + '0'));
+ r.append((char) (((c >> 0) & 07) + '0'));
+ }
+ if (reuse)
+ return instr;
+ r.append('"');
+ return r.toString();
+ }
+
+ @Override
+ public String dequote(final byte[] in, final int inPtr, final int inEnd) {
+ if (2 <= inEnd - inPtr && in[inPtr] == '"' && in[inEnd - 1] == '"')
+ return dq(in, inPtr + 1, inEnd - 1);
+ return RawParseUtils.decode(Constants.CHARSET, in, inPtr, inEnd);
+ }
+
+ private static String dq(final byte[] in, int inPtr, final int inEnd) {
+ final byte[] r = new byte[inEnd - inPtr];
+ int rPtr = 0;
+ while (inPtr < inEnd) {
+ final byte b = in[inPtr++];
+ if (b != '\\') {
+ r[rPtr++] = b;
+ continue;
+ }
+
+ if (inPtr == inEnd) {
+ // Lone trailing backslash. Treat it as a literal.
+ //
+ r[rPtr++] = '\\';
+ break;
+ }
+
+ switch (in[inPtr++]) {
+ case 'a':
+ r[rPtr++] = 0x07 /* \a = BEL */;
+ continue;
+ case 'b':
+ r[rPtr++] = '\b';
+ continue;
+ case 'f':
+ r[rPtr++] = '\f';
+ continue;
+ case 'n':
+ r[rPtr++] = '\n';
+ continue;
+ case 'r':
+ r[rPtr++] = '\r';
+ continue;
+ case 't':
+ r[rPtr++] = '\t';
+ continue;
+ case 'v':
+ r[rPtr++] = 0x0B/* \v = VT */;
+ continue;
+
+ case '\\':
+ case '"':
+ r[rPtr++] = in[inPtr - 1];
+ continue;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3': {
+ int cp = in[inPtr - 1] - '0';
+ while (inPtr < inEnd) {
+ final byte c = in[inPtr];
+ if ('0' <= c && c <= '7') {
+ cp <<= 3;
+ cp |= c - '0';
+ inPtr++;
+ } else {
+ break;
+ }
+ }
+ r[rPtr++] = (byte) cp;
+ continue;
+ }
+
+ default:
+ // Any other code is taken literally.
+ //
+ r[rPtr++] = '\\';
+ r[rPtr++] = in[inPtr - 1];
+ continue;
+ }
+ }
+
+ return RawParseUtils.decode(Constants.CHARSET, r, 0, rPtr);
+ }
+
+ private GitPathStyle() {
+ // Singleton
+ }
+ }
+}
--
1.6.1.rc2.299.gead4c
^ permalink raw reply related
* Re: [JGIT PATCH 4/6] Add QuotedString class to handle C-style quoting rules
From: Shawn O. Pearce @ 2008-12-10 23:41 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <200812110022.03719.robin.rosenberg@dewire.com>
Robin Rosenberg <robin.rosenberg@dewire.com> wrote:
> onsdag 10 december 2008 23:05:49 skrev Shawn O. Pearce:
> > Git patch files can contain file names which are quoted using the
> > C language quoting rules. In order to correctly create or parse
>
> Should we maybe call this Git-style since we really do not care
> about C (which version btw?).
Yea, I think you are right. I'll change the name.
> Making two interfaces is better. We may share the implementation initially,
> but parsing file names in Git patches and parsing C strings are different
> operations.
Well, if we ever supported other C-style string names we could just
swap the implementation reference. I'll try to make it clearer
this format, although like a C-style string, is really meant for
Git path names within patches.
> > + public void testQuote_OctalAll() {
> > + assertQuote("\1", "\\001");
> > + assertQuote("~", "\\176");
> > + assertQuote("\u00ff", "\\303\\277"); // \u00ff in UTF-8
> > + }
>
> What do we do with non-UTF8 names? I think we should
> follow the logic we use when parsing commits and paths
> in other places.
Then we're totally f'd.
Git has no specific encoding on file names. If we get a standard
Java Unicode string and get asked to quote it characters with
code points above 127 need to be escaped as an octal escape code
according to the Git style. Further the Git style only permits
octal escapes that result in a value <= 255, aka an unsigned char.
The name needs to be encoded into an 8-bit encoding, and UTF-8 is
the only encoding that will represent every valid Unicode character.
Elsewhere we sort of take the attitude that when writing data *out*
we produce UTF-8, even if we read in ISO-whatever. Here I'm doing
the same thing.
> > + public void testDequote_UnknownEscapeQ() {
> > + assertDequote("\\q", "\\q");
> > + }
>
> Would Git generate this style in a name?
No, but a mangled patch might have it. Rather than throw an
exception I try to parse the string as faithfully as I can, so we
can continue on and mine the stream for more information. We may
be able to work around the breakage (there's a lot of redundant
data about path names in the git patch format).
As far as I can tell C Git handles this style of escape the same way:
$ cat F
diff --git "a/\q" "b/\q"
--- "a/\q"
+++ "b/\q"
$ git apply --stat F
"\\q\"" | 0
1 files changed, 0 insertions(+), 0 deletions(-)
Actually, I think there's a bug, its reading the closing quote as
part of the file name. But anyway, my point is that C git handles
an unknown escape sequence as though it were a literal.
> > + quote['\b'] = 'b';
> \e = esc
Oddly enough, C Git doesn't output \e. It uses \033. It doesn't
recognize \e either, so we can't produce it even if we wanted to
honor it on input. I can add it to our input table (but keep it
out of our output table), but then we'd treat \e as \033 while C
Git would treat \e as a literal. Bad.
So no, I won't add \e here.
> > + return decode(Constants.CHARSET, r, 0, rPtr);
>
> Importing methods really obscures things. Please qualify with class name
> of RawparseUtils here instead.
Hmmph. I wonder how you'll feel then about the patch parser code.
I import 4 methods from RawParseUtils because they are so commonly
invoked that I got tired of reading RawParseUtils.foo.
There's only two calls here so I changed it to be qualified.
--
Shawn.
^ permalink raw reply
* Re: epic fsck SIGSEGV! (was Recovering from epic fail (deleted .git/objects/pack))
From: Linus Torvalds @ 2008-12-10 23:40 UTC (permalink / raw)
To: R. Tyler Ballance; +Cc: Johannes Sixt, Junio C Hamano, git
In-Reply-To: <1228949523.27061.20.camel@starfruit.local>
On Wed, 10 Dec 2008, R. Tyler Ballance wrote:
>
> I decided to endure the 30 minutes long this took on machine, and ran
> the operation in gdb. As a result, I got the SIGSEGV again, and a 13MB
> stacktrace.
>
> In fact, the stack trace was probably longer, but this happened while I
> printed out `bt full`:
Wow. You even got _gdb_ to segfault.
You're my hero. If it can break, you will do it.
> I think I'm going to need to have a drink :-/
Have one for me too.
Anyway, that's a really annoying problem, and it's a bug in git.
Admittedly it's probably brought on by you having a fairly small stack
ulimit, which is also what likely brought gdb to its knees.
That stupid fsck commit walker walks the parents recursively. That's
horribly bogus. So you have a recursion that goes from the top-level
commit all the way to the root, doing
fsck_walk_commit -> walk(parent) -> fsck_walk-commit -> ..
and you have a fairly deep commit tree.
When it hits parent number 80,000+, you run out of stack space, and
SIGSEGV. And judging by the fact that gdb also SIGSEGV's for you when
doing the backtrace, it looks like the gdb backtrace tracer is _also_
recursive, and _also_ hits the same issue ;)
Anyway, with a 8M stack-size I can fsck the kernel repo without any
problem, but while the kernel repo has something like 120k commits in it,
it's a very "bushy" repository (lots of parallelism and merges), and the
path from the top parent to the root is actually much shorter, at just 27k
commits.
I take it that your project has a very long and linear history, which is
why you have a long path from your HEAD to your root.
(You can do something like
git rev-list --first-parent HEAD | wc -l
to get the depth of your history when just walking the first parent, and
if I'm right you'll have a number that is bgger then 80k.)
So you have definitely found a real bug. Right now, you should be able to
work around it by just making your stack depth rather bigger. The
recursion is not very complicated, so even though it's 80,000 deep, each
entry probably is about a hundred bytes on the stack.
In fact, if you're on Linux, most default stack depths would be 8 MB,
which would roughly match that "80k entries of 100 bytes each".
But we should definitely fix this braindamage in fsck. Rather than
recursively walk the commits, we should add them to a commit list and just
walk the list iteratively.
Junio?
Linus
^ permalink raw reply
* Re: [PATCH (resend)] Fix typo in comment in builtin-add.c
From: Junio C Hamano @ 2008-12-10 23:38 UTC (permalink / raw)
To: Alexander Potashev; +Cc: Boyd Stephen Smith Jr., git
In-Reply-To: <1228948064-4006-1-git-send-email-aspotashev@gmail.com>
Alexander Potashev <aspotashev@gmail.com> writes:
> Reported-by: Tim Daly <daly@axiom-developer.org>
> Cc: Boyd Stephen Smith Jr. <bss03@volumehost.net>
> Cc: Junio C Hamano <gitster@pobox.com>
> Cc: <git@vger.kernel.org>
> Signed-off-by: Alexander Potashev <aspotashev@gmail.com>
Eek. Why so many Cc: here for such a trivial patch?
Will apply, thanks.
^ permalink raw reply
* Re: [PATCH] modify/delete conflict resolution overwrites untracked file
From: Junio C Hamano @ 2008-12-10 23:36 UTC (permalink / raw)
To: Clemens Buchacher; +Cc: git, Johannes Schindelin, Alex Riesen
In-Reply-To: <20081210211147.GA13624@localhost>
Clemens Buchacher <drizzd@aon.at> writes:
> On Wed, Dec 10, 2008 at 12:51:59PM -0800, Junio C Hamano wrote:
>> Clemens Buchacher <drizzd@aon.at> writes:
>>
>> > If it's a regression, it dates far back, since 1.5.0 fails as well.
>>
>> A good lit(h)mus test to see if it is a regression or just a plain bug in
>> the recursive strategy would be to see what 'resolve' strategy does
>> (replace "merge" with "merge -s resolve" in your test).
>
> "merge -s resolve" fails with
>
> Trying really trivial in-index merge...
> error: Merge requires file-level merging
> Nope.
> Trying simple merge.
> Simple merge failed, trying Automatic merge.
> ERROR: c1.c: Not handling case ae9304576a6ec3419b231b2b9c8e33a06f97f9fb ->
> -> 8173b675dc61bb578b411c769c9fb654625a7c4e
> fatal: merge program failed
> Automatic merge failed; fix conflicts and then commit the result.
>
> and therefore passes the test.
Are you saying that:
(1) the step should result in conflict and the merge should fail, but it
should not clobber c1.c nevertheless; and
(2) resolve fails to merge (as expected), and it does not clobber c1.c
(as expected); therefore it passes the test.
If so, then you now established that it is a bug in merge-recursive,
right [implementors of recursive-in-C CC'ed]?
Or are you saying that the step should not fail to begin with?
^ permalink raw reply
* Re: [JGIT PATCH 4/6] Add QuotedString class to handle C-style quoting rules
From: Robin Rosenberg @ 2008-12-10 23:22 UTC (permalink / raw)
To: Shawn O. Pearce; +Cc: git
In-Reply-To: <1228946751-12708-5-git-send-email-spearce@spearce.org>
onsdag 10 december 2008 23:05:49 skrev Shawn O. Pearce:
> Git patch files can contain file names which are quoted using the
> C language quoting rules. In order to correctly create or parse
Should we maybe call this Git-style since we really do not care
about C (which version btw?).
> QuotedString itself is an abstract API so callers can be passed a
> quoting style based on the context of where their output will be
> used, and multiple styles could be supported. This may be useful
> if jgit ever grows a "git for-each-ref" style of output where Perl,
> Python, Tcl and Bourne style quoting might be necessary.
>
> References through the singleton QuotedString.C should be able to
> bypass the virtual function table, as the specific type is mentioned
> in the field declaration and that type is final. A good JIT should
> be able to remove the abstraction costs when the caller has hardcoded
> the quoting style.
Making two interfaces is better. We may share the implementation initially,
but parsing file names in Git patches and parsing C strings are different
operations.
> + public void testQuote_OctalAll() {
> + assertQuote("\1", "\\001");
> + assertQuote("~", "\\176");
> + assertQuote("\u00ff", "\\303\\277"); // \u00ff in UTF-8
> + }
What do we do with non-UTF8 names? I think we should
follow the logic we use when parsing commits and paths
in other places.
> +
> + public void testDequote_UnknownEscapeQ() {
> + assertDequote("\\q", "\\q");
> + }
Would Git generate this style in a name?
> + quote[' '] = 0;
> + quote['+'] = 0;
> + quote[','] = 0;
> + quote['-'] = 0;
> + quote['.'] = 0;
> + quote['/'] = 0;
> + quote['='] = 0;
> + quote['_'] = 0;
> + quote['^'] = 0;
> +
> + quote['\u0007'] = 'a';
> + quote['\b'] = 'b';
\e = esc
> + default:
> + // Any other code is taken literally.
> + //
> + r[rPtr++] = '\\';
> + r[rPtr++] = in[inPtr - 1];
> + continue;
> + }
> + }
> +
> + return decode(Constants.CHARSET, r, 0, rPtr);
Importing methods really obscures things. Please qualify with class name
of RawparseUtils here instead.
-- robin
^ permalink raw reply
* [JGIT PATCH 3/3] Change AnyObjectId.abbreviate() to return AbbreviatedObjectId
From: Shawn O. Pearce @ 2008-12-10 23:18 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <1228951107-5546-3-git-send-email-spearce@spearce.org>
By returning our abstraction type we can reuse the logic inside
AbbreviatedObjectId to format the abbreviated string. A result
can also be used to test against another ObjectId.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../ui/internal/components/RefContentProposal.java | 2 +-
.../egit/ui/internal/fetch/FetchResultTable.java | 12 ++++----
.../egit/ui/internal/push/PushResultTable.java | 21 ++++++++-------
.../src/org/spearce/jgit/pgm/Branch.java | 2 +-
.../src/org/spearce/jgit/pgm/Fetch.java | 8 +++---
.../src/org/spearce/jgit/pgm/Push.java | 5 ++-
.../org/spearce/jgit/lib/AbbreviatedObjectId.java | 4 +-
.../src/org/spearce/jgit/lib/AnyObjectId.java | 26 +++++++++++++++++--
8 files changed, 51 insertions(+), 29 deletions(-)
diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/components/RefContentProposal.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/components/RefContentProposal.java
index 60abaf3..b63c428 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/components/RefContentProposal.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/components/RefContentProposal.java
@@ -111,7 +111,7 @@ public String getDescription() {
final StringBuilder sb = new StringBuilder();
sb.append(refName);
sb.append('\n');
- sb.append(objectId.abbreviate(db));
+ sb.append(objectId.abbreviate(db).name());
sb.append(" - ");
if (obj instanceof Commit) {
final Commit c = ((Commit) obj);
diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/fetch/FetchResultTable.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/fetch/FetchResultTable.java
index 868ca94..f1169d1 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/fetch/FetchResultTable.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/fetch/FetchResultTable.java
@@ -137,15 +137,15 @@ else if (tru.getLocalName().startsWith(Constants.R_TAGS))
}
if (r == RefUpdate.Result.FORCED) {
- final String aOld = tru.getOldObjectId().abbreviate(db);
- final String aNew = tru.getNewObjectId().abbreviate(db);
- return aOld + "..." + aNew; //$NON-NLS-1$
+ final String o = tru.getOldObjectId().abbreviate(db).name();
+ final String n = tru.getNewObjectId().abbreviate(db).name();
+ return o + "..." + n; //$NON-NLS-1$
}
if (r == RefUpdate.Result.FAST_FORWARD) {
- final String aOld = tru.getOldObjectId().abbreviate(db);
- final String aNew = tru.getNewObjectId().abbreviate(db);
- return aOld + ".." + aNew; //$NON-NLS-1$
+ final String o = tru.getOldObjectId().abbreviate(db).name();
+ final String n = tru.getNewObjectId().abbreviate(db).name();
+ return o + ".." + n; //$NON-NLS-1$
}
if (r == RefUpdate.Result.REJECTED)
diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/push/PushResultTable.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/push/PushResultTable.java
index c5e476b..6f460dc 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/push/PushResultTable.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/push/PushResultTable.java
@@ -233,9 +233,9 @@ public String getText(Object element) {
return UIText.PushResultTable_statusOkNewBranch;
}
- return oldRef.getObjectId().abbreviate(localDb)
+ return oldRef.getObjectId().abbreviate(localDb).name()
+ (rru.isFastForward() ? ".." : "...")
- + rru.getNewObjectId().abbreviate(localDb);
+ + rru.getNewObjectId().abbreviate(localDb).name();
case UP_TO_DATE:
return UIText.PushResultTable_statusUpToDate;
case NON_EXISTING:
@@ -289,7 +289,7 @@ public String getToolTipText(Object element) {
case OK:
if (rru.isDelete())
return NLS.bind(UIText.PushResultTable_statusDetailDeleted,
- oldRef.getObjectId().abbreviate(localDb));
+ oldRef.getObjectId().abbreviate(localDb).name());
if (oldRef == null)
return null;
if (rru.isFastForward())
@@ -305,20 +305,21 @@ public String getToolTipText(Object element) {
return UIText.PushResultTable_statusDetailNonFastForward;
case REJECTED_REMOTE_CHANGED:
final Ref remoteRef = oldRef;
- final String currentValue;
+ final String curVal;
if (remoteRef == null)
- currentValue = UIText.PushResultTable_refNonExisting;
+ curVal = UIText.PushResultTable_refNonExisting;
else
- currentValue = remoteRef.getObjectId().abbreviate(localDb);
+ curVal = remoteRef.getObjectId().abbreviate(localDb).name();
+
final ObjectId expectedOldObjectId = rru
.getExpectedOldObjectId();
- final String expectedValue;
+ final String expVal;
if (expectedOldObjectId.equals(ObjectId.zeroId()))
- expectedValue = UIText.PushResultTable_refNonExisting;
+ expVal = UIText.PushResultTable_refNonExisting;
else
- expectedValue = expectedOldObjectId.abbreviate(localDb);
+ expVal = expectedOldObjectId.abbreviate(localDb).name();
return NLS.bind(UIText.PushResultTable_statusDetailChanged,
- currentValue, expectedValue);
+ curVal, expVal);
case REJECTED_OTHER_REASON:
return rru.getMessage();
default:
diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Branch.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Branch.java
index db0aab8..11002f0 100644
--- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Branch.java
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Branch.java
@@ -167,7 +167,7 @@ private void printHead(final String ref, final boolean isCurrent,
final int spaces = maxNameLength - ref.length() + 1;
out.print(String.format("%" + spaces + "s", ""));
final ObjectId objectId = refObj.getObjectId();
- out.print(objectId.abbreviate(db));
+ out.print(objectId.abbreviate(db).name());
out.print(' ');
out.print(rw.parseCommit(objectId).getShortMessage());
}
diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Fetch.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Fetch.java
index ad7e08f..e9d3260 100644
--- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Fetch.java
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Fetch.java
@@ -131,14 +131,14 @@ else if (u.getLocalName().startsWith(Constants.R_TAGS))
}
if (r == RefUpdate.Result.FORCED) {
- final String aOld = u.getOldObjectId().abbreviate(db);
- final String aNew = u.getNewObjectId().abbreviate(db);
+ final String aOld = u.getOldObjectId().abbreviate(db).name();
+ final String aNew = u.getNewObjectId().abbreviate(db).name();
return aOld + "..." + aNew;
}
if (r == RefUpdate.Result.FAST_FORWARD) {
- final String aOld = u.getOldObjectId().abbreviate(db);
- final String aNew = u.getNewObjectId().abbreviate(db);
+ final String aOld = u.getOldObjectId().abbreviate(db).name();
+ final String aNew = u.getNewObjectId().abbreviate(db).name();
return aOld + ".." + aNew;
}
diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Push.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Push.java
index 53ad080..19d31a1 100644
--- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Push.java
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Push.java
@@ -181,8 +181,9 @@ private void printRefUpdateResult(final URIish uri,
boolean fastForward = rru.isFastForward();
final char flag = fastForward ? ' ' : '+';
final String summary = oldRef.getObjectId().abbreviate(db)
+ .name()
+ (fastForward ? ".." : "...")
- + rru.getNewObjectId().abbreviate(db);
+ + rru.getNewObjectId().abbreviate(db).name();
final String message = fastForward ? null : "forced update";
printUpdateLine(flag, summary, srcRef, remoteName, message);
}
@@ -205,7 +206,7 @@ printUpdateLine('!', "[rejected]", srcRef, remoteName,
case REJECTED_REMOTE_CHANGED:
final String message = "remote ref object changed - is not expected one "
- + rru.getExpectedOldObjectId().abbreviate(db);
+ + rru.getExpectedOldObjectId().abbreviate(db).name();
printUpdateLine('!', "[rejected]", srcRef, remoteName, message);
break;
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java b/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java
index 206cc2f..33b62b9 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java
@@ -52,7 +52,7 @@
* This class converts the hex string into a binary form, to make it more
* efficient for matching against an object.
*/
-public class AbbreviatedObjectId {
+public final class AbbreviatedObjectId {
/**
* Convert an AbbreviatedObjectId from hex characters (US-ASCII).
*
@@ -152,7 +152,7 @@ static int mask(final int nibbles, final int word, final int v) {
final int w5;
- private AbbreviatedObjectId(final int n, final int new_1, final int new_2,
+ AbbreviatedObjectId(final int n, final int new_1, final int new_2,
final int new_3, final int new_4, final int new_5) {
nibbles = n;
w1 = new_1;
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java b/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java
index 8872017..7d7d61b 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java
@@ -432,16 +432,36 @@ public final String name() {
/**
* Return unique abbreviation (prefix) of this object SHA-1.
* <p>
+ * This method is a utility for <code>abbreviate(repo, 8)</code>.
+ *
+ * @param repo
+ * repository for checking uniqueness within.
+ * @return SHA-1 abbreviation.
+ */
+ public AbbreviatedObjectId abbreviate(final Repository repo) {
+ return abbreviate(repo, 8);
+ }
+
+ /**
+ * Return unique abbreviation (prefix) of this object SHA-1.
+ * <p>
* Current implementation is not guaranteeing uniqueness, it just returns
* fixed-length prefix of SHA-1 string.
- *
+ *
* @param repo
* repository for checking uniqueness within.
+ * @param len
+ * minimum length of the abbreviated string.
* @return SHA-1 abbreviation.
*/
- public String abbreviate(final Repository repo) {
+ public AbbreviatedObjectId abbreviate(final Repository repo, final int len) {
// TODO implement checking for uniqueness
- return name().substring(0, 7);
+ final int a = AbbreviatedObjectId.mask(len, 1, w1);
+ final int b = AbbreviatedObjectId.mask(len, 2, w2);
+ final int c = AbbreviatedObjectId.mask(len, 3, w3);
+ final int d = AbbreviatedObjectId.mask(len, 4, w4);
+ final int e = AbbreviatedObjectId.mask(len, 5, w5);
+ return new AbbreviatedObjectId(len, a, b, c, d, e);
}
/**
--
1.6.1.rc2.299.gead4c
^ permalink raw reply related
* [JGIT PATCH 2/3] Add ObjectId.startsWith(AbbreviatedObjectId)
From: Shawn O. Pearce @ 2008-12-10 23:18 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <1228951107-5546-2-git-send-email-spearce@spearce.org>
This test can be useful to determine if the object id at least
begins with an abbreviated id.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../spearce/jgit/lib/AbbreviatedObjectIdTest.java | 58 ++++++++++++++++++++
.../org/spearce/jgit/lib/AbbreviatedObjectId.java | 57 +++++++++++++++++++
.../src/org/spearce/jgit/lib/AnyObjectId.java | 11 ++++
3 files changed, 126 insertions(+), 0 deletions(-)
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java
index f540f49..3f82d50 100644
--- a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java
@@ -224,4 +224,62 @@ public void testNotEquals_DiffLength() {
assertFalse(a.equals(b));
assertFalse(b.equals(a));
}
+
+ public void testPrefixCompare_Full() {
+ final String s1 = "7b6e8067ec96acef9a4184b43210d583b6d2f99a";
+ final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(s1);
+ final ObjectId i1 = ObjectId.fromString(s1);
+ assertEquals(0, a.prefixCompare(i1));
+ assertTrue(i1.startsWith(a));
+
+ final String s2 = "7b6e8067ec96acef9a4184b43210d583b6d2f99b";
+ final ObjectId i2 = ObjectId.fromString(s2);
+ assertTrue(a.prefixCompare(i2) < 0);
+ assertFalse(i2.startsWith(a));
+
+ final String s3 = "7b6e8067ec96acef9a4184b43210d583b6d2f999";
+ final ObjectId i3 = ObjectId.fromString(s3);
+ assertTrue(a.prefixCompare(i3) > 0);
+ assertFalse(i3.startsWith(a));
+ }
+
+ public void testPrefixCompare_1() {
+ final String sa = "7";
+ final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(sa);
+
+ final String s1 = "7b6e8067ec96acef9a4184b43210d583b6d2f99a";
+ final ObjectId i1 = ObjectId.fromString(s1);
+ assertEquals(0, a.prefixCompare(i1));
+ assertTrue(i1.startsWith(a));
+
+ final String s2 = "8b6e8067ec96acef9a4184b43210d583b6d2f99a";
+ final ObjectId i2 = ObjectId.fromString(s2);
+ assertTrue(a.prefixCompare(i2) < 0);
+ assertFalse(i2.startsWith(a));
+
+ final String s3 = "6b6e8067ec96acef9a4184b43210d583b6d2f99a";
+ final ObjectId i3 = ObjectId.fromString(s3);
+ assertTrue(a.prefixCompare(i3) > 0);
+ assertFalse(i3.startsWith(a));
+ }
+
+ public void testPrefixCompare_17() {
+ final String sa = "7b6e8067ec96acef9";
+ final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(sa);
+
+ final String s1 = "7b6e8067ec96acef9a4184b43210d583b6d2f99a";
+ final ObjectId i1 = ObjectId.fromString(s1);
+ assertEquals(0, a.prefixCompare(i1));
+ assertTrue(i1.startsWith(a));
+
+ final String s2 = "7b6e8067eca6acef9a4184b43210d583b6d2f99a";
+ final ObjectId i2 = ObjectId.fromString(s2);
+ assertTrue(a.prefixCompare(i2) < 0);
+ assertFalse(i2.startsWith(a));
+
+ final String s3 = "7b6e8067ec86acef9a4184b43210d583b6d2f99a";
+ final ObjectId i3 = ObjectId.fromString(s3);
+ assertTrue(a.prefixCompare(i3) > 0);
+ assertFalse(i3.startsWith(a));
+ }
}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java b/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java
index 1a8d296..206cc2f 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java
@@ -39,6 +39,8 @@
import java.io.UnsupportedEncodingException;
+import org.spearce.jgit.util.NB;
+
/**
* A prefix abbreviation of an {@link ObjectId}.
* <p>
@@ -119,6 +121,24 @@ private static final int hexUInt32(final byte[] bs, int p, final int end) {
return r << (8 - n) * 4;
}
+ static int mask(final int nibbles, final int word, final int v) {
+ final int b = (word - 1) * 8;
+ if (b + 8 <= nibbles) {
+ // We have all of the bits required for this word.
+ //
+ return v;
+ }
+
+ if (nibbles < b) {
+ // We have none of the bits required for this word.
+ //
+ return 0;
+ }
+
+ final int s = 32 - (nibbles - b) * 4;
+ return (v >>> s) << s;
+ }
+
/** Number of half-bytes used by this id. */
final int nibbles;
@@ -157,6 +177,43 @@ public ObjectId toObjectId() {
return isComplete() ? new ObjectId(w1, w2, w3, w4, w5) : null;
}
+ /**
+ * Compares this abbreviation to a full object id.
+ *
+ * @param other
+ * the other object id.
+ * @return <0 if this abbreviation names an object that is less than
+ * <code>other</code>; 0 if this abbreviation exactly matches the
+ * first {@link #length()} digits of <code>other.name()</code>;
+ * >0 if this abbreviation names an object that is after
+ * <code>other</code>.
+ */
+ public int prefixCompare(final AnyObjectId other) {
+ int cmp;
+
+ cmp = NB.compareUInt32(w1, mask(1, other.w1));
+ if (cmp != 0)
+ return cmp;
+
+ cmp = NB.compareUInt32(w2, mask(2, other.w2));
+ if (cmp != 0)
+ return cmp;
+
+ cmp = NB.compareUInt32(w3, mask(3, other.w3));
+ if (cmp != 0)
+ return cmp;
+
+ cmp = NB.compareUInt32(w4, mask(4, other.w4));
+ if (cmp != 0)
+ return cmp;
+
+ return NB.compareUInt32(w5, mask(5, other.w5));
+ }
+
+ private int mask(final int word, final int v) {
+ return mask(nibbles, word, v);
+ }
+
@Override
public int hashCode() {
return w2;
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java b/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java
index e88e09d..8872017 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java
@@ -226,6 +226,17 @@ int compareTo(final int[] bs, final int p) {
return NB.compareUInt32(w5, bs[p + 4]);
}
+ /**
+ * Tests if this ObjectId starts with the given abbreviation.
+ *
+ * @param abbr
+ * the abbreviation.
+ * @return true if this ObjectId begins with the abbreviation; else false.
+ */
+ public boolean startsWith(final AbbreviatedObjectId abbr) {
+ return abbr.prefixCompare(this) == 0;
+ }
+
public int hashCode() {
return w2;
}
--
1.6.1.rc2.299.gead4c
^ permalink raw reply related
* [JGIT PATCH 1/3] Define an abstraction for handling abbreviated SHA-1 strings
From: Shawn O. Pearce @ 2008-12-10 23:18 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <1228951107-5546-1-git-send-email-spearce@spearce.org>
The AbbreviatedObjectId class parses an abbreviated SHA-1 string
into a binary format, permitting it to be more efficiently matched
against existing binary ObjectId fields.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../spearce/jgit/lib/AbbreviatedObjectIdTest.java | 227 ++++++++++++++++++++
.../org/spearce/jgit/lib/AbbreviatedObjectId.java | 205 ++++++++++++++++++
.../src/org/spearce/jgit/lib/AnyObjectId.java | 2 +-
3 files changed, 433 insertions(+), 1 deletions(-)
create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java
new file mode 100644
index 0000000..f540f49
--- /dev/null
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ *
+ * 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 Git Development Community 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.spearce.jgit.lib;
+
+import junit.framework.TestCase;
+
+public class AbbreviatedObjectIdTest extends TestCase {
+ public void testEmpty_FromByteArray() {
+ final AbbreviatedObjectId i;
+ i = AbbreviatedObjectId.fromString(new byte[] {}, 0, 0);
+ assertNotNull(i);
+ assertEquals(0, i.length());
+ assertFalse(i.isComplete());
+ assertEquals("", i.name());
+ }
+
+ public void testEmpty_FromString() {
+ final AbbreviatedObjectId i = AbbreviatedObjectId.fromString("");
+ assertNotNull(i);
+ assertEquals(0, i.length());
+ assertFalse(i.isComplete());
+ assertEquals("", i.name());
+ }
+
+ public void testFull_FromByteArray() {
+ final String s = "7b6e8067ec96acef9a4184b43210d583b6d2f99a";
+ final byte[] b = Constants.encodeASCII(s);
+ final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(b, 0,
+ b.length);
+ assertNotNull(i);
+ assertEquals(s.length(), i.length());
+ assertTrue(i.isComplete());
+ assertEquals(s, i.name());
+
+ final ObjectId f = i.toObjectId();
+ assertNotNull(f);
+ assertEquals(ObjectId.fromString(s), f);
+ assertEquals(f.hashCode(), i.hashCode());
+ }
+
+ public void testFull_FromString() {
+ final String s = "7b6e8067ec96acef9a4184b43210d583b6d2f99a";
+ final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+ assertNotNull(i);
+ assertEquals(s.length(), i.length());
+ assertTrue(i.isComplete());
+ assertEquals(s, i.name());
+
+ final ObjectId f = i.toObjectId();
+ assertNotNull(f);
+ assertEquals(ObjectId.fromString(s), f);
+ assertEquals(f.hashCode(), i.hashCode());
+ }
+
+ public void test1_FromString() {
+ final String s = "7";
+ final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+ assertNotNull(i);
+ assertEquals(s.length(), i.length());
+ assertFalse(i.isComplete());
+ assertEquals(s, i.name());
+ assertNull(i.toObjectId());
+ }
+
+ public void test2_FromString() {
+ final String s = "7b";
+ final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+ assertNotNull(i);
+ assertEquals(s.length(), i.length());
+ assertFalse(i.isComplete());
+ assertEquals(s, i.name());
+ assertNull(i.toObjectId());
+ }
+
+ public void test3_FromString() {
+ final String s = "7b6";
+ final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+ assertNotNull(i);
+ assertEquals(s.length(), i.length());
+ assertFalse(i.isComplete());
+ assertEquals(s, i.name());
+ assertNull(i.toObjectId());
+ }
+
+ public void test4_FromString() {
+ final String s = "7b6e";
+ final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+ assertNotNull(i);
+ assertEquals(s.length(), i.length());
+ assertFalse(i.isComplete());
+ assertEquals(s, i.name());
+ assertNull(i.toObjectId());
+ }
+
+ public void test5_FromString() {
+ final String s = "7b6e8";
+ final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+ assertNotNull(i);
+ assertEquals(s.length(), i.length());
+ assertFalse(i.isComplete());
+ assertEquals(s, i.name());
+ assertNull(i.toObjectId());
+ }
+
+ public void test6_FromString() {
+ final String s = "7b6e80";
+ final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+ assertNotNull(i);
+ assertEquals(s.length(), i.length());
+ assertFalse(i.isComplete());
+ assertEquals(s, i.name());
+ assertNull(i.toObjectId());
+ }
+
+ public void test7_FromString() {
+ final String s = "7b6e806";
+ final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+ assertNotNull(i);
+ assertEquals(s.length(), i.length());
+ assertFalse(i.isComplete());
+ assertEquals(s, i.name());
+ assertNull(i.toObjectId());
+ }
+
+ public void test8_FromString() {
+ final String s = "7b6e8067";
+ final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+ assertNotNull(i);
+ assertEquals(s.length(), i.length());
+ assertFalse(i.isComplete());
+ assertEquals(s, i.name());
+ assertNull(i.toObjectId());
+ }
+
+ public void test9_FromString() {
+ final String s = "7b6e8067e";
+ final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+ assertNotNull(i);
+ assertEquals(s.length(), i.length());
+ assertFalse(i.isComplete());
+ assertEquals(s, i.name());
+ assertNull(i.toObjectId());
+ }
+
+ public void test17_FromString() {
+ final String s = "7b6e8067ec96acef9";
+ final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+ assertNotNull(i);
+ assertEquals(s.length(), i.length());
+ assertFalse(i.isComplete());
+ assertEquals(s, i.name());
+ assertNull(i.toObjectId());
+ }
+
+ public void testEquals_Short() {
+ final String s = "7b6e8067";
+ final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(s);
+ final AbbreviatedObjectId b = AbbreviatedObjectId.fromString(s);
+ assertNotSame(a, b);
+ assertTrue(a.hashCode() == b.hashCode());
+ assertTrue(a.equals(b));
+ assertTrue(b.equals(a));
+ }
+
+ public void testEquals_Full() {
+ final String s = "7b6e8067ec96acef9a4184b43210d583b6d2f99a";
+ final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(s);
+ final AbbreviatedObjectId b = AbbreviatedObjectId.fromString(s);
+ assertNotSame(a, b);
+ assertTrue(a.hashCode() == b.hashCode());
+ assertTrue(a.equals(b));
+ assertTrue(b.equals(a));
+ }
+
+ public void testNotEquals_SameLength() {
+ final String sa = "7b6e8067";
+ final String sb = "7b6e806e";
+ final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(sa);
+ final AbbreviatedObjectId b = AbbreviatedObjectId.fromString(sb);
+ assertFalse(a.equals(b));
+ assertFalse(b.equals(a));
+ }
+
+ public void testNotEquals_DiffLength() {
+ final String sa = "7b6e8067abcd";
+ final String sb = "7b6e8067";
+ final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(sa);
+ final AbbreviatedObjectId b = AbbreviatedObjectId.fromString(sb);
+ assertFalse(a.equals(b));
+ assertFalse(b.equals(a));
+ }
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java b/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java
new file mode 100644
index 0000000..1a8d296
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ *
+ * 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 Git Development Community 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.spearce.jgit.lib;
+
+import java.io.UnsupportedEncodingException;
+
+/**
+ * A prefix abbreviation of an {@link ObjectId}.
+ * <p>
+ * Sometimes Git produces abbreviated SHA-1 strings, using sufficient leading
+ * digits from the ObjectId name to still be unique within the repository the
+ * string was generated from. These ids are likely to be unique for a useful
+ * period of time, especially if they contain at least 6-10 hex digits.
+ * <p>
+ * This class converts the hex string into a binary form, to make it more
+ * efficient for matching against an object.
+ */
+public class AbbreviatedObjectId {
+ /**
+ * Convert an AbbreviatedObjectId from hex characters (US-ASCII).
+ *
+ * @param buf
+ * the US-ASCII buffer to read from.
+ * @param offset
+ * position to read the first character from.
+ * @param end
+ * one past the last position to read (<code>end-offset</code> is
+ * the length of the string).
+ * @return the converted object id.
+ */
+ public static final AbbreviatedObjectId fromString(final byte[] buf,
+ final int offset, final int end) {
+ if (end - offset > AnyObjectId.STR_LEN)
+ throw new IllegalArgumentException("Invalid id");
+ return fromHexString(buf, offset, end);
+ }
+
+ /**
+ * Convert an AbbreviatedObjectId from hex characters.
+ *
+ * @param str
+ * the string to read from. Must be <= 40 characters.
+ * @return the converted object id.
+ */
+ public static final AbbreviatedObjectId fromString(final String str) {
+ if (str.length() > AnyObjectId.STR_LEN)
+ throw new IllegalArgumentException("Invalid id: " + str);
+ final byte[] b = Constants.encodeASCII(str);
+ return fromHexString(b, 0, b.length);
+ }
+
+ private static final AbbreviatedObjectId fromHexString(final byte[] bs,
+ int ptr, final int end) {
+ try {
+ final int a = hexUInt32(bs, ptr, end);
+ final int b = hexUInt32(bs, ptr + 8, end);
+ final int c = hexUInt32(bs, ptr + 16, end);
+ final int d = hexUInt32(bs, ptr + 24, end);
+ final int e = hexUInt32(bs, ptr + 32, end);
+ return new AbbreviatedObjectId(end - ptr, a, b, c, d, e);
+ } catch (ArrayIndexOutOfBoundsException e1) {
+ try {
+ final String str = new String(bs, ptr, end - ptr, "US-ASCII");
+ throw new IllegalArgumentException("Invalid id: " + str);
+ } catch (UnsupportedEncodingException e2) {
+ throw new IllegalArgumentException("Invalid id");
+ }
+ }
+ }
+
+ private static final int hexUInt32(final byte[] bs, int p, final int end) {
+ if (8 <= end - p)
+ return AnyObjectId.hexUInt32(bs, p);
+
+ int r = 0, n = 0;
+ while (n < 8 && p < end) {
+ final int v = AnyObjectId.fromhex[bs[p++]];
+ if (v < 0)
+ throw new ArrayIndexOutOfBoundsException();
+ r <<= 4;
+ r |= v;
+ n++;
+ }
+ return r << (8 - n) * 4;
+ }
+
+ /** Number of half-bytes used by this id. */
+ final int nibbles;
+
+ final int w1;
+
+ final int w2;
+
+ final int w3;
+
+ final int w4;
+
+ final int w5;
+
+ private AbbreviatedObjectId(final int n, final int new_1, final int new_2,
+ final int new_3, final int new_4, final int new_5) {
+ nibbles = n;
+ w1 = new_1;
+ w2 = new_2;
+ w3 = new_3;
+ w4 = new_4;
+ w5 = new_5;
+ }
+
+ /** @return number of hex digits appearing in this id */
+ public int length() {
+ return nibbles;
+ }
+
+ /** @return true if this ObjectId is actually a complete id. */
+ public boolean isComplete() {
+ return length() == AnyObjectId.RAW_LEN * 2;
+ }
+
+ /** @return a complete ObjectId; null if {@link #isComplete()} is false */
+ public ObjectId toObjectId() {
+ return isComplete() ? new ObjectId(w1, w2, w3, w4, w5) : null;
+ }
+
+ @Override
+ public int hashCode() {
+ return w2;
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (o instanceof AbbreviatedObjectId) {
+ final AbbreviatedObjectId b = (AbbreviatedObjectId) o;
+ return nibbles == b.nibbles && w1 == b.w1 && w2 == b.w2
+ && w3 == b.w3 && w4 == b.w4 && w5 == b.w5;
+ }
+ return false;
+ }
+
+ /**
+ * @return string form of the abbreviation, in lower case hexadecimal.
+ */
+ public final String name() {
+ final char[] b = new char[AnyObjectId.STR_LEN];
+
+ AnyObjectId.formatHexChar(b, 0, w1);
+ if (nibbles <= 8)
+ return new String(b, 0, nibbles);
+
+ AnyObjectId.formatHexChar(b, 8, w2);
+ if (nibbles <= 16)
+ return new String(b, 0, nibbles);
+
+ AnyObjectId.formatHexChar(b, 16, w3);
+ if (nibbles <= 24)
+ return new String(b, 0, nibbles);
+
+ AnyObjectId.formatHexChar(b, 24, w4);
+ if (nibbles <= 32)
+ return new String(b, 0, nibbles);
+
+ AnyObjectId.formatHexChar(b, 32, w5);
+ return new String(b, 0, nibbles);
+ }
+
+ @Override
+ public String toString() {
+ return "AbbreviatedObjectId[" + name() + "]";
+ }
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java b/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java
index a534202..e88e09d 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java
@@ -396,7 +396,7 @@ private void toHexCharArray(final char[] dst) {
private static final char[] hexchar = { '0', '1', '2', '3', '4', '5', '6',
'7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
- private static void formatHexChar(final char[] dst, final int p, int w) {
+ static void formatHexChar(final char[] dst, final int p, int w) {
int o = p + 7;
while (o >= p && w != 0) {
dst[o--] = hexchar[w & 0xf];
--
1.6.1.rc2.299.gead4c
^ permalink raw reply related
* [JGIT PATCH 0/3] Introduce AbbreviatedObjectId
From: Shawn O. Pearce @ 2008-12-10 23:18 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
I'm using this new type to handle the "index" line of a git patch
file, where object ids are generally shorter than 40 characters
and thus aren't parsable by ObjectId.
Reading the short id is important because we can validate that a
patch applies correctly by computing the SHA-1 of the result and
testing it against the abbreviated id read in the "index" line.
If the base object SHA-1 matches the abbreviated line then the
result of applying the patch must also match; if it doesn't the
patch application logic is broken.
Shawn O. Pearce (3):
Define an abstraction for handling abbreviated SHA-1 strings
Add ObjectId.startsWith(AbbreviatedObjectId)
Change AnyObjectId.abbreviate() to return AbbreviatedObjectId
.../ui/internal/components/RefContentProposal.java | 2 +-
.../egit/ui/internal/fetch/FetchResultTable.java | 12 +-
.../egit/ui/internal/push/PushResultTable.java | 21 +-
.../src/org/spearce/jgit/pgm/Branch.java | 2 +-
.../src/org/spearce/jgit/pgm/Fetch.java | 8 +-
.../src/org/spearce/jgit/pgm/Push.java | 5 +-
.../spearce/jgit/lib/AbbreviatedObjectIdTest.java | 285 ++++++++++++++++++++
.../org/spearce/jgit/lib/AbbreviatedObjectId.java | 262 ++++++++++++++++++
.../src/org/spearce/jgit/lib/AnyObjectId.java | 39 +++-
9 files changed, 608 insertions(+), 28 deletions(-)
create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java
^ permalink raw reply
* epic fsck SIGSEGV! (was Recovering from epic fail (deleted .git/objects/pack))
From: R. Tyler Ballance @ 2008-12-10 22:52 UTC (permalink / raw)
To: Johannes Sixt; +Cc: Junio C Hamano, git
In-Reply-To: <493FAA5A.8070801@viscovery.net>
[-- Attachment #1: Type: text/plain, Size: 1750 bytes --]
On Wed, 2008-12-10 at 12:39 +0100, Johannes Sixt wrote:
> R. Tyler Ballance schrieb:
> > On Tue, 2008-12-09 at 16:19 -0800, Junio C Hamano wrote:
> >> See if "fsck --full" complains after that. If the repository was not
> >> repacked during that period, all objects created by the activity by the
> >> unfortunate developer would be loose, so ...
> >
> > tyler@ccnet:~/source/slide/brian_main> time git fsck --full
> > Segmentation fault
>
> Please make a backup (tarball) of the repository that shows this segfault.
> 'git fsck' is not supposed to segfault, no matter what garbage is thrown
> at it.
>
> Can you make a backtrace of this failing 'git fsck --full' invocation?
I decided to endure the 30 minutes long this took on machine, and ran
the operation in gdb. As a result, I got the SIGSEGV again, and a 13MB
stacktrace.
In fact, the stack trace was probably longer, but this happened while I
printed out `bt full`:
#80496 0x00000000004244bc in fsck_handle_ref (refname=0x162aa61
"refs/heads/master", sha1=0x162aa39 "S\236\024(f\210��V\027�'�E
\025�u�g",
flag=<value optimized out>, cb_data=<value optimized out>)
at builtin-fsck.c:118
obj = <value optimized out>
#80497 0x000000000047f61c in do_for_each_ref (base=0x4a7022
"refs/", fn=0x424450 <fsck_handle_ref>, trim=0, cb_data=0x0) at
refs.c:582
[1] 29388 segmentation fault (core dumped) gdb git
tyler@ccnet:~/source/slide/brian_main>
The "full" trace is here:
http://pineapple.monkeypox.org/scratch/git-1.6.0.2-fsck-sigsegv.trace
I think I'm going to need to have a drink :-/
--
-R. Tyler Ballance
Slide, Inc.
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply
* [RFC/PATCH] Add support for a pdf version of the user manual
From: Miklos Vajna @ 2008-12-10 22:44 UTC (permalink / raw)
To: git
Use dblatex in order to create a pdf version of the git user manual. No
existing Makefile targets (including "all") are touched, so you need to
explicitly say
make pdf
sudo make install-pdf
to get user-manual.pdf created and installed.
Signed-off-by: Miklos Vajna <vmiklos@frugalware.org>
---
Hi,
It turns out that people prefer reading long documents (such as the User
Manual) in a pdf reader, rather then in a web browser. This patch makes
them happy.
I marked it RFC as I'm not sure if using the asciidoc dblatex sty and
xsl file is a good idea or not.
(Oh and because we are in the rc period and this is not a bugfix.)
The other (info/man/html) formats do not make use of the config files in
/etc/asciidoc, so maybe it would be better to just copy them in the
Documentation dir. OTOH I did not want to cause a duplication without a
good reason.
Opinions?
Thanks.
Documentation/Makefile | 13 +++++++++++++
INSTALL | 3 +++
Makefile | 6 ++++++
3 files changed, 22 insertions(+), 0 deletions(-)
diff --git a/Documentation/Makefile b/Documentation/Makefile
index c34c1ca..69f4ade 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -32,6 +32,7 @@ DOC_MAN7=$(patsubst %.txt,%.7,$(MAN7_TXT))
prefix?=$(HOME)
bindir?=$(prefix)/bin
htmldir?=$(prefix)/share/doc/git-doc
+pdfdir?=$(prefix)/share/doc/git-doc
mandir?=$(prefix)/share/man
man1dir=$(mandir)/man1
man5dir=$(mandir)/man5
@@ -50,6 +51,7 @@ infodir?=$(prefix)/share/info
MAKEINFO=makeinfo
INSTALL_INFO=install-info
DOCBOOK2X_TEXI=docbook2x-texi
+DBLATEX=dblatex
ifndef PERL_PATH
PERL_PATH = /usr/bin/perl
endif
@@ -87,6 +89,8 @@ man7: $(DOC_MAN7)
info: git.info gitman.info
+pdf: user-manual.pdf
+
install: install-man
install-man: man
@@ -107,6 +111,10 @@ install-info: info
echo "No directory found in $(DESTDIR)$(infodir)" >&2 ; \
fi
+install-pdf: pdf
+ $(INSTALL) -d -m 755 $(DESTDIR)$(pdfdir)
+ $(INSTALL) -m 644 user-manual.pdf $(DESTDIR)$(pdfdir)
+
install-html: html
sh ./install-webdoc.sh $(DESTDIR)$(htmldir)
@@ -190,6 +198,11 @@ user-manual.texi: user-manual.xml
$(DOCBOOK2X_TEXI) user-manual.xml --to-stdout | $(PERL_PATH) fix-texi.perl >$@+
mv $@+ $@
+user-manual.pdf: user-manual.xml
+ $(RM) $@+ $@
+ $(DBLATEX) -o $@+ -p /etc/asciidoc/dblatex/asciidoc-dblatex.xsl -s /etc/asciidoc/dblatex/asciidoc-dblatex.sty $<
+ mv $@+ $@
+
gitman.texi: $(MAN_XML) cat-texi.perl
$(RM) $@+ $@
($(foreach xml,$(MAN_XML),$(DOCBOOK2X_TEXI) --to-stdout $(xml);)) | \
diff --git a/INSTALL b/INSTALL
index d1deb0b..ae7f750 100644
--- a/INSTALL
+++ b/INSTALL
@@ -101,6 +101,9 @@ Issues of note:
Building and installing the info file additionally requires
makeinfo and docbook2X. Version 0.8.3 is known to work.
+ Building and installing the pdf file additionally requires
+ dblatex. Version 0.2.7 with asciidoc >= 8.2.7 is known to work.
+
The documentation is written for AsciiDoc 7, but "make
ASCIIDOC8=YesPlease doc" will let you format with AsciiDoc 8.
diff --git a/Makefile b/Makefile
index 5158197..b1456a2 100644
--- a/Makefile
+++ b/Makefile
@@ -1306,6 +1306,9 @@ html:
info:
$(MAKE) -C Documentation info
+pdf:
+ $(MAKE) -C Documentation pdf
+
TAGS:
$(RM) TAGS
$(FIND) . -name '*.[hcS]' -print | xargs etags -a
@@ -1448,6 +1451,9 @@ install-html:
install-info:
$(MAKE) -C Documentation install-info
+install-pdf:
+ $(MAKE) -C Documentation install-pdf
+
quick-install-doc:
$(MAKE) -C Documentation quick-install
--
1.6.1.rc1.35.gae26e.dirty
^ permalink raw reply related
* [PATCH (resend)] Fix typo in comment in builtin-add.c
From: Alexander Potashev @ 2008-12-10 22:27 UTC (permalink / raw)
To: A S Potashev
Cc: Alexander Potashev, Boyd Stephen Smith Jr., Junio C Hamano, git
In-Reply-To: <200812101910.mBAJAsF04710@localhost.localdomain>
Reported-by: Tim Daly <daly@axiom-developer.org>
Cc: Boyd Stephen Smith Jr. <bss03@volumehost.net>
Cc: Junio C Hamano <gitster@pobox.com>
Cc: <git@vger.kernel.org>
Signed-off-by: Alexander Potashev <aspotashev@gmail.com>
---
builtin-add.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/builtin-add.c b/builtin-add.c
index ea4e771..719de8b 100644
--- a/builtin-add.c
+++ b/builtin-add.c
@@ -23,7 +23,7 @@ static void fill_pathspec_matches(const char **pathspec, char *seen, int specs)
int num_unmatched = 0, i;
/*
- * Since we are walking the index as if we are warlking the directory,
+ * Since we are walking the index as if we were walking the directory,
* we have to mark the matched pathspec as seen; otherwise we will
* mistakenly think that the user gave a pathspec that did not match
* anything.
--
1.6.0.4
^ permalink raw reply related
* Re: fatal output from git-show really wants a terminal
From: Boyd Stephen Smith Jr. @ 2008-12-10 22:24 UTC (permalink / raw)
To: git; +Cc: Johannes Sixt, Tim Olsen
In-Reply-To: <200812102046.50186.j6t@kdbg.org>
[-- Attachment #1: Type: text/plain, Size: 932 bytes --]
On Wednesday 2008 December 10 13:46:50 you wrote:
>On Mittwoch, 10. Dezember 2008, Tim Olsen wrote:
>> It appears that when outputting a fatal error, git-show will choose
>> stdout over stderr if stdout is a terminal and stderr is not.
>
>This is by design.
Then it is poor design. :P j/k
Why not use the pager only if git-show is "interactive", using the same test
for interactivity as SUSv3/POSIX shells use? IIRC, a shell is interactive if
both stdin and stderr are terminals. That test for interactivity -- a
associated difference in behavior -- predates git by a number of years. Is
there a reason for being different? Is the porcelain consistent about that
behavior?
--
Boyd Stephen Smith Jr. ,= ,-_-. =.
bss03@volumehost.net ((_/)o o(\_))
ICQ: 514984 YM/AIM: DaTwinkDaddy `-'(. .)`-'
http://iguanasuicide.org/ \_/
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply
* [JGIT PATCH 6/6] Add ~user friendly Bourne style quoting for TransportGitSsh
From: Shawn O. Pearce @ 2008-12-10 22:05 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <1228946751-12708-6-git-send-email-spearce@spearce.org>
This mostly completes the migration of our quoting rules from the
SSH transport to our QuotedString pattern. User names may be left
alone for the shell to expand when the string is evaluated, if the
caller wants that sort of behavior in a particular context.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../util/QuotedStringBourneUserPathStyleTest.java | 130 ++++++++++++++++++++
.../spearce/jgit/transport/TransportGitSsh.java | 27 +----
.../src/org/spearce/jgit/util/QuotedString.java | 28 ++++
3 files changed, 160 insertions(+), 25 deletions(-)
create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/util/QuotedStringBourneUserPathStyleTest.java
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/util/QuotedStringBourneUserPathStyleTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/util/QuotedStringBourneUserPathStyleTest.java
new file mode 100644
index 0000000..36fb52a
--- /dev/null
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/util/QuotedStringBourneUserPathStyleTest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ *
+ * 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 Git Development Community 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.spearce.jgit.util;
+
+import static org.spearce.jgit.util.QuotedString.BOURNE_USER_PATH;
+import junit.framework.TestCase;
+
+import org.spearce.jgit.lib.Constants;
+
+public class QuotedStringBourneUserPathStyleTest extends TestCase {
+ private static void assertQuote(final String in, final String exp) {
+ final String r = BOURNE_USER_PATH.quote(in);
+ assertNotSame(in, r);
+ assertFalse(in.equals(r));
+ assertEquals('\'' + exp + '\'', r);
+ }
+
+ private static void assertDequote(final String exp, final String in) {
+ final byte[] b = Constants.encode('\'' + in + '\'');
+ final String r = BOURNE_USER_PATH.dequote(b, 0, b.length);
+ assertEquals(exp, r);
+ }
+
+ public void testQuote_Empty() {
+ assertEquals("''", BOURNE_USER_PATH.quote(""));
+ }
+
+ public void testDequote_Empty1() {
+ assertEquals("", BOURNE_USER_PATH.dequote(new byte[0], 0, 0));
+ }
+
+ public void testDequote_Empty2() {
+ assertEquals("", BOURNE_USER_PATH.dequote(new byte[] { '\'', '\'' }, 0,
+ 2));
+ }
+
+ public void testDequote_SoleSq() {
+ assertEquals("", BOURNE_USER_PATH.dequote(new byte[] { '\'' }, 0, 1));
+ }
+
+ public void testQuote_BareA() {
+ assertQuote("a", "a");
+ }
+
+ public void testDequote_BareA() {
+ final String in = "a";
+ final byte[] b = Constants.encode(in);
+ assertEquals(in, BOURNE_USER_PATH.dequote(b, 0, b.length));
+ }
+
+ public void testDequote_BareABCZ_OnlyBC() {
+ final String in = "abcz";
+ final byte[] b = Constants.encode(in);
+ final int p = in.indexOf('b');
+ assertEquals("bc", BOURNE_USER_PATH.dequote(b, p, p + 2));
+ }
+
+ public void testDequote_LoneBackslash() {
+ assertDequote("\\", "\\");
+ }
+
+ public void testQuote_NamedEscapes() {
+ assertQuote("'", "'\\''");
+ assertQuote("!", "'\\!'");
+
+ assertQuote("a'b", "a'\\''b");
+ assertQuote("a!b", "a'\\!'b");
+ }
+
+ public void testDequote_NamedEscapes() {
+ assertDequote("'", "'\\''");
+ assertDequote("!", "'\\!'");
+
+ assertDequote("a'b", "a'\\''b");
+ assertDequote("a!b", "a'\\!'b");
+ }
+
+ public void testQuote_User() {
+ assertEquals("~foo/", BOURNE_USER_PATH.quote("~foo"));
+ assertEquals("~foo/", BOURNE_USER_PATH.quote("~foo/"));
+ assertEquals("~/", BOURNE_USER_PATH.quote("~/"));
+
+ assertEquals("~foo/'a'", BOURNE_USER_PATH.quote("~foo/a"));
+ assertEquals("~/'a'", BOURNE_USER_PATH.quote("~/a"));
+ }
+
+ public void testDequote_User() {
+ assertEquals("~foo", BOURNE_USER_PATH.dequote("~foo"));
+ assertEquals("~foo/", BOURNE_USER_PATH.dequote("~foo/"));
+ assertEquals("~/", BOURNE_USER_PATH.dequote("~/"));
+
+ assertEquals("~foo/a", BOURNE_USER_PATH.dequote("~foo/'a'"));
+ assertEquals("~/a", BOURNE_USER_PATH.dequote("~/'a'"));
+ }
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java
index e3f5ae8..d4bf466 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java
@@ -131,31 +131,8 @@ private static void sqAlways(final StringBuilder cmd, final String val) {
}
private static void sq(final StringBuilder cmd, final String val) {
- int i = 0;
-
- if (val.length() == 0)
- return;
- if (val.matches("^~[A-Za-z0-9_-]+$")) {
- // If the string is just "~user" we can assume they
- // mean "~user/" and evaluate it within the shell.
- //
- cmd.append(val);
- cmd.append('/');
- return;
- }
-
- if (val.matches("^~[A-Za-z0-9_-]*/.*$")) {
- // If the string is of "~/path" or "~user/path"
- // we must not escape ~/ or ~user/ from the shell
- // as we need that portion to be evaluated.
- //
- i = val.indexOf('/') + 1;
- cmd.append(val.substring(0, i));
- if (i == val.length())
- return;
- }
-
- cmd.append(QuotedString.BOURNE.quote(val.substring(i)));
+ if (val.length() > 0)
+ cmd.append(QuotedString.BOURNE.quote(val));
}
private void initSession() throws TransportException {
diff --git a/org.spearce.jgit/src/org/spearce/jgit/util/QuotedString.java b/org.spearce.jgit/src/org/spearce/jgit/util/QuotedString.java
index 1089e9e..d2f71b4 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/util/QuotedString.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/util/QuotedString.java
@@ -57,6 +57,9 @@
*/
public static final BourneStyle BOURNE = new BourneStyle();
+ /** Bourne style, but permits <code>~user</code> at the start of the string. */
+ public static final BourneUserPathStyle BOURNE_USER_PATH = new BourneUserPathStyle();
+
/**
* Quote an input string by the quoting rules.
* <p>
@@ -176,6 +179,31 @@ public String dequote(final byte[] in, int ip, final int ie) {
}
}
+ /** Bourne style, but permits <code>~user</code> at the start of the string. */
+ public static class BourneUserPathStyle extends BourneStyle {
+ @Override
+ public String quote(final String in) {
+ if (in.matches("^~[A-Za-z0-9_-]+$")) {
+ // If the string is just "~user" we can assume they
+ // mean "~user/".
+ //
+ return in + "/";
+ }
+
+ if (in.matches("^~[A-Za-z0-9_-]*/.*$")) {
+ // If the string is of "~/path" or "~user/path"
+ // we must not escape ~/ or ~user/ from the shell.
+ //
+ final int i = in.indexOf('/') + 1;
+ if (i == in.length())
+ return in;
+ return in.substring(0, i) + super.quote(in.substring(i));
+ }
+
+ return super.quote(in);
+ }
+ }
+
/** Quoting style that obeys the rules of the C programming language. */
public static final class C_Style extends QuotedString {
private static final byte[] quote;
--
1.6.1.rc2.299.gead4c
^ permalink raw reply related
* [JGIT PATCH 5/6] Add Bourne style quoting for TransportGitSsh
From: Shawn O. Pearce @ 2008-12-10 22:05 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <1228946751-12708-5-git-send-email-spearce@spearce.org>
Now that we have a nice QuotedString abstraction we can port our
string quoting logic from being private within the SSH transport
code to being available in the rest of the library.
Currently we only support the super-restrictive quoting style used
for the repository path name argument over SSH. We don't support the
"minimal" style used to invoke the command name, nor do we support
the ~user/ style format, which cannot be quoted.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../jgit/util/QuotedStringBourneStyleTest.java | 111 ++++++++++++++++++++
.../spearce/jgit/transport/TransportGitSsh.java | 13 +--
.../src/org/spearce/jgit/util/QuotedString.java | 66 ++++++++++++
3 files changed, 179 insertions(+), 11 deletions(-)
create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/util/QuotedStringBourneStyleTest.java
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/util/QuotedStringBourneStyleTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/util/QuotedStringBourneStyleTest.java
new file mode 100644
index 0000000..86d46fe
--- /dev/null
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/util/QuotedStringBourneStyleTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ *
+ * 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 Git Development Community 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.spearce.jgit.util;
+
+import static org.spearce.jgit.util.QuotedString.BOURNE;
+import junit.framework.TestCase;
+
+import org.spearce.jgit.lib.Constants;
+
+public class QuotedStringBourneStyleTest extends TestCase {
+ private static void assertQuote(final String in, final String exp) {
+ final String r = BOURNE.quote(in);
+ assertNotSame(in, r);
+ assertFalse(in.equals(r));
+ assertEquals('\'' + exp + '\'', r);
+ }
+
+ private static void assertDequote(final String exp, final String in) {
+ final byte[] b = Constants.encode('\'' + in + '\'');
+ final String r = BOURNE.dequote(b, 0, b.length);
+ assertEquals(exp, r);
+ }
+
+ public void testQuote_Empty() {
+ assertEquals("''", BOURNE.quote(""));
+ }
+
+ public void testDequote_Empty1() {
+ assertEquals("", BOURNE.dequote(new byte[0], 0, 0));
+ }
+
+ public void testDequote_Empty2() {
+ assertEquals("", BOURNE.dequote(new byte[] { '\'', '\'' }, 0, 2));
+ }
+
+ public void testDequote_SoleSq() {
+ assertEquals("", BOURNE.dequote(new byte[] { '\'' }, 0, 1));
+ }
+
+ public void testQuote_BareA() {
+ assertQuote("a", "a");
+ }
+
+ public void testDequote_BareA() {
+ final String in = "a";
+ final byte[] b = Constants.encode(in);
+ assertEquals(in, BOURNE.dequote(b, 0, b.length));
+ }
+
+ public void testDequote_BareABCZ_OnlyBC() {
+ final String in = "abcz";
+ final byte[] b = Constants.encode(in);
+ final int p = in.indexOf('b');
+ assertEquals("bc", BOURNE.dequote(b, p, p + 2));
+ }
+
+ public void testDequote_LoneBackslash() {
+ assertDequote("\\", "\\");
+ }
+
+ public void testQuote_NamedEscapes() {
+ assertQuote("'", "'\\''");
+ assertQuote("!", "'\\!'");
+
+ assertQuote("a'b", "a'\\''b");
+ assertQuote("a!b", "a'\\!'b");
+ }
+
+ public void testDequote_NamedEscapes() {
+ assertDequote("'", "'\\''");
+ assertDequote("!", "'\\!'");
+
+ assertDequote("a'b", "a'\\''b");
+ assertDequote("a!b", "a'\\!'b");
+ }
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java
index 3f2cd37..e3f5ae8 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java
@@ -47,6 +47,7 @@
import org.spearce.jgit.errors.NoRemoteRepositoryException;
import org.spearce.jgit.errors.TransportException;
import org.spearce.jgit.lib.Repository;
+import org.spearce.jgit.util.QuotedString;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSchException;
@@ -154,17 +155,7 @@ private static void sq(final StringBuilder cmd, final String val) {
return;
}
- cmd.append('\'');
- for (; i < val.length(); i++) {
- final char c = val.charAt(i);
- if (c == '\'')
- cmd.append("'\\''");
- else if (c == '!')
- cmd.append("'\\!'");
- else
- cmd.append(c);
- }
- cmd.append('\'');
+ cmd.append(QuotedString.BOURNE.quote(val.substring(i)));
}
private void initSession() throws TransportException {
diff --git a/org.spearce.jgit/src/org/spearce/jgit/util/QuotedString.java b/org.spearce.jgit/src/org/spearce/jgit/util/QuotedString.java
index 4aaa8ff..1089e9e 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/util/QuotedString.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/util/QuotedString.java
@@ -49,6 +49,15 @@
public static final C_Style C = new C_Style();
/**
+ * Quoting style used by the Bourne shell.
+ * <p>
+ * Quotes are unconditionally inserted during {@link #quote(String)}. This
+ * protects shell meta-characters like <code>$</code> or <code>~</code> from
+ * being recognized as special.
+ */
+ public static final BourneStyle BOURNE = new BourneStyle();
+
+ /**
* Quote an input string by the quoting rules.
* <p>
* If the input string does not require any quoting, the same String
@@ -110,6 +119,63 @@ public String dequote(final String in) {
*/
public abstract String dequote(byte[] in, int offset, int end);
+ /**
+ * Quoting style used by the Bourne shell.
+ * <p>
+ * Quotes are unconditionally inserted during {@link #quote(String)}. This
+ * protects shell meta-characters like <code>$</code> or <code>~</code> from
+ * being recognized as special.
+ */
+ public static class BourneStyle extends QuotedString {
+ @Override
+ public String quote(final String in) {
+ final StringBuilder r = new StringBuilder();
+ r.append('\'');
+ int start = 0, i = 0;
+ for (; i < in.length(); i++) {
+ switch (in.charAt(i)) {
+ case '\'':
+ case '!':
+ r.append(in, start, i);
+ r.append('\'');
+ r.append('\\');
+ r.append(in.charAt(i));
+ r.append('\'');
+ start = i + 1;
+ break;
+ }
+ }
+ r.append(in, start, i);
+ r.append('\'');
+ return r.toString();
+ }
+
+ @Override
+ public String dequote(final byte[] in, int ip, final int ie) {
+ boolean inquote = false;
+ final byte[] r = new byte[ie - ip];
+ int rPtr = 0;
+ while (ip < ie) {
+ final byte b = in[ip++];
+ switch (b) {
+ case '\'':
+ inquote = !inquote;
+ continue;
+ case '\\':
+ if (inquote || ip == ie)
+ r[rPtr++] = b; // literal within a quote
+ else
+ r[rPtr++] = in[ip++];
+ continue;
+ default:
+ r[rPtr++] = b;
+ continue;
+ }
+ }
+ return decode(Constants.CHARSET, r, 0, rPtr);
+ }
+ }
+
/** Quoting style that obeys the rules of the C programming language. */
public static final class C_Style extends QuotedString {
private static final byte[] quote;
--
1.6.1.rc2.299.gead4c
^ permalink raw reply related
* [JGIT PATCH 4/6] Add QuotedString class to handle C-style quoting rules
From: Shawn O. Pearce @ 2008-12-10 22:05 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <1228946751-12708-4-git-send-email-spearce@spearce.org>
Git patch files can contain file names which are quoted using the
C language quoting rules. In order to correctly create or parse
these files we must implement a quoting style that matches those
specific rules.
QuotedString itself is an abstract API so callers can be passed a
quoting style based on the context of where their output will be
used, and multiple styles could be supported. This may be useful
if jgit ever grows a "git for-each-ref" style of output where Perl,
Python, Tcl and Bourne style quoting might be necessary.
References through the singleton QuotedString.C should be able to
bypass the virtual function table, as the specific type is mentioned
in the field declaration and that type is final. A good JIT should
be able to remove the abstraction costs when the caller has hardcoded
the quoting style.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../spearce/jgit/util/QuotedStringC_StyleTest.java | 144 +++++++++++
.../src/org/spearce/jgit/util/QuotedString.java | 270 ++++++++++++++++++++
2 files changed, 414 insertions(+), 0 deletions(-)
create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/util/QuotedStringC_StyleTest.java
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/util/QuotedString.java
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/util/QuotedStringC_StyleTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/util/QuotedStringC_StyleTest.java
new file mode 100644
index 0000000..493869c
--- /dev/null
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/util/QuotedStringC_StyleTest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ *
+ * 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 Git Development Community 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.spearce.jgit.util;
+
+import static org.spearce.jgit.util.QuotedString.C;
+import junit.framework.TestCase;
+
+import org.spearce.jgit.lib.Constants;
+
+public class QuotedStringC_StyleTest extends TestCase {
+ private static void assertQuote(final String in, final String exp) {
+ final String r = C.quote(in);
+ assertNotSame(in, r);
+ assertFalse(in.equals(r));
+ assertEquals('"' + exp + '"', r);
+ }
+
+ private static void assertDequote(final String exp, final String in) {
+ final byte[] b = Constants.encode('"' + in + '"');
+ final String r = C.dequote(b, 0, b.length);
+ assertEquals(exp, r);
+ }
+
+ public void testQuote_Empty() {
+ assertEquals("\"\"", C.quote(""));
+ }
+
+ public void testDequote_Empty1() {
+ assertEquals("", C.dequote(new byte[0], 0, 0));
+ }
+
+ public void testDequote_Empty2() {
+ assertEquals("", C.dequote(new byte[] { '"', '"' }, 0, 2));
+ }
+
+ public void testDequote_SoleDq() {
+ assertEquals("\"", C.dequote(new byte[] { '"' }, 0, 1));
+ }
+
+ public void testQuote_BareA() {
+ final String in = "a";
+ assertSame(in, C.quote(in));
+ }
+
+ public void testDequote_BareA() {
+ final String in = "a";
+ final byte[] b = Constants.encode(in);
+ assertEquals(in, C.dequote(b, 0, b.length));
+ }
+
+ public void testDequote_BareABCZ_OnlyBC() {
+ final String in = "abcz";
+ final byte[] b = Constants.encode(in);
+ final int p = in.indexOf('b');
+ assertEquals("bc", C.dequote(b, p, p + 2));
+ }
+
+ public void testDequote_LoneBackslash() {
+ assertDequote("\\", "\\");
+ }
+
+ public void testQuote_NamedEscapes() {
+ assertQuote("\u0007", "\\a");
+ assertQuote("\b", "\\b");
+ assertQuote("\f", "\\f");
+ assertQuote("\n", "\\n");
+ assertQuote("\r", "\\r");
+ assertQuote("\t", "\\t");
+ assertQuote("\u000B", "\\v");
+ assertQuote("\\", "\\\\");
+ assertQuote("\"", "\\\"");
+ }
+
+ public void testDequote_NamedEscapes() {
+ assertDequote("\u0007", "\\a");
+ assertDequote("\b", "\\b");
+ assertDequote("\f", "\\f");
+ assertDequote("\n", "\\n");
+ assertDequote("\r", "\\r");
+ assertDequote("\t", "\\t");
+ assertDequote("\u000B", "\\v");
+ assertDequote("\\", "\\\\");
+ assertDequote("\"", "\\\"");
+ }
+
+ public void testDequote_OctalAll() {
+ for (int i = 0; i < 256; i++) {
+ String s = Integer.toOctalString(i);
+ while (s.length() < 3) {
+ s = "0" + s;
+ }
+ assertDequote("" + (char) i, "\\" + s);
+ }
+ }
+
+ public void testQuote_OctalAll() {
+ assertQuote("\1", "\\001");
+ assertQuote("~", "\\176");
+ assertQuote("\u00ff", "\\303\\277"); // \u00ff in UTF-8
+ }
+
+ public void testDequote_UnknownEscapeQ() {
+ assertDequote("\\q", "\\q");
+ }
+
+ public void testDequote_FooTabBar() {
+ assertDequote("foo\tbar", "foo\\tbar");
+ }
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/util/QuotedString.java b/org.spearce.jgit/src/org/spearce/jgit/util/QuotedString.java
new file mode 100644
index 0000000..4aaa8ff
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/util/QuotedString.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ *
+ * 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 Git Development Community 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.spearce.jgit.util;
+
+import static org.spearce.jgit.util.RawParseUtils.decode;
+
+import java.util.Arrays;
+
+import org.spearce.jgit.lib.Constants;
+
+/** Utility functions related to quoted string handling. */
+public abstract class QuotedString {
+ /** Quoting style that obeys the rules of the C programming language. */
+ public static final C_Style C = new C_Style();
+
+ /**
+ * Quote an input string by the quoting rules.
+ * <p>
+ * If the input string does not require any quoting, the same String
+ * reference is returned to the caller.
+ * <p>
+ * Otherwise a quoted string is returned, including the opening and closing
+ * quotation marks at the start and end of the string. If the style does not
+ * permit raw Unicode characters then the string will first be encoded in
+ * UTF-8, with unprintable sequences possibly escaped by the rules.
+ *
+ * @param in
+ * any non-null Unicode string.
+ * @return a quoted string. See above for details.
+ */
+ public abstract String quote(String in);
+
+ /**
+ * Clean a previously quoted input, decoding the result via UTF-8.
+ * <p>
+ * This method must match quote such that:
+ *
+ * <pre>
+ * a.equals(dequote(quote(a)));
+ * </pre>
+ *
+ * is true for any <code>a</code>.
+ *
+ * @param in
+ * a Unicode string to remove quoting from.
+ * @return the cleaned string.
+ * @see #dequote(byte[], int, int)
+ */
+ public String dequote(final String in) {
+ final byte[] b = Constants.encode(in);
+ return dequote(b, 0, b.length);
+ }
+
+ /**
+ * Decode a previously quoted input, scanning a UTF-8 encoded buffer.
+ * <p>
+ * This method must match quote such that:
+ *
+ * <pre>
+ * a.equals(dequote(Constants.encode(quote(a))));
+ * </pre>
+ *
+ * is true for any <code>a</code>.
+ * <p>
+ * This method removes any opening/closing quotation marks added by
+ * {@link #quote(String)}.
+ *
+ * @param in
+ * the input buffer to parse.
+ * @param offset
+ * first position within <code>in</code> to scan.
+ * @param end
+ * one position past in <code>in</code> to scan.
+ * @return the cleaned string.
+ */
+ public abstract String dequote(byte[] in, int offset, int end);
+
+ /** Quoting style that obeys the rules of the C programming language. */
+ public static final class C_Style extends QuotedString {
+ private static final byte[] quote;
+ static {
+ quote = new byte[128];
+ Arrays.fill(quote, (byte) -1);
+
+ for (int i = '0'; i <= '9'; i++)
+ quote[i] = 0;
+ for (int i = 'a'; i <= 'z'; i++)
+ quote[i] = 0;
+ for (int i = 'A'; i <= 'Z'; i++)
+ quote[i] = 0;
+ quote[' '] = 0;
+ quote['+'] = 0;
+ quote[','] = 0;
+ quote['-'] = 0;
+ quote['.'] = 0;
+ quote['/'] = 0;
+ quote['='] = 0;
+ quote['_'] = 0;
+ quote['^'] = 0;
+
+ quote['\u0007'] = 'a';
+ quote['\b'] = 'b';
+ quote['\f'] = 'f';
+ quote['\n'] = 'n';
+ quote['\r'] = 'r';
+ quote['\t'] = 't';
+ quote['\u000B'] = 'v';
+ quote['\\'] = '\\';
+ quote['"'] = '"';
+ }
+
+ @Override
+ public String quote(final String instr) {
+ if (instr.length() == 0)
+ return "\"\"";
+ boolean reuse = true;
+ final byte[] in = Constants.encode(instr);
+ final StringBuilder r = new StringBuilder(2 + in.length);
+ r.append('"');
+ for (int i = 0; i < in.length; i++) {
+ final int c = in[i] & 0xff;
+ if (c < quote.length) {
+ final byte style = quote[c];
+ if (style == 0) {
+ r.append((char) c);
+ continue;
+ }
+ if (style > 0) {
+ reuse = false;
+ r.append('\\');
+ r.append((char) style);
+ continue;
+ }
+ }
+
+ reuse = false;
+ r.append('\\');
+ r.append((char) (((c >> 6) & 03) + '0'));
+ r.append((char) (((c >> 3) & 07) + '0'));
+ r.append((char) (((c >> 0) & 07) + '0'));
+ }
+ if (reuse)
+ return instr;
+ r.append('"');
+ return r.toString();
+ }
+
+ @Override
+ public String dequote(final byte[] in, final int inPtr, final int inEnd) {
+ if (2 <= inEnd - inPtr && in[inPtr] == '"' && in[inEnd - 1] == '"')
+ return dq(in, inPtr + 1, inEnd - 1);
+ return decode(Constants.CHARSET, in, inPtr, inEnd);
+ }
+
+ private static String dq(final byte[] in, int inPtr, final int inEnd) {
+ final byte[] r = new byte[inEnd - inPtr];
+ int rPtr = 0;
+ while (inPtr < inEnd) {
+ final byte b = in[inPtr++];
+ if (b != '\\') {
+ r[rPtr++] = b;
+ continue;
+ }
+
+ if (inPtr == inEnd) {
+ // Lone trailing backslash. Treat it as a literal.
+ //
+ r[rPtr++] = '\\';
+ break;
+ }
+
+ switch (in[inPtr++]) {
+ case 'a':
+ r[rPtr++] = 0x07 /* \a = BEL */;
+ continue;
+ case 'b':
+ r[rPtr++] = '\b';
+ continue;
+ case 'f':
+ r[rPtr++] = '\f';
+ continue;
+ case 'n':
+ r[rPtr++] = '\n';
+ continue;
+ case 'r':
+ r[rPtr++] = '\r';
+ continue;
+ case 't':
+ r[rPtr++] = '\t';
+ continue;
+ case 'v':
+ r[rPtr++] = 0x0B/* \v = VT */;
+ continue;
+
+ case '\\':
+ case '"':
+ r[rPtr++] = in[inPtr - 1];
+ continue;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3': {
+ int cp = in[inPtr - 1] - '0';
+ while (inPtr < inEnd) {
+ final byte c = in[inPtr];
+ if ('0' <= c && c <= '7') {
+ cp <<= 3;
+ cp |= c - '0';
+ inPtr++;
+ } else {
+ break;
+ }
+ }
+ r[rPtr++] = (byte) cp;
+ continue;
+ }
+
+ default:
+ // Any other code is taken literally.
+ //
+ r[rPtr++] = '\\';
+ r[rPtr++] = in[inPtr - 1];
+ continue;
+ }
+ }
+
+ return decode(Constants.CHARSET, r, 0, rPtr);
+ }
+
+ private C_Style() {
+ // Singleton
+ }
+ }
+}
--
1.6.1.rc2.299.gead4c
^ permalink raw reply related
* [JGIT PATCH 2/6] Simplify RawParseUtils next and nextLF loops
From: Shawn O. Pearce @ 2008-12-10 22:05 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <1228946751-12708-2-git-send-email-spearce@spearce.org>
We always need ptr + 1 after we read the current position,
so we might as well do the much more common foo[ptr++]. A
good JIT would be more likely to optimize this case over
the weird else branch we had.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../src/org/spearce/jgit/util/RawParseUtils.java | 12 ++++--------
1 files changed, 4 insertions(+), 8 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java b/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java
index 10c2239..5a40911 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java
@@ -221,10 +221,8 @@ public static final int parseTimeZoneOffset(final byte[] b, int ptr) {
public static final int next(final byte[] b, int ptr, final char chrA) {
final int sz = b.length;
while (ptr < sz) {
- if (b[ptr] == chrA)
- return ptr + 1;
- else
- ptr++;
+ if (b[ptr++] == chrA)
+ return ptr;
}
return ptr;
}
@@ -260,11 +258,9 @@ public static final int nextLF(final byte[] b, int ptr) {
public static final int nextLF(final byte[] b, int ptr, final char chrA) {
final int sz = b.length;
while (ptr < sz) {
- final byte c = b[ptr];
+ final byte c = b[ptr++];
if (c == chrA || c == '\n')
- return ptr + 1;
- else
- ptr++;
+ return ptr;
}
return ptr;
}
--
1.6.1.rc2.299.gead4c
^ permalink raw reply related
* [JGIT PATCH 3/6] Correct Javadoc of RawParseUtils next and nextLF methods
From: Shawn O. Pearce @ 2008-12-10 22:05 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <1228946751-12708-3-git-send-email-spearce@spearce.org>
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../src/org/spearce/jgit/util/RawParseUtils.java | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java b/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java
index 5a40911..8896d38 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java
@@ -213,10 +213,10 @@ public static final int parseTimeZoneOffset(final byte[] b, int ptr) {
* @param b
* buffer to scan.
* @param ptr
- * position within buffer to start looking for LF at.
+ * position within buffer to start looking for chrA at.
* @param chrA
* character to find.
- * @return new position just after chr.
+ * @return new position just after chrA.
*/
public static final int next(final byte[] b, int ptr, final char chrA) {
final int sz = b.length;
@@ -250,10 +250,10 @@ public static final int nextLF(final byte[] b, int ptr) {
* @param b
* buffer to scan.
* @param ptr
- * position within buffer to start looking for LF at.
+ * position within buffer to start looking for chrA or LF at.
* @param chrA
* character to find.
- * @return new position just after the first chrA or chrB to be found.
+ * @return new position just after the first chrA or LF to be found.
*/
public static final int nextLF(final byte[] b, int ptr, final char chrA) {
final int sz = b.length;
--
1.6.1.rc2.299.gead4c
^ permalink raw reply related
* [JGIT PATCH 1/6] Simplify RawParseUtils.nextLF invocations
From: Shawn O. Pearce @ 2008-12-10 22:05 UTC (permalink / raw)
To: Robin Rosenberg; +Cc: git
In-Reply-To: <1228946751-12708-1-git-send-email-spearce@spearce.org>
Most of the time when we call next('\n') or nextLF('\n') we really
meant to just say nextLF(), which is logically identical to next()
but could be micro-optimized for the LF byte.
This refactoring shifts the calls to use the new nextLF wrapper for
next('\n'), so we can later chose to make this optimization, or to
leave the code as-is. But either way the call sites are now much
clearer to read.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
.../src/org/spearce/jgit/lib/ObjectChecker.java | 4 +-
.../src/org/spearce/jgit/revwalk/RevTag.java | 2 +-
.../src/org/spearce/jgit/util/RawParseUtils.java | 25 ++++++++++++++++----
3 files changed, 23 insertions(+), 8 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectChecker.java b/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectChecker.java
index b303d6f..75e3c77 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectChecker.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectChecker.java
@@ -205,11 +205,11 @@ public void checkTag(final byte[] raw) throws CorruptObjectException {
if ((ptr = match(raw, ptr, type)) < 0)
throw new CorruptObjectException("no type header");
- ptr = nextLF(raw, ptr, '\n');
+ ptr = nextLF(raw, ptr);
if ((ptr = match(raw, ptr, tag)) < 0)
throw new CorruptObjectException("no tag header");
- ptr = nextLF(raw, ptr, '\n');
+ ptr = nextLF(raw, ptr);
if ((ptr = match(raw, ptr, tagger)) < 0)
throw new CorruptObjectException("no tagger header");
diff --git a/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevTag.java b/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevTag.java
index bbb18ee..77a55cd 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevTag.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevTag.java
@@ -90,7 +90,7 @@ void parseCanonical(final RevWalk walk, final byte[] rawTag)
object = walk.lookupAny(walk.idBuffer, oType);
int p = pos.value += 4; // "tag "
- final int nameEnd = RawParseUtils.next(rawTag, p, '\n') - 1;
+ final int nameEnd = RawParseUtils.nextLF(rawTag, p) - 1;
name = RawParseUtils.decode(Constants.CHARSET, rawTag, p, nameEnd);
buffer = rawTag;
flags |= PARSED;
diff --git a/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java b/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java
index 4b96439..10c2239 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/util/RawParseUtils.java
@@ -230,6 +230,21 @@ public static final int next(final byte[] b, int ptr, final char chrA) {
}
/**
+ * Locate the first position after the next LF.
+ * <p>
+ * This method stops on the first '\n' it finds.
+ *
+ * @param b
+ * buffer to scan.
+ * @param ptr
+ * position within buffer to start looking for LF at.
+ * @return new position just after the first LF found.
+ */
+ public static final int nextLF(final byte[] b, int ptr) {
+ return next(b, ptr, '\n');
+ }
+
+ /**
* Locate the first position after either the given character or LF.
* <p>
* This method stops on the first match it finds from either chrA or '\n'.
@@ -296,7 +311,7 @@ public static final int committer(final byte[] b, int ptr) {
while (ptr < sz && b[ptr] == 'p')
ptr += 48; // skip this parent.
if (ptr < sz && b[ptr] == 'a')
- ptr = next(b, ptr, '\n');
+ ptr = nextLF(b, ptr);
return match(b, ptr, committer);
}
@@ -320,7 +335,7 @@ public static final int encoding(final byte[] b, int ptr) {
return -1;
if (b[ptr] == 'e')
break;
- ptr = next(b, ptr, '\n');
+ ptr = nextLF(b, ptr);
}
return match(b, ptr, encoding);
}
@@ -342,7 +357,7 @@ public static Charset parseEncoding(final byte[] b) {
final int enc = encoding(b, 0);
if (enc < 0)
return Constants.CHARSET;
- final int lf = next(b, enc, '\n');
+ final int lf = nextLF(b, enc);
return Charset.forName(decode(Constants.CHARSET, b, enc, lf - 1));
}
@@ -505,7 +520,7 @@ public static final int commitMessage(final byte[] b, int ptr) {
// header line type is.
//
while (ptr < sz && b[ptr] != '\n')
- ptr = next(b, ptr, '\n');
+ ptr = nextLF(b, ptr);
if (ptr < sz && b[ptr] == '\n')
return ptr + 1;
return -1;
@@ -529,7 +544,7 @@ public static final int endOfParagraph(final byte[] b, final int start) {
int ptr = start;
final int sz = b.length;
while (ptr < sz && b[ptr] != '\n')
- ptr = next(b, ptr, '\n');
+ ptr = nextLF(b, ptr);
while (0 < ptr && start < ptr && b[ptr - 1] == '\n')
ptr--;
return ptr;
--
1.6.1.rc2.299.gead4c
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox