~abentley/bzrtools/bzrtools.dev

0.9.11 by Alexander Belchenko
Added GPL header
1
# Written by Alexander Belchenko
0.9.1 by Alexander Belchenko
first version of heads command. thanks to Robert Collins for algorithm
2
# based on Robert Collins code
0.9.11 by Alexander Belchenko
Added GPL header
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
0.9.1 by Alexander Belchenko
first version of heads command. thanks to Robert Collins for algorithm
17
0.9.2 by Wouter van Heyst
also work when in a branch
18
"""Show all 'heads' in a repository"""
19
20
0.9.14 by Alexander Belchenko
bzrtool's iter_branches is too slow. Added --debug-time feature show this fact
21
import os
22
import time
23
0.9.17 by Alexander Belchenko
Restored support for running from standalone branch or not from root of shared repo
24
import bzrlib
0.9.1 by Alexander Belchenko
first version of heads command. thanks to Robert Collins for algorithm
25
from bzrlib.commands import Command, display_command, register_command
0.9.17 by Alexander Belchenko
Restored support for running from standalone branch or not from root of shared repo
26
from bzrlib import errors
0.9.10 by Alexander Belchenko
Implemented sort by date
27
from bzrlib.option import Option
0.9.27 by Aaron Bentley
Support remote locations
28
from bzrlib.urlutils import unescape_for_display
0.9.1 by Alexander Belchenko
first version of heads command. thanks to Robert Collins for algorithm
29
30
31
class cmd_heads(Command):
0.9.2 by Wouter van Heyst
also work when in a branch
32
    """Show all revisions in a repository not having descendants.
0.9.1 by Alexander Belchenko
first version of heads command. thanks to Robert Collins for algorithm
33
    """
0.9.25 by Aaron Bentley
Update option grammar
34
    takes_options = [Option('by-date',
35
                     help='Sort heads by date (descending).'),
36
                     Option('all', help='Show all heads (dead and alive).'),
37
                     Option('dead-only', help='Show only dead heads.'),
38
                     Option('tips', help='Show tips of all branches.'),
39
                     Option('debug-time',
40
                     help='Enable debug print of operations times.'),
0.9.10 by Alexander Belchenko
Implemented sort by date
41
                    ]
42
0.9.1 by Alexander Belchenko
first version of heads command. thanks to Robert Collins for algorithm
43
    encoding_type = "replace"
0.9.27 by Aaron Bentley
Support remote locations
44
    takes_args = ['location?']
0.9.1 by Alexander Belchenko
first version of heads command. thanks to Robert Collins for algorithm
45
46
    @display_command
0.9.27 by Aaron Bentley
Support remote locations
47
    def run(self, by_date=False, all=False, dead_only=False, tips=False,
48
            debug_time=False, location='.'):
0.9.21 by Alexander Belchenko
fix usage of bzrlib.branch without explicit import
49
        import bzrlib.branch
0.9.1 by Alexander Belchenko
first version of heads command. thanks to Robert Collins for algorithm
50
        from bzrlib.osutils import format_date
51
        import bzrlib.repository
0.9.4 by Alexander Belchenko
- Use different return codes for differnet cases
52
0.9.14 by Alexander Belchenko
bzrtool's iter_branches is too slow. Added --debug-time feature show this fact
53
        self._init_elapsed_time(debug_time)
54
0.9.4 by Alexander Belchenko
- Use different return codes for differnet cases
55
        to_file = self.outf
56
0.9.13 by Alexander Belchenko
implemented select of heads by dead/alive mark
57
        branch = None
0.9.1 by Alexander Belchenko
first version of heads command. thanks to Robert Collins for algorithm
58
        try:
0.9.27 by Aaron Bentley
Support remote locations
59
            branch = bzrlib.branch.Branch.open_containing(location)[0]
0.9.13 by Alexander Belchenko
implemented select of heads by dead/alive mark
60
            repo = branch.repository
0.9.2 by Wouter van Heyst
also work when in a branch
61
        except errors.NotBranchError:
62
            try:
0.9.27 by Aaron Bentley
Support remote locations
63
                repo = bzrlib.repository.Repository.open(location)
0.9.2 by Wouter van Heyst
also work when in a branch
64
            except errors.NotBranchError:
0.9.4 by Alexander Belchenko
- Use different return codes for differnet cases
65
                print >>to_file, \
66
                      ("You need to run this command "
67
                       "either from the root of a shared repository,\n"
0.9.2 by Wouter van Heyst
also work when in a branch
68
                       "or from a branch.")
0.9.4 by Alexander Belchenko
- Use different return codes for differnet cases
69
                return 3
0.9.22 by Aaron Bentley
Improve heads performance
70
        repo.lock_read()
71
        try:
639 by Aaron Bentley
Avoid using deprecated interface for heads
72
            possible_heads = set(repo.all_revision_ids())
73
            g = repo.get_graph().get_parent_map(possible_heads)
0.9.22 by Aaron Bentley
Improve heads performance
74
            not_heads = set()
75
            for parents in g.values():
76
                not_heads.update(set(parents))
77
78
            self.heads = possible_heads.difference(not_heads)
79
80
            # TODO: use different sorting schemes instead of alphabetical sort
81
            self.heads = list(self.heads)
82
83
            self._print_elapsed_time('get heads:')
84
85
            ## mark heads as dead or alive
86
            # mark all heads as dead
87
            self.head_mark = {}
