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 * which accompanies this distribution, and is available at
8 * http://www.eclipse.org/legal/epl-v10.html
9 *******************************************************************************/
10 package org
.eclipse
.egit
.core
.internal
.storage
;
12 import java
.io
.IOException
;
13 import java
.util
.Collections
;
15 import org
.eclipse
.core
.resources
.IResource
;
16 import org
.eclipse
.core
.runtime
.IAdaptable
;
17 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
18 import org
.eclipse
.egit
.core
.Activator
;
19 import org
.eclipse
.egit
.core
.project
.RepositoryMapping
;
20 import org
.eclipse
.team
.core
.history
.IFileHistoryProvider
;
21 import org
.eclipse
.team
.core
.history
.IFileRevision
;
22 import org
.eclipse
.team
.core
.history
.provider
.FileHistory
;
23 import org
.eclipse
.jgit
.lib
.AnyObjectId
;
24 import org
.eclipse
.jgit
.lib
.Constants
;
25 import org
.eclipse
.jgit
.lib
.Repository
;
26 import org
.eclipse
.jgit
.revwalk
.RevCommit
;
27 import org
.eclipse
.jgit
.treewalk
.filter
.AndTreeFilter
;
28 import org
.eclipse
.jgit
.treewalk
.filter
.PathFilterGroup
;
29 import org
.eclipse
.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
) {
55 revisions
= buildRevisions(monitor
, flags
);
58 private KidWalk
buildWalk() {
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 // Only return a revision if it was matched by this filtered history
171 for (IFileRevision r
: revisions
) {
172 if (r
.getContentIdentifier().equals(id
))
178 public IFileRevision
[] getFileRevisions() {
179 final IFileRevision
[] r
= new IFileRevision
[revisions
.length
];
180 System
.arraycopy(revisions
, 0, r
, 0, r
.length
);
184 public Object
getAdapter(Class adapter
) {