/** * Parse an annotated tag from its canonical format. * * <p>This method inserts the tag directly into the caller supplied revision pool, making it * appear as though the tag exists in the repository, even if it doesn't. The repository under the * pool is not affected. * * @param rw the revision pool to allocate the tag within. The tag's object pointer will be * obtained from this pool. * @param raw the canonical formatted tag to be parsed. * @return the parsed tag, in an isolated revision pool that is not available to the caller. * @throws CorruptObjectException the tag contains a malformed header that cannot be handled. */ public static RevTag parse(RevWalk rw, byte[] raw) throws CorruptObjectException { ObjectInserter.Formatter fmt = new ObjectInserter.Formatter(); boolean retain = rw.isRetainBody(); rw.setRetainBody(true); RevTag r = rw.lookupTag(fmt.idFor(Constants.OBJ_TAG, raw)); r.parseCanonical(rw, raw); rw.setRetainBody(retain); return r; }
/** * Parse a commit from its canonical format. * * <p>This method inserts the commit directly into the caller supplied revision pool, making it * appear as though the commit exists in the repository, even if it doesn't. The repository under * the pool is not affected. * * @param rw the revision pool to allocate the commit within. The commit's tree and parent * pointers will be obtained from this pool. * @param raw the canonical formatted commit to be parsed. * @return the parsed commit, in an isolated revision pool that is not available to the caller. * @throws IOException in case of RevWalk initialization fails */ public static RevCommit parse(RevWalk rw, byte[] raw) throws IOException { ObjectInserter.Formatter fmt = new ObjectInserter.Formatter(); boolean retain = rw.isRetainBody(); rw.setRetainBody(true); RevCommit r = rw.lookupCommit(fmt.idFor(Constants.OBJ_COMMIT, raw)); r.parseCanonical(rw, raw); rw.setRetainBody(retain); return r; }
void parseCanonical(final RevWalk walk, final byte[] raw) throws IOException { if (!walk.shallowCommitsInitialized) walk.initializeShallowCommits(); final MutableObjectId idBuffer = walk.idBuffer; idBuffer.fromString(raw, 5); tree = walk.lookupTree(idBuffer); int ptr = 46; if (parents == null) { RevCommit[] pList = new RevCommit[1]; int nParents = 0; for (; ; ) { if (raw[ptr] != 'p') break; idBuffer.fromString(raw, ptr + 7); final RevCommit p = walk.lookupCommit(idBuffer); if (nParents == 0) pList[nParents++] = p; else if (nParents == 1) { pList = new RevCommit[] {pList[0], p}; nParents = 2; } else { if (pList.length <= nParents) { RevCommit[] old = pList; pList = new RevCommit[pList.length + 32]; System.arraycopy(old, 0, pList, 0, nParents); } pList[nParents++] = p; } ptr += 48; } if (nParents != pList.length) { RevCommit[] old = pList; pList = new RevCommit[nParents]; System.arraycopy(old, 0, pList, 0, nParents); } parents = pList; } // extract time from "committer " ptr = RawParseUtils.committer(raw, ptr); if (ptr > 0) { ptr = RawParseUtils.nextLF(raw, ptr, '>'); // In 2038 commitTime will overflow unless it is changed to long. commitTime = RawParseUtils.parseBase10(raw, ptr, null); } if (walk.isRetainBody()) buffer = raw; flags |= PARSED; }
void parseCanonical(final RevWalk walk, final byte[] rawTag) throws CorruptObjectException { final MutableInteger pos = new MutableInteger(); final int oType; pos.value = 53; // "object $sha1\ntype " oType = Constants.decodeTypeString(this, rawTag, (byte) '\n', pos); walk.idBuffer.fromString(rawTag, 7); object = walk.lookupAny(walk.idBuffer, oType); int p = pos.value += 4; // "tag " final int nameEnd = RawParseUtils.nextLF(rawTag, p) - 1; tagName = RawParseUtils.decode(Constants.CHARSET, rawTag, p, nameEnd); if (walk.isRetainBody()) buffer = rawTag; flags |= PARSED; }
@Override void parseBody(final RevWalk walk) throws MissingObjectException, IncorrectObjectTypeException, IOException { if (buffer == null) { buffer = walk.getCachedBytes(this); if ((flags & PARSED) == 0) parseCanonical(walk, buffer); } }
@Override protected void reset(final int retainFlags) { super.reset(retainFlags); pendingObjects = new BlockObjQueue(); treeWalk = new CanonicalTreeParser(); currentTree = null; last = null; }
@Override public void dispose() { super.dispose(); pendingObjects = new BlockObjQueue(); treeWalk = new CanonicalTreeParser(); currentTree = null; last = null; }
/** * Mark an object or commit to start graph traversal from. * * <p>Callers are encouraged to use {@link RevWalk#parseAny(AnyObjectId)} instead of {@link * RevWalk#lookupAny(AnyObjectId, int)}, as this method requires the object to be parsed before it * can be added as a root for the traversal. * * <p>The method will automatically parse an unparsed object, but error handling may be more * difficult for the application to explain why a RevObject is not actually valid. The object pool * of this walker would also be 'poisoned' by the invalid RevObject. * * <p>This method will automatically call {@link RevWalk#markStart(RevCommit)} if passed RevCommit * instance, or a RevTag that directly (or indirectly) references a RevCommit. * * @param o the object to start traversing from. The object passed must be from this same revision * walker. * @throws MissingObjectException the object supplied is not available from the object database. * This usually indicates the supplied object is invalid, but the reference was constructed * during an earlier invocation to {@link RevWalk#lookupAny(AnyObjectId, int)}. * @throws IncorrectObjectTypeException the object was not parsed yet and it was discovered during * parsing that it is not actually the type of the instance passed in. This usually indicates * the caller used the wrong type in a {@link RevWalk#lookupAny(AnyObjectId, int)} call. * @throws IOException a pack file or loose object could not be read. */ public void markStart(RevObject o) throws MissingObjectException, IncorrectObjectTypeException, IOException { while (o instanceof RevTag) { addObject(o); o = ((RevTag) o).getObject(); parseHeaders(o); } if (o instanceof RevCommit) super.markStart((RevCommit) o); else addObject(o); }
/** * Mark an object to not produce in the output. * * <p>Uninteresting objects denote not just themselves but also their entire reachable chain, back * until the merge base of an uninteresting commit and an otherwise interesting commit. * * <p>Callers are encouraged to use {@link RevWalk#parseAny(AnyObjectId)} instead of {@link * RevWalk#lookupAny(AnyObjectId, int)}, as this method requires the object to be parsed before it * can be added as a root for the traversal. * * <p>The method will automatically parse an unparsed object, but error handling may be more * difficult for the application to explain why a RevObject is not actually valid. The object pool * of this walker would also be 'poisoned' by the invalid RevObject. * * <p>This method will automatically call {@link RevWalk#markStart(RevCommit)} if passed RevCommit * instance, or a RevTag that directly (or indirectly) references a RevCommit. * * @param o the object to start traversing from. The object passed must be * @throws MissingObjectException the object supplied is not available from the object database. * This usually indicates the supplied object is invalid, but the reference was constructed * during an earlier invocation to {@link RevWalk#lookupAny(AnyObjectId, int)}. * @throws IncorrectObjectTypeException the object was not parsed yet and it was discovered during * parsing that it is not actually the type of the instance passed in. This usually indicates * the caller used the wrong type in a {@link RevWalk#lookupAny(AnyObjectId, int)} call. * @throws IOException a pack file or loose object could not be read. */ public void markUninteresting(RevObject o) throws MissingObjectException, IncorrectObjectTypeException, IOException { while (o instanceof RevTag) { o.flags |= UNINTERESTING; if (hasRevSort(RevSort.BOUNDARY)) addObject(o); o = ((RevTag) o).getObject(); parseHeaders(o); } if (o instanceof RevCommit) super.markUninteresting((RevCommit) o); else if (o instanceof RevTree) markTreeUninteresting((RevTree) o); else o.flags |= UNINTERESTING; if (o.getType() != Constants.OBJ_COMMIT && hasRevSort(RevSort.BOUNDARY)) { addObject(o); } }
@Override void parseHeaders(final RevWalk walk) throws MissingObjectException, IncorrectObjectTypeException, IOException { parseCanonical(walk, walk.getCachedBytes(this)); }
@Override RevCommit next() throws MissingObjectException, IncorrectObjectTypeException, IOException { Generator g; final RevWalk w = walker; RevFilter rf = w.getRevFilter(); final TreeFilter tf = w.getTreeFilter(); AbstractRevQueue q = walker.queue; if (rf == RevFilter.MERGE_BASE) { // Computing for merge bases is a special case and does not // use the bulk of the generator pipeline. // if (tf != TreeFilter.ALL) throw new IllegalStateException( "Cannot combine TreeFilter " + tf + " with RevFilter " + rf + "."); final MergeBaseGenerator mbg = new MergeBaseGenerator(w); walker.pending = mbg; walker.queue = AbstractRevQueue.EMPTY_QUEUE; mbg.init(q); return mbg.next(); } final boolean uninteresting = q.anybodyHasFlag(RevWalk.UNINTERESTING); boolean boundary = walker.hasRevSort(RevSort.BOUNDARY); if (!boundary && walker instanceof ObjectWalk) { // The object walker requires boundary support to color // trees and blobs at the boundary uninteresting so it // does not produce those in the result. // boundary = true; } if (boundary && !uninteresting) { // If we were not fed uninteresting commits we will never // construct a boundary. There is no reason to include the // extra overhead associated with that in our pipeline. // boundary = false; } final DateRevQueue pending; int pendingOutputType = 0; if (q instanceof DateRevQueue) pending = (DateRevQueue) q; else pending = new DateRevQueue(q); if (tf != TreeFilter.ALL) { rf = AndRevFilter.create(rf, new RewriteTreeFilter(w, tf)); pendingOutputType |= HAS_REWRITE | NEEDS_REWRITE; } walker.queue = q; g = new PendingGenerator(w, pending, rf, pendingOutputType); if (boundary) { // Because the boundary generator may produce uninteresting // commits we cannot allow the pending generator to dispose // of them early. // ((PendingGenerator) g).canDispose = false; } if ((g.outputType() & NEEDS_REWRITE) != 0) { // Correction for an upstream NEEDS_REWRITE is to buffer // fully and then apply a rewrite generator that can // pull through the rewrite chain and produce a dense // output graph. // g = new FIFORevQueue(g); g = new RewriteGenerator(g); } if (walker.hasRevSort(RevSort.TOPO) && (g.outputType() & SORT_TOPO) == 0) g = new TopoSortGenerator(g); if (walker.hasRevSort(RevSort.REVERSE)) g = new LIFORevQueue(g); if (boundary) g = new BoundaryGenerator(w, g); else if (uninteresting) { // Try to protect ourselves from uninteresting commits producing // due to clock skew in the commit time stamps. Delay such that // we have a chance at coloring enough of the graph correctly, // and then strip any UNINTERESTING nodes that may have leaked // through early. // if (pending.peek() != null) g = new DelayRevQueue(g); g = new FixUninterestingGenerator(g); } w.pending = g; return g.next(); }