Use try-with-resource to avoid leaks with RevWalk and TreeWalk
[egit/eclipse.git] / org.eclipse.egit.ui / src / org / eclipse / egit / ui / internal / search / CommitSearchQuery.java
blob5b61ebeaa6581e9dd11b2939c2eec3e11e405d54
1 /*******************************************************************************
2 * Copyright (c) 2011 GitHub Inc.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
8 * Contributors:
9 * Kevin Sawicki (GitHub Inc.) - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.egit.ui.internal.search;
13 import java.io.File;
14 import java.io.IOException;
15 import java.text.MessageFormat;
16 import java.util.LinkedList;
17 import java.util.List;
18 import java.util.regex.Pattern;
20 import org.eclipse.core.runtime.IProgressMonitor;
21 import org.eclipse.core.runtime.IStatus;
22 import org.eclipse.core.runtime.OperationCanceledException;
23 import org.eclipse.core.runtime.Status;
24 import org.eclipse.egit.core.Activator;
25 import org.eclipse.egit.ui.internal.UIText;
26 import org.eclipse.egit.ui.internal.commit.RepositoryCommit;
27 import org.eclipse.jgit.lib.Constants;
28 import org.eclipse.jgit.lib.ObjectId;
29 import org.eclipse.jgit.lib.PersonIdent;
30 import org.eclipse.jgit.lib.Ref;
31 import org.eclipse.jgit.lib.Repository;
32 import org.eclipse.jgit.revwalk.RevCommit;
33 import org.eclipse.jgit.revwalk.RevTree;
34 import org.eclipse.jgit.revwalk.RevWalk;
35 import org.eclipse.search.ui.ISearchQuery;
36 import org.eclipse.search.ui.ISearchResult;
38 /**
39 * Commit search query class that runs a {@link RevWalk} for all
40 * {@link Repository} objects included in the {@link CommitSearchSettings} and
41 * matches all {@link RevCommit} objects against the search settings.
43 public class CommitSearchQuery implements ISearchQuery {
45 private abstract class SearchMatcher {
47 abstract boolean matches(Pattern pattern, RevCommit commit);
49 protected boolean matches(Pattern pattern, String input) {
50 return input != null && input.length() > 0
51 && pattern.matcher(input).find();
56 private class AuthorMatcher extends SearchMatcher {
58 @Override
59 public boolean matches(Pattern pattern, RevCommit commit) {
60 PersonIdent author = commit.getAuthorIdent();
61 if (author != null)
62 return matches(pattern, author.getName())
63 || matches(pattern, author.getEmailAddress());
64 else
65 return false;
69 private class CommitterMatcher extends SearchMatcher {
71 @Override
72 public boolean matches(Pattern pattern, RevCommit commit) {
73 PersonIdent committer = commit.getCommitterIdent();
74 if (committer != null)
75 return matches(pattern, committer.getName())
76 || matches(pattern, committer.getEmailAddress());
77 else
78 return false;
82 private class MessageMatcher extends SearchMatcher {
84 @Override
85 public boolean matches(Pattern pattern, RevCommit commit) {
86 return matches(pattern, commit.getFullMessage());
90 private class CommitNameMatcher extends SearchMatcher {
92 @Override
93 public boolean matches(Pattern pattern, RevCommit commit) {
94 return matches(pattern, commit.name());
99 private class TreeMatcher extends SearchMatcher {
101 @Override
102 public boolean matches(Pattern pattern, RevCommit commit) {
103 RevTree tree = commit.getTree();
104 return tree != null ? matches(pattern, tree.name()) : false;
108 private class ParentMatcher extends SearchMatcher {
110 @Override
111 public boolean matches(Pattern pattern, RevCommit commit) {
112 for (RevCommit parent : commit.getParents())
113 if (matches(pattern, parent.name()))
114 return true;
115 return false;
120 private CommitSearchResult result = new CommitSearchResult(this);
122 private CommitSearchSettings settings;
124 private List<SearchMatcher> matchers = new LinkedList<SearchMatcher>();
127 * Create git search query
129 * @param settings
131 public CommitSearchQuery(CommitSearchSettings settings) {
132 this.settings = settings;
134 if (this.settings.isMatchAuthor())
135 matchers.add(new AuthorMatcher());
136 if (this.settings.isMatchCommitter())
137 matchers.add(new CommitterMatcher());
138 if (this.settings.isMatchMessage())
139 matchers.add(new MessageMatcher());
140 if (this.settings.isMatchCommit())
141 matchers.add(new CommitNameMatcher());
142 if (this.settings.isMatchTree())
143 matchers.add(new TreeMatcher());
144 if (this.settings.isMatchParents())
145 matchers.add(new ParentMatcher());
149 * Get text pattern being searched for
151 * @return pattern
153 public String getPattern() {
154 return this.settings.getTextPattern();
157 private Repository getRepository(String name) throws IOException {
158 Repository repository = null;
159 File path = new File(name);
160 if (path.exists())
161 repository = Activator.getDefault().getRepositoryCache()
162 .lookupRepository(path);
163 return repository;
167 * @see org.eclipse.search.ui.ISearchQuery#run(org.eclipse.core.runtime.IProgressMonitor)
169 @Override
170 public IStatus run(IProgressMonitor monitor)
171 throws OperationCanceledException {
172 this.result.removeAll();
174 Pattern pattern = PatternUtils.createPattern(
175 this.settings.getTextPattern(),
176 this.settings.isCaseSensitive(), this.settings.isRegExSearch());
177 List<String> paths = settings.getRepositories();
178 try {
179 for (String path : paths) {
180 if (monitor.isCanceled())
181 throw new OperationCanceledException();
183 Repository repo = getRepository(path);
184 if (repo == null)
185 continue;
187 monitor.setTaskName(MessageFormat.format(
188 UIText.CommitSearchQuery_TaskSearchCommits, repo
189 .getDirectory().getParentFile().getName()));
190 walkRepository(repo, pattern, monitor);
192 } catch (IOException e) {
193 org.eclipse.egit.ui.Activator.handleError(
194 "Error searching commits", e, true); //$NON-NLS-1$
196 return Status.OK_STATUS;
199 private void walkRepository(Repository repository, Pattern pattern,
200 IProgressMonitor monitor) throws IOException {
201 try (RevWalk walk = new RevWalk(repository)) {
202 walk.setRetainBody(true);
203 List<RevCommit> commits = new LinkedList<RevCommit>();
204 if (this.settings.isAllBranches()) {
205 for (Ref ref : repository.getRefDatabase()
206 .getRefs(Constants.R_HEADS).values())
207 if (!ref.isSymbolic())
208 commits.add(walk.parseCommit(ref.getObjectId()));
209 for (Ref ref : repository.getRefDatabase()
210 .getRefs(Constants.R_REMOTES).values())
211 if (!ref.isSymbolic())
212 commits.add(walk.parseCommit(ref.getObjectId()));
213 } else {
214 ObjectId headCommit = repository.resolve(Constants.HEAD);
215 if (headCommit != null)
216 commits.add(walk.parseCommit(headCommit));
219 if (!commits.isEmpty()) {
220 walk.markStart(commits);
221 for (RevCommit commit : walk) {
222 if (monitor.isCanceled())
223 throw new OperationCanceledException();
224 for (SearchMatcher matcher : this.matchers)
225 if (matcher.matches(pattern, commit)) {
226 result.addResult(new RepositoryCommit(repository,
227 commit));
228 break;
236 * @see org.eclipse.search.ui.ISearchQuery#getLabel()
238 @Override
239 public String getLabel() {
240 return UIText.CommitSearchQuery_Label;
244 * @see org.eclipse.search.ui.ISearchQuery#canRerun()
246 @Override
247 public boolean canRerun() {
248 return true;
252 * @see org.eclipse.search.ui.ISearchQuery#canRunInBackground()
254 @Override
255 public boolean canRunInBackground() {
256 return true;
260 * @see org.eclipse.search.ui.ISearchQuery#getSearchResult()
262 @Override
263 public ISearchResult getSearchResult() {
264 return this.result;