2245.3.2
by John Arbash Meinel
Cleanup according to Wouter's suggestions. |
1 |
# Copyright (C) 2004, 2005, 2006, 2007 Canonical Ltd
|
2052.3.1
by John Arbash Meinel
Add tests to cleanup the copyright of all source files |
2 |
#
|
1385
by Martin Pool
- simple weave-based annotate code (not complete) |
3 |
# This program is free software; you can redistribute it and/or modify
|
4 |
# it under the terms of the GNU General Public License as published by
|
|
5 |
# the Free Software Foundation; either version 2 of the License, or
|
|
6 |
# (at your option) any later version.
|
|
2052.3.1
by John Arbash Meinel
Add tests to cleanup the copyright of all source files |
7 |
#
|
1385
by Martin Pool
- simple weave-based annotate code (not complete) |
8 |
# This program 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
|
|
11 |
# GNU General Public License for more details.
|
|
2052.3.1
by John Arbash Meinel
Add tests to cleanup the copyright of all source files |
12 |
#
|
1385
by Martin Pool
- simple weave-based annotate code (not complete) |
13 |
# You should have received a copy of the GNU General Public License
|
14 |
# along with this program; if not, write to the Free Software
|
|
15 |
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
16 |
||
17 |
"""File annotate based on weave storage"""
|
|
18 |
||
1185.16.8
by Martin Pool
doc |
19 |
# TODO: Choice of more or less verbose formats:
|
20 |
#
|
|
21 |
# interposed: show more details between blocks of modified lines
|
|
22 |
||
23 |
# TODO: Show which revision caused a line to merge into the parent
|
|
24 |
||
1185.16.57
by Martin Pool
[merge] from aaron |
25 |
# TODO: perhaps abbreviate timescales depending on how recent they are
|
26 |
# e.g. "3:12 Tue", "13 Oct", "Oct 2005", etc.
|
|
27 |
||
1385
by Martin Pool
- simple weave-based annotate code (not complete) |
28 |
import sys |
1185.16.1
by Martin Pool
- update annotate for new branch api |
29 |
import time |
1385
by Martin Pool
- simple weave-based annotate code (not complete) |
30 |
|
2182.3.1
by John Arbash Meinel
Annotate now shows dotted revnos instead of plain revnos. |
31 |
from bzrlib import ( |
32 |
errors, |
|
2593.1.3
by Adeodato Simó
Cope with to_file.encoding being None or not present. |
33 |
osutils, |
1551.9.19
by Aaron Bentley
Merge from bzr.dev |
34 |
patiencediff, |
2182.3.1
by John Arbash Meinel
Annotate now shows dotted revnos instead of plain revnos. |
35 |
tsort, |
36 |
)
|
|
1185.16.53
by Martin Pool
- annotate improvements from Goffreddo, with extra bug fixes and tests |
37 |
from bzrlib.config import extract_email_address |
38 |
||
39 |
||
40 |
def annotate_file(branch, rev_id, file_id, verbose=False, full=False, |
|
2182.3.1
by John Arbash Meinel
Annotate now shows dotted revnos instead of plain revnos. |
41 |
to_file=None, show_ids=False): |
1385
by Martin Pool
- simple weave-based annotate code (not complete) |
42 |
if to_file is None: |
43 |
to_file = sys.stdout |
|
1185.16.53
by Martin Pool
- annotate improvements from Goffreddo, with extra bug fixes and tests |
44 |
|
45 |
prevanno='' |
|
2182.3.9
by John Arbash Meinel
Faster annotate --show-ids. No need to pull the history or the revision info |
46 |
last_rev_id = None |
47 |
if show_ids: |
|
48 |
w = branch.repository.weave_store.get_weave(file_id, |
|
49 |
branch.repository.get_transaction()) |
|
50 |
annotations = list(w.annotate_iter(rev_id)) |
|
51 |
max_origin_len = max(len(origin) for origin, text in annotations) |
|
52 |
for origin, text in annotations: |
|
53 |
if full or last_rev_id != origin: |
|
54 |
this = origin |
|
55 |
else: |
|
56 |
this = '' |
|
57 |
to_file.write('%*s | %s' % (max_origin_len, this, text)) |
|
58 |
last_rev_id = origin |
|
59 |
return
|
|
60 |
||
1185.33.39
by Martin Pool
[patch] annotate --long (robey pointer) |
61 |
annotation = list(_annotate_file(branch, rev_id, file_id)) |
2027.3.1
by John Arbash Meinel
'bzr annotate' shouldn't fail on an empty file: fix bug #56814 |
62 |
if len(annotation) == 0: |
2182.3.4
by John Arbash Meinel
add show-ids and test that nearby areas are collapsed without full |
63 |
max_origin_len = max_revno_len = max_revid_len = 0 |
2027.3.1
by John Arbash Meinel
'bzr annotate' shouldn't fail on an empty file: fix bug #56814 |
64 |
else: |
2182.3.8
by John Arbash Meinel
Some cleanup to make annotate.py < 79 chars wide. |
65 |
max_origin_len = max(len(x[1]) for x in annotation) |
2182.3.1
by John Arbash Meinel
Annotate now shows dotted revnos instead of plain revnos. |
66 |
max_revno_len = max(len(x[0]) for x in annotation) |
2182.3.4
by John Arbash Meinel
add show-ids and test that nearby areas are collapsed without full |
67 |
max_revid_len = max(len(x[3]) for x in annotation) |
2182.3.1
by John Arbash Meinel
Annotate now shows dotted revnos instead of plain revnos. |
68 |
|
2182.3.2
by John Arbash Meinel
Use shortened revnos unless --long is supplied |
69 |
if not verbose: |
2182.3.7
by John Arbash Meinel
Cleanup and add blackbox tests for annotate. |
70 |
max_revno_len = min(max_revno_len, 12) |
71 |
max_revno_len = max(max_revno_len, 3) |
|
2182.3.2
by John Arbash Meinel
Use shortened revnos unless --long is supplied |
72 |
|
2182.3.4
by John Arbash Meinel
add show-ids and test that nearby areas are collapsed without full |
73 |
for (revno_str, author, date_str, line_rev_id, text) in annotation: |
2182.3.9
by John Arbash Meinel
Faster annotate --show-ids. No need to pull the history or the revision info |
74 |
if verbose: |
75 |
anno = '%-*s %-*s %8s ' % (max_revno_len, revno_str, |
|
76 |
max_origin_len, author, date_str) |
|
1185.16.53
by Martin Pool
- annotate improvements from Goffreddo, with extra bug fixes and tests |
77 |
else: |
2182.3.9
by John Arbash Meinel
Faster annotate --show-ids. No need to pull the history or the revision info |
78 |
if len(revno_str) > max_revno_len: |
79 |
revno_str = revno_str[:max_revno_len-1] + '>' |
|
80 |
anno = "%-*s %-7s " % (max_revno_len, revno_str, author[:7]) |
|
1185.16.53
by Martin Pool
- annotate improvements from Goffreddo, with extra bug fixes and tests |
81 |
|
82 |
if anno.lstrip() == "" and full: anno = prevanno |
|
2593.1.1
by Adeodato Simó
Improve annotate to prevent unicode exceptions in certain situations. |
83 |
try: |
84 |
to_file.write(anno) |
|
85 |
except UnicodeEncodeError: |
|
2593.1.4
by Adeodato Simó
Add comment from John to the try/except block. |
86 |
# cmd_annotate should be passing in an 'exact' object, which means
|
87 |
# we have a direct handle to sys.stdout or equivalent. It may not
|
|
88 |
# be able to handle the exact Unicode characters, but 'annotate' is
|
|
89 |
# a user function (non-scripting), so shouldn't die because of
|
|
90 |
# unrepresentable annotation characters. So encode using 'replace',
|
|
91 |
# and write them again.
|
|
2593.1.3
by Adeodato Simó
Cope with to_file.encoding being None or not present. |
92 |
encoding = getattr(to_file, 'encoding', None) or \ |
93 |
osutils.get_terminal_encoding() |
|
94 |
to_file.write(anno.encode(encoding, 'replace')) |
|
2593.1.1
by Adeodato Simó
Improve annotate to prevent unicode exceptions in certain situations. |
95 |
print >>to_file, '| %s' % (text,) |
1185.16.53
by Martin Pool
- annotate improvements from Goffreddo, with extra bug fixes and tests |
96 |
prevanno=anno |
97 |
||
2182.3.10
by John Arbash Meinel
minor cleanup. |
98 |
|
2245.3.1
by John Arbash Meinel
bzr annotate should use Branch's dotted revnos. |
99 |
def _annotate_file(branch, rev_id, file_id): |
2182.3.10
by John Arbash Meinel
minor cleanup. |
100 |
"""Yield the origins for each line of a file.
|
101 |
||
102 |
This includes detailed information, such as the committer name, and
|
|
103 |
date string for the commit, rather than just the revision id.
|
|
104 |
"""
|
|
2418.5.8
by John Arbash Meinel
Update annotate.py to use the new helper function. |
105 |
revision_id_to_revno = branch.get_revision_id_to_revno_map() |
2182.3.1
by John Arbash Meinel
Annotate now shows dotted revnos instead of plain revnos. |
106 |
w = branch.repository.weave_store.get_weave(file_id, |
1185.67.2
by Aaron Bentley
Renamed Branch.storage to Branch.repository |
107 |
branch.repository.get_transaction()) |
1385
by Martin Pool
- simple weave-based annotate code (not complete) |
108 |
last_origin = None |
1551.9.6
by Aaron Bentley
Optimize annotate by retrieving all revisions at once |
109 |
annotations = list(w.annotate_iter(rev_id)) |
110 |
revision_ids = set(o for o, t in annotations) |
|
111 |
revision_ids = [o for o in revision_ids if |
|
112 |
branch.repository.has_revision(o)] |
|
113 |
revisions = dict((r.revision_id, r) for r in |
|
114 |
branch.repository.get_revisions(revision_ids)) |
|
115 |
for origin, text in annotations: |
|
1385
by Martin Pool
- simple weave-based annotate code (not complete) |
116 |
text = text.rstrip('\r\n') |
117 |
if origin == last_origin: |
|
1185.16.53
by Martin Pool
- annotate improvements from Goffreddo, with extra bug fixes and tests |
118 |
(revno_str, author, date_str) = ('','','') |
1385
by Martin Pool
- simple weave-based annotate code (not complete) |
119 |
else: |
120 |
last_origin = origin |
|
1551.9.6
by Aaron Bentley
Optimize annotate by retrieving all revisions at once |
121 |
if origin not in revisions: |
1185.16.53
by Martin Pool
- annotate improvements from Goffreddo, with extra bug fixes and tests |
122 |
(revno_str, author, date_str) = ('?','?','?') |
1185.16.1
by Martin Pool
- update annotate for new branch api |
123 |
else: |
2182.3.1
by John Arbash Meinel
Annotate now shows dotted revnos instead of plain revnos. |
124 |
revno_str = '.'.join(str(i) for i in |
125 |
revision_id_to_revno[origin]) |
|
1551.9.6
by Aaron Bentley
Optimize annotate by retrieving all revisions at once |
126 |
rev = revisions[origin] |
1185.16.32
by Martin Pool
- add a basic annotate built-in command |
127 |
tz = rev.timezone or 0 |
2182.3.8
by John Arbash Meinel
Some cleanup to make annotate.py < 79 chars wide. |
128 |
date_str = time.strftime('%Y%m%d', |
1185.16.32
by Martin Pool
- add a basic annotate built-in command |
129 |
time.gmtime(rev.timestamp + tz)) |
130 |
# a lazy way to get something like the email address
|
|
131 |
# TODO: Get real email address
|
|
1185.16.53
by Martin Pool
- annotate improvements from Goffreddo, with extra bug fixes and tests |
132 |
author = rev.committer |
133 |
try: |
|
134 |
author = extract_email_address(author) |
|
2182.3.1
by John Arbash Meinel
Annotate now shows dotted revnos instead of plain revnos. |
135 |
except errors.NoEmailInUsername: |
1185.16.53
by Martin Pool
- annotate improvements from Goffreddo, with extra bug fixes and tests |
136 |
pass # use the whole name |
1563.2.1
by Robert Collins
Merge in a variation of the versionedfile api from versioned-file. |
137 |
yield (revno_str, author, date_str, origin, text) |
1551.9.16
by Aaron Bentley
Implement Tree.annotate_iter for RevisionTree and WorkingTree |
138 |
|
139 |
||
1551.9.17
by Aaron Bentley
Annotate for working trees across all parents |
140 |
def reannotate(parents_lines, new_lines, new_revision_id): |
1551.9.16
by Aaron Bentley
Implement Tree.annotate_iter for RevisionTree and WorkingTree |
141 |
"""Create a new annotated version from new lines and parent annotations.
|
142 |
|
|
1551.9.17
by Aaron Bentley
Annotate for working trees across all parents |
143 |
:param parents_lines: List of annotated lines for all parents
|
1551.9.16
by Aaron Bentley
Implement Tree.annotate_iter for RevisionTree and WorkingTree |
144 |
:param new_lines: The un-annotated new lines
|
145 |
:param new_revision_id: The revision-id to associate with new lines
|
|
146 |
(will often be CURRENT_REVISION)
|
|
147 |
"""
|
|
1551.9.17
by Aaron Bentley
Annotate for working trees across all parents |
148 |
if len(parents_lines) == 1: |
149 |
for data in _reannotate(parents_lines[0], new_lines, new_revision_id): |
|
150 |
yield data |
|
151 |
else: |
|
152 |
reannotations = [list(_reannotate(p, new_lines, new_revision_id)) for |
|
153 |
p in parents_lines] |
|
154 |
for annos in zip(*reannotations): |
|
155 |
origins = set(a for a, l in annos) |
|
156 |
line = annos[0][1] |
|
157 |
if len(origins) == 1: |
|
158 |
yield iter(origins).next(), line |
|
159 |
elif len(origins) == 2 and new_revision_id in origins: |
|
160 |
yield (x for x in origins if x != new_revision_id).next(), line |
|
161 |
else: |
|
162 |
yield new_revision_id, line |
|
1551.9.18
by Aaron Bentley
Updates from review comments |
163 |
|
1551.9.17
by Aaron Bentley
Annotate for working trees across all parents |
164 |
|
165 |
def _reannotate(parent_lines, new_lines, new_revision_id): |
|
1551.9.16
by Aaron Bentley
Implement Tree.annotate_iter for RevisionTree and WorkingTree |
166 |
plain_parent_lines = [l for r, l in parent_lines] |
1551.9.18
by Aaron Bentley
Updates from review comments |
167 |
matcher = patiencediff.PatienceSequenceMatcher(None, plain_parent_lines, |
1551.9.16
by Aaron Bentley
Implement Tree.annotate_iter for RevisionTree and WorkingTree |
168 |
new_lines) |
169 |
new_cur = 0 |
|
170 |
for i, j, n in matcher.get_matching_blocks(): |
|
171 |
for line in new_lines[new_cur:j]: |
|
172 |
yield new_revision_id, line |
|
173 |
for data in parent_lines[i:i+n]: |
|
1551.9.18
by Aaron Bentley
Updates from review comments |
174 |
yield data |
1551.9.16
by Aaron Bentley
Implement Tree.annotate_iter for RevisionTree and WorkingTree |
175 |
new_cur = j + n |