Browse Source
These routines create a fairly clean DSL for writing out the structure of a repository in a test case. Abstract them into a helper class that we can reuse in other test environments. Change-Id: I55cce3d557e1a28afe2fdf37b3a5b67e2651c9f1 Signed-off-by: Shawn O. Pearce <spearce@spearce.org>stable-0.7
Shawn O. Pearce
15 years ago
9 changed files with 704 additions and 102 deletions
@ -0,0 +1,650 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2009-2010, Google Inc. |
||||||
|
* and other copyright owners as documented in the project's IP log. |
||||||
|
* |
||||||
|
* This program and the accompanying materials are made available |
||||||
|
* under the terms of the Eclipse Distribution License v1.0 which |
||||||
|
* accompanies this distribution, is reproduced below, and is |
||||||
|
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||||
|
* |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or |
||||||
|
* without modification, are permitted provided that the following |
||||||
|
* conditions are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above |
||||||
|
* copyright notice, this list of conditions and the following |
||||||
|
* disclaimer in the documentation and/or other materials provided |
||||||
|
* with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of the Eclipse Foundation, Inc. nor the |
||||||
|
* names of its contributors may be used to endorse or promote |
||||||
|
* products derived from this software without specific prior |
||||||
|
* written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.eclipse.jgit.junit; |
||||||
|
|
||||||
|
import java.io.File; |
||||||
|
import java.io.IOException; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Collections; |
||||||
|
import java.util.Date; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import junit.framework.Assert; |
||||||
|
import junit.framework.AssertionFailedError; |
||||||
|
|
||||||
|
import org.eclipse.jgit.dircache.DirCache; |
||||||
|
import org.eclipse.jgit.dircache.DirCacheBuilder; |
||||||
|
import org.eclipse.jgit.dircache.DirCacheEditor; |
||||||
|
import org.eclipse.jgit.dircache.DirCacheEntry; |
||||||
|
import org.eclipse.jgit.dircache.DirCacheEditor.DeletePath; |
||||||
|
import org.eclipse.jgit.dircache.DirCacheEditor.DeleteTree; |
||||||
|
import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit; |
||||||
|
import org.eclipse.jgit.errors.ObjectWritingException; |
||||||
|
import org.eclipse.jgit.lib.AnyObjectId; |
||||||
|
import org.eclipse.jgit.lib.Commit; |
||||||
|
import org.eclipse.jgit.lib.Constants; |
||||||
|
import org.eclipse.jgit.lib.FileMode; |
||||||
|
import org.eclipse.jgit.lib.LockFile; |
||||||
|
import org.eclipse.jgit.lib.ObjectDirectory; |
||||||
|
import org.eclipse.jgit.lib.ObjectId; |
||||||
|
import org.eclipse.jgit.lib.ObjectWriter; |
||||||
|
import org.eclipse.jgit.lib.PersonIdent; |
||||||
|
import org.eclipse.jgit.lib.Ref; |
||||||
|
import org.eclipse.jgit.lib.RefUpdate; |
||||||
|
import org.eclipse.jgit.lib.RefWriter; |
||||||
|
import org.eclipse.jgit.lib.Repository; |
||||||
|
import org.eclipse.jgit.lib.Tag; |
||||||
|
import org.eclipse.jgit.revwalk.RevBlob; |
||||||
|
import org.eclipse.jgit.revwalk.RevCommit; |
||||||
|
import org.eclipse.jgit.revwalk.RevObject; |
||||||
|
import org.eclipse.jgit.revwalk.RevTag; |
||||||
|
import org.eclipse.jgit.revwalk.RevTree; |
||||||
|
import org.eclipse.jgit.revwalk.RevWalk; |
||||||
|
import org.eclipse.jgit.treewalk.TreeWalk; |
||||||
|
import org.eclipse.jgit.treewalk.filter.PathFilterGroup; |
||||||
|
|
||||||
|
/** Wrapper to make creating test data easier. */ |
||||||
|
public class TestRepository { |
||||||
|
private static final PersonIdent author; |
||||||
|
|
||||||
|
private static final PersonIdent committer; |
||||||
|
|
||||||
|
static { |
||||||
|
final MockSystemReader m = new MockSystemReader(); |
||||||
|
final long now = m.getCurrentTime(); |
||||||
|
final int tz = m.getTimezone(now); |
||||||
|
|
||||||
|
final String an = "J. Author"; |
||||||
|
final String ae = "jauthor@example.com"; |
||||||
|
author = new PersonIdent(an, ae, now, tz); |
||||||
|
|
||||||
|
final String cn = "J. Committer"; |
||||||
|
final String ce = "jcommitter@example.com"; |
||||||
|
committer = new PersonIdent(cn, ce, now, tz); |
||||||
|
} |
||||||
|
|
||||||
|
private final Repository db; |
||||||
|
|
||||||
|
private final RevWalk pool; |
||||||
|
|
||||||
|
private final ObjectWriter writer; |
||||||
|
|
||||||
|
private long now; |
||||||
|
|
||||||
|
/** |
||||||
|
* Wrap a repository with test building tools. |
||||||
|
* |
||||||
|
* @param db |
||||||
|
* the test repository to write into. |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
public TestRepository(Repository db) throws Exception { |
||||||
|
this(db, new RevWalk(db)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Wrap a repository with test building tools. |
||||||
|
* |
||||||
|
* @param db |
||||||
|
* the test repository to write into. |
||||||
|
* @param rw |
||||||
|
* the RevObject pool to use for object lookup. |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
public TestRepository(Repository db, RevWalk rw) throws Exception { |
||||||
|
this.db = db; |
||||||
|
this.pool = rw; |
||||||
|
this.writer = new ObjectWriter(db); |
||||||
|
this.now = 1236977987000L; |
||||||
|
} |
||||||
|
|
||||||
|
/** @return the repository this helper class operates against. */ |
||||||
|
public Repository getRepository() { |
||||||
|
return db; |
||||||
|
} |
||||||
|
|
||||||
|
/** @return get the RevWalk pool all objects are allocated through. */ |
||||||
|
public RevWalk getRevWalk() { |
||||||
|
return pool; |
||||||
|
} |
||||||
|
|
||||||
|
/** @return current time adjusted by {@link #tick(int)}. */ |
||||||
|
public Date getClock() { |
||||||
|
return new Date(now); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Adjust the current time that will used by the next commit. |
||||||
|
* |
||||||
|
* @param secDelta |
||||||
|
* number of seconds to add to the current time. |
||||||
|
*/ |
||||||
|
public void tick(final int secDelta) { |
||||||
|
now += secDelta * 1000L; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new blob object in the repository. |
||||||
|
* |
||||||
|
* @param content |
||||||
|
* file content, will be UTF-8 encoded. |
||||||
|
* @return reference to the blob. |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
public RevBlob blob(final String content) throws Exception { |
||||||
|
return blob(content.getBytes("UTF-8")); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new blob object in the repository. |
||||||
|
* |
||||||
|
* @param content |
||||||
|
* binary file content. |
||||||
|
* @return reference to the blob. |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
public RevBlob blob(final byte[] content) throws Exception { |
||||||
|
return pool.lookupBlob(writer.writeBlob(content)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Construct a regular file mode tree entry. |
||||||
|
* |
||||||
|
* @param path |
||||||
|
* path of the file. |
||||||
|
* @param blob |
||||||
|
* a blob, previously constructed in the repository. |
||||||
|
* @return the entry. |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
public DirCacheEntry file(final String path, final RevBlob blob) |
||||||
|
throws Exception { |
||||||
|
final DirCacheEntry e = new DirCacheEntry(path); |
||||||
|
e.setFileMode(FileMode.REGULAR_FILE); |
||||||
|
e.setObjectId(blob); |
||||||
|
return e; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Construct a tree from a specific listing of file entries. |
||||||
|
* |
||||||
|
* @param entries |
||||||
|
* the files to include in the tree. The collection does not need |
||||||
|
* to be sorted properly and may be empty. |
||||||
|
* @return reference to the tree specified by the entry list. |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
public RevTree tree(final DirCacheEntry... entries) throws Exception { |
||||||
|
final DirCache dc = DirCache.newInCore(); |
||||||
|
final DirCacheBuilder b = dc.builder(); |
||||||
|
for (final DirCacheEntry e : entries) |
||||||
|
b.add(e); |
||||||
|
b.finish(); |
||||||
|
return pool.lookupTree(dc.writeTree(writer)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Lookup an entry stored in a tree, failing if not present. |
||||||
|
* |
||||||
|
* @param tree |
||||||
|
* the tree to search. |
||||||
|
* @param path |
||||||
|
* the path to find the entry of. |
||||||
|
* @return the parsed object entry at this path, never null. |
||||||
|
* @throws AssertionFailedError |
||||||
|
* if the path does not exist in the given tree. |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
public RevObject get(final RevTree tree, final String path) |
||||||
|
throws AssertionFailedError, Exception { |
||||||
|
final TreeWalk tw = new TreeWalk(db); |
||||||
|
tw.setFilter(PathFilterGroup.createFromStrings(Collections |
||||||
|
.singleton(path))); |
||||||
|
tw.reset(tree); |
||||||
|
while (tw.next()) { |
||||||
|
if (tw.isSubtree() && !path.equals(tw.getPathString())) { |
||||||
|
tw.enterSubtree(); |
||||||
|
continue; |
||||||
|
} |
||||||
|
final ObjectId entid = tw.getObjectId(0); |
||||||
|
final FileMode entmode = tw.getFileMode(0); |
||||||
|
return pool.lookupAny(entid, entmode.getObjectType()); |
||||||
|
} |
||||||
|
Assert.fail("Can't find " + path + " in tree " + tree.name()); |
||||||
|
return null; // never reached.
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new commit. |
||||||
|
* <p> |
||||||
|
* See {@link #commit(int, RevTree, RevCommit...)}. The tree is the empty |
||||||
|
* tree (no files or subdirectories). |
||||||
|
* |
||||||
|
* @param parents |
||||||
|
* zero or more parents of the commit. |
||||||
|
* @return the new commit. |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
public RevCommit commit(final RevCommit... parents) throws Exception { |
||||||
|
return commit(1, tree(), parents); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new commit. |
||||||
|
* <p> |
||||||
|
* See {@link #commit(int, RevTree, RevCommit...)}. |
||||||
|
* |
||||||
|
* @param tree |
||||||
|
* the root tree for the commit. |
||||||
|
* @param parents |
||||||
|
* zero or more parents of the commit. |
||||||
|
* @return the new commit. |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
public RevCommit commit(final RevTree tree, final RevCommit... parents) |
||||||
|
throws Exception { |
||||||
|
return commit(1, tree, parents); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new commit. |
||||||
|
* <p> |
||||||
|
* See {@link #commit(int, RevTree, RevCommit...)}. The tree is the empty |
||||||
|
* tree (no files or subdirectories). |
||||||
|
* |
||||||
|
* @param secDelta |
||||||
|
* number of seconds to advance {@link #tick(int)} by. |
||||||
|
* @param parents |
||||||
|
* zero or more parents of the commit. |
||||||
|
* @return the new commit. |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
public RevCommit commit(final int secDelta, final RevCommit... parents) |
||||||
|
throws Exception { |
||||||
|
return commit(secDelta, tree(), parents); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new commit. |
||||||
|
* <p> |
||||||
|
* The author and committer identities are stored using the current |
||||||
|
* timestamp, after being incremented by {@code secDelta}. The message body |
||||||
|
* is empty. |
||||||
|
* |
||||||
|
* @param secDelta |
||||||
|
* number of seconds to advance {@link #tick(int)} by. |
||||||
|
* @param tree |
||||||
|
* the root tree for the commit. |
||||||
|
* @param parents |
||||||
|
* zero or more parents of the commit. |
||||||
|
* @return the new commit. |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
public RevCommit commit(final int secDelta, final RevTree tree, |
||||||
|
final RevCommit... parents) throws Exception { |
||||||
|
tick(secDelta); |
||||||
|
|
||||||
|
final Commit c = new Commit(db); |
||||||
|
c.setTreeId(tree); |
||||||
|
c.setParentIds(parents); |
||||||
|
c.setAuthor(new PersonIdent(author, new Date(now))); |
||||||
|
c.setCommitter(new PersonIdent(committer, new Date(now))); |
||||||
|
c.setMessage(""); |
||||||
|
return pool.lookupCommit(writer.writeCommit(c)); |
||||||
|
} |
||||||
|
|
||||||
|
/** @return a new commit builder. */ |
||||||
|
public CommitBuilder commit() { |
||||||
|
return new CommitBuilder(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Construct an annotated tag object pointing at another object. |
||||||
|
* <p> |
||||||
|
* The tagger is the committer identity, at the current time as specified by |
||||||
|
* {@link #tick(int)}. The time is not increased. |
||||||
|
* <p> |
||||||
|
* The tag message is empty. |
||||||
|
* |
||||||
|
* @param name |
||||||
|
* name of the tag. Traditionally a tag name should not start |
||||||
|
* with {@code refs/tags/}. |
||||||
|
* @param dst |
||||||
|
* object the tag should be pointed at. |
||||||
|
* @return the annotated tag object. |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
public RevTag tag(final String name, final RevObject dst) throws Exception { |
||||||
|
final Tag t = new Tag(db); |
||||||
|
t.setType(Constants.typeString(dst.getType())); |
||||||
|
t.setObjId(dst.toObjectId()); |
||||||
|
t.setTag(name); |
||||||
|
t.setTagger(new PersonIdent(committer, new Date(now))); |
||||||
|
t.setMessage(""); |
||||||
|
return (RevTag) pool.lookupAny(writer.writeTag(t), Constants.OBJ_TAG); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Update a reference to point to an object. |
||||||
|
* |
||||||
|
* @param ref |
||||||
|
* the name of the reference to update to. If {@code ref} does |
||||||
|
* not start with {@code refs/} and is not the magic names |
||||||
|
* {@code HEAD} {@code FETCH_HEAD} or {@code MERGE_HEAD}, then |
||||||
|
* {@code refs/heads/} will be prefixed in front of the given |
||||||
|
* name, thereby assuming it is a branch. |
||||||
|
* @param to |
||||||
|
* the target object. |
||||||
|
* @return the target object. |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
public RevCommit update(String ref, CommitBuilder to) throws Exception { |
||||||
|
return update(ref, to.create()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Update a reference to point to an object. |
||||||
|
* |
||||||
|
* @param <T> |
||||||
|
* type of the target object. |
||||||
|
* @param ref |
||||||
|
* the name of the reference to update to. If {@code ref} does |
||||||
|
* not start with {@code refs/} and is not the magic names |
||||||
|
* {@code HEAD} {@code FETCH_HEAD} or {@code MERGE_HEAD}, then |
||||||
|
* {@code refs/heads/} will be prefixed in front of the given |
||||||
|
* name, thereby assuming it is a branch. |
||||||
|
* @param obj |
||||||
|
* the target object. |
||||||
|
* @return the target object. |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
public <T extends AnyObjectId> T update(String ref, T obj) throws Exception { |
||||||
|
if (Constants.HEAD.equals(ref)) { |
||||||
|
} else if ("FETCH_HEAD".equals(ref)) { |
||||||
|
} else if ("MERGE_HEAD".equals(ref)) { |
||||||
|
} else if (ref.startsWith(Constants.R_REFS)) { |
||||||
|
} else |
||||||
|
ref = Constants.R_HEADS + ref; |
||||||
|
|
||||||
|
RefUpdate u = db.updateRef(ref); |
||||||
|
u.setNewObjectId(obj); |
||||||
|
switch (u.forceUpdate()) { |
||||||
|
case FAST_FORWARD: |
||||||
|
case FORCED: |
||||||
|
case NEW: |
||||||
|
case NO_CHANGE: |
||||||
|
updateServerInfo(); |
||||||
|
return obj; |
||||||
|
|
||||||
|
default: |
||||||
|
throw new IOException("Cannot write " + ref + " " + u.getResult()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Update the dumb client server info files. |
||||||
|
* |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
public void updateServerInfo() throws Exception { |
||||||
|
if (db.getObjectDatabase() instanceof ObjectDirectory) { |
||||||
|
RefWriter rw = new RefWriter(db.getAllRefs().values()) { |
||||||
|
@Override |
||||||
|
protected void writeFile(final String name, final byte[] bin) |
||||||
|
throws IOException { |
||||||
|
final File p = new File(db.getDirectory(), name); |
||||||
|
final LockFile lck = new LockFile(p); |
||||||
|
if (!lck.lock()) |
||||||
|
throw new ObjectWritingException("Can't write " + p); |
||||||
|
try { |
||||||
|
lck.write(bin); |
||||||
|
} catch (IOException ioe) { |
||||||
|
throw new ObjectWritingException("Can't write " + p); |
||||||
|
} |
||||||
|
if (!lck.commit()) |
||||||
|
throw new ObjectWritingException("Can't write " + p); |
||||||
|
} |
||||||
|
}; |
||||||
|
rw.writePackedRefs(); |
||||||
|
rw.writeInfoRefs(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Ensure the body of the given object has been parsed. |
||||||
|
* |
||||||
|
* @param <T> |
||||||
|
* type of object, e.g. {@link RevTag} or {@link RevCommit}. |
||||||
|
* @param object |
||||||
|
* reference to the (possibly unparsed) object to force body |
||||||
|
* parsing of. |
||||||
|
* @return {@code object} |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
public <T extends RevObject> T parseBody(final T object) throws Exception { |
||||||
|
pool.parseBody(object); |
||||||
|
return object; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new branch builder for this repository. |
||||||
|
* |
||||||
|
* @param ref |
||||||
|
* name of the branch to be constructed. If {@code ref} does not |
||||||
|
* start with {@code refs/} the prefix {@code refs/heads/} will |
||||||
|
* be added. |
||||||
|
* @return builder for the named branch. |
||||||
|
*/ |
||||||
|
public BranchBuilder branch(String ref) { |
||||||
|
if (Constants.HEAD.equals(ref)) { |
||||||
|
} else if (ref.startsWith(Constants.R_REFS)) { |
||||||
|
} else |
||||||
|
ref = Constants.R_HEADS + ref; |
||||||
|
return new BranchBuilder(ref); |
||||||
|
} |
||||||
|
|
||||||
|
/** Helper to build a branch with one or more commits */ |
||||||
|
public class BranchBuilder { |
||||||
|
private final String ref; |
||||||
|
|
||||||
|
BranchBuilder(final String ref) { |
||||||
|
this.ref = ref; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return construct a new commit builder that updates this branch. If |
||||||
|
* the branch already exists, the commit builder will have its |
||||||
|
* first parent as the current commit and its tree will be |
||||||
|
* initialized to the current files. |
||||||
|
* @throws Exception |
||||||
|
* the commit builder can't read the current branch state |
||||||
|
*/ |
||||||
|
public CommitBuilder commit() throws Exception { |
||||||
|
return new CommitBuilder(this); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Forcefully update this branch to a particular commit. |
||||||
|
* |
||||||
|
* @param to |
||||||
|
* the commit to update to. |
||||||
|
* @return {@code to}. |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
public RevCommit update(CommitBuilder to) throws Exception { |
||||||
|
return update(to.create()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Forcefully update this branch to a particular commit. |
||||||
|
* |
||||||
|
* @param to |
||||||
|
* the commit to update to. |
||||||
|
* @return {@code to}. |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
public RevCommit update(RevCommit to) throws Exception { |
||||||
|
return TestRepository.this.update(ref, to); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** Helper to generate a commit. */ |
||||||
|
public class CommitBuilder { |
||||||
|
private final BranchBuilder branch; |
||||||
|
|
||||||
|
private final DirCache tree = DirCache.newInCore(); |
||||||
|
|
||||||
|
private final List<RevCommit> parents = new ArrayList<RevCommit>(2); |
||||||
|
|
||||||
|
private int tick = 1; |
||||||
|
|
||||||
|
private String message = ""; |
||||||
|
|
||||||
|
private RevCommit self; |
||||||
|
|
||||||
|
CommitBuilder() { |
||||||
|
branch = null; |
||||||
|
} |
||||||
|
|
||||||
|
CommitBuilder(BranchBuilder b) throws Exception { |
||||||
|
branch = b; |
||||||
|
|
||||||
|
Ref ref = db.getRef(branch.ref); |
||||||
|
if (ref != null) { |
||||||
|
parent(pool.parseCommit(ref.getObjectId())); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
CommitBuilder(CommitBuilder prior) throws Exception { |
||||||
|
branch = prior.branch; |
||||||
|
|
||||||
|
DirCacheBuilder b = tree.builder(); |
||||||
|
for (int i = 0; i < prior.tree.getEntryCount(); i++) |
||||||
|
b.add(prior.tree.getEntry(i)); |
||||||
|
b.finish(); |
||||||
|
|
||||||
|
parents.add(prior.create()); |
||||||
|
} |
||||||
|
|
||||||
|
public CommitBuilder parent(RevCommit p) throws Exception { |
||||||
|
if (parents.isEmpty()) { |
||||||
|
DirCacheBuilder b = tree.builder(); |
||||||
|
parseBody(p); |
||||||
|
b.addTree(new byte[0], DirCacheEntry.STAGE_0, db, p.getTree()); |
||||||
|
b.finish(); |
||||||
|
} |
||||||
|
parents.add(p); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public CommitBuilder noParents() { |
||||||
|
parents.clear(); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public CommitBuilder noFiles() { |
||||||
|
tree.clear(); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public CommitBuilder add(String path, String content) throws Exception { |
||||||
|
return add(path, blob(content)); |
||||||
|
} |
||||||
|
|
||||||
|
public CommitBuilder add(String path, final RevBlob id) |
||||||
|
throws Exception { |
||||||
|
DirCacheEditor e = tree.editor(); |
||||||
|
e.add(new PathEdit(path) { |
||||||
|
@Override |
||||||
|
public void apply(DirCacheEntry ent) { |
||||||
|
ent.setFileMode(FileMode.REGULAR_FILE); |
||||||
|
ent.setObjectId(id); |
||||||
|
} |
||||||
|
}); |
||||||
|
e.finish(); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public CommitBuilder rm(String path) { |
||||||
|
DirCacheEditor e = tree.editor(); |
||||||
|
e.add(new DeletePath(path)); |
||||||
|
e.add(new DeleteTree(path)); |
||||||
|
e.finish(); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public CommitBuilder message(String m) { |
||||||
|
message = m; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public CommitBuilder tick(int secs) { |
||||||
|
tick = secs; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public RevCommit create() throws Exception { |
||||||
|
if (self == null) { |
||||||
|
TestRepository.this.tick(tick); |
||||||
|
|
||||||
|
final Commit c = new Commit(db); |
||||||
|
c.setTreeId(pool.lookupTree(tree.writeTree(writer))); |
||||||
|
c.setParentIds(parents.toArray(new RevCommit[parents.size()])); |
||||||
|
c.setAuthor(new PersonIdent(author, new Date(now))); |
||||||
|
c.setCommitter(new PersonIdent(committer, new Date(now))); |
||||||
|
c.setMessage(message); |
||||||
|
|
||||||
|
self = pool.lookupCommit(writer.writeCommit(c)); |
||||||
|
|
||||||
|
if (branch != null) |
||||||
|
branch.update(self); |
||||||
|
} |
||||||
|
return self; |
||||||
|
} |
||||||
|
|
||||||
|
public CommitBuilder child() throws Exception { |
||||||
|
return new CommitBuilder(this); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue