~abentley/bzrtools/bzrtools.dev

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# Written by Alexander Belchenko
# based on Robert Collins code
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

"""Show all 'heads' in a repository"""


import time

import bzrlib
from bzrlib.commands import Command, display_command
from bzrlib import errors
from bzrlib.option import Option
from bzrlib.urlutils import unescape_for_display


class cmd_heads(Command):
    """Show all revisions in a repository not having descendants.
    """
    takes_options = [Option('by-date',
                     help='Sort heads by date (descending).'),
                     Option('all', help='Show all heads (dead and alive).'),
                     Option('dead-only', help='Show only dead heads.'),
                     Option('tips', help='Show tips of all branches.'),
                     Option('debug-time',
                     help='Enable debug print of operations times.'),
                    ]

    encoding_type = "replace"
    takes_args = ['location?']

    @display_command
    def run(self, by_date=False, all=False, dead_only=False, tips=False,
            debug_time=False, location='.'):
        import bzrlib.branch
        from bzrlib.osutils import format_date
        import bzrlib.repository

        self._init_elapsed_time(debug_time)

        to_file = self.outf

        branch = None
        try:
            branch = bzrlib.branch.Branch.open_containing(location)[0]
            repo = branch.repository
        except errors.NotBranchError:
            try:
                repo = bzrlib.repository.Repository.open(location)
            except errors.NotBranchError:
                print >>to_file, \
                      ("You need to run this command "
                       "either from the root of a shared repository,\n"
                       "or from a branch.")
                return 3
        repo.lock_read()
        try:
            possible_heads = set(repo.all_revision_ids())
            g = repo.get_graph().get_parent_map(possible_heads)
            not_heads = set()
            for parents in g.values():
                not_heads.update(set(parents))

            self.heads = possible_heads.difference(not_heads)

            # TODO: use different sorting schemes instead of alphabetical sort
            self.heads = list(self.heads)

            self._print_elapsed_time('get heads:')

            ## mark heads as dead or alive
            # mark all heads as dead
            self.head_mark = {}
            self.tips = {}
            for head in self.heads:
                self.head_mark[head] = 'dead'
            # give the list of live branches in repository or current branch
            # tip
            self._iter_branches_update_marks(repo, self.outf.encoding)
            self._print_elapsed_time('make head marks:')

            if tips:
                heads_tips = set(self.heads)
                heads_tips.update(set(self.tips.keys()))
                self.heads = list(heads_tips)
            head_revisions = dict(zip(self.heads,
                                  repo.get_revisions(self.heads)))

            # sorting by date
            if by_date:
                dates = {}
                for head in self.heads:
                    rev = head_revisions[head]
                    timestamp = rev.timestamp
                    dates[timestamp] = head
                keys = dates.keys()
                keys.sort()
                keys.reverse()
                self.heads = []
                for k in keys:
                    self.heads.append(dates[k])
                self._print_elapsed_time('sort by date:')


            # show time
            indent = ' '*2
            show_timezone = 'original'

            for head in self.heads:

                mark = self.head_mark[head]
                if not all:
                    if dead_only:
                        if mark != 'dead':
                            continue
                    else:
                        if mark != 'alive':
                            if not tips or mark != 'tip':
                                continue

                # tips
                if mark in ('alive', 'tip'):
                    t = self.tips[head]
                    if len(t) > 1:
                        print >>to_file, 'TIP of branches:',
                        print >>to_file, '[', ', '.join(t), ']'
                    else:
                        print >>to_file, 'TIP of branch:', t[0]

                if mark in ('alive', 'dead'):
                    print >>to_file, 'HEAD:',

                print >>to_file, "revision-id:", head,
                if mark == 'dead':  print >>to_file, '(dead)'
                else:               print >>to_file

                rev = head_revisions[head]
                # borrowed from LongLogFormatter
                print >>to_file,  indent+'committer:', rev.committer
                try:
                    print >>to_file, indent+'branch nick: %s' % \
                        rev.properties['branch-nick']
                except KeyError:
                    pass
                date_str = format_date(rev.timestamp,
                                       rev.timezone or 0,
                                       show_timezone)
                print >>to_file,  indent+'timestamp: %s' % date_str

                print >>to_file,  indent+'message:'
                if not rev.message:
                    print >>to_file,  indent+'  (no message)'
                else:
                    message = rev.message.rstrip('\r\n')
                    for l in message.split('\n'):
                        print >>to_file,  indent+'  ' + l
                self._print_elapsed_time('print head:')
                print

            if not self.heads:
                print >>to_file, 'No heads found'
                return 1
        finally:
            repo.unlock()

    def _iter_branches_update_marks(self, repo, encoding):
        for b in repo.find_branches(using=True):
            last_revid = b.last_revision()
            if last_revid in self.heads:
                self.head_mark[last_revid] = 'alive'
            else:
                self.head_mark[last_revid] = 'tip'
            escaped = unescape_for_display(b.base, encoding)
            self.tips.setdefault(last_revid, []).append(escaped)

    def _init_elapsed_time(self, debug_time=False):
        self.debug_time = debug_time
        if debug_time:
            self._time = time.time()

    def _print_elapsed_time(self, msg):
        if self.debug_time:
            last_time = time.time()
            print msg, last_time - self._time
            self._time = last_time
#/class cmd_heads