~abentley/bzrtools/bzrtools.dev

« back to all changes in this revision

Viewing changes to heads.py

  • Committer: Aaron Bentley
  • Date: 2012-03-20 02:40:57 UTC
  • Revision ID: aaron@aaronbentley.com-20120320024057-mqltf93xxs09r0ry
Compatibility fixes for bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Written by Alexander Belchenko
 
2
# based on Robert Collins code
 
3
#
 
4
#    This program is free software; you can redistribute it and/or modify
 
5
#    it under the terms of the GNU General Public License as published by
 
6
#    the Free Software Foundation; either version 2 of the License, or
 
7
#    (at your option) any later version.
 
8
#
 
9
#    This program is distributed in the hope that it will be useful,
 
10
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
#    GNU General Public License for more details.
 
13
#
 
14
#    You should have received a copy of the GNU General Public License
 
15
#    along with this program; if not, write to the Free Software
 
16
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
17
 
 
18
"""Show all 'heads' in a repository"""
 
19
 
 
20
 
 
21
import time
 
22
 
 
23
import bzrlib
 
24
from bzrlib.commands import Command, display_command
 
25
from bzrlib import errors
 
26
from bzrlib.option import Option
 
27
from bzrlib.urlutils import unescape_for_display
 
28
 
 
29
 
 
30
class cmd_heads(Command):
 
31
    """Show all revisions in a repository not having descendants.
 
32
    """
 
33
    takes_options = [Option('by-date',
 
34
                     help='Sort heads by date (descending).'),
 
35
                     Option('all', help='Show all heads (dead and alive).'),
 
36
                     Option('dead-only', help='Show only dead heads.'),
 
37
                     Option('tips', help='Show tips of all branches.'),
 
38
                     Option('debug-time',
 
39
                     help='Enable debug print of operations times.'),
 
40
                    ]
 
41
 
 
42
    encoding_type = "replace"
 
43
    takes_args = ['location?']
 
44
 
 
45
    @display_command
 
46
    def run(self, by_date=False, all=False, dead_only=False, tips=False,
 
47
            debug_time=False, location='.'):
 
48
        import bzrlib.branch
 
49
        from bzrlib.osutils import format_date
 
50
        import bzrlib.repository
 
51
 
 
52
        self._init_elapsed_time(debug_time)
 
53
 
 
54
        to_file = self.outf
 
55
 
 
56
        branch = None
 
57
        try:
 
58
            branch = bzrlib.branch.Branch.open_containing(location)[0]
 
59
            repo = branch.repository
 
60
        except errors.NotBranchError:
 
61
            try:
 
62
                repo = bzrlib.repository.Repository.open(location)
 
63
            except errors.NotBranchError:
 
64
                print >>to_file, \
 
65
                      ("You need to run this command "
 
66
                       "either from the root of a shared repository,\n"
 
67
                       "or from a branch.")
 
68
                return 3
 
69
        repo.lock_read()
 
70
        try:
 
71
            possible_heads = set(repo.all_revision_ids())
 
72
            g = repo.get_graph().get_parent_map(possible_heads)
 
73
            not_heads = set()
 
74
            for parents in g.values():
 
75
                not_heads.update(set(parents))
 
76
 
 
77
            self.heads = possible_heads.difference(not_heads)
 
78
 
 
79
            # TODO: use different sorting schemes instead of alphabetical sort
 
80
            self.heads = list(self.heads)
 
81
 
 
82
            self._print_elapsed_time('get heads:')
 
83
 
 
84
            ## mark heads as dead or alive
 
85
            # mark all heads as dead
 
86
            self.head_mark = {}
 
87
            self.tips = {}
 
88
            for head in self.heads:
 
89
                self.head_mark[head] = 'dead'
 
90
            # give the list of live branches in repository or current branch
 
91
            # tip
 
92
            self._iter_branches_update_marks(repo, self.outf.encoding)
 
93
            self._print_elapsed_time('make head marks:')
 
94
 
 
95
            if tips:
 
96
                heads_tips = set(self.heads)
 
