~abentley/bzrtools/bzrtools.dev

« back to all changes in this revision

Viewing changes to __init__.py

  • Committer: Alexander Belchenko
  • Date: 2007-06-12 18:31:58 UTC
  • mto: This revision was merged to the branch mainline in revision 637.
  • Revision ID: bialix@ukr.net-20070612183158-sqt205eb1s910jca
AUTHORS

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 os
 
22
import time
 
23
 
 
24
import bzrlib
 
25
from bzrlib.commands import Command, display_command, register_command
 
26
from bzrlib import errors
 
27
from bzrlib.option import Option
 
28
 
 
29
 
 
30
class cmd_heads(Command):
 
31
    """Show all revisions in a repository not having descendants.
 
32
    """
 
33
    takes_options = [Option('by-date', help='Sort heads by date (descending)'),
 
34
                     Option('all', help='Show all heads (dead and alive)'),
 
35
                     Option('dead-only', help='Show only dead heads'),
 
36
                     Option('tips', help='Show tips of all branches'),
 
37
                     Option('debug-time', help='Enable debug print of operations times'),
 
38
                    ]
 
39
 
 
40
    encoding_type = "replace"
 
41
 
 
42
    @display_command
 
43
    def run(self, by_date=False, all=False, dead_only=False, tips=False, debug_time=False):
 
44
        import bzrlib.branch
 
45
        from bzrlib.osutils import format_date
 
46
        import bzrlib.repository
 
47
 
 
48
        self._init_elapsed_time(debug_time)
 
49
 
 
50
        to_file = self.outf
 
51
 
 
52
        branch = None
 
53
        try:
 
54
            branch = bzrlib.branch.Branch.open_containing('.')[0]
 
55
            repo = branch.repository
 
56
        except errors.NotBranchError:
 
57
            try:
 
58
                repo = bzrlib.repository.Repository.open('.')
 
59
            except errors.NotBranchError:
 
60
                print >>to_file, \
 
61
                      ("You need to run this command "
 
62
                       "either from the root of a shared repository,\n"
 
63
                       "or from a branch.")
 
64
                return 3
 
65
        repo.lock_read()
 
66
        try:
 
67
            g = repo.get_revision_graph()
 
68
            possible_heads = set(g.keys())
 
69
            not_heads = set()
 
70
            for parents in g.values():
 
71
                not_heads.update(set(parents))
 
72
 
 
73
            self.heads = possible_heads.difference(not_heads)
 
74
 
 
75
            # TODO: use different sorting schemes instead of alphabetical sort
 
76
            self.heads = list(self.heads)
 
77
 
 
78
            self._print_elapsed_time('get heads:')
 
79
 
 
80
            ## mark heads as dead or alive
 
81
            # mark all heads as dead
 
82
            self.head_mark = {}
 
83
            self.tips = {}
 
84
            for head in self.heads:
 
85
                self.head_mark[head] = 'dead'
 
86
            # give the list of live branches in repository or current branch
 
87
            # tip
 
88
            if not branch:
 
89
                # runs from shared repo root
 
90
                self._iter_branches_update_marks(u'.')
 
91
            else:
 
92
                from bzrlib.urlutils import (dirname, local_path_from_url)
 
93
                # runs from branch
 
94
                repo_base = repo.bzrdir.transport.base
 
95
                branch_base = branch.bzrdir.transport.base
 
96
                if repo_base == branch_base:
 
97
                    # standalone branch
 
98
                    last_revid = branch.last_revision()
 
99
                    if last_revid in self.heads:
 
100
                        self.head_mark[last_revid] = 'alive'
 
101
                    else:
 
102
                        self.head_mark[last_revid] = 'tip'
 
103
                    self.tips.setdefault(last_revid, []).\
 
104
                        append(local_path_from_url(dirname(branch_base)))
 
105
                else:
 
106
                    # repo
 
107
                    repo_root = local_path_from_url(dirname(repo_base))
 
108
                    self._iter_branches_update_marks(repo_root)
 
109
            self._print_elapsed_time('make head marks:')
 
110
 
 
111
            if tips:
 
112
                heads_tips = set(self.heads)
 
113
                heads_tips.update(set(self.tips.keys()))
 
114
                self.heads = list(heads_tips)
 
115
            head_revisions = dict(zip(self.heads,
 
116
                                  repo.get_revisions(self.heads)))
 