88
            self.tips = {}
89
            for head in self.heads:
90
                self.head_mark[head] = 'dead'
91
            # give the list of live branches in repository or current branch
92
            # tip
0.9.28 by Aaron Bentley
Simplify code by letting find_branches handle standalone branches
93
            self._iter_branches_update_marks(repo, self.outf.encoding)
0.9.22 by Aaron Bentley
Improve heads performance
94
            self._print_elapsed_time('make head marks:')
95
96
            if tips:
97
                heads_tips = set(self.heads)
98
                heads_tips.update(set(self.tips.keys()))
99
                self.heads = list(heads_tips)
0.9.23 by Aaron Bentley
defer getting revisions until self.heads is finalized
100
            head_revisions = dict(zip(self.heads,
101
                                  repo.get_revisions(self.heads)))
0.9.22 by Aaron Bentley
Improve heads performance
102
103
            # sorting by date
104
            if by_date:
105
                dates = {}
106
                for head in self.heads:
107
                    rev = head_revisions[head]
108
                    timestamp = rev.timestamp
109
                    dates[timestamp] = head
110
                keys = dates.keys()
111
                keys.sort()
112
                keys.reverse()
113
                self.heads = []
114
                for k in keys:
115
                    self.heads.append(dates[k])
116
                self._print_elapsed_time('sort by date:')
117
118
119
            # show time
120
            indent = ' '*2
121
            show_timezone = 'original'
122
0.9.18 by Alexander Belchenko
Prepare to list tips of branches
123
            for head in self.heads:
0.9.22 by Aaron Bentley
Improve heads performance
124
125
                mark = self.head_mark[head]
126
                if not all:
127
                    if dead_only:
128
                        if mark != 'dead':
0.9.19 by Alexander Belchenko
Added new flag --tips to show tips (last revid) of all branches in repo
129
                            continue
0.9.22 by Aaron Bentley
Improve heads performance
130
                    else:
131
                        if mark != 'alive':
132
                            if not tips or mark != 'tip':
133
                                continue
134
135
                # tips
136
                if mark in ('alive', 'tip'):
137
                    t = self.tips[head]
138
                    if len(t) > 1:
139
                        print >>to_file, 'TIP of branches:',
140
                        print >>to_file, '[', ', '.join(t), ']'
141
                    else:
142
                        print >>to_file, 'TIP of branch:', t[0]
143
144
                if mark in ('alive', 'dead'):
145
                    print >>to_file, 'HEAD:',
146
147
                print >>to_file, "revision-id:", head,
148
                if mark == 'dead':  print >>to_file, '(dead)'
149
                else:               print >>to_file
150
151
                rev = head_revisions[head]
152
                # borrowed from LongLogFormatter
153
                print >>to_file,  indent+'committer:', rev.committer
154
                try:
155
                    print >>to_file, indent+'branch nick: %s' % \
156
                        rev.properties['branch-nick']
157
                except KeyError:
158
                    pass
159
                date_str = format_date(rev.timestamp,
160
                                       rev.timezone or 0,
161
                                       show_timezone)
162
                print >>to_file,  indent+'timestamp: %s' % date_str
163
164
                print >>to_file,  indent+'message:'
165
                if not rev.message:
166
                    print >>to_file,  indent+'  (no message)'
0.9.19 by Alexander Belchenko
Added new flag --tips to show tips (last revid) of all branches in repo
167
                else:
0.9.22 by Aaron Bentley
Improve heads performance
168
                    message = rev.message.rstrip('\r\n')
169
                    for l in message.split('\n'):
170
                        print >>to_file,  indent+'  ' + l
171
                self._print_elapsed_time('print head:')
172
                print
173
174
            if not self.heads:
175
                print >>to_file, 'No heads found'
176
                return 1
177
        finally:
178
            repo.unlock()
0.9.14 by Alexander Belchenko
bzrtool's iter_branches is too slow. Added --debug-time feature show this fact
179
0.9.27 by Aaron Bentley
Support remote locations
180
    def _iter_branches_update_marks(self, repo, encoding):
0.9.26 by Aaron Bentley
Update to use new find_branches API
181
        for b in repo.find_branches(using=True):
0.9.17 by Alexander Belchenko
Restored support for running from standalone branch or not from root of shared repo
182
            last_revid = b.last_revision()
0.9.18 by Alexander Belchenko
Prepare to list tips of branches
183
            if last_revid in self.heads:
184
                self.head_mark[last_revid] = 'alive'
185
            else:
186
                self.head_mark[last_revid] = 'tip'
0.9.27 by Aaron Bentley
Support remote locations
187
            escaped = unescape_for_display(b.base, encoding)
188
            self.tips.setdefault(last_revid, []).append(escaped)
0.9.17 by Alexander Belchenko
Restored support for running from standalone branch or not from root of shared repo
189
0.9.14 by Alexander Belchenko
bzrtool's iter_branches is too slow. Added --debug-time feature show this fact
190
    def _init_elapsed_time(self, debug_time=False):
191
        self.debug_time = debug_time
192
        if debug_time:
193
            self._time = time.time()
194
195
    def _print_elapsed_time(self, msg):
196
        if self.debug_time:
197
            last_time = time.time()
198
            print msg, last_time - self._time
199
            self._time = last_time
0.9.1 by Alexander Belchenko
first version of heads command. thanks to Robert Collins for algorithm
200
#/class cmd_heads