2 * Copyright (C) 2008 Shawn Pearce <spearce@spearce.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License, version 2, as published by the Free Software Foundation.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
17 package org
.spearce
.jgit
.revwalk
;
19 import java
.io
.IOException
;
20 import java
.nio
.charset
.Charset
;
22 import org
.spearce
.jgit
.errors
.IncorrectObjectTypeException
;
23 import org
.spearce
.jgit
.errors
.MissingObjectException
;
24 import org
.spearce
.jgit
.lib
.AnyObjectId
;
25 import org
.spearce
.jgit
.lib
.Commit
;
26 import org
.spearce
.jgit
.lib
.Constants
;
27 import org
.spearce
.jgit
.lib
.MutableObjectId
;
28 import org
.spearce
.jgit
.lib
.ObjectLoader
;
29 import org
.spearce
.jgit
.lib
.PersonIdent
;
30 import org
.spearce
.jgit
.util
.RawParseUtils
;
32 /** A commit reference to a commit in the DAG. */
33 public class RevCommit
extends RevObject
{
34 static final RevCommit
[] NO_PARENTS
= {};
36 private static final String TYPE_COMMIT
= Constants
.TYPE_COMMIT
;
46 private byte[] buffer
;
49 * Create a new commit reference.
52 * object name for the commit.
54 protected RevCommit(final AnyObjectId id
) {
59 void parse(final RevWalk walk
) throws MissingObjectException
,
60 IncorrectObjectTypeException
, IOException
{
61 final ObjectLoader ldr
= walk
.db
.openObject(walk
.curs
, this);
63 throw new MissingObjectException(this, TYPE_COMMIT
);
64 final byte[] data
= ldr
.getCachedBytes();
65 if (Constants
.OBJ_COMMIT
!= ldr
.getType())
66 throw new IncorrectObjectTypeException(this, TYPE_COMMIT
);
67 parseCanonical(walk
, data
);
70 void parseCanonical(final RevWalk walk
, final byte[] raw
) {
71 final MutableObjectId idBuffer
= walk
.idBuffer
;
72 idBuffer
.fromString(raw
, 5);
73 tree
= walk
.lookupTree(idBuffer
);
76 if (parents
== null) {
77 RevCommit
[] pList
= new RevCommit
[1];
82 idBuffer
.fromString(raw
, ptr
+ 7);
83 final RevCommit p
= walk
.lookupCommit(idBuffer
);
85 pList
[nParents
++] = p
;
86 else if (nParents
== 1) {
87 pList
= new RevCommit
[] { pList
[0], p
};
90 if (pList
.length
<= nParents
) {
91 RevCommit
[] old
= pList
;
92 pList
= new RevCommit
[pList
.length
+ 32];
93 System
.arraycopy(old
, 0, pList
, 0, nParents
);
95 pList
[nParents
++] = p
;
99 if (nParents
!= pList
.length
) {
100 RevCommit
[] old
= pList
;
101 pList
= new RevCommit
[nParents
];
102 System
.arraycopy(old
, 0, pList
, 0, nParents
);
107 // extract time from "committer "
108 ptr
= RawParseUtils
.committer(raw
, ptr
);
110 ptr
= RawParseUtils
.nextLF(raw
, ptr
, '>');
111 commitTime
= RawParseUtils
.parseBase10(raw
, ptr
, null);
118 static void carryFlags(RevCommit c
, final int carry
) {
120 final RevCommit
[] pList
= c
.parents
;
123 final int n
= pList
.length
;
127 for (int i
= 1; i
< n
; i
++) {
128 final RevCommit p
= pList
[i
];
130 carryFlags(p
, carry
);
138 void carryFlags(final int carryMask
) {
139 final int carry
= flags
& carryMask
;
142 carryFlags(this, carry
);
146 * Carry a RevFlag set on this commit to its parents.
148 * If this commit is parsed, has parents, and has the supplied flag set on
149 * it we automatically add it to the parents, grand-parents, and so on until
150 * an unparsed commit or a commit with no parents is discovered. This
151 * permits applications to force a flag through the history chain when
155 * the single flag value to carry back onto parents.
157 public void carry(final RevFlag flag
) {
158 carryFlags(flags
& flag
.mask
);
162 * Time from the "committer " line of the buffer.
164 * @return time, expressed as seconds since the epoch.
166 public final int getCommitTime() {
171 * Parse this commit buffer for display.
174 * revision walker owning this reference.
175 * @return parsed commit.
177 public final Commit
asCommit(final RevWalk walk
) {
178 return new Commit(walk
.db
, this, buffer
);
182 * Get a reference to this commit's tree.
184 * @return tree of this commit.
186 public final RevTree
getTree() {
191 * Get the number of parent commits listed in this commit.
193 * @return number of parents; always a positive value but can be 0.
195 public final int getParentCount() {
196 return parents
.length
;
200 * Get the nth parent from this commit's parent list.
203 * parent index to obtain. Must be in the range 0 through
204 * {@link #getParentCount()}-1.
205 * @return the specified parent.
206 * @throws ArrayIndexOutOfBoundsException
207 * an invalid parent index was specified.
209 public final RevCommit
getParent(final int nth
) {
214 * Obtain an array of all parents (<b>NOTE - THIS IS NOT A COPY</b>).
216 * This method is exposed only to provide very fast, efficient access to
217 * this commit's parent list. Applications relying on this list should be
218 * very careful to ensure they do not modify its contents during their use
221 * @return the array of parents.
223 public final RevCommit
[] getParents() {
228 * Obtain the raw unparsed commit body (<b>NOTE - THIS IS NOT A COPY</b>).
230 * This method is exposed only to provide very fast, efficient access to
231 * this commit's message buffer within a RevFilter. Applications relying on
232 * this buffer should be very careful to ensure they do not modify its
233 * contents during their use of it.
235 * @return the raw unparsed commit body. This is <b>NOT A COPY</b>.
236 * Altering the contents of this buffer may alter the walker's
237 * knowledge of this commit, and the results it produces.
239 public final byte[] getRawBuffer() {
244 * Parse the author identity from the raw buffer.
246 * This method parses and returns the content of the author line, after
247 * taking the commit's character set into account and decoding the author
248 * name and email address. This method is fairly expensive and produces a
249 * new PersonIdent instance on each invocation. Callers should invoke this
250 * method only if they are certain they will be outputting the result, and
251 * should cache the return value for as long as necessary to use all
252 * information from it.
254 * RevFilter implementations should try to use {@link RawParseUtils} to scan
255 * the {@link #getRawBuffer()} instead, as this will allow faster evaluation
258 * @return identity of the author (name, email) and the time the commit was
259 * made by the author; null if no author line was found.
261 public final PersonIdent
getAuthorIdent() {
262 final byte[] raw
= buffer
;
263 final int nameB
= RawParseUtils
.author(raw
, 0);
266 return RawParseUtils
.parsePersonIdent(raw
, nameB
);
270 * Parse the committer identity from the raw buffer.
272 * This method parses and returns the content of the committer line, after
273 * taking the commit's character set into account and decoding the committer
274 * name and email address. This method is fairly expensive and produces a
275 * new PersonIdent instance on each invocation. Callers should invoke this
276 * method only if they are certain they will be outputting the result, and
277 * should cache the return value for as long as necessary to use all
278 * information from it.
280 * RevFilter implementations should try to use {@link RawParseUtils} to scan
281 * the {@link #getRawBuffer()} instead, as this will allow faster evaluation
284 * @return identity of the committer (name, email) and the time the commit
285 * was made by the comitter; null if no committer line was found.
287 public final PersonIdent
getCommitterIdent() {
288 final byte[] raw
= buffer
;
289 final int nameB
= RawParseUtils
.committer(raw
, 0);
292 return RawParseUtils
.parsePersonIdent(raw
, nameB
);
296 * Parse the complete commit message and decode it to a string.
298 * This method parses and returns the message portion of the commit buffer,
299 * after taking the commit's character set into account and decoding the
300 * buffer using that character set. This method is a fairly expensive
301 * operation and produces a new string on each invocation.
303 * @return decoded commit message as a string. Never null.
305 public final String
getFullMessage() {
306 final byte[] raw
= buffer
;
307 final int msgB
= RawParseUtils
.commitMessage(raw
, 0);
310 final Charset enc
= RawParseUtils
.parseEncoding(raw
);
311 return RawParseUtils
.decode(enc
, raw
, msgB
, raw
.length
);
315 * Parse the commit message and return the first "line" of it.
317 * The first line is everything up to the first pair of LFs. This is the
318 * "oneline" format, suitable for output in a single line display.
320 * This method parses and returns the message portion of the commit buffer,
321 * after taking the commit's character set into account and decoding the
322 * buffer using that character set. This method is a fairly expensive
323 * operation and produces a new string on each invocation.
325 * @return decoded commit message as a string. Never null. The returned
326 * string does not contain any LFs, even if the first paragraph
327 * spanned multiple lines. Embedded LFs are converted to spaces.
329 public final String
getShortMessage() {
330 final byte[] raw
= buffer
;
331 final int msgB
= RawParseUtils
.commitMessage(raw
, 0);
335 final Charset enc
= RawParseUtils
.parseEncoding(raw
);
336 final int msgE
= RawParseUtils
.endOfParagraph(raw
, msgB
);
337 String str
= RawParseUtils
.decode(enc
, raw
, msgB
, msgE
);
338 if (hasLF(raw
, msgB
, msgE
))
339 str
= str
.replace('\n', ' ');
343 private static boolean hasLF(final byte[] r
, int b
, final int e
) {
351 * Reset this commit to allow another RevWalk with the same instances.
353 * Subclasses <b>must</b> call <code>super.reset()</code> to ensure the
354 * basic information can be correctly cleared out.
356 public void reset() {
360 public void dispose() {