82
83
bzrlib.ui.ui_factory = ThreadSafeUIFactory()
86
def _process_side_by_side_buffers(line_list, delete_list, insert_list):
87
while len(delete_list) < len(insert_list):
88
delete_list.append((None, '', 'context'))
89
while len(insert_list) < len(delete_list):
90
insert_list.append((None, '', 'context'))
91
while len(delete_list) > 0:
92
d = delete_list.pop(0)
93
i = insert_list.pop(0)
94
line_list.append(util.Container(old_lineno=d[0], new_lineno=i[0],
95
old_line=d[1], new_line=i[1],
96
old_type=d[2], new_type=i[2]))
99
def _make_side_by_side(chunk_list):
101
turn a normal unified-style diff (post-processed by parse_delta) into a
102
side-by-side diff structure. the new structure is::
110
type: str('context' or 'changed'),
115
for chunk in chunk_list:
117
delete_list, insert_list = [], []
118
for line in chunk.diff:
119
if line.type == 'context':
120
if len(delete_list) or len(insert_list):
121
_process_side_by_side_buffers(line_list, delete_list, insert_list)
122
delete_list, insert_list = [], []
123
line_list.append(util.Container(old_lineno=line.old_lineno, new_lineno=line.new_lineno,
124
old_line=line.line, new_line=line.line,
125
old_type=line.type, new_type=line.type))
126
elif line.type == 'delete':
127
delete_list.append((line.old_lineno, line.line, line.type))
128
elif line.type == 'insert':
129
insert_list.append((line.new_lineno, line.line, line.type))
130
if len(delete_list) or len(insert_list):
131
_process_side_by_side_buffers(line_list, delete_list, insert_list)
132
out_chunk_list.append(util.Container(diff=line_list))
133
return out_chunk_list
136
def is_branch(folder):
138
bzrlib.branch.Branch.open(folder)
144
def clean_message(message):
145
# clean up a commit message and return it and a short (1-line) version
146
message = message.splitlines()
147
if len(message) == 1:
148
# robey-style 1-line long message
149
message = textwrap.wrap(message[0])
151
# make short form of commit message
152
short_message = message[0]
153
if len(short_message) > 60:
154
short_message = short_message[:60] + '...'
156
return message, short_message
86
160
class _RevListToTimestamps(object):
87
161
"""This takes a list of revisions, and allows you to bisect by date"""
531
617
cPickle.dump(stats, open('lsprof.stats', 'w'), 2)
618
self.log.info('lsprof complete!')
621
def _get_deltas_for_revisions_with_trees(self, revisions):
622
"""Produce a generator of revision deltas.
624
Note that the input is a sequence of REVISIONS, not revision_ids.
625
Trees will be held in memory until the generator exits.
626
Each delta is relative to the revision's lefthand predecessor.
628
required_trees = set()
629
for revision in revisions:
630
required_trees.add(revision.revision_id)
631
required_trees.update(revision.parent_ids[:1])
632
trees = dict((t.get_revision_id(), t) for
633
t in self._branch.repository.revision_trees(required_trees))
635
self._branch.repository.lock_read()
637
for revision in revisions:
638
if not revision.parent_ids:
639
old_tree = self._branch.repository.revision_tree(None)
641
old_tree = trees[revision.parent_ids[0]]
642
tree = trees[revision.revision_id]
643
ret.append((tree, old_tree, tree.changes_from(old_tree)))
646
self._branch.repository.unlock()
648
def entry_from_revision(self, revision):
649
commit_time = datetime.datetime.fromtimestamp(revision.timestamp)
651
parents = [util.Container(revid=r, revno=self.get_revno(r)) for r in revision.parent_ids]
653
if len(parents) == 0:
656
left_parent = revision.parent_ids[0]
658
message, short_message = clean_message(revision.message)
661
'revid': revision.revision_id,
662
'revno': self.get_revno(revision.revision_id),
664
'author': revision.committer,
665
'branch_nick': revision.properties.get('branch-nick', None),
666
'short_comment': short_message,
667
'comment': revision.message,
668
'comment_clean': [util.html_clean(s) for s in message],
671
return util.Container(entry)
534
673
@with_branch_lock
535
674
@with_bzrlib_read_lock
536
675
def get_changes_uncached(self, revid_list, get_diffs=False):
538
rev_list = self._branch.repository.get_revisions(revid_list)
539
except (KeyError, bzrlib.errors.NoSuchRevision):
679
rev_list = self._branch.repository.get_revisions(revid_list)
681
except (KeyError, bzrlib.errors.NoSuchRevision), e:
682
# this sometimes happens with arch-converted branches.
683
# i don't know why. :(
684
self.log.debug('No such revision (skipping): %s', e)
685
revid_list.remove(e.revision)
542
delta_list = self._branch.repository.get_deltas_for_revisions(rev_list)
687
delta_list = self._get_deltas_for_revisions_with_trees(rev_list)
543
688
combined_list = zip(rev_list, delta_list)
547
# lookup the trees for each revision, so we can calculate diffs
550
lookup_set.add(rev.revision_id)
551
if len(rev.parent_ids) > 0:
552
lookup_set.add(rev.parent_ids[0])
553
tree_map = dict((t.get_revision_id(), t) for t in self._branch.repository.revision_trees(lookup_set))
554
# also the root tree, in case we hit the origin:
555
tree_map[None] = self._branch.repository.revision_tree(None)
558
for rev, delta in combined_list:
559
commit_time = datetime.datetime.fromtimestamp(rev.timestamp)
561
parents = [util.Container(revid=r, revno=self.get_revno(r)) for r in rev.parent_ids]
563
if len(parents) == 0:
566
left_parent = rev.parent_ids[0]
568
message = rev.message.splitlines()
569
if len(message) == 1:
570
# robey-style 1-line long message
571
message = textwrap.wrap(message[0])
573
# make short form of commit message
574
short_message = message[0]
575
if len(short_message) > 60:
576
short_message = short_message[:60] + '...'
578
old_tree, new_tree = None, None
580
new_tree = tree_map[rev.revision_id]
581
old_tree = tree_map[left_parent]
584
'revid': rev.revision_id,
585
'revno': self.get_revno(rev.revision_id),
587
'author': rev.committer,
588
'branch_nick': rev.properties.get('branch-nick', None),
589
'short_comment': short_message,
590
'comment': rev.message,
591
'comment_clean': [util.html_clean(s) for s in message],
593
'changes': self.parse_delta(delta, get_diffs, old_tree, new_tree),
595
entries.append(util.Container(entry))
691
for rev, (new_tree, old_tree, delta) in combined_list:
692
entry = self.entry_from_revision(rev)
693
entry.changes = self.parse_delta(delta, get_diffs, old_tree, new_tree)
694
entries.append(entry)
698
@with_bzrlib_read_lock
699
def _get_diff(self, revid1, revid2):
700
rev_tree1 = self._branch.repository.revision_tree(revid1)
701
rev_tree2 = self._branch.repository.revision_tree(revid2)
702
delta = rev_tree2.changes_from(rev_tree1)
703
return rev_tree1, rev_tree2, delta
705
def get_diff(self, revid1, revid2):
706
rev_tree1, rev_tree2, delta = self._get_diff(revid1, revid2)
707
entry = self.get_changes([ revid2 ], False)[0]
708
entry.changes = self.parse_delta(delta, True, rev_tree1, rev_tree2)
599
711
@with_branch_lock
600
712
def get_file(self, file_id, revid):
601
"returns (filename, data)"
602
inv_entry = self.get_inventory(revid)[file_id]
713
"returns (path, filename, data)"
714
inv = self.get_inventory(revid)
715
inv_entry = inv[file_id]
603
716
rev_tree = self._branch.repository.revision_tree(inv_entry.revision)
604
return inv_entry.name, rev_tree.get_file_text(file_id)
717
path = inv.id2path(file_id)
718
if not path.startswith('/'):
720
return path, inv_entry.name, rev_tree.get_file_text(file_id)
606
722
@with_branch_lock
607
723
def parse_delta(self, delta, get_diffs=True, old_tree=None, new_tree=None):