View Javadoc
1   /*
2    * Copyright (C) 2020, Google LLC and others
3    *
4    * This program and the accompanying materials are made available under the
5    * terms of the Eclipse Distribution License v. 1.0 which is available at
6    * https://www.eclipse.org/org/documents/edl-v10.php.
7    *
8    * SPDX-License-Identifier: BSD-3-Clause
9    */
10  package org.eclipse.jgit.internal.revwalk;
11  
12  import java.io.IOException;
13  import java.io.InvalidObjectException;
14  import java.util.Collection;
15  import java.util.Iterator;
16  import java.util.Optional;
17  import java.util.stream.Stream;
18  
19  import org.eclipse.jgit.errors.MissingObjectException;
20  import org.eclipse.jgit.revwalk.ObjectReachabilityChecker;
21  import org.eclipse.jgit.revwalk.ObjectWalk;
22  import org.eclipse.jgit.revwalk.RevCommit;
23  import org.eclipse.jgit.revwalk.RevObject;
24  import org.eclipse.jgit.revwalk.RevSort;
25  
26  /**
27   * Checks if all objects are reachable from certain starting points doing a
28   * walk.
29   */
30  public class PedestrianObjectReachabilityChecker
31  		implements ObjectReachabilityChecker {
32  	private final ObjectWalk walk;
33  
34  	/**
35  	 * New instance of the reachability checker using a existing walk.
36  	 *
37  	 * @param walk
38  	 *            ObjectWalk instance to reuse. Caller retains ownership.
39  	 */
40  	public PedestrianObjectReachabilityChecker(ObjectWalk walk) {
41  		this.walk = walk;
42  	}
43  
44  	/**
45  	 * {@inheritDoc}
46  	 */
47  	@Override
48  	public Optional<RevObject> areAllReachable(Collection<RevObject> targets,
49  			Stream<RevObject> starters) throws IOException {
50  		try {
51  			walk.reset();
52  			walk.sort(RevSort.TOPO);
53  			for (RevObject target : targets) {
54  				walk.markStart(target);
55  			}
56  
57  			Iterator<RevObject> iterator = starters.iterator();
58  			while (iterator.hasNext()) {
59  				RevObject o = iterator.next();
60  				walk.markUninteresting(o);
61  
62  				RevObject peeled = walk.peel(o);
63  				if (peeled instanceof RevCommit) {
64  					// By default, for performance reasons, ObjectWalk does not
65  					// mark
66  					// a tree as uninteresting when we mark a commit. Mark it
67  					// ourselves so that we can determine reachability exactly.
68  					walk.markUninteresting(((RevCommit) peeled).getTree());
69  				}
70  			}
71  
72  			RevCommit commit = walk.next();
73  			if (commit != null) {
74  				return Optional.of(commit);
75  			}
76  
77  			RevObject object = walk.nextObject();
78  			if (object != null) {
79  				return Optional.of(object);
80  			}
81  
82  			return Optional.empty();
83  		} catch (MissingObjectException | InvalidObjectException e) {
84  			throw new IllegalStateException(e);
85  		}
86  	}
87  }