StartGenerator.java

  1. /*
  2.  * Copyright (C) 2008-2009, Google Inc.
  3.  * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
  4.  * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others
  5.  *
  6.  * This program and the accompanying materials are made available under the
  7.  * terms of the Eclipse Distribution License v. 1.0 which is available at
  8.  * https://www.eclipse.org/org/documents/edl-v10.php.
  9.  *
  10.  * SPDX-License-Identifier: BSD-3-Clause
  11.  */

  12. package org.eclipse.jgit.revwalk;

  13. import java.io.IOException;
  14. import java.text.MessageFormat;

  15. import org.eclipse.jgit.errors.IncorrectObjectTypeException;
  16. import org.eclipse.jgit.errors.MissingObjectException;
  17. import org.eclipse.jgit.internal.JGitText;
  18. import org.eclipse.jgit.revwalk.filter.AndRevFilter;
  19. import org.eclipse.jgit.revwalk.filter.RevFilter;
  20. import org.eclipse.jgit.treewalk.filter.TreeFilter;

  21. /**
  22.  * Initial RevWalk generator that bootstraps a new walk.
  23.  * <p>
  24.  * Initially RevWalk starts with this generator as its chosen implementation.
  25.  * The first request for a RevCommit from the RevWalk instance calls to our
  26.  * {@link #next()} method, and we replace ourselves with the best Generator
  27.  * implementation available based upon the current RevWalk configuration.
  28.  */
  29. class StartGenerator extends Generator {
  30.     private final RevWalk walker;

  31.     StartGenerator(RevWalk w) {
  32.         super(w.isFirstParent());
  33.         walker = w;
  34.     }

  35.     @Override
  36.     int outputType() {
  37.         return 0;
  38.     }

  39.     @Override
  40.     RevCommit next() throws MissingObjectException,
  41.             IncorrectObjectTypeException, IOException {
  42.         Generator g;

  43.         final RevWalk w = walker;
  44.         RevFilter rf = w.getRevFilter();
  45.         final TreeFilter tf = w.getTreeFilter();
  46.         AbstractRevQueue q = walker.queue;

  47.         if (rf == RevFilter.MERGE_BASE) {
  48.             // Computing for merge bases is a special case and does not
  49.             // use the bulk of the generator pipeline.
  50.             //
  51.             if (tf != TreeFilter.ALL) {
  52.                 throw new IllegalStateException(MessageFormat.format(
  53.                         JGitText.get().cannotCombineTreeFilterWithRevFilter, tf, rf));
  54.             }
  55.             if (w.isFirstParent()) {
  56.                 throw new IllegalStateException(
  57.                         JGitText.get().cannotFindMergeBaseUsingFirstParent);
  58.             }

  59.             final MergeBaseGenerator mbg = new MergeBaseGenerator(w);
  60.             walker.pending = mbg;
  61.             walker.queue = AbstractRevQueue.EMPTY_QUEUE;
  62.             mbg.init(q);
  63.             return mbg.next();
  64.         }

  65.         final boolean uninteresting = q.anybodyHasFlag(RevWalk.UNINTERESTING);
  66.         boolean boundary = walker.hasRevSort(RevSort.BOUNDARY);

  67.         if (!boundary && walker instanceof ObjectWalk) {
  68.             // The object walker requires boundary support to color
  69.             // trees and blobs at the boundary uninteresting so it
  70.             // does not produce those in the result.
  71.             //
  72.             boundary = true;
  73.         }
  74.         if (boundary && !uninteresting) {
  75.             // If we were not fed uninteresting commits we will never
  76.             // construct a boundary. There is no reason to include the
  77.             // extra overhead associated with that in our pipeline.
  78.             //
  79.             boundary = false;
  80.         }

  81.         final DateRevQueue pending;
  82.         int pendingOutputType = 0;
  83.         if (q instanceof DateRevQueue)
  84.             pending = (DateRevQueue)q;
  85.         else
  86.             pending = new DateRevQueue(q);
  87.         if (tf != TreeFilter.ALL) {
  88.             int rewriteFlag;
  89.             if (w.getRewriteParents()) {
  90.                 pendingOutputType |= HAS_REWRITE | NEEDS_REWRITE;
  91.                 rewriteFlag = RevWalk.REWRITE;
  92.             } else
  93.                 rewriteFlag = 0;
  94.             rf = AndRevFilter.create(new TreeRevFilter(w, tf, rewriteFlag), rf);
  95.         }

  96.         walker.queue = q;

  97.         if (walker instanceof DepthWalk) {
  98.             DepthWalk dw = (DepthWalk) walker;
  99.             g = new DepthGenerator(dw, pending);
  100.         } else {
  101.             g = new PendingGenerator(w, pending, rf, pendingOutputType);

  102.             if (walker.hasRevSort(RevSort.BOUNDARY)) {
  103.                 // Because the boundary generator may produce uninteresting
  104.                 // commits we cannot allow the pending generator to dispose
  105.                 // of them early.
  106.                 //
  107.                 ((PendingGenerator) g).canDispose = false;
  108.             }
  109.         }

  110.         if ((g.outputType() & NEEDS_REWRITE) != 0) {
  111.             // Correction for an upstream NEEDS_REWRITE is to buffer
  112.             // fully and then apply a rewrite generator that can
  113.             // pull through the rewrite chain and produce a dense
  114.             // output graph.
  115.             //
  116.             g = new FIFORevQueue(g);
  117.             g = new RewriteGenerator(g);
  118.         }

  119.         if (walker.hasRevSort(RevSort.TOPO)
  120.                 && walker.hasRevSort(RevSort.TOPO_KEEP_BRANCH_TOGETHER)) {
  121.             throw new IllegalStateException(JGitText
  122.                     .get().cannotCombineTopoSortWithTopoKeepBranchTogetherSort);
  123.         }

  124.         if (walker.hasRevSort(RevSort.TOPO)
  125.                 && (g.outputType() & SORT_TOPO) == 0) {
  126.             g = new TopoSortGenerator(g);
  127.         } else if (walker.hasRevSort(RevSort.TOPO_KEEP_BRANCH_TOGETHER)
  128.                 && (g.outputType() & SORT_TOPO) == 0) {
  129.             g = new TopoNonIntermixSortGenerator(g);
  130.         }
  131.         if (walker.hasRevSort(RevSort.REVERSE))
  132.             g = new LIFORevQueue(g);
  133.         if (boundary)
  134.             g = new BoundaryGenerator(w, g);
  135.         else if (uninteresting) {
  136.             // Try to protect ourselves from uninteresting commits producing
  137.             // due to clock skew in the commit time stamps. Delay such that
  138.             // we have a chance at coloring enough of the graph correctly,
  139.             // and then strip any UNINTERESTING nodes that may have leaked
  140.             // through early.
  141.             //
  142.             if (pending.peek() != null)
  143.                 g = new DelayRevQueue(g);
  144.             g = new FixUninterestingGenerator(g);
  145.         }

  146.         w.pending = g;
  147.         return g.next();
  148.     }
  149. }