2 * Copyright (C) 2006 Robin Rosenberg
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License, version 2.1, as published by the Free Software Foundation.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
17 package org
.spearce
.egit
.core
.internal
.mapping
;
19 import java
.io
.IOException
;
20 import java
.util
.ArrayList
;
21 import java
.util
.Collection
;
22 import java
.util
.Collections
;
23 import java
.util
.Date
;
24 import java
.util
.HashMap
;
25 import java
.util
.List
;
27 import java
.util
.concurrent
.CancellationException
;
29 import org
.eclipse
.core
.resources
.IContainer
;
30 import org
.eclipse
.core
.resources
.IResource
;
31 import org
.eclipse
.core
.runtime
.IAdaptable
;
32 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
33 import org
.eclipse
.team
.core
.RepositoryProvider
;
34 import org
.eclipse
.team
.core
.history
.IFileHistoryProvider
;
35 import org
.eclipse
.team
.core
.history
.IFileRevision
;
36 import org
.eclipse
.team
.core
.history
.provider
.FileHistory
;
37 import org
.spearce
.egit
.core
.GitIndexFileRevision
;
38 import org
.spearce
.egit
.core
.GitProvider
;
39 import org
.spearce
.egit
.core
.GitWorkspaceFileRevision
;
40 import org
.spearce
.egit
.core
.project
.RepositoryMapping
;
41 import org
.spearce
.jgit
.lib
.Commit
;
42 import org
.spearce
.jgit
.lib
.MappedList
;
43 import org
.spearce
.jgit
.lib
.ObjectId
;
44 import org
.spearce
.jgit
.lib
.Repository
;
45 import org
.spearce
.jgit
.lib
.SuperList
;
46 import org
.spearce
.jgit
.lib
.TopologicalWalker
;
47 import org
.spearce
.jgit
.lib
.Tree
;
48 import org
.spearce
.jgit
.lib
.TreeEntry
;
49 import org
.spearce
.jgit
.lib
.GitIndex
.Entry
;
51 public class GitFileHistory
extends FileHistory
implements IAdaptable
{
53 private final IResource resource
;
55 private final String
[] relativeResourceName
;
57 private final int flags
;
59 private List
<IFileRevision
> revisions
;
61 private final boolean returnAll
;
63 public GitFileHistory(IResource resource
, int flags
, IProgressMonitor monitor
, boolean returnAll
) {
64 this.resource
= resource
;
66 this.returnAll
= returnAll
;
67 String prefix
= RepositoryMapping
.getMapping(resource
).getSubset();
68 String
[] prefixSegments
= prefix
!=null ? prefix
.split("/") : new String
[0];
69 String
[] resourceSegments
= resource
.getProjectRelativePath().segments();
70 relativeResourceName
= new String
[prefixSegments
.length
+ resourceSegments
.length
];
71 System
.arraycopy(prefixSegments
, 0, relativeResourceName
, 0, prefixSegments
.length
);
72 System
.arraycopy(resourceSegments
, 0, relativeResourceName
, prefixSegments
.length
, resourceSegments
.length
);
73 if ((flags
& IFileHistoryProvider
.SINGLE_LINE_OF_DESCENT
) == 0) {
74 findSingleRevision(monitor
);
77 findRevisions(monitor
);
78 } catch (IOException e
) {
84 public IFileRevision
[] getContributors(IFileRevision revision
) {
85 if (revision
instanceof GitCommitFileRevision
) {
86 GitCommitFileRevision grevision
= (GitCommitFileRevision
)revision
;
87 ObjectId
[] parents
= grevision
.getCommit().getParentIds();
88 IFileRevision
[] ret
= new IFileRevision
[parents
.length
];
89 for (int i
= 0; i
< parents
.length
; ++i
) {
90 ret
[i
] = new GitCommitFileRevision(parents
[i
], grevision
95 return new IFileRevision
[0];
98 public IFileRevision
getFileRevision(String id
) {
100 return new GitWorkspaceFileRevision(resource
, -1);
101 if (id
.equals("Index"))
102 return new GitIndexFileRevision(resource
, 0);
103 return new GitCommitFileRevision(new ObjectId(id
), resource
, 0);
106 static class EclipseWalker
extends TopologicalWalker
{
109 private final IProgressMonitor monitor
;
110 private Map
<ObjectId
, IFileRevision
> revisions
= new HashMap
<ObjectId
, IFileRevision
>();
112 EclipseWalker(Repository repository
, Commit
[] starts
, String
[] relativeResourceName
,boolean leafIsBlob
,IResource resource
,boolean followMainOnly
, Boolean merges
, ObjectId lastActiveDiffId
, boolean returnAll
, IProgressMonitor monitor
) {
113 super(repository
, starts
, relativeResourceName
, leafIsBlob
, followMainOnly
, merges
, lastActiveDiffId
, returnAll
);
114 this.resource
= resource
;
115 this.monitor
= monitor
;
118 protected void collect(Commit commit
, int count
, int breadth
) {
119 super.collect(commit
, count
, breadth
);
120 if (commit
.getCommitId().equals(ObjectId
.zeroId()))
121 revisions
.put(commit
.getCommitId(), new GitIndexFileRevision(resource
, count
));
123 revisions
.put(commit
.getCommitId(), new GitCommitFileRevision(commit
.getCommitId(), resource
, count
));
126 public boolean isCancelled() {
127 return monitor
.isCanceled();
131 public Collection
collectHistory() {
132 Collection rawList
= super.collectHistory();
133 List
<IFileRevision
> ret
= new MappedList
<ObjectId
,IFileRevision
>((List
)rawList
) {
134 public IFileRevision
map(ObjectId in
) {
135 GitFileRevision ret
= (GitFileRevision
)revisions
.get(in
);
136 if (ret
== null && isReturnAll())
137 if (in
.equals(ObjectId
.zeroId()))
138 ret
= new GitIndexFileRevision(resource
, -1);
140 ret
= new GitCommitFileRevision(in
, resource
, -1);
142 ret
.setLane(getLane(in
));
150 protected void record(ObjectId pred
, ObjectId succ
) {
151 super.record(pred
, succ
);
152 if (monitor
.isCanceled()) {
153 System
.out
.println("Cancelled");
154 throw new CancellationException("history refresh cancelled");
159 public IFileRevision
[] getFileRevisions() {
160 return revisions
.toArray(new IFileRevision
[revisions
.size()]);
163 public List
<IFileRevision
> getFileRevisionsList() {
168 * Get a single file revision suitable for quickdiff.
170 * We have two modes. For a branch set up for Stacked Git that has a patch
171 * return the revision prior to the topmost patch, be it another patch or a
172 * normal Git Commit. This is the revision in HEAD^. Otherwise we return the
176 private void findSingleRevision(IProgressMonitor monitor
) {
178 Repository repository
= RepositoryMapping
.getMapping(resource
).getRepository();
179 ObjectId id
= repository
.resolve("HEAD");
180 Commit current
= repository
.mapCommit(id
);
181 if (repository
.isStGitMode()) {
182 ObjectId
[] parentIds
= current
.getParentIds();
183 if (parentIds
!= null && parentIds
.length
> 0)
184 current
= repository
.mapCommit(parentIds
[0]);
186 revisions
= Collections
.emptyList();
190 TreeEntry currentEntry
= current
.getTree();
191 for (int i
=0; i
< relativeResourceName
.length
&& currentEntry
!= null; ++i
) {
192 if (i
== relativeResourceName
.length
-1 && resource
.getType() == IResource
.FILE
)
193 ((Tree
)currentEntry
).findBlobMember(relativeResourceName
[i
]);
195 ((Tree
)currentEntry
).findTreeMember(relativeResourceName
[i
]);
197 if (currentEntry
!= null)
198 revisions
= Collections
.singletonList(
199 (IFileRevision
)new GitCommitFileRevision(current
.getCommitId(), resource
, -1));
201 revisions
= Collections
.emptyList();
203 } catch (IOException e
) {
205 revisions
= Collections
.emptyList();
209 private void findRevisions(IProgressMonitor monitor
) throws IOException
{
210 RepositoryProvider provider
= RepositoryProvider
.getProvider(resource
212 if (provider
instanceof GitProvider
) {
213 GitWorkspaceFileRevision wsrevision
= new GitWorkspaceFileRevision(resource
, -1);
215 long time0
= new Date().getTime();
216 System
.out
.println("getting file history");
217 SuperList
<IFileRevision
> ret
= new SuperList
<IFileRevision
>();
218 ObjectId activeDiffLeafId
= null;
219 RepositoryMapping mapping
= RepositoryMapping
.getMapping(resource
);
220 Repository repository
= mapping
.getRepository();
221 if (!(resource
instanceof IContainer
)) {
222 String relativeResourceNameString
= mapping
223 .getRepoRelativePath(resource
);
224 Entry entry
= repository
.getIndex().getEntry(
225 relativeResourceNameString
);
227 if (entry
.isModified(mapping
.getWorkDir(), entry
.getSize() < 500000)) {
228 activeDiffLeafId
= ObjectId
.zeroId();
229 wsrevision
= new GitWorkspaceFileRevision(resource
, 0); // mark "interesting"
231 activeDiffLeafId
= entry
.getObjectId();
234 activeDiffLeafId
= ObjectId
.zeroId();
238 Collection
<IFileRevision
> githistory
;
239 ObjectId head
= repository
.resolve("HEAD");
241 List
<Commit
> startList
= new ArrayList
<Commit
>();
243 startList
.add(repository
.mapCommit(head
));
244 for(String branch
: repository
.getBranches()) {
245 Commit commit
= repository
.mapCommit(branch
);
247 startList
.add(commit
);
249 Commit
[] starts
= startList
.toArray(new Commit
[startList
.size()]);
250 EclipseWalker walker
= new EclipseWalker(
253 relativeResourceName
,
254 resource
.getType() == IResource
.FILE
,
256 (flags
& IFileHistoryProvider
.SINGLE_LINE_OF_DESCENT
) == 0,
261 githistory
= walker
.collectHistory();
263 githistory
= new ArrayList
<IFileRevision
>();
265 if (githistory
.size() > 0) {
266 if (resource
.getType()==IResource
.FILE
) {
269 ret
.addAll(githistory
);
271 ret
.addAll(githistory
);
276 long time1
= new Date().getTime();
277 System
.out
.println("got file history in " + (time1
- time0
)
283 revisions
= Collections
.emptyList();
287 public IFileRevision
[] getTargets(IFileRevision revision
) {
288 if (revision
instanceof GitCommitFileRevision
) {
289 GitCommitFileRevision grevision
= (GitCommitFileRevision
) revision
;
290 ObjectId targetCommitId
= grevision
.getCommit().getCommitId();
291 List
<IFileRevision
> ret
= new ArrayList
<IFileRevision
>(4);
292 for(IFileRevision r
: revisions
) {
293 Commit ref
= ((GitCommitFileRevision
)r
).getCommit();
294 ObjectId
[] parentIds
= ref
.getParentIds();
295 for (int j
= 0; j
< parentIds
.length
; ++j
) {
296 if (parentIds
[j
].equals(targetCommitId
)) {
302 return ret
.toArray(new IFileRevision
[ret
.size()]);
304 return new IFileRevision
[0];
307 public Object
getAdapter(Class adapter
) {
308 System
.out
.println("GitFileHistory.getAdapter "+adapter
.getName());