Browse Source

Move commit and tag formatting to CommitBuilder, TagBuilder

These objects should be responsible for their own formatting,
rather than delegating it to some obtuse type called ObjectInserter.

While we are at it, simplify the way we insert these into a database.
Passing in the type and calling format in application code turned
out to be a huge mistake in terms of ease-of-use of the insert API.

Change-Id: Id5bb95ee56aa2a002243e9b7853b84ec8df1d7bf
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
stable-0.9
Shawn O. Pearce 14 years ago
parent
commit
6df5d3397c
  1. 7
      org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java
  2. 2
      org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java
  3. 2
      org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java
  4. 3
      org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/CherryPickTest.java
  5. 3
      org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SimpleMergeTest.java
  6. 2
      org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java
  7. 2
      org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevTagParseTest.java
  8. 8
      org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/T0003_Basic.java
  9. 3
      org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
  10. 99
      org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitBuilder.java
  11. 148
      org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectInserter.java
  12. 6
      org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectWriter.java
  13. 68
      org.eclipse.jgit/src/org/eclipse/jgit/lib/TagBuilder.java

7
org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java

@ -368,7 +368,7 @@ public class TestRepository<R extends Repository> {
c.setMessage(""); c.setMessage("");
ObjectId id; ObjectId id;
try { try {
id = inserter.insert(Constants.OBJ_COMMIT, inserter.format(c)); id = inserter.insert(c);
inserter.flush(); inserter.flush();
} finally { } finally {
inserter.release(); inserter.release();
@ -405,7 +405,7 @@ public class TestRepository<R extends Repository> {
t.setMessage(""); t.setMessage("");
ObjectId id; ObjectId id;
try { try {
id = inserter.insert(Constants.OBJ_TAG, inserter.format(t)); id = inserter.insert(t);
inserter.flush(); inserter.flush();
} finally { } finally {
inserter.release(); inserter.release();
@ -822,8 +822,7 @@ public class TestRepository<R extends Repository> {
ObjectId commitId; ObjectId commitId;
try { try {
c.setTreeId(tree.writeTree(inserter)); c.setTreeId(tree.writeTree(inserter));
commitId = inserter.insert(Constants.OBJ_COMMIT, inserter commitId = inserter.insert(c);
.format(c));
inserter.flush(); inserter.flush();
} finally { } finally {
inserter.release(); inserter.release();

2
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java

@ -100,7 +100,7 @@ class Tag extends TextBuiltin {
tag.setTagger(new PersonIdent(db)); tag.setTagger(new PersonIdent(db));
tag.setMessage(message.replaceAll("\r", "")); tag.setMessage(message.replaceAll("\r", ""));
tag.setTag(shortName); tag.setTag(shortName);
id = inserter.insert(Constants.OBJ_TAG, inserter.format(tag)); id = inserter.insert(tag);
inserter.flush(); inserter.flush();
} finally { } finally {
inserter.release(); inserter.release();

2
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java

@ -197,7 +197,7 @@ class RebuildCommitGraph extends TextBuiltin {
newc.setCommitter(newc.getAuthor()); newc.setCommitter(newc.getAuthor());
newc.setParentIds(newParents); newc.setParentIds(newParents);
newc.setMessage("ORIGINAL " + t.oldId.name() + "\n"); newc.setMessage("ORIGINAL " + t.oldId.name() + "\n");
t.newId = oi.insert(Constants.OBJ_COMMIT,oi.format(newc)); t.newId = oi.insert(newc);
rewrites.put(t.oldId, t.newId); rewrites.put(t.oldId, t.newId);
pm.update(1); pm.update(1);
} }

3
org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/CherryPickTest.java

@ -45,7 +45,6 @@
package org.eclipse.jgit.merge; package org.eclipse.jgit.merge;
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB; import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
import static org.eclipse.jgit.lib.Constants.OBJ_COMMIT;
import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheBuilder; import org.eclipse.jgit.dircache.DirCacheBuilder;
@ -137,7 +136,7 @@ public class CherryPickTest extends RepositoryTestCase {
c.setCommitter(c.getAuthor()); c.setCommitter(c.getAuthor());
c.setParentIds(parentIds); c.setParentIds(parentIds);
c.setMessage("Tree " + c.getTreeId().name()); c.setMessage("Tree " + c.getTreeId().name());
ObjectId id = odi.insert(OBJ_COMMIT, odi.format(c)); ObjectId id = odi.insert(c);
odi.flush(); odi.flush();
return id; return id;
} }

3
org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SimpleMergeTest.java

@ -45,7 +45,6 @@
package org.eclipse.jgit.merge; package org.eclipse.jgit.merge;
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB; import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
import static org.eclipse.jgit.lib.Constants.OBJ_COMMIT;
import java.io.IOException; import java.io.IOException;
@ -373,7 +372,7 @@ public class SimpleMergeTest extends SampleDataRepositoryTestCase {
c.setCommitter(c.getAuthor()); c.setCommitter(c.getAuthor());
c.setParentIds(parentIds); c.setParentIds(parentIds);
c.setMessage("Tree " + c.getTreeId().name()); c.setMessage("Tree " + c.getTreeId().name());
ObjectId id = odi.insert(OBJ_COMMIT, odi.format(c)); ObjectId id = odi.insert(c);
odi.flush(); odi.flush();
return id; return id;
} }

2
org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java

@ -327,7 +327,7 @@ public class RevCommitParseTest extends RepositoryTestCase {
src.setCommitter(committer); src.setCommitter(committer);
src.setMessage("Test commit\n\nThis is a test.\n"); src.setMessage("Test commit\n\nThis is a test.\n");
RevCommit p = RevCommit.parse(fmt.format(src)); RevCommit p = RevCommit.parse(src.format());
assertEquals(src.getTreeId(), p.getTree()); assertEquals(src.getTreeId(), p.getTree());
assertEquals(0, p.getParentCount()); assertEquals(0, p.getParentCount());
assertEquals(author, p.getAuthorIdent()); assertEquals(author, p.getAuthorIdent());

2
org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevTagParseTest.java

@ -407,7 +407,7 @@ public class RevTagParseTest extends RepositoryTestCase {
src.setTag("a.test"); src.setTag("a.test");
src.setMessage("Test tag\n\nThis is a test.\n"); src.setMessage("Test tag\n\nThis is a test.\n");
RevTag p = RevTag.parse(fmt.format(src)); RevTag p = RevTag.parse(src.format());
assertEquals(src.getObjectId(), p.getObject()); assertEquals(src.getObjectId(), p.getObject());
assertEquals(committer, p.getTaggerIdent()); assertEquals(committer, p.getTaggerIdent());
assertEquals("a.test", p.getTagName()); assertEquals("a.test", p.getTagName());

8
org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/T0003_Basic.java

@ -693,13 +693,12 @@ public class T0003_Basic extends SampleDataRepositoryTestCase {
} }
private ObjectId insertCommit(final CommitBuilder commit) throws IOException, private ObjectId insertCommit(final CommitBuilder builder) throws IOException,
UnsupportedEncodingException { UnsupportedEncodingException {
ObjectInserter oi = db.newObjectInserter(); ObjectInserter oi = db.newObjectInserter();
try { try {
ObjectId id = oi.insert(Constants.OBJ_COMMIT, oi.format(commit)); ObjectId id = oi.insert(builder);
oi.flush(); oi.flush();
commit.setCommitId(id);
return id; return id;
} finally { } finally {
oi.release(); oi.release();
@ -721,9 +720,8 @@ public class T0003_Basic extends SampleDataRepositoryTestCase {
UnsupportedEncodingException { UnsupportedEncodingException {
ObjectInserter oi = db.newObjectInserter(); ObjectInserter oi = db.newObjectInserter();
try { try {
ObjectId id = oi.insert(Constants.OBJ_TAG, oi.format(tag)); ObjectId id = oi.insert(tag);
oi.flush(); oi.flush();
tag.setTagId(id);
return id; return id;
} finally { } finally {
oi.release(); oi.release();

3
org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java

@ -169,8 +169,7 @@ public class CommitCommand extends GitCommand<RevCommit> {
commit.setParentIds(parents); commit.setParentIds(parents);
commit.setTreeId(indexTreeId); commit.setTreeId(indexTreeId);
ObjectId commitId = odi.insert(Constants.OBJ_COMMIT, odi ObjectId commitId = odi.insert(commit);
.format(commit));
odi.flush(); odi.flush();
RevWalk revWalk = new RevWalk(repo); RevWalk revWalk = new RevWalk(repo);

99
org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitBuilder.java

@ -45,6 +45,10 @@
package org.eclipse.jgit.lib; package org.eclipse.jgit.lib;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.List; import java.util.List;
@ -62,6 +66,16 @@ import java.util.List;
public class CommitBuilder { public class CommitBuilder {
private static final ObjectId[] EMPTY_OBJECTID_LIST = new ObjectId[0]; private static final ObjectId[] EMPTY_OBJECTID_LIST = new ObjectId[0];
private static final byte[] htree = Constants.encodeASCII("tree");
private static final byte[] hparent = Constants.encodeASCII("parent");
private static final byte[] hauthor = Constants.encodeASCII("author");
private static final byte[] hcommitter = Constants.encodeASCII("committer");
private static final byte[] hencoding = Constants.encodeASCII("encoding");
private ObjectId commitId; private ObjectId commitId;
private ObjectId treeId; private ObjectId treeId;
@ -262,6 +276,91 @@ public class CommitBuilder {
return encoding; return encoding;
} }
/**
* Format this builder's state as a commit object.
*
* As a side effect, {@link #getCommitId()} will be populated with the
* proper ObjectId for the formatted content.
*
* @return this object in the canonical commit format, suitable for storage
* in a repository.
* @throws UnsupportedEncodingException
* the encoding specified by {@link #getEncoding()} is not
* supported by this Java runtime.
*/
public byte[] format() throws UnsupportedEncodingException {
return format(new ObjectInserter.Formatter());
}
/**
* Format this builder's state as a commit object.
*
* As a side effect, {@link #getCommitId()} will be populated with the
* proper ObjectId for the formatted content.
*
* @param oi
* the inserter whose formatting support will be reused. The
* inserter itself is not affected, and the commit is not
* actually inserted into the repository.
* @return this object in the canonical commit format, suitable for storage
* in a repository.
* @throws UnsupportedEncodingException
* the encoding specified by {@link #getEncoding()} is not
* supported by this Java runtime.
*/
public byte[] format(ObjectInserter oi) throws UnsupportedEncodingException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
OutputStreamWriter w = new OutputStreamWriter(os, getEncoding());
try {
os.write(htree);
os.write(' ');
getTreeId().copyTo(os);
os.write('\n');
for (ObjectId p : getParentIds()) {
os.write(hparent);
os.write(' ');
p.copyTo(os);
os.write('\n');
}
os.write(hauthor);
os.write(' ');
w.write(getAuthor().toExternalString());
w.flush();
os.write('\n');
os.write(hcommitter);
os.write(' ');
w.write(getCommitter().toExternalString());
w.flush();
os.write('\n');
if (getEncoding() != Constants.CHARSET) {
os.write(hencoding);
os.write(' ');
os.write(Constants.encodeASCII(getEncoding().name()));
os.write('\n');
}
os.write('\n');
if (getMessage() != null) {
w.write(getMessage());
w.flush();
}
} catch (IOException err) {
// This should never occur, the only way to get it above is
// for the ByteArrayOutputStream to throw, but it doesn't.
//
throw new RuntimeException(err);
}
byte[] content = os.toByteArray();
setCommitId(oi.idFor(Constants.OBJ_COMMIT, content));
return content;
}
@Override @Override
public String toString() { public String toString() {
StringBuilder r = new StringBuilder(); StringBuilder r = new StringBuilder();

148
org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectInserter.java

@ -51,9 +51,6 @@ import java.io.ByteArrayOutputStream;
import java.io.EOFException; import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.text.MessageFormat; import java.text.MessageFormat;
@ -73,16 +70,6 @@ import org.eclipse.jgit.errors.ObjectWritingException;
* otherwise making the returned ObjectIds visible to other code. * otherwise making the returned ObjectIds visible to other code.
*/ */
public abstract class ObjectInserter { public abstract class ObjectInserter {
private static final byte[] htree = Constants.encodeASCII("tree");
private static final byte[] hparent = Constants.encodeASCII("parent");
private static final byte[] hauthor = Constants.encodeASCII("author");
private static final byte[] hcommitter = Constants.encodeASCII("committer");
private static final byte[] hencoding = Constants.encodeASCII("encoding");
/** An inserter that can be used for formatting and id generation only. */ /** An inserter that can be used for formatting and id generation only. */
public static class Formatter extends ObjectInserter { public static class Formatter extends ObjectInserter {
@Override @Override
@ -194,6 +181,38 @@ public abstract class ObjectInserter {
return ObjectId.fromRaw(md.digest()); return ObjectId.fromRaw(md.digest());
} }
/**
* Insert a single commit into the store, returning its unique name.
*
* As a side effect, {@link CommitBuilder#getCommitId()} will also be
* populated with the returned ObjectId.
*
* @param builder
* the builder containing the proposed commit's data.
* @return the name of the commit object.
* @throws IOException
* the object could not be stored.
*/
public final ObjectId insert(CommitBuilder builder) throws IOException {
return insert(Constants.OBJ_COMMIT, builder.format(this));
}
/**
* Insert a single annotated tag into the store, returning its unique name.
*
* As a side effect, {@link TagBuilder#getTagId()} will also be populated
* with the returned ObjectId.
*
* @param builder
* the builder containing the proposed tag's data.
* @return the name of the tag object.
* @throws IOException
* the object could not be stored.
*/
public final ObjectId insert(TagBuilder builder) throws IOException {
return insert(Constants.OBJ_TAG, builder.format(this));
}
/** /**
* Insert a single object into the store, returning its unique name. * Insert a single object into the store, returning its unique name.
* *
@ -293,107 +312,4 @@ public abstract class ObjectInserter {
} }
return o.toByteArray(); return o.toByteArray();
} }
/**
* Format a Commit in canonical format.
*
* @param commit
* the commit object to format
* @return canonical encoding of the commit object.
* @throws UnsupportedEncodingException
* the commit's chosen encoding isn't supported on this JVM.
*/
public final byte[] format(CommitBuilder commit)
throws UnsupportedEncodingException {
Charset encoding = commit.getEncoding();
ByteArrayOutputStream os = new ByteArrayOutputStream();
OutputStreamWriter w = new OutputStreamWriter(os, encoding);
try {
os.write(htree);
os.write(' ');
commit.getTreeId().copyTo(os);
os.write('\n');
for (ObjectId p : commit.getParentIds()) {
os.write(hparent);
os.write(' ');
p.copyTo(os);
os.write('\n');
}
os.write(hauthor);
os.write(' ');
w.write(commit.getAuthor().toExternalString());
w.flush();
os.write('\n');
os.write(hcommitter);
os.write(' ');
w.write(commit.getCommitter().toExternalString());
w.flush();
os.write('\n');
if (encoding != Constants.CHARSET) {
os.write(hencoding);
os.write(' ');
os.write(Constants.encodeASCII(encoding.name()));
os.write('\n');
}
os.write('\n');
if (commit.getMessage() != null) {
w.write(commit.getMessage());
w.flush();
}
} catch (IOException err) {
// This should never occur, the only way to get it above is
// for the ByteArrayOutputStream to throw, but it doesn't.
//
throw new RuntimeException(err);
}
return os.toByteArray();
}
/**
* Format a Tag in canonical format.
*
* @param tag
* the tag object to format
* @return canonical encoding of the tag object.
*/
public final byte[] format(TagBuilder tag) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
OutputStreamWriter w = new OutputStreamWriter(os, Constants.CHARSET);
try {
w.write("object ");
tag.getObjectId().copyTo(w);
w.write('\n');
w.write("type ");
w.write(Constants.typeString(tag.getObjectType()));
w.write("\n");
w.write("tag ");
w.write(tag.getTag());
w.write("\n");
if (tag.getTagger() != null) {
w.write("tagger ");
w.write(tag.getTagger().toExternalString());
w.write('\n');
}
w.write('\n');
if (tag.getMessage() != null)
w.write(tag.getMessage());
w.close();
} catch (IOException err) {
// This should never occur, the only way to get it above is
// for the ByteArrayOutputStream to throw, but it doesn't.
//
throw new RuntimeException(err);
}
return os.toByteArray();
}
} }

6
org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectWriter.java

@ -46,8 +46,6 @@
package org.eclipse.jgit.lib; package org.eclipse.jgit.lib;
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB; import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
import static org.eclipse.jgit.lib.Constants.OBJ_COMMIT;
import static org.eclipse.jgit.lib.Constants.OBJ_TAG;
import static org.eclipse.jgit.lib.Constants.OBJ_TREE; import static org.eclipse.jgit.lib.Constants.OBJ_TREE;
import java.io.File; import java.io.File;
@ -174,7 +172,7 @@ public class ObjectWriter {
*/ */
public ObjectId writeCommit(CommitBuilder commit) throws IOException { public ObjectId writeCommit(CommitBuilder commit) throws IOException {
try { try {
ObjectId id = inserter.insert(OBJ_COMMIT, inserter.format(commit)); ObjectId id = inserter.insert(commit);
inserter.flush(); inserter.flush();
return id; return id;
} finally { } finally {
@ -192,7 +190,7 @@ public class ObjectWriter {
*/ */
public ObjectId writeTag(TagBuilder tag) throws IOException { public ObjectId writeTag(TagBuilder tag) throws IOException {
try { try {
ObjectId id = inserter.insert(OBJ_TAG, inserter.format(tag)); ObjectId id = inserter.insert(tag);
inserter.flush(); inserter.flush();
return id; return id;
} finally { } finally {

68
org.eclipse.jgit/src/org/eclipse/jgit/lib/TagBuilder.java

@ -45,6 +45,10 @@
package org.eclipse.jgit.lib; package org.eclipse.jgit.lib;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import org.eclipse.jgit.revwalk.RevObject; import org.eclipse.jgit.revwalk.RevObject;
/** /**
@ -169,6 +173,70 @@ public class TagBuilder {
tagId = null; tagId = null;
} }
/**
* Format this builder's state as an annotated tag object.
*
* As a side effect, {@link #getTagId()} will be populated with the proper
* ObjectId for the formatted content.
*
* @return this object in the canonical annotated tag format, suitable for
* storage in a repository.
*/
public byte[] format() {
return format(new ObjectInserter.Formatter());
}
/**
* Format this builder's state as an annotated tag object.
*
* As a side effect, {@link #getTagId()} will be populated with the proper
* ObjectId for the formatted content.
*
* @param oi
* the inserter whose formatting support will be reused. The
* inserter itself is not affected, and the annotated tag is not
* actually inserted into the repository.
* @return this object in the canonical annotated tag format, suitable for
* storage in a repository.
*/
public byte[] format(ObjectInserter oi) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
OutputStreamWriter w = new OutputStreamWriter(os, Constants.CHARSET);
try {
w.write("object ");
getObjectId().copyTo(w);
w.write('\n');
w.write("type ");
w.write(Constants.typeString(getObjectType()));
w.write("\n");
w.write("tag ");
w.write(getTag());
w.write("\n");
if (getTagger() != null) {
w.write("tagger ");
w.write(getTagger().toExternalString());
w.write('\n');
}
w.write('\n');
if (getMessage() != null)
w.write(getMessage());
w.close();
} catch (IOException err) {
// This should never occur, the only way to get it above is
// for the ByteArrayOutputStream to throw, but it doesn't.
//
throw new RuntimeException(err);
}
byte[] content = os.toByteArray();
setTagId(oi.idFor(Constants.OBJ_TAG, content));
return content;
}
@Override @Override
public String toString() { public String toString() {
StringBuilder r = new StringBuilder(); StringBuilder r = new StringBuilder();

Loading…
Cancel
Save