View Javadoc
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  
13  package org.eclipse.jgit.revwalk;
14  
15  import java.io.IOException;
16  import java.text.MessageFormat;
17  
18  import org.eclipse.jgit.errors.IncorrectObjectTypeException;
19  import org.eclipse.jgit.errors.MissingObjectException;
20  import org.eclipse.jgit.internal.JGitText;
21  import org.eclipse.jgit.revwalk.filter.AndRevFilter;
22  import org.eclipse.jgit.revwalk.filter.RevFilter;
23  import org.eclipse.jgit.treewalk.filter.TreeFilter;
24  
25  /**
26   * Initial RevWalk generator that bootstraps a new walk.
27   * <p>
28   * Initially RevWalk starts with this generator as its chosen implementation.
29   * The first request for a RevCommit from the RevWalk instance calls to our
30   * {@link #next()} method, and we replace ourselves with the best Generator
31   * implementation available based upon the current RevWalk configuration.
32   */
33  class StartGenerator extends Generator {
34  	private final RevWalk walker;
35  
36  	StartGenerator(RevWalk w) {
37  		super(w.isFirstParent());
38  		walker = w;
39  	}
40  
41  	@Override
42  	int outputType() {
43  		return 0;
44  	}
45  
46  	@Override
47  	RevCommit next() throws MissingObjectException,
48  			IncorrectObjectTypeException, IOException {
49  		Generator g;
50  
51  		final RevWalk w = walker;
52  		RevFilter rf = w.getRevFilter();
53  		final TreeFilter tf = w.getTreeFilter();
54  		AbstractRevQueue q = walker.queue;
55  
56  		if (rf == RevFilter.MERGE_BASE) {
57  			// Computing for merge bases is a special case and does not
58  			// use the bulk of the generator pipeline.
59  			//
60  			if (tf != TreeFilter.ALL) {
61  				throw new IllegalStateException(MessageFormat.format(
62  						JGitText.get().cannotCombineTreeFilterWithRevFilter, tf, rf));
63  			}
64  			if (w.isFirstParent()) {
65  				throw new IllegalStateException(
66  						JGitText.get().cannotFindMergeBaseUsingFirstParent);
67  			}
68  
69  			final MergeBaseGeneratorerator.html#MergeBaseGenerator">MergeBaseGenerator mbg = new MergeBaseGenerator(w);
70  			walker.pending = mbg;
71  			walker.queue = AbstractRevQueue.EMPTY_QUEUE;
72  			mbg.init(q);
73  			return mbg.next();
74  		}
75  
76  		final boolean uninteresting = q.anybodyHasFlag(RevWalk.UNINTERESTING);
77  		boolean boundary = walker.hasRevSort(RevSort.BOUNDARY);
78  
79  		if (!boundary && walker instanceof ObjectWalk) {
80  			// The object walker requires boundary support to color
81  			// trees and blobs at the boundary uninteresting so it
82  			// does not produce those in the result.
83  			//
84  			boundary = true;
85  		}
86  		if (boundary && !uninteresting) {
87  			// If we were not fed uninteresting commits we will never
88  			// construct a boundary. There is no reason to include the
89  			// extra overhead associated with that in our pipeline.
90  			//
91  			boundary = false;
92  		}
93  
94  		final DateRevQueue pending;
95  		int pendingOutputType = 0;
96  		if (q instanceof DateRevQueue)
97  			pending = (DateRevQueue)q;
98  		else
99  			pending = new DateRevQueue(q);
100 		if (tf != TreeFilter.ALL) {
101 			int rewriteFlag;
102 			if (w.getRewriteParents()) {
103 				pendingOutputType |= HAS_REWRITE | NEEDS_REWRITE;
104 				rewriteFlag = RevWalk.REWRITE;
105 			} else
106 				rewriteFlag = 0;
107 			rf = AndRevFilter.create(new TreeRevFilter(w, tf, rewriteFlag), rf);
108 		}
109 
110 		walker.queue = q;
111 
112 		if (walker instanceof DepthWalk) {
113 			DepthWalk dw = (DepthWalk) walker;
114 			g = new DepthGenerator(dw, pending);
115 		} else {
116 			g = new PendingGenerator(w, pending, rf, pendingOutputType);
117 
118 			if (walker.hasRevSort(RevSort.BOUNDARY)) {
119 				// Because the boundary generator may produce uninteresting
120 				// commits we cannot allow the pending generator to dispose
121 				// of them early.
122 				//
123 				((PendingGenerator) g).canDispose = false;
124 			}
125 		}
126 
127 		if ((g.outputType() & NEEDS_REWRITE) != 0) {
128 			// Correction for an upstream NEEDS_REWRITE is to buffer
129 			// fully and then apply a rewrite generator that can
130 			// pull through the rewrite chain and produce a dense
131 			// output graph.
132 			//
133 			g = new FIFORevQueue(g);
134 			g = new RewriteGenerator(g);
135 		}
136 
137 		if (walker.hasRevSort(RevSort.TOPO)
138 				&& walker.hasRevSort(RevSort.TOPO_KEEP_BRANCH_TOGETHER)) {
139 			throw new IllegalStateException(JGitText
140 					.get().cannotCombineTopoSortWithTopoKeepBranchTogetherSort);
141 		}
142 
143 		if (walker.hasRevSort(RevSort.TOPO)
144 				&& (g.outputType() & SORT_TOPO) == 0) {
145 			g = new TopoSortGenerator(g);
146 		} else if (walker.hasRevSort(RevSort.TOPO_KEEP_BRANCH_TOGETHER)
147 				&& (g.outputType() & SORT_TOPO) == 0) {
148 			g = new TopoNonIntermixSortGenerator(g);
149 		}
150 		if (walker.hasRevSort(RevSort.REVERSE))
151 			g = new LIFORevQueue(g);
152 		if (boundary)
153 			g = new BoundaryGenerator(w, g);
154 		else if (uninteresting) {
155 			// Try to protect ourselves from uninteresting commits producing
156 			// due to clock skew in the commit time stamps. Delay such that
157 			// we have a chance at coloring enough of the graph correctly,
158 			// and then strip any UNINTERESTING nodes that may have leaked
159 			// through early.
160 			//
161 			if (pending.peek() != null)
162 				g = new DelayRevQueue(g);
163 			g = new FixUninterestingGenerator(g);
164 		}
165 
166 		w.pending = g;
167 		return g.next();
168 	}
169 }