1 /*******************************************************************************
2 * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
3 * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
5 * All rights reserved. This program and the accompanying materials
6 * are made available under the terms of the Eclipse Public License v1.0
7 * See LICENSE for the full license text, also available.
8 *******************************************************************************/
9 package org
.spearce
.egit
.core
.internal
.storage
;
11 import java
.io
.IOException
;
12 import java
.util
.Collections
;
14 import org
.eclipse
.core
.resources
.IResource
;
15 import org
.eclipse
.core
.runtime
.IAdaptable
;
16 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
17 import org
.eclipse
.team
.core
.history
.IFileHistoryProvider
;
18 import org
.eclipse
.team
.core
.history
.IFileRevision
;
19 import org
.eclipse
.team
.core
.history
.provider
.FileHistory
;
20 import org
.spearce
.egit
.core
.Activator
;
21 import org
.spearce
.egit
.core
.project
.RepositoryMapping
;
22 import org
.spearce
.jgit
.lib
.AnyObjectId
;
23 import org
.spearce
.jgit
.lib
.Constants
;
24 import org
.spearce
.jgit
.lib
.ObjectId
;
25 import org
.spearce
.jgit
.lib
.Repository
;
26 import org
.spearce
.jgit
.revwalk
.RevCommit
;
27 import org
.spearce
.jgit
.treewalk
.filter
.AndTreeFilter
;
28 import org
.spearce
.jgit
.treewalk
.filter
.PathFilterGroup
;
29 import org
.spearce
.jgit
.treewalk
.filter
.TreeFilter
;
32 * A list of revisions for a specific resource according to some filtering
33 * criterion. Though git really does not do file tracking, this corresponds to
34 * listing all files with the same path.
36 class GitFileHistory
extends FileHistory
implements IAdaptable
{
37 private static final int SINGLE_REVISION
= IFileHistoryProvider
.SINGLE_REVISION
;
39 private static final IFileRevision
[] NO_REVISIONS
= {};
41 private static final int BATCH_SIZE
= 256;
43 private final IResource resource
;
45 private String gitPath
;
47 private final KidWalk walk
;
49 private final IFileRevision
[] revisions
;
51 GitFileHistory(final IResource rsrc
, final int flags
,
52 final IProgressMonitor monitor
) {
54 walk
= buildWalk(flags
);
55 revisions
= buildRevisions(monitor
, flags
);
58 private KidWalk
buildWalk(final int flags
) {
59 final RepositoryMapping rm
= RepositoryMapping
.getMapping(resource
);
61 Activator
.logError("Git not attached to project "
62 + resource
.getProject().getName() + ".", null);
66 final KidWalk w
= new KidWalk(rm
.getRepository());
67 gitPath
= rm
.getRepoRelativePath(resource
);
68 w
.setTreeFilter(AndTreeFilter
.create(PathFilterGroup
69 .createFromStrings(Collections
.singleton(gitPath
)),
70 TreeFilter
.ANY_DIFF
));
74 private IFileRevision
[] buildRevisions(final IProgressMonitor monitor
,
79 final Repository db
= walk
.getRepository();
82 final AnyObjectId headId
= db
.resolve(Constants
.HEAD
);
84 Activator
.logError("No HEAD revision available from Git"
85 + " for project " + resource
.getProject().getName()
90 root
= walk
.parseCommit(headId
);
91 if ((flags
& SINGLE_REVISION
) == SINGLE_REVISION
) {
92 // If all Eclipse wants is one revision it probably is
93 // for the editor "quick diff" feature. We can pass off
94 // just the repository HEAD, even though it may not be
95 // the revision that most recently modified the path.
97 final CommitFileRevision single
;
98 single
= new CommitFileRevision(db
, root
, gitPath
);
99 return new IFileRevision
[] { single
};
102 walk
.markStart(root
);
103 } catch (IOException e
) {
104 Activator
.logError("Invalid HEAD revision for project "
105 + resource
.getProject().getName() + ".", e
);
109 final KidCommitList list
= new KidCommitList();
113 final int oldsz
= list
.size();
114 list
.fillTo(oldsz
+ BATCH_SIZE
- 1);
115 if (oldsz
== list
.size())
117 if (monitor
!= null && monitor
.isCanceled())
120 } catch (IOException e
) {
121 Activator
.logError("Error parsing history for "
122 + resource
.getFullPath() + ".", e
);
126 final IFileRevision
[] r
= new IFileRevision
[list
.size()];
127 for (int i
= 0; i
< r
.length
; i
++)
128 r
[i
] = new CommitFileRevision(db
, list
.get(i
), gitPath
);
132 public IFileRevision
[] getContributors(final IFileRevision ifr
) {
133 if (!(ifr
instanceof CommitFileRevision
))
136 final CommitFileRevision rev
= (CommitFileRevision
) ifr
;
137 final Repository db
= walk
.getRepository();
138 final String p
= rev
.getGitPath();
139 final RevCommit c
= rev
.getRevCommit();
140 final IFileRevision
[] r
= new IFileRevision
[c
.getParentCount()];
141 for (int i
= 0; i
< r
.length
; i
++)
142 r
[i
] = new CommitFileRevision(db
, c
.getParent(i
), p
);
146 public IFileRevision
[] getTargets(final IFileRevision ifr
) {
147 if (!(ifr
instanceof CommitFileRevision
))
150 final CommitFileRevision rev
= (CommitFileRevision
) ifr
;
151 final Repository db
= walk
.getRepository();
152 final String p
= rev
.getGitPath();
153 final RevCommit rc
= rev
.getRevCommit();
154 if (!(rc
instanceof KidCommit
))
157 final KidCommit c
= (KidCommit
) rc
;
158 final IFileRevision
[] r
= new IFileRevision
[c
.children
.length
];
159 for (int i
= 0; i
< r
.length
; i
++)
160 r
[i
] = new CommitFileRevision(db
, c
.children
[i
], p
);
164 public IFileRevision
getFileRevision(final String id
) {
165 if (id
== null || id
.equals("") || GitFileRevision
.WORKSPACE
.equals(id
))
166 return new WorkspaceFileRevision(resource
);
167 if (GitFileRevision
.INDEX
.equals(id
))
168 return new IndexFileRevision(walk
.getRepository(), gitPath
);
170 // If we have no walk we somehow failed to initialize during our
171 // constructor, but there is no clear way to report errors other
172 // than to just construct yourself anyway and then later return
173 // no results to the user.
179 final ObjectId binId
= ObjectId
.fromString(id
);
180 final Repository db
= walk
.getRepository();
181 return new CommitFileRevision(db
, walk
.parseCommit(binId
), gitPath
);
182 } catch (IllegalArgumentException e
) {
184 } catch (IOException e
) {
185 // The interface definition suggests we should be returning
186 // null if the supplied id string is invalid for a revision.
188 Activator
.logError("Error commit for file revision " + id
+ " of "
189 + resource
.getFullPath(), e
);
194 public IFileRevision
[] getFileRevisions() {
195 final IFileRevision
[] r
= new IFileRevision
[revisions
.length
];
196 System
.arraycopy(revisions
, 0, r
, 0, r
.length
);
200 public Object
getAdapter(Class adapter
) {