[EGIT PATCH 0/9] Misc minor fixes
This is a set of smaller fixes necessary to implement larger features ( to be submitted later on ).
-- robin
threads / patch / 7025
Subject: [EGIT PATCH 9/9] Performance test for jgit.
[EGIT PATCH 0/9] Misc minor fixes
This is a set of smaller fixes necessary to implement larger features ( to be submitted later on ).
-- robin
[EGIT PATCH 1/9] Minor fix.
Eclipse's strict checking thinks there is an error.
Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com> ---
.../src/org/spearce/jgit/lib/WindowedFile.java | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/WindowedFile.java b/org.spearce.jgit/src/org/spearce/jgit/lib/WindowedFile.java index 28b495f..827cc22 100644 --- a/org.spearce.jgit/src/org/spearce/jgit/lib/WindowedFile.java +++ b/org.spearce.jgit/src/org/spearce/jgit/lib/WindowedFile.java @@ -21,6 +21,7 @@ import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; import java.nio.channels.FileChannel.MapMode; import java.util.zip.DataFormatException; import java.util.zip.Inflater; @@ -85,7 +86,7 @@ public class WindowedFile { * use the same window cache. * @param file * the file to open. The file will be opened for reading only, - * unless {@link MapMode#READ_WRITE} or {@link MapMode#PRIVATE} + * unless {@link FileChannel.MapMode#READ_WRITE} or {@link FileChannel.MapMode#PRIVATE} * is given. * @param windowSz * number of bytes within a window. This value must be a power of
[EGIT PATCH 2/9] Catch mmap errors and retry.
At least JDK 1.4 and 1.5 versions can hit an IOException if memory cannot be mapped. A workaround is to catch the exception and retry once.
Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com> ---
.../src/org/spearce/jgit/lib/Repository.java | 19 ++++++++++++++++--- 1 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java index c9e8a2d..5e0e89a 100644 --- a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java +++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java @@ -145,9 +145,22 @@ public class Repository { return ol; } catch (IOException ioe) { // This shouldn't happen unless the pack was corrupted - // after we opened it. We'll ignore the error as though - // the object does not exist in this pack. - // + // after we opened it or the VM runs out of memory. This is + // a know problem with memory mapped I/O in java and have + // been noticed with JDK < 1.6. Tell the gc that now is a good + // time to collect and try once more. + try { + System.gc(); + final ObjectLoader ol = packs[k].get(id, tmp); + if (ol != null) + return ol; + } catch (IOException ioe2) { + ioe2.printStackTrace(); + ioe.printStackTrace(); + // Still fails.. that's BAD, maybe the pack has + // been corrupted after all, or the gc didn't manage + // to release enough previously mmaped areas. + } } } while (k > 0); }
[EGIT PATCH 3/9] Use mmap per default.
A small test of mine show a tenfold speed improvemnt looking for a blob while scanning the history (11K commit, blob three trees down). This was on a x86 platform. For other platforms Shawn noted that memory mapping was about 10% slower than normall reading of files.
Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com> ---
.../src/org/spearce/jgit/lib/PackFile.java | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/PackFile.java b/org.spearce.jgit/src/org/spearce/jgit/lib/PackFile.java index ee4b8a1..d33aa97 100644 --- a/org.spearce.jgit/src/org/spearce/jgit/lib/PackFile.java +++ b/org.spearce.jgit/src/org/spearce/jgit/lib/PackFile.java @@ -42,7 +42,7 @@ public class PackFile { repo = parentRepo; // FIXME window size and mmap type should be configurable pack = new WindowedFile(repo.getWindowCache(), packFile, - 64 * 1024 * 1024, false); + 64 * 1024 * 1024, true); try { readPackHeader(); @@ -53,7 +53,7 @@ public class PackFile { + ".idx"); // FIXME window size and mmap type should be configurable idx = new WindowedFile(repo.getWindowCache(), idxFile, - 64 * 1024 * 1024, false); + 64 * 1024 * 1024, true); try { idxHeader = readIndexHeader(); } catch (IOException ioe) {
[EGIT PATCH 4/9] Add .qualifier to the plugin version.
This makes every exported plugin have a different name. This is not the git SHA1, but a timestamp.
Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com> ---
org.spearce.egit.core/META-INF/MANIFEST.MF | 2 +- org.spearce.egit.ui/META-INF/MANIFEST.MF | 2 +- org.spearce.jgit/META-INF/MANIFEST.MF | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-)
org.spearce.egit.core/META-INF/MANIFEST.MF, org.spearce.egit.ui/META-INF/MANIFEST.MF, org.spearce.jgit/META-INF/MANIFEST.MF
diff --git a/org.spearce.egit.core/META-INF/MANIFEST.MF b/org.spearce.egit.core/META-INF/MANIFEST.MF index f295c3c..a8349a1 100644 --- a/org.spearce.egit.core/META-INF/MANIFEST.MF +++ b/org.spearce.egit.core/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.spearce.egit.core; singleton:=true -Bundle-Version: 0.2 +Bundle-Version: 0.2.0.qualifier Bundle-Activator: org.spearce.egit.core.Activator Bundle-Vendor: %provider_name Bundle-Localization: plugin diff --git a/org.spearce.egit.ui/META-INF/MANIFEST.MF b/org.spearce.egit.ui/META-INF/MANIFEST.MF index 5c97648..63dcec8 100644 --- a/org.spearce.egit.ui/META-INF/MANIFEST.MF +++ b/org.spearce.egit.ui/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.spearce.egit.ui; singleton:=true -Bundle-Version: 0.2 +Bundle-Version: 0.2.0.qualifier Bundle-Activator: org.spearce.egit.ui.Activator Bundle-Vendor: %plugin_provider Bundle-Localization: plugin diff --git a/org.spearce.jgit/META-INF/MANIFEST.MF b/org.spearce.jgit/META-INF/MANIFEST.MF index 2f959e1..1485bb9 100644 --- a/org.spearce.jgit/META-INF/MANIFEST.MF +++ b/org.spearce.jgit/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %plugin_name Bundle-SymbolicName: org.spearce.jgit -Bundle-Version: 0.2 +Bundle-Version: 0.2.0.qualifier Bundle-Localization: plugin Bundle-Vendor: %provider_name Export-Package: org.spearce.jgit.errors,
[EGIT PATCH 5/9] Force full checkpoint for CheckpointOperation.
Until further notice we need this operation not to cut any corners but to do everything in order to clean up because it is still too easy to mess upp the checkpoint tree completely.
Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com> ---
.../spearce/egit/core/op/CheckpointOperation.java | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/org.spearce.egit.core/src/org/spearce/egit/core/op/CheckpointOperation.java b/org.spearce.egit.core/src/org/spearce/egit/core/op/CheckpointOperation.java index 9534039..6cf80ca 100644 --- a/org.spearce.egit.core/src/org/spearce/egit/core/op/CheckpointOperation.java +++ b/org.spearce.egit.core/src/org/spearce/egit/core/op/CheckpointOperation.java @@ -68,7 +68,7 @@ public class CheckpointOperation implements IWorkspaceRunnable { final IProject project = (IProject) i.next(); final GitProjectData projectData = GitProjectData.get(project); if (projectData != null) - projectData.checkpointIfNecessary(); + projectData.fullUpdate(); } } }
[EGIT PATCH 6/9] Add branch and StGit patch to decorator
This makes it easier to see in what context you are working.
Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com> ---
.../internal/decorators/GitResourceDecorator.java | 20 ++++++++++++++++---- .../src/org/spearce/jgit/lib/Repository.java | 22 ++++++++++++++++++++++ 2 files changed, 38 insertions(+), 4 deletions(-)
org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java, org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java index bde6182..da2e256 100644 --- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java +++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java @@ -16,6 +16,8 @@ */ package org.spearce.egit.ui.internal.decorators; +import java.io.IOException; + import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; @@ -30,6 +32,7 @@ import org.spearce.egit.core.project.RepositoryMapping; import org.spearce.egit.ui.UIIcons; import org.spearce.egit.ui.UIText; import org.spearce.jgit.lib.MergedTree; +import org.spearce.jgit.lib.Repository; import org.spearce.jgit.lib.TreeEntry; /** @@ -110,10 +113,19 @@ public class GitResourceDecorator extends LabelProvider implements final MergedTree diff = mapped.getActiveDiff(); if (diff != null && diff.isModified()) decoration.addPrefix(">"); - if (mapped.getRepository().isStGitMode()) - decoration.addSuffix(" [StGit]"); - else - decoration.addSuffix(" [Git]"); + Repository repo = mapped.getRepository(); + try { + String branch = repo.getBranch(); + if (repo.isStGitMode()) { + String patch = repo.getPatch(); + decoration.addSuffix(" [StGit " + patch + "@" + branch +"]"); + } else { + decoration.addSuffix(" [Git @ "+ branch + "]"); + } + } catch (IOException e) { + e.printStackTrace(); + decoration.addSuffix(" [Git ?]"); + } decoration.addOverlay(UIIcons.OVR_SHARED); return; } diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java index 5e0e89a..d2943c3 100644 --- a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java +++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java @@ -342,6 +342,27 @@ public class Repository { return "Repository[" + getDirectory() + "]"; } + public String getPatch() throws IOException { + final File ptr = new File(getDirectory(),"patches/"+getBranch()+"/current"); + final BufferedReader br = new BufferedReader(new FileReader(ptr)); + final String line = br.readLine(); + return line; + } + public String getBranch() throws IOException { + final File ptr = new File(getDirectory(),"HEAD"); + final BufferedReader br = new BufferedReader(new FileReader(ptr)); + final String line = br.readLine(); + + String ref; + if (line.startsWith("ref: ")) + ref = line.substring(5); + else + ref = line; + if (ref.startsWith("refs/heads/")) + ref = ref.substring(11); + return ref; + } + public Collection getBranches() { return listFilesRecursively(new File(refsDir, "heads"), null); } @@ -391,4 +412,5 @@ public class Repository { } return ret; } + }
Re: [EGIT PATCH 6/9] Add branch and StGit patch to decorator
Robin Rosenberg <robin.rosenberg@dewire.com> wrote:
> + public String getPatch() throws IOException {
> + final File ptr = new File(getDirectory(),"patches/"+getBranch()+"/current");
> + final BufferedReader br = new BufferedReader(new FileReader(ptr));
> + final String line = br.readLine();
> + return line;
> + }Last time I checked leaking a file descriptor was a bad idea. I fixed it (in both methods) when I applied the patch.
Your whole series is now pushed. Thanks for the cleanups.
-- Shawn.
Re: [EGIT PATCH 6/9] Add branch and StGit patch to decorator
torsdag 01 mars 2007 04:59 skrev Shawn O. Pearce:
> Robin Rosenberg <robin.rosenberg@dewire.com> wrote:
> > + public String getPatch() throws IOException {
> > + final File ptr = new File(getDirectory(),"patches/"+getBranch()+"/current");
> > + final BufferedReader br = new BufferedReader(new FileReader(ptr));
> > + final String line = br.readLine();
> > + return line;
> > + }
>
> Last time I checked leaking a file descriptor was a bad idea.It's a hallmark of mine. Sooner or later the GC picks them up :), but you're right.
> I fixed it (in both methods) when I applied the patch. > > Your whole series is now pushed. Thanks for the cleanups. >
-- robin
[EGIT PATCH 7/9] Support tag objects
A tag refers to another object and can carry information about who created the tag and when.
Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com> ---
.../src/org/spearce/jgit/lib/Commit.java | 2 .../src/org/spearce/jgit/lib/ObjectWriter.java | 37 +++++ .../src/org/spearce/jgit/lib/Repository.java | 15 ++ org.spearce.jgit/src/org/spearce/jgit/lib/Tag.java | 172 ++++++++++++++++++++ .../tst/org/spearce/jgit/lib/T0003_Basic.java | 66 +++++++++ 5 files changed, 291 insertions(+), 1 deletions(-)
org.spearce.jgit/src/org/spearce/jgit/lib/Commit.java, org.spearce.jgit/src/org/spearce/jgit/lib/ObjectWriter.java, org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java, org.spearce.jgit/src/org/spearce/jgit/lib/Tag.java, org.spearce.jgit/tst/org/spearce/jgit/lib/T0003_Basic.java
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Commit.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Commit.java index 498f983..d1ef5de 100644 --- a/org.spearce.jgit/src/org/spearce/jgit/lib/Commit.java +++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Commit.java @@ -79,7 +79,7 @@ public class Commit implements Treeish { } public void setTreeId(final ObjectId id) { - if (!treeId.equals(id)) { + if (treeId==null || !treeId.equals(id)) { treeObj = null; } treeId = id; diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectWriter.java b/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectWriter.java index 620f1cd..0ff092c 100644 --- a/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectWriter.java +++ b/org.spearce.jgit/src/org/spearce/jgit/lib/ObjectWriter.java @@ -137,6 +137,38 @@ public class ObjectWriter { return writeCommit(os.toByteArray()); } + public ObjectId writeTag(final byte[] b) throws IOException { + return writeTag(b.length, new ByteArrayInputStream(b)); + } + + public ObjectId writeTag(final Tag c) throws IOException { + final ByteArrayOutputStream os = new ByteArrayOutputStream(); + final OutputStreamWriter w = new OutputStreamWriter(os, + Constants.CHARACTER_ENCODING); + + w.write("object "); + c.getObjId().copyTo(w); + w.write('\n'); + + w.write("type "); + w.write(c.getType()); + w.write("\n"); + + w.write("tag "); + w.write(c.getTag()); + w.write("\n"); + + w.write("tagger "); + w.write(c.getAuthor().toExternalString()); + w.write('\n'); + + w.write('\n'); + w.write(c.getMessage()); + w.close(); + + return writeTag(os.toByteArray()); + } + public ObjectId writeCommit(final byte[] b) throws IOException { return writeCommit(b.length, new ByteArrayInputStream(b)); } @@ -146,6 +178,11 @@ public class ObjectWriter { return writeObject(Constants.OBJ_COMMIT, Constants.TYPE_COMMIT, len, is); } + public ObjectId writeTag(final long len, final InputStream is) + throws IOException { + return writeObject(Constants.OBJ_TAG, Constants.TYPE_TAG, len, is); + } + public ObjectId writeObject(final int typeCode, final String type, long len, final InputStream is) throws IOException { final File t; diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java index d2943c3..069c650 100644 --- a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java +++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java @@ -211,6 +211,21 @@ public class Repository { throw new IncorrectObjectTypeException(id, Constants.TYPE_TREE); } + public Tag mapTag(String revstr) throws IOException { + final ObjectId id = resolve(revstr); + return id != null ? mapTag(id) : null; + } + + public Tag mapTag(final ObjectId id) throws IOException { + final ObjectLoader or = openObject(id); + if (or == null) + return null; + final byte[] raw = or.getBytes(); + if (Constants.TYPE_TAG.equals(or.getType())) + return new Tag(this, id, raw); + throw new IncorrectObjectTypeException(id, Constants.TYPE_TAG); + } + public RefLock lockRef(final String ref) throws IOException { final RefLock l = new RefLock(readRef(ref, true)); return l.lock() ? l : null; diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Tag.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Tag.java new file mode 100644 index 0000000..d9e6990 --- /dev/null +++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Tag.java @@ -0,0 +1,172 @@ +/* + * Copyright (C) 20067 Robin Rosenberg <robin.rosenberg@dewire.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License, version 2, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + */ +package org.spearce.jgit.lib; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStreamReader; + +import org.spearce.jgit.errors.CorruptObjectException; + +public class Tag { + private final Repository objdb; + + private ObjectId tagId; + + private PersonIdent tagger; + + private String message; + + private byte[] raw; + + private String type; + + private String tag; + + private ObjectId objId; + + public Tag(final Repository db) { + objdb = db; + } + + public Tag(final Repository db, final ObjectId id, final byte[] raw) { + objdb = db; + tagId = id; + objId = ObjectId.fromString(raw, 7); + this.raw = raw; + } + + public PersonIdent getAuthor() { + decode(); + return tagger; + } + + public void setAuthor(final PersonIdent a) { + tagger = a; + } + + public String getMessage() { + decode(); + return message; + } + + private void decode() { + // FIXME: handle I/O errors + if (raw != null) { + try { + BufferedReader br = new BufferedReader(new InputStreamReader( + new ByteArrayInputStream(raw))); + String n = br.readLine(); + if (n == null || !n.startsWith("object ")) { + throw new CorruptObjectException(tagId, "no object"); + } + objId = new ObjectId(n.substring(7)); + n = br.readLine(); + if (n == null || !n.startsWith("type ")) { + throw new CorruptObjectException(tagId, "no type"); + } + type = n.substring("type ".length()); + n = br.readLine(); + + if (n == null || !n.startsWith("tag ")) { + throw new CorruptObjectException(tagId, "no tag name"); + } + tag = n.substring("tag ".length()); + n = br.readLine(); + + if (n == null || !n.startsWith("tagger ")) { + throw new CorruptObjectException(tagId, "no tagger"); + } + tagger = new PersonIdent(n.substring("tagger ".length())); + + n = br.readLine(); + if (n == null || !n.equals("")) { + throw new CorruptObjectException(tagId, + "malformed header"); + } + StringBuffer tempMessage = new StringBuffer(); + char[] readBuf = new char[2048]; + int readLen; + while ((readLen = br.read(readBuf)) > 0) { + tempMessage.append(readBuf, 0, readLen); + } + message = tempMessage.toString(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + raw = null; + } + } + } + + public void setMessage(final String m) { + message = m; + } + + public void tag() throws IOException { + if (getTagId() != null) + throw new IllegalStateException("exists " + getTagId()); + setTagId(new ObjectWriter(objdb).writeTag(this)); + } + + public String toString() { + return "tag[" + getTag() + getType() + getObjId() + " " + getAuthor() + "]"; + } + + public ObjectId getTagId() { + return tagId; + } + + public void setTagId(ObjectId tagId) { + this.tagId = tagId; + } + + public PersonIdent getTagger() { + decode(); + return tagger; + } + + public void setTagger(PersonIdent tagger) { + this.tagger = tagger; + } + + public String getType() { + decode(); + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getTag() { + return tag; + } + + public void setTag(String tag) { + this.tag = tag; + } + + public ObjectId getObjId() { + return objId; + } + + public void setObjId(ObjectId objId) { + this.objId = objId; + } +} diff --git a/org.spearce.jgit/tst/org/spearce/jgit/lib/T0003_Basic.java b/org.spearce.jgit/tst/org/spearce/jgit/lib/T0003_Basic.java index a1bf803..0b135b1 100644 --- a/org.spearce.jgit/tst/org/spearce/jgit/lib/T0003_Basic.java +++ b/org.spearce.jgit/tst/org/spearce/jgit/lib/T0003_Basic.java @@ -319,4 +319,70 @@ public class T0003_Basic extends RepositoryTestCase { assertEquals(new ObjectId("b47a8f0a4190f7572e11212769090523e23eb1ea"), t.getId()); } + + public void test020_createBlobTag() throws IOException { + final ObjectId emptyId = new ObjectWriter(db).writeBlob(new byte[0]); + final Tag t = new Tag(db); + t.setObjId(emptyId); + t.setType("blob"); + t.setTag("test020"); + t.setAuthor(new PersonIdent(jauthor, 1154236443000L, -4 * 60)); + t.setMessage("test020 tagged\n"); + t.tag(); + assertEquals("6759556b09fbb4fd8ae5e315134481cc25d46954", t.getTagId().toString()); + + Tag mapTag = db.mapTag("6759556b09fbb4fd8ae5e315134481cc25d46954"); + assertEquals("blob", mapTag.getType()); + assertEquals("test020 tagged\n", mapTag.getMessage()); + assertEquals(new PersonIdent(jauthor, 1154236443000L, -4 * 60), mapTag.getAuthor()); + assertEquals("e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", mapTag.getObjId().toString()); + } + + public void test021_createTreeTag() throws IOException { + final ObjectId emptyId = new ObjectWriter(db).writeBlob(new byte[0]); + final Tree almostEmptyTree = new Tree(db); + almostEmptyTree.addEntry(new FileTreeEntry(almostEmptyTree, emptyId, "empty".getBytes(), false)); + final ObjectId almostEmptyTreeId = new ObjectWriter(db).writeTree(almostEmptyTree); + final Tag t = new Tag(db); + t.setObjId(almostEmptyTreeId); + t.setType("tree"); + t.setTag("test021"); + t.setAuthor(new PersonIdent(jauthor, 1154236443000L, -4 * 60)); + t.setMessage("test021 tagged\n"); + t.tag(); + assertEquals("b0517bc8dbe2096b419d42424cd7030733f4abe5", t.getTagId().toString()); + + Tag mapTag = db.mapTag("b0517bc8dbe2096b419d42424cd7030733f4abe5"); + assertEquals("tree", mapTag.getType()); + assertEquals("test021 tagged\n", mapTag.getMessage()); + assertEquals(new PersonIdent(jauthor, 1154236443000L, -4 * 60), mapTag.getAuthor()); + assertEquals("417c01c8795a35b8e835113a85a5c0c1c77f67fb", mapTag.getObjId().toString()); + } + + public void test022_createCommitTag() throws IOException { + final ObjectId emptyId = new ObjectWriter(db).writeBlob(new byte[0]); + final Tree almostEmptyTree = new Tree(db); + almostEmptyTree.addEntry(new FileTreeEntry(almostEmptyTree, emptyId, "empty".getBytes(), false)); + final ObjectId almostEmptyTreeId = new ObjectWriter(db).writeTree(almostEmptyTree); + final Commit almostEmptyCommit = new Commit(db); + almostEmptyCommit.setAuthor(new PersonIdent(jauthor, 1154236443000L, -2 * 60)); // not exactly the same + almostEmptyCommit.setCommitter(new PersonIdent(jauthor, 1154236443000L, -2 * 60)); + almostEmptyCommit.setMessage("test022\n"); + almostEmptyCommit.setTreeId(almostEmptyTreeId); + ObjectId almostEmptyCommitId = new ObjectWriter(db).writeCommit(almostEmptyCommit); + final Tag t = new Tag(db); + t.setObjId(almostEmptyCommitId); + t.setType("commit"); + t.setTag("test022"); + t.setAuthor(new PersonIdent(jauthor, 1154236443000L, -4 * 60)); + t.setMessage("test022 tagged\n"); + t.tag(); + assertEquals("0ce2ebdb36076ef0b38adbe077a07d43b43e3807", t.getTagId().toString()); + + Tag mapTag = db.mapTag("0ce2ebdb36076ef0b38adbe077a07d43b43e3807"); + assertEquals("commit", mapTag.getType()); + assertEquals("test022 tagged\n", mapTag.getMessage()); + assertEquals(new PersonIdent(jauthor, 1154236443000L, -4 * 60), mapTag.getAuthor()); + assertEquals("b5d3b45a96b340441f5abb9080411705c51cc86c", mapTag.getObjId().toString()); + } }
[EGIT PATCH 8/9] Handle odd tag formats created by tools such as cvsimport.
These lack a date and have a message without a newline
Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com> ---
.../src/org/spearce/jgit/lib/PersonIdent.java | 68 +++++++++++++---------- org.spearce.jgit/src/org/spearce/jgit/lib/Tag.java | 8 +- 2 files changed, 40 insertions(+), 36 deletions(-)
org.spearce.jgit/src/org/spearce/jgit/lib/PersonIdent.java, org.spearce.jgit/src/org/spearce/jgit/lib/Tag.java
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/PersonIdent.java b/org.spearce.jgit/src/org/spearce/jgit/lib/PersonIdent.java index bfcb34d..50a6a3b 100644 --- a/org.spearce.jgit/src/org/spearce/jgit/lib/PersonIdent.java +++ b/org.spearce.jgit/src/org/spearce/jgit/lib/PersonIdent.java @@ -24,7 +24,7 @@ public class PersonIdent { private final String emailAddress; - private final long when; + private final Long when; private final int tzOffset; @@ -43,7 +43,7 @@ public class PersonIdent { public PersonIdent(final PersonIdent pi, final Date aWhen) { name = pi.getName(); emailAddress = pi.getEmailAddress(); - when = aWhen.getTime(); + when = new Long(aWhen.getTime()); tzOffset = pi.tzOffset; } @@ -51,22 +51,22 @@ public class PersonIdent { final Date aWhen, final TimeZone aTZ) { name = aName; emailAddress = aEmailAddress; - when = aWhen.getTime(); - tzOffset = aTZ.getOffset(when) / (60 * 1000); + when = new Long(aWhen.getTime()); + tzOffset = aTZ.getOffset(when.longValue()) / (60 * 1000); } public PersonIdent(final String aName, final String aEmailAddress, final long aWhen, final int aTZ) { name = aName; emailAddress = aEmailAddress; - when = aWhen; + when = new Long(aWhen); tzOffset = aTZ; } public PersonIdent(final PersonIdent pi, final long aWhen, final int aTZ) { name = pi.getName(); emailAddress = pi.getEmailAddress(); - when = aWhen; + when = new Long(aWhen); tzOffset = aTZ; } @@ -83,22 +83,23 @@ public class PersonIdent { } final int sp = in.indexOf(' ', gt + 2); if (sp == -1) { - throw new IllegalArgumentException("Malformed PersonIdent string" - + " (no time zone found): " + in); - } - final String tzHoursStr = in.substring(sp + 1, sp + 4).trim(); - final int tzHours; - if (tzHoursStr.charAt(0) == '+') { - tzHours = Integer.parseInt(tzHoursStr.substring(1)); + when = null; + tzOffset = -1; } else { - tzHours = Integer.parseInt(tzHoursStr); + final String tzHoursStr = in.substring(sp + 1, sp + 4).trim(); + final int tzHours; + if (tzHoursStr.charAt(0) == '+') { + tzHours = Integer.parseInt(tzHoursStr.substring(1)); + } else { + tzHours = Integer.parseInt(tzHoursStr); + } + final int tzMins = Integer.parseInt(in.substring(sp + 4).trim()); + when = new Long(Long.parseLong(in.substring(gt + 1, sp).trim()) * 1000); + tzOffset = tzHours * 60 + tzMins; } - final int tzMins = Integer.parseInt(in.substring(sp + 4).trim()); name = in.substring(0, lt).trim(); emailAddress = in.substring(lt + 1, gt).trim(); - when = Long.parseLong(in.substring(gt + 1, sp).trim()) * 1000; - tzOffset = tzHours * 60 + tzMins; } public String getName() { @@ -110,11 +111,13 @@ public class PersonIdent { } public Date getWhen() { - return new Date(when); + if (when != null) + return new Date(when.longValue()); + return null; } public int hashCode() { - return getEmailAddress().hashCode() ^ ((int) when); + return getEmailAddress().hashCode() ^ (when.intValue()); } public boolean equals(final Object o) { @@ -148,18 +151,19 @@ public class PersonIdent { r.append(" <"); r.append(getEmailAddress()); r.append("> "); - r.append(when / 1000); - r.append(' '); - r.append(sign); - if (offsetHours < 10) { - r.append('0'); - } - r.append(offsetHours); - if (offsetMins < 10) { - r.append('0'); + if (when != null) { + r.append(when.longValue() / 1000); + r.append(' '); + r.append(sign); + if (offsetHours < 10) { + r.append('0'); + } + r.append(offsetHours); + if (offsetMins < 10) { + r.append('0'); + } + r.append(offsetMins); } - r.append(offsetMins); - return r.toString(); } @@ -176,7 +180,9 @@ public class PersonIdent { r.append(", "); r.append(getEmailAddress()); r.append(", "); - r.append(new Date(when + minutes * 60)); + if (when != null) { + r.append(new Date(when.longValue() + minutes * 60)); + } r.append("]"); return r.toString(); diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Tag.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Tag.java index d9e6990..cd59ee9 100644 --- a/org.spearce.jgit/src/org/spearce/jgit/lib/Tag.java +++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Tag.java @@ -94,11 +94,7 @@ public class Tag { } tagger = new PersonIdent(n.substring("tagger ".length())); - n = br.readLine(); - if (n == null || !n.equals("")) { - throw new CorruptObjectException(tagId, - "malformed header"); - } + // Message should start with an empty line, but StringBuffer tempMessage = new StringBuffer(); char[] readBuf = new char[2048]; int readLen; @@ -106,6 +102,8 @@ public class Tag { tempMessage.append(readBuf, 0, readLen); } message = tempMessage.toString(); + if (message.startsWith("\n")) + message = message.substring(1); } catch (IOException e) { e.printStackTrace(); } finally {
Having these things is a test suite is dubious, but useful anyway.
Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com> ---
.../tst/org/spearce/jgit/lib/SpeedTestBase.java | 48 ++++++++++++++++ .../spearce/jgit/lib/T0005_ShallowSpeedTest.java | 67 ++++++++++++++++++++++ .../org/spearce/jgit/lib/T0006_DeepSpeedTest.java | 70 +++++++++++++++++++++++ 3 files changed, 185 insertions(+), 0 deletions(-)
org.spearce.jgit/tst/org/spearce/jgit/lib/SpeedTestBase.java, org.spearce.jgit/tst/org/spearce/jgit/lib/T0005_ShallowSpeedTest.java, org.spearce.jgit/tst/org/spearce/jgit/lib/T0006_DeepSpeedTest.java
diff --git a/org.spearce.jgit/tst/org/spearce/jgit/lib/SpeedTestBase.java b/org.spearce.jgit/tst/org/spearce/jgit/lib/SpeedTestBase.java new file mode 100644 index 0000000..6601407 --- /dev/null +++ b/org.spearce.jgit/tst/org/spearce/jgit/lib/SpeedTestBase.java @@ -0,0 +1,48 @@ +package org.spearce.jgit.lib; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; + +import junit.framework.TestCase; + +public abstract class SpeedTestBase extends TestCase { + protected long nativeTime; + protected String kernelrepo; + + protected void prepare(String[] refcmd) throws Exception { + try { + BufferedReader bufferedReader = new BufferedReader(new FileReader("kernel.ref")); + kernelrepo = bufferedReader.readLine(); + bufferedReader.close(); + timeNativeGit(kernelrepo, refcmd); + nativeTime = timeNativeGit(kernelrepo, refcmd); + } catch (Exception e) { + System.out.println("Create a file named kernel.ref and put the path to the Linux kernels repository there"); + throw e; + } + } + + private static long timeNativeGit(String kernelrepo, String[] refcmd) throws IOException, + InterruptedException, Exception { + long start = System.currentTimeMillis(); + Process p = Runtime.getRuntime().exec(refcmd, null, new File(kernelrepo,"..")); + InputStream inputStream = p.getInputStream(); + InputStream errorStream = p.getErrorStream(); + byte[] buf=new byte[1024*1024]; + while (inputStream.read(buf)>=0) + ; // empty + if (p.waitFor()!=0) { + int c; + while ((c=errorStream.read())!=-1) + System.err.print((char)c); + throw new Exception("git log failed"); + } + inputStream.close(); + errorStream.close(); + long stop = System.currentTimeMillis(); + return stop - start; + } +} diff --git a/org.spearce.jgit/tst/org/spearce/jgit/lib/T0005_ShallowSpeedTest.java b/org.spearce.jgit/tst/org/spearce/jgit/lib/T0005_ShallowSpeedTest.java new file mode 100644 index 0000000..7187e9a --- /dev/null +++ b/org.spearce.jgit/tst/org/spearce/jgit/lib/T0005_ShallowSpeedTest.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2006 Robin Rosenberg <robin.rosenberg@dewire.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License, version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + */ +package org.spearce.jgit.lib; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import junit.textui.TestRunner; + +public class T0005_ShallowSpeedTest extends SpeedTestBase { + + protected void setUp() throws Exception { + prepare(new String[] { "git", "rev-list", "365bbe0d0caaf2ba74d56556827babf0bc66965d" }); + } + + public void testShallowHistoryScan() throws IOException { + long start = System.currentTimeMillis(); + Repository db = new Repository(new File(kernelrepo)); + Commit commit = db.mapCommit("365bbe0d0caaf2ba74d56556827babf0bc66965d"); + int n = 1; + do { + // System.out.println("commit="+commit.getCommitId()); + List parent = commit.getParentIds(); + if (parent.size() > 0) { + ObjectId parentId = (ObjectId) parent.get(0); + commit = db.mapCommit(parentId); + commit.getCommitId().toString(); + ++n; + } else { + commit = null; + } + } while (commit != null); + assertEquals(12275, n); + long stop = System.currentTimeMillis(); + long time = stop - start; + System.out.println("native="+nativeTime); + System.out.println("jgit="+time); + // ~0.750s (hot cache), ok + /* +native=1748 +jgit=774 + */ + // native git seems to run SLOWER than jgit here, at roughly half the speed + // creating the git process is not the issue here, btw. + long factor10 = (nativeTime*110/time+50)/100; + assertEquals(2, factor10); + } + + public static void main(String[] args) { + TestRunner.run(T0005_ShallowSpeedTest.class); + } +} diff --git a/org.spearce.jgit/tst/org/spearce/jgit/lib/T0006_DeepSpeedTest.java b/org.spearce.jgit/tst/org/spearce/jgit/lib/T0006_DeepSpeedTest.java new file mode 100644 index 0000000..5bd480c --- /dev/null +++ b/org.spearce.jgit/tst/org/spearce/jgit/lib/T0006_DeepSpeedTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2006 Shawn Pearce <spearce@spearce.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License, version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + */ +package org.spearce.jgit.lib; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import junit.textui.TestRunner; + +public class T0006_DeepSpeedTest extends SpeedTestBase { + + protected void setUp() throws Exception { + prepare(new String[] { "git", "rev-list", "365bbe0d0caaf2ba74d56556827babf0bc66965d","--","net/netfilter/nf_queue.c" }); + } + + public void testDeepHistoryScan() throws IOException { + long start = System.currentTimeMillis(); + Repository db = new Repository(new File(kernelrepo)); + Commit commit = db.mapCommit("365bbe0d0caaf2ba74d56556827babf0bc66965d"); + int n = 1; + do { + // System.out.println("commit="+commit.getCommitId()); + List parent = commit.getParentIds(); + if (parent.size() > 0) { + ObjectId parentId = (ObjectId) parent.get(0); + commit = db.mapCommit(parentId); + TreeEntry m = commit.getTree().findMember("net/netfilter/nf_queue.c"); + if (m != null) + commit.getCommitId().toString(); + ++n; + } else { + commit = null; + } + } while (commit != null); + // + assertEquals(12275, n); + long stop = System.currentTimeMillis(); + long time = stop - start; + System.out.println("native="+nativeTime); + System.out.println("jgit="+time); + /* + native=1355 + jgit=5449 + */ + // This is not an exact factor, but we'd expect native git to perform this + // about 4 times quicker. If for some reason we find jgit to be faster than + // this the cause should be found and secured. + long factor = (time*110/nativeTime+50)/100; + assertEquals(4, factor); + } + + public static void main(String[] args) { + TestRunner.run(T0006_DeepSpeedTest.class); + } +}