2
This code is derived from jgit (http://eclipse.org/jgit).
3
Copyright owners are documented in jgit's IP log.
5
This program and the accompanying materials are made available
6
under the terms of the Eclipse Distribution License v1.0 which
7
accompanies this distribution, is reproduced below, and is
8
available at http://www.eclipse.org/org/documents/edl-v10.php
12
Redistribution and use in source and binary forms, with or
13
without modification, are permitted provided that the following
16
- Redistributions of source code must retain the above copyright
17
notice, this list of conditions and the following disclaimer.
19
- Redistributions in binary form must reproduce the above
20
copyright notice, this list of conditions and the following
21
disclaimer in the documentation and/or other materials provided
22
with the distribution.
24
- Neither the name of the Eclipse Foundation, Inc. nor the
25
names of its contributors may be used to endorse or promote
26
products derived from this software without specific prior
29
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
30
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
31
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53
/// <summary>Collects line annotations for inspection by applications.</summary>
55
/// Collects line annotations for inspection by applications.
57
/// A result is usually updated incrementally as the BlameGenerator digs back
58
/// further through history. Applications that want to lay annotations down text
59
/// to the original source file in a viewer may find the BlameResult structure an
60
/// easy way to acquire the information, at the expense of keeping tables in
61
/// memory tracking every line of the result file.
63
/// This class is not thread-safe.
65
/// During blame processing there are two files involved:
67
/// <li>result - The file whose lines are being examined. This is the revision
68
/// the user is trying to view blame/annotation information alongside of.</li>
69
/// <li>source - The file that was blamed with supplying one or more lines of
70
/// data into result. The source may be a different file path (due to copy or
71
/// rename). Source line numbers may differ from result line numbers due to lines
72
/// being added/removed in intermediate revisions.</li>
75
public class BlameResult
77
/// <summary>Construct a new BlameResult for a generator.</summary>
78
/// <remarks>Construct a new BlameResult for a generator.</remarks>
79
/// <param name="gen">the generator the result will consume records from.</param>
81
/// the new result object. null if the generator cannot find the path
84
/// <exception cref="System.IO.IOException">the repository cannot be read.</exception>
85
public static NGit.Blame.BlameResult Create(BlameGenerator gen)
87
string path = gen.GetResultPath();
88
RawText contents = gen.GetResultContents();
94
return new NGit.Blame.BlameResult(gen, path, contents);
97
private readonly string resultPath;
99
private readonly RevCommit[] sourceCommits;
101
private readonly PersonIdent[] sourceAuthors;
103
private readonly PersonIdent[] sourceCommitters;
105
private readonly string[] sourcePaths;
107
/// <summary>Warning: these are actually 1-based.</summary>
108
/// <remarks>Warning: these are actually 1-based.</remarks>
109
private readonly int[] sourceLines;
111
private RawText resultContents;
113
private BlameGenerator generator;
115
private int lastLength;
117
internal BlameResult(BlameGenerator bg, string path, RawText text)
121
resultContents = text;
122
int cnt = text.Size();
123
sourceCommits = new RevCommit[cnt];
124
sourceAuthors = new PersonIdent[cnt];
125
sourceCommitters = new PersonIdent[cnt];
126
sourceLines = new int[cnt];
127
sourcePaths = new string[cnt];
130
/// <returns>path of the file this result annotates.</returns>
131
public virtual string GetResultPath()
136
/// <returns>contents of the result file, available for display.</returns>
137
public virtual RawText GetResultContents()
139
return resultContents;
144
/// <see cref="GetResultContents()">GetResultContents()</see>
147
public virtual void DiscardResultContents()
149
resultContents = null;
152
/// <summary>Check if the given result line has been annotated yet.</summary>
153
/// <remarks>Check if the given result line has been annotated yet.</remarks>
154
/// <param name="idx">line to read data of, 0 based.</param>
155
/// <returns>true if the data has been annotated, false otherwise.</returns>
156
public virtual bool HasSourceData(int idx)
158
return sourceLines[idx] != 0;
161
/// <summary>Check if the given result line has been annotated yet.</summary>
162
/// <remarks>Check if the given result line has been annotated yet.</remarks>
163
/// <param name="start">first index to examine.</param>
164
/// <param name="end">last index to examine.</param>
165
/// <returns>true if the data has been annotated, false otherwise.</returns>
166
public virtual bool HasSourceData(int start, int end)
168
for (; start < end; start++)
170
if (sourceLines[start] == 0)
178
/// <summary>Get the commit that provided the specified line of the result.</summary>
180
/// Get the commit that provided the specified line of the result.
182
/// The source commit may be null if the line was blamed to an uncommitted
183
/// revision, such as the working tree copy, or during a reverse blame if the
184
/// line survives to the end revision (e.g. the branch tip).
186
/// <param name="idx">line to read data of, 0 based.</param>
188
/// commit that provided line
192
public virtual RevCommit GetSourceCommit(int idx)
194
return sourceCommits[idx];
197
/// <summary>Get the author that provided the specified line of the result.</summary>
198
/// <remarks>Get the author that provided the specified line of the result.</remarks>
199
/// <param name="idx">line to read data of, 0 based.</param>
201
/// author that provided line
205
public virtual PersonIdent GetSourceAuthor(int idx)
207
return sourceAuthors[idx];
210
/// <summary>Get the committer that provided the specified line of the result.</summary>
211
/// <remarks>Get the committer that provided the specified line of the result.</remarks>
212
/// <param name="idx">line to read data of, 0 based.</param>
214
/// committer that provided line
218
public virtual PersonIdent GetSourceCommitter(int idx)
220
return sourceCommitters[idx];
223
/// <summary>Get the file path that provided the specified line of the result.</summary>
224
/// <remarks>Get the file path that provided the specified line of the result.</remarks>
225
/// <param name="idx">line to read data of, 0 based.</param>
227
/// source file path that provided line
231
public virtual string GetSourcePath(int idx)
233
return sourcePaths[idx];
236
/// <summary>Get the corresponding line number in the source file.</summary>
237
/// <remarks>Get the corresponding line number in the source file.</remarks>
238
/// <param name="idx">line to read data of, 0 based.</param>
239
/// <returns>matching line number in the source file.</returns>
240
public virtual int GetSourceLine(int idx)
242
return sourceLines[idx] - 1;
245
/// <summary>Compute all pending information.</summary>
246
/// <remarks>Compute all pending information.</remarks>
247
/// <exception cref="System.IO.IOException">the repository cannot be read.</exception>
248
public virtual void ComputeAll()
250
BlameGenerator gen = generator;
269
/// <summary>Compute the next available segment and return the first index.</summary>
271
/// Compute the next available segment and return the first index.
273
/// Computes one segment and returns to the caller the first index that is
274
/// available. After return the caller can also inspect
275
/// <see cref="LastLength()">LastLength()</see>
276
/// to determine how many lines of the result were computed.
278
/// <returns>index that is now available. -1 if no more are available.</returns>
279
/// <exception cref="System.IO.IOException">the repository cannot be read.</exception>
280
public virtual int ComputeNext()
282
BlameGenerator gen = generator;
290
lastLength = gen.GetRegionLength();
291
return gen.GetResultStart();
302
/// length of the last segment found by
303
/// <see cref="ComputeNext()">ComputeNext()</see>
306
public virtual int LastLength()
311
/// <summary>Compute until the entire range has been populated.</summary>
312
/// <remarks>Compute until the entire range has been populated.</remarks>
313
/// <param name="start">first index to examine.</param>
314
/// <param name="end">last index to examine.</param>
315
/// <exception cref="System.IO.IOException">the repository cannot be read.</exception>
316
public virtual void ComputeRange(int start, int end)
318
BlameGenerator gen = generator;
325
if (HasSourceData(start, end))
336
// If the result contains either end of our current range bounds,
337
// update the bounds to avoid scanning that section during the
338
// next loop iteration.
339
int resLine = gen.GetResultStart();
340
int resEnd = gen.GetResultEnd();
341
if (resLine <= start && start < resEnd)
345
if (resLine <= end && end < resEnd)
352
public override string ToString()
354
StringBuilder r = new StringBuilder();
355
r.Append("BlameResult: ");
356
r.Append(GetResultPath());
360
private void LoadFrom(BlameGenerator gen)
362
RevCommit srcCommit = gen.GetSourceCommit();
363
PersonIdent srcAuthor = gen.GetSourceAuthor();
364
PersonIdent srcCommitter = gen.GetSourceCommitter();
365
string srcPath = gen.GetSourcePath();
366
int srcLine = gen.GetSourceStart();
367
int resLine = gen.GetResultStart();
368
int resEnd = gen.GetResultEnd();
369
for (; resLine < resEnd; resLine++)
371
// Reverse blame can generate multiple results for the same line.
372
// Favor the first one selected, as this is the oldest and most
373
// likely to be nearest to the inquiry made by the user.
374
if (sourceLines[resLine] != 0)
378
sourceCommits[resLine] = srcCommit;
379
sourceAuthors[resLine] = srcAuthor;
380
sourceCommitters[resLine] = srcCommitter;
381
sourcePaths[resLine] = srcPath;
382
// Since sourceLines is 1-based to permit hasSourceData to use 0 to
383
// mean the line has not been annotated yet, pre-increment instead
384
// of the traditional post-increment when making the assignment.
385
sourceLines[resLine] = ++srcLine;