117
 
 
118
            # sorting by date
 
119
            if by_date:
 
120
                dates = {}
 
121
                for head in self.heads:
 
122
                    rev = head_revisions[head]
 
123
                    timestamp = rev.timestamp
 
124
                    dates[timestamp] = head
 
125
                keys = dates.keys()
 
126
                keys.sort()
 
127
                keys.reverse()
 
128
                self.heads = []
 
129
                for k in keys:
 
130
                    self.heads.append(dates[k])
 
131
                self._print_elapsed_time('sort by date:')
 
132
 
 
133
 
 
134
            # show time
 
135
            indent = ' '*2
 
136
            show_timezone = 'original'
 
137
 
 
138
            for head in self.heads:
 
139
 
 
140
                mark = self.head_mark[head]
 
141
                if not all:
 
142
                    if dead_only:
 
143
                        if mark != 'dead':
 
144
                            continue
 
145
                    else:
 
146
                        if mark != 'alive':
 
147
                            if not tips or mark != 'tip':
 
148
                                continue
 
149
 
 
150
                # tips
 
151
                if mark in ('alive', 'tip'):
 
152
                    t = self.tips[head]
 
153
                    if len(t) > 1:
 
154
                        print >>to_file, 'TIP of branches:',
 
155
                        print >>to_file, '[', ', '.join(t), ']'
 
156
                    else:
 
157
                        print >>to_file, 'TIP of branch:', t[0]
 
158
 
 
159
                if mark in ('alive', 'dead'):
 
160
                    print >>to_file, 'HEAD:',
 
161
 
 
162
                print >>to_file, "revision-id:", head,
 
163
                if mark == 'dead':  print >>to_file, '(dead)'
 
164
                else:               print >>to_file
 
165
 
 
166
                rev = head_revisions[head]
 
167
                # borrowed from LongLogFormatter
 
168
                print >>to_file,  indent+'committer:', rev.committer
 
169
                try:
 
170
                    print >>to_file, indent+'branch nick: %s' % \
 
171
                        rev.properties['branch-nick']
 
172
                except KeyError:
 
173
                    pass
 
174
                date_str = format_date(rev.timestamp,
 
175
                                       rev.timezone or 0,
 
176
                                       show_timezone)
 
177
                print >>to_file,  indent+'timestamp: %s' % date_str
 
178
 
 
179
                print >>to_file,  indent+'message:'
 
180
                if not rev.message:
 
181
                    print >>to_file,  indent+'  (no message)'
 
182
                else:
 
183
                    message = rev.message.rstrip('\r\n')
 
184
                    for l in message.split('\n'):
 
185
                        print >>to_file,  indent+'  ' + l
 
186
                self._print_elapsed_time('print head:')
 
187
                print
 
188
 
 
189
            if not self.heads:
 
190
                print >>to_file, 'No heads found'
 
191
                return 1
 
192
        finally:
 
193
            repo.unlock()
 
194
 
 
195
    def _iter_branches_update_marks(self, root):
 
196
        cwd = os.getcwdu()
 
197
        os.chdir(root)
 
198
        for directory in os.listdir(u'.'):
 
199
            if directory == '.bzr':
 
200
                continue
 
201
            if not os.path.isdir(os.path.join(directory, '.bzr')):
 
202
                continue
 
203
            try:
 
204
                b = bzrlib.branch.Branch.open_containing(directory)[0]
 
205
            except errors.NotBranchError:
 
206
                continue
 
207
            last_revid = b.last_revision()
 
208
            if last_revid in self.heads:
 
209
                self.head_mark[last_revid] = 'alive'
 
210
            else:
 
211
                self.head_mark[last_revid] = 'tip'
 
212
            self.tips.setdefault(last_revid, []).append(directory)
 
213
        os.chdir(cwd)
 
214
 
 
215
    def _init_elapsed_time(self, debug_time=False):
 
216
        self.debug_time = debug_time
 
217
        if debug_time:
 
218
            self._time = time.time()
 
219
 
 
220
    def _print_elapsed_time(self, msg):
 
221
        if self.debug_time:
 
222
            last_time = time.time()
 
223
            print msg, last_time - self._time
 
224
            self._time = last_time
 
225
#/class cmd_heads
 
226
 
 
227
 
 
228
register_command(cmd_heads)