97
                heads_tips.update(set(self.tips.keys()))
 
98
                self.heads = list(heads_tips)
 
99
            head_revisions = dict(zip(self.heads,
 
100
                                  repo.get_revisions(self.heads)))
 
101
 
 
102
            # sorting by date
 
103
            if by_date:
 
104
                dates = {}
 
105
                for head in self.heads:
 
106
                    rev = head_revisions[head]
 
107
                    timestamp = rev.timestamp
 
108
                    dates[timestamp] = head
 
109
                keys = dates.keys()
 
110
                keys.sort()
 
111
                keys.reverse()
 
112
                self.heads = []
 
113
                for k in keys:
 
114
                    self.heads.append(dates[k])
 
115
                self._print_elapsed_time('sort by date:')
 
116
 
 
117
 
 
118
            # show time
 
119
            indent = ' '*2
 
120
            show_timezone = 'original'
 
121
 
 
122
            for head in self.heads:
 
123
 
 
124
                mark = self.head_mark[head]
 
125
                if not all:
 
126
                    if dead_only:
 
127
                        if mark != 'dead':
 
128
                            continue
 
129
                    else:
 
130
                        if mark != 'alive':
 
131
                            if not tips or mark != 'tip':
 
132
                                continue
 
133
 
 
134
                # tips
 
135
                if mark in ('alive', 'tip'):
 
136
                    t = self.tips[head]
 
137
                    if len(t) > 1:
 
138
                        print >>to_file, 'TIP of branches:',
 
139
                        print >>to_file, '[', ', '.join(t), ']'
 
140
                    else:
 
141
                        print >>to_file, 'TIP of branch:', t[0]
 
142
 
 
143
                if mark in ('alive', 'dead'):
 
144
                    print >>to_file, 'HEAD:',
 
145
 
 
146
                print >>to_file, "revision-id:", head,
 
147
                if mark == 'dead':  print >>to_file, '(dead)'
 
148
                else:               print >>to_file
 
149
 
 
150
                rev = head_revisions[head]
 
151
                # borrowed from LongLogFormatter
 
152
                print >>to_file,  indent+'committer:', rev.committer
 
153
                try:
 
154
                    print >>to_file, indent+'branch nick: %s' % \
 
155
                        rev.properties['branch-nick']
 
156
                except KeyError:
 
157
                    pass
 
158
                date_str = format_date(rev.timestamp,
 
159
                                       rev.timezone or 0,
 
160
                                       show_timezone)
 
161
                print >>to_file,  indent+'timestamp: %s' % date_str
 
162
 
 
163
                print >>to_file,  indent+'message:'
 
164
                if not rev.message:
 
165
                    print >>to_file,  indent+'  (no message)'
 
166
                else:
 
167
                    message = rev.message.rstrip('\r\n')
 
168
                    for l in message.split('\n'):
 
169
                        print >>to_file,  indent+'  ' + l
 
170
                self._print_elapsed_time('print head:')
 
171
                print
 
172
 
 
173
            if not self.heads:
 
174
                print >>to_file, 'No heads found'
 
175
                return 1
 
176
        finally:
 
177
            repo.unlock()
 
178
 
 
179
    def _iter_branches_update_marks(self, repo, encoding):
 
180
        for b in repo.find_branches(using=True):
 
181
            last_revid = b.last_revision()
 
182
            if last_revid in self.heads:
 
183
                self.head_mark[last_revid] = 'alive'
 
184
            else:
 
185
                self.head_mark[last_revid] = 'tip'
 
186
            escaped = unescape_for_display(b.base, encoding)
 
187
            self.tips.setdefault(last_revid, []).append(escaped)
 
188
 
 
189
    def _init_elapsed_time(self, debug_time=False):
 
190
        self.debug_time = debug_time
 
191
        if debug_time:
 
192
            self._time = time.time()
 
193
 
 
194
    def _print_elapsed_time(self, msg):
 
195
        if self.debug_time:
 
196
            last_time = time.time()
 
197
            print msg, last_time - self._time
 
198
            self._time = last_time
 
199
#/class cmd_heads