| Jonathan Nieder | e5a8b41 | 2019-11-25 15:59:25 -0800 | [diff] [blame] | 1 | // Copyright 2019 Google LLC |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // https://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| Ivan Frade | ac7d524 | 2019-05-23 15:32:11 -0700 | [diff] [blame] | 15 | package com.google.gitiles; |
| 16 | |
| Ivan Frade | f0b1806 | 2019-05-09 11:51:41 -0700 | [diff] [blame] | 17 | import com.google.common.collect.ImmutableList; |
| Ivan Frade | ac7d524 | 2019-05-23 15:32:11 -0700 | [diff] [blame] | 18 | import java.io.IOException; |
| 19 | import java.util.Collection; |
| 20 | import org.eclipse.jgit.errors.IncorrectObjectTypeException; |
| 21 | import org.eclipse.jgit.errors.MissingObjectException; |
| 22 | import org.eclipse.jgit.lib.ObjectId; |
| Ivan Frade | ac7d524 | 2019-05-23 15:32:11 -0700 | [diff] [blame] | 23 | import org.eclipse.jgit.lib.RefDatabase; |
| 24 | import org.eclipse.jgit.revwalk.RevCommit; |
| Ivan Frade | ac7d524 | 2019-05-23 15:32:11 -0700 | [diff] [blame] | 25 | import org.eclipse.jgit.revwalk.RevWalk; |
| 26 | |
| 27 | /** |
| 28 | * Checks for object visibility |
| 29 | * |
| 30 | * <p>Objects are visible if they are reachable from any of the references visible to the user. |
| 31 | */ |
| 32 | public class VisibilityChecker { |
| 33 | |
| Ivan Frade | ac7d524 | 2019-05-23 15:32:11 -0700 | [diff] [blame] | 34 | /** |
| 35 | * Check if any of the refs in {@code refDb} points to the object {@code id}. |
| 36 | * |
| 37 | * @param refDb a reference database |
| 38 | * @param id object we are looking for |
| 39 | * @return true if the any of the references in the db points directly to the id |
| 40 | * @throws IOException the reference space cannot be accessed |
| 41 | */ |
| 42 | protected boolean isTipOfBranch(RefDatabase refDb, ObjectId id) throws IOException { |
| 43 | // If any reference directly points at the requested object, permit display. Common for displays |
| 44 | // of pending patch sets in Gerrit Code Review, or bookmarks to the commit a tag points at. |
| Ivan Frade | 13cb517 | 2019-04-08 15:51:03 -0700 | [diff] [blame] | 45 | return !refDb.getTipsWithSha1(id).isEmpty(); |
| Ivan Frade | ac7d524 | 2019-05-23 15:32:11 -0700 | [diff] [blame] | 46 | } |
| 47 | |
| 48 | /** |
| 49 | * Check if {@code commit} is reachable starting from {@code starters}. |
| 50 | * |
| 51 | * @param description Description of the ids (e.g. "heads"). Mainly for tracing. |
| 52 | * @param walk The walk to use for the reachability check |
| 53 | * @param commit The starting commit. It *MUST* come from the walk in use |
| 54 | * @param starters visible commits. Anything reachable from these commits is visible. Missing ids |
| Ivan Frade | f0b1806 | 2019-05-09 11:51:41 -0700 | [diff] [blame] | 55 | * or ids referring to other kinds of objects are ignored. |
| Ivan Frade | ac7d524 | 2019-05-23 15:32:11 -0700 | [diff] [blame] | 56 | * @return true if we can get to {@code commit} from the {@code starters} |
| 57 | * @throws IOException a pack file or loose object could not be read |
| 58 | */ |
| 59 | protected boolean isReachableFrom( |
| David Pursehouse | d79cca7 | 2019-06-10 12:32:46 +0900 | [diff] [blame] | 60 | String description, RevWalk walk, RevCommit commit, Collection<ObjectId> starters) |
| Ivan Frade | ac7d524 | 2019-05-23 15:32:11 -0700 | [diff] [blame] | 61 | throws IOException { |
| 62 | if (starters.isEmpty()) { |
| 63 | return false; |
| 64 | } |
| 65 | |
| Ivan Frade | f0b1806 | 2019-05-09 11:51:41 -0700 | [diff] [blame] | 66 | ImmutableList<RevCommit> startCommits = objectIdsToCommits(walk, starters); |
| 67 | if (startCommits.isEmpty()) { |
| 68 | return false; |
| Ivan Frade | ac7d524 | 2019-05-23 15:32:11 -0700 | [diff] [blame] | 69 | } |
| 70 | |
| Ivan Frade | f0b1806 | 2019-05-09 11:51:41 -0700 | [diff] [blame] | 71 | return !walk.createReachabilityChecker() |
| 72 | .areAllReachable(ImmutableList.of(commit), startCommits) |
| 73 | .isPresent(); |
| Ivan Frade | ac7d524 | 2019-05-23 15:32:11 -0700 | [diff] [blame] | 74 | } |
| 75 | |
| Ivan Frade | f0b1806 | 2019-05-09 11:51:41 -0700 | [diff] [blame] | 76 | private static ImmutableList<RevCommit> objectIdsToCommits(RevWalk walk, Collection<ObjectId> ids) |
| 77 | throws IOException { |
| 78 | ImmutableList.Builder<RevCommit> commits = ImmutableList.builder(); |
| 79 | for (ObjectId id : ids) { |
| 80 | try { |
| 81 | commits.add(walk.parseCommit(id)); |
| 82 | } catch (MissingObjectException e) { |
| 83 | // TODO(ifrade): ResolveParser has already checked that the object exists in the repo. |
| 84 | // Report as AssertionError. |
| 85 | } catch (IncorrectObjectTypeException e) { |
| 86 | // Ignore, doesn't affect commit reachability |
| 87 | } |
| Ivan Frade | ac7d524 | 2019-05-23 15:32:11 -0700 | [diff] [blame] | 88 | } |
| Ivan Frade | f0b1806 | 2019-05-09 11:51:41 -0700 | [diff] [blame] | 89 | return commits.build(); |
| Ivan Frade | ac7d524 | 2019-05-23 15:32:11 -0700 | [diff] [blame] | 90 | } |
| 91 | } |