4 package org
.spearce
.jgit
.lib
;
6 import java
.io
.IOException
;
7 import java
.util
.ArrayList
;
8 import java
.util
.Arrays
;
9 import java
.util
.Collection
;
10 import java
.util
.Iterator
;
13 public abstract class Walker
{
14 private String
[] relativeResourceName
;
15 private boolean leafIsBlob
;
16 private boolean followMainOnly
;
17 protected Repository repository
;
18 private ObjectId activeDiffLeafId
;
19 protected final Commit
[] starts
;
20 private final Boolean merges
;
21 private Map donewith
= new ObjectIdMap();
22 private Collection
<Todo
> todo
= new ArrayList
<Todo
>(20000);
24 protected abstract boolean isCancelled();
26 protected abstract void collect(Commit commit
, int count
,int breadth
);
27 protected abstract void record(ObjectId pred
, ObjectId succ
);
30 * Create a revision walker. A revision walker traverses the revision tree
31 * and collects revisions that represents changes. The first revision is
32 * a state outside the commit and is returned as null in the list. The
33 * changes are detected in reverse order, i.e. we start with the current
34 * state as represented by activeDiffLeafId and then we list all commits
35 * that introduces a change against the older state.
37 * Consider these states
44 * If the state of CURRENT and HEAD is the same, but HEAD~1 has a different
45 * state, the HEAD is listed..
47 * If the state of CURRENT and HEAD is different CURRENT is listed. The default
48 * impleementation listes it as a null commit (without a commit id).
50 * @param repostory The repository to scan
51 * @param starts HEAD in this context
52 * @param relativeResourceName The path to log, split by path components
53 * @param leafIsBlob We refer to a CURRENT state which is a blob
54 * @param followMainOnly Follow the first parent only
55 * @param merges Include or eclude merges or both as a tristate Boolean.
56 * @param activeDiffLeafId a SHA-1 or null to start comparing with.2
58 protected Walker(Repository repostory
, Commit
[] starts
,
59 String
[] relativeResourceName
, boolean leafIsBlob
,
60 boolean followMainOnly
, Boolean merges
, ObjectId activeDiffLeafId
) {
61 this.repository
= repostory
;
63 this.relativeResourceName
= relativeResourceName
;
64 this.leafIsBlob
= leafIsBlob
;
65 this.followMainOnly
= followMainOnly
;
67 this.activeDiffLeafId
= activeDiffLeafId
;
71 * Entry point for executing the collection process.
73 * @return a Collection of Commit's (default), but subclasses could return another type.
75 public Collection
collectHistory() {
76 for (int i
=0; i
<starts
.length
; ++i
) {
77 ObjectId
[] initialResourceHash
= new ObjectId
[relativeResourceName
.length
];
78 Arrays
.fill(initialResourceHash
, ObjectId
.zeroId());
79 Commit initialPrevious
;
80 // The first commit is special. We compare it with a reference
82 if (activeDiffLeafId
!= null && initialResourceHash
.length
> 0) {
83 initialResourceHash
[initialResourceHash
.length
-1] = activeDiffLeafId
;
84 initialPrevious
= new Commit(repository
);
85 initialPrevious
.setCommitId(ObjectId
.zeroId());
86 record(null, initialPrevious
.getCommitId());
88 record(ObjectId
.zeroId(), starts
[i
].getCommitId());
89 initialPrevious
= null;
92 initialPrevious
= null;
94 todo
.add(new Todo(0, 0, initialResourceHash
, null, starts
[i
], initialPrevious
));
96 for (Iterator
<Todo
> ti
= todo
.iterator(); ti
.hasNext(); ti
=todo
.iterator()) {
97 Todo next
= ti
.next();
100 } catch (IOException e
) {
101 // TODO Auto-generated catch block
106 donewith
= null; // turn over to gc
113 private ObjectId
[] lastResourceHash
;
114 private TreeEntry lastEntry
;
116 private Commit previous
;
119 public boolean equals(Object other
) {
120 return top
.equals(((Todo
)other
).top
);
124 public int hashCode() {
125 return top
.hashCode();
128 Todo(int count
, int breadth
, ObjectId
[] lastResourceHash
, TreeEntry lastEntry
,
129 Commit top
, Commit previous
) {
131 this.breadth
= breadth
;
132 this.previous
= previous
;
133 this.lastResourceHash
= new ObjectId
[lastResourceHash
.length
];
134 for (int i
=0; i
<lastResourceHash
.length
; ++i
)
135 this.lastResourceHash
[i
] = lastResourceHash
[i
];
136 this.lastEntry
= lastEntry
;
138 assert previous
==null || !previous
.equals(top
);
140 void run() throws IOException
{
141 // System.out.println("todo.run(+"+top+"...");
144 Commit current
= top
;
147 TreeEntry currentEntry
= lastEntry
;
148 ObjectId
[] currentResourceHash
= new ObjectId
[lastResourceHash
.length
];
149 Tree t
= current
!=null ? current
.getTree() : null;
150 for (int i
= 0; i
< currentResourceHash
.length
; ++i
) {
153 if (i
== relativeResourceName
.length
-1 && leafIsBlob
)
154 m
= t
.findBlobMember(relativeResourceName
[i
]);
156 m
= t
.findTreeMember(relativeResourceName
[i
]);
161 ObjectId id
= m
.getId();
162 currentResourceHash
[i
] = id
;
163 if (id
.equals(lastResourceHash
[i
])) {
164 while (++i
< currentResourceHash
.length
) {
165 currentResourceHash
[i
] = lastResourceHash
[i
];
168 if (m
instanceof Tree
) {
171 if (i
== currentResourceHash
.length
- 1) {
175 while (++i
< currentResourceHash
.length
) {
176 currentResourceHash
[i
] = ObjectId
.zeroId();
182 for (; i
< currentResourceHash
.length
; ++i
) {
183 currentResourceHash
[i
] = ObjectId
.zeroId();
188 if (previous
!= null) {
189 if (currentResourceHash
.length
== 0 || !currentResourceHash
[currentResourceHash
.length
-1].equals(lastResourceHash
[currentResourceHash
.length
-1])) {
190 ObjectId
[] pparents
= previous
.getParentIds();
191 if (current
!= previous
) {
193 || merges
.booleanValue() && pparents
.length
> 1
194 || !merges
.booleanValue() && pparents
.length
<= 1) {
195 collect(previous
, count
, breadth
);
201 record(previous
!=null ? previous
.getCommitId() : null, current
!=null ? current
.getCommitId() : null);
203 if (current
!= null) {
204 if (!followMainOnly
&& donewith
.put(current
.getCommitId(), current
.getCommitId()) != null) {
210 lastResourceHash
= currentResourceHash
;
213 if (current
!= null) {
214 ObjectId
[] parents
= current
.getParentIds();
215 if (!followMainOnly
) {
216 for (int i
= 1; i
< parents
.length
; ++i
) {
217 ObjectId mergeParentId
= parents
[i
];
220 mergeParent
= repository
.mapCommit(mergeParentId
);
221 Todo newTodo
= new Todo(0, breadth
+ 1, lastResourceHash
,
222 currentEntry
, mergeParent
, previous
);
223 if (!todo
.contains(todo
))
225 } catch (IOException e
) {
230 if (parents
.length
> 0) {
231 ObjectId parentId
= parents
[0];
233 current
= repository
.mapCommit(parentId
);
234 } catch (IOException e
) {
243 } while (previous
!= null && !isCancelled());