Use try-with-resource to avoid leaks with RevWalk and TreeWalk
[egit/eclipse.git] / org.eclipse.egit.ui / src / org / eclipse / egit / ui / internal / synchronize / model / GitModelBlob.java
blob80487b87d8db850133813a90b4dcafef2b30b71f
1 /*******************************************************************************
2 * Copyright (C) 2010, Dariusz Luksza <dariusz@luksza.org>
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *******************************************************************************/
9 package org.eclipse.egit.ui.internal.synchronize.model;
11 import static org.eclipse.compare.structuremergeviewer.Differencer.RIGHT;
12 import static org.eclipse.egit.ui.internal.synchronize.compare.GitCompareInput.getFileRevisionLabel;
13 import static org.eclipse.jgit.lib.ObjectId.zeroId;
15 import java.io.IOException;
17 import org.eclipse.compare.CompareConfiguration;
18 import org.eclipse.compare.IResourceProvider;
19 import org.eclipse.compare.ITypedElement;
20 import org.eclipse.compare.structuremergeviewer.ICompareInput;
21 import org.eclipse.compare.structuremergeviewer.ICompareInputChangeListener;
22 import org.eclipse.core.resources.IFile;
23 import org.eclipse.core.resources.IResource;
24 import org.eclipse.core.resources.ResourcesPlugin;
25 import org.eclipse.core.runtime.CoreException;
26 import org.eclipse.core.runtime.IPath;
27 import org.eclipse.core.runtime.IProgressMonitor;
28 import org.eclipse.egit.core.Activator;
29 import org.eclipse.egit.core.synchronize.GitCommitsModelCache.Change;
30 import org.eclipse.egit.ui.internal.synchronize.compare.ComparisonDataSource;
31 import org.eclipse.egit.ui.internal.synchronize.compare.GitCompareInput;
32 import org.eclipse.jgit.lib.AbbreviatedObjectId;
33 import org.eclipse.jgit.lib.ObjectId;
34 import org.eclipse.jgit.lib.Repository;
35 import org.eclipse.jgit.revwalk.RevCommit;
36 import org.eclipse.jgit.revwalk.RevWalk;
37 import org.eclipse.swt.graphics.Image;
38 import org.eclipse.team.ui.mapping.ISynchronizationCompareInput;
39 import org.eclipse.team.ui.mapping.SaveableComparison;
41 /**
42 * Git blob object representation in Git ChangeSet
44 public class GitModelBlob extends GitModelObject implements
45 ISynchronizationCompareInput, IResourceProvider {
47 private static final GitModelObject[] empty = new GitModelObject[0];
49 private final Change change;
51 private ITypedElement ancestorElement;
53 private ITypedElement leftElement;
55 private ITypedElement rightElement;
57 /**
58 * Absolute path to changed object
60 protected final IPath path;
62 /**
63 * {@link Repository} associated with this object
65 protected final Repository repo;
67 /**
68 * @param parent
69 * parent object
70 * @param repo
71 * repository associated with this object
72 * @param change
73 * change associated with this object
74 * @param path
75 * absolute path of change
77 public GitModelBlob(GitModelObjectContainer parent, Repository repo,
78 Change change, IPath path) {
79 super(parent);
80 this.repo = repo;
81 this.path = path;
82 this.change = change;
85 @Override
86 public GitModelObject[] getChildren() {
87 return empty;
90 @Override
91 public String getName() {
92 return path.lastSegment();
95 @Override
96 public IPath getLocation() {
97 return path;
100 @Override
101 public boolean isContainer() {
102 return false;
105 @Override
106 public int getKind() {
107 return change.getKind();
111 * @return abbreviated object id of base commit
113 public AbbreviatedObjectId getBaseCommitId() {
114 return change.getCommitId();
118 * @return abbreviated object id of remote commit
120 public AbbreviatedObjectId getRemoteCommitId() {
121 return change.getRemoteCommitId();
124 @Override
125 public int repositoryHashCode() {
126 return repo.getWorkTree().hashCode();
129 @Override
130 public void dispose() {
131 // there is nothing to dispose
134 @Override
135 public String toString() {
136 return "ModelBlob[objectId=" + change.getObjectId() + ", location=" + getLocation() + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
139 @Override
140 public Image getImage() {
141 // not used
142 return null;
145 @Override
146 public ITypedElement getAncestor() {
147 prepareTypedElements();
148 return ancestorElement;
151 @Override
152 public ITypedElement getLeft() {
153 prepareTypedElements();
154 return leftElement;
157 @Override
158 public ITypedElement getRight() {
159 prepareTypedElements();
160 return rightElement;
163 @Override
164 public void addCompareInputChangeListener(
165 ICompareInputChangeListener listener) {
166 // data in commit will never change, therefore change listeners are
167 // useless
170 @Override
171 public void removeCompareInputChangeListener(
172 ICompareInputChangeListener listener) {
173 // data in commit will never change, therefore change listeners are
174 // useless
177 @Override
178 public void copy(boolean leftToRight) {
179 // do nothing, we should disallow coping content between commits
182 @Override
183 public SaveableComparison getSaveable() {
184 // unused
185 return null;
188 @Override
189 public void prepareInput(CompareConfiguration configuration,
190 IProgressMonitor monitor) throws CoreException {
191 configuration.setLeftLabel(getFileRevisionLabel(getLeft()));
192 configuration.setRightLabel(getFileRevisionLabel(getRight()));
195 @Override
196 public String getFullPath() {
197 return path.toOSString();
200 @Override
201 public boolean isCompareInputFor(Object object) {
202 // not used
203 return false;
206 @Override
207 public int hashCode() {
208 int baseHash = 1;
209 if (change != null)
210 baseHash = change.getObjectId() != null ? change.getObjectId()
211 .hashCode() : 31;
212 int remoteHash = 11;
213 if (change != null)
214 remoteHash = change.getRemoteObjectId() != null ? change
215 .getRemoteObjectId().hashCode() : 41;
217 return baseHash ^ remoteHash ^ path.hashCode();
220 @Override
221 public boolean equals(Object obj) {
222 if (this == obj)
223 return true;
224 if (obj == null)
225 return false;
226 if (getClass() != obj.getClass())
227 return false;
228 GitModelBlob other = (GitModelBlob) obj;
229 if (change == null) {
230 if (other.change != null)
231 return false;
232 } else if (!change.equals(other.change))
233 return false;
234 if (path == null) {
235 if (other.path != null)
236 return false;
237 } else if (!path.equals(other.path))
238 return false;
240 return true;
243 private void prepareTypedElements() {
244 if (ancestorElement != null) // other elements should also not be null
245 return;
247 ComparisonDataSource baseData;
248 ComparisonDataSource remoteData;
250 RevCommit baseCommit = null;
251 RevCommit remoteCommit = null;
252 try (RevWalk rw = new RevWalk(repo)) {
253 rw.setRetainBody(true);
254 if (change.getCommitId() != null)
255 baseCommit = rw.parseCommit(change.getCommitId().toObjectId());
256 if (change.getRemoteCommitId() != null)
257 remoteCommit = rw.parseCommit(change.getRemoteCommitId()
258 .toObjectId());
259 } catch (IOException e) {
260 Activator.logError(e.getMessage(), e);
262 if (baseCommit == null && remoteCommit != null)
263 baseCommit = remoteCommit; // prevent from NPE for deleted files
265 ObjectId localId = extractObjectId(change.getObjectId());
266 ObjectId remoteId = extractObjectId(change.getRemoteObjectId());
268 if ((getKind() & RIGHT) == RIGHT) {
269 baseData = new ComparisonDataSource(baseCommit, localId);
270 remoteData = new ComparisonDataSource(remoteCommit, remoteId);
271 } else /* getKind() == LEFT */{
272 baseData = new ComparisonDataSource(remoteCommit, remoteId);
273 remoteData = new ComparisonDataSource(baseCommit, localId);
276 GitCompareInput compareInput = getCompareInput(baseData, remoteData, remoteData);
278 ancestorElement = compareInput.getAncestor();
279 leftElement = compareInput.getLeft();
280 rightElement = compareInput.getRight();
283 @Override
284 public IResource getResource() {
285 IFile file = ResourcesPlugin.getWorkspace().getRoot()
286 .getFileForLocation(path);
288 return file;
292 * Returns specific instance of {@link GitCompareInput} for particular
293 * compare input.
295 * @param baseData
296 * @param remoteData
297 * @param ancestorData
298 * @return Git specific {@link ICompareInput}
300 protected GitCompareInput getCompareInput(ComparisonDataSource baseData,
301 ComparisonDataSource remoteData, ComparisonDataSource ancestorData) {
302 String gitPath = Repository.stripWorkDir(repo.getWorkTree(), path.toFile());
304 return new GitCompareInput(repo, ancestorData, baseData, remoteData,
305 gitPath);
308 private ObjectId extractObjectId(AbbreviatedObjectId objectId) {
309 if (objectId != null)
310 return objectId.toObjectId();
311 else
312 return zeroId();