~lifeless/bzrtools/trunk

« back to all changes in this revision

Viewing changes to heads.py

  • Committer: Robert Collins
  • Date: 2008-07-08 04:11:21 UTC
  • mfrom: (623.1.33 bzrtools)
  • Revision ID: robertc@robertcollins.net-20080708041121-lo0k7os2y03uclt2
Merge trunk.

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
from bzrlib.urlutils import unescape_for_display
 
29
 
 
30
 
 
31
class cmd_heads(Command):
 
32
    """Show all revisions in a repository not having descendants.
 
33
    """
 
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.'),
 
41
                    ]
 
42
 
 
43
    encoding_type = "replace"
 
44
    takes_args = ['location?']
 
45
 
 
46
    @display_command
 
47
    def run(self, by_date=False, all=False, dead_only=False, tips=False,
 
48
            debug_time=False, location='.'):
 
49
        import bzrlib.branch
 
50
        from bzrlib.osutils import format_date
 
51
        import bzrlib.repository
 
52
 
 
53
        self._init_elapsed_time(debug_time)
 
54
 
 
55
        to_file = self.outf
 
56
 
 
57
        branch = None
 
58
        try:
 
59
            branch = bzrlib.branch.Branch.open_containing(location)[0]
 
60
            repo = branch.repository
 
61
        except errors.NotBranchError:
 
62
            try:
 
63
                repo = bzrlib.repository.Repository.open(location)
 
64
            except errors.NotBranchError:
 
65
                print >>to_file, \
 
66
                      ("You need to run this command "
 
67
                       "either from the root of a shared repository,\n"
 
68
                       "or from a branch.")
 
69
                return 3
 
70
        repo.lock_read()
 
71
        try:
 
72
            possible_heads = set(repo.all_revision_ids())
 
73
            g = repo.get_graph().get_parent_map(possible_heads)
 
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
 
93
            self._iter_branches_update_marks(repo, self.outf.encoding)
 
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)
 
100
            head_revisions = dict(zip(self.heads,
 
101
                                  repo.get_revisions(self.heads)))
 
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
 
 
123
            for head in self.heads:
 
124
 
 
125
                mark = self.head_mark[head]
 
126
                if not all:
 
127
                    if dead_only:
 
128
                        if mark != 'dead':
 
129
                            continue
 
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)'
 
167
                else:
 
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()
 
179
 
 
180
    def _iter_branches_update_marks(self, repo, encoding):
 
181
        for b in repo.find_branches(using=True):
 
182
            last_revid = b.last_revision()
 
183
            if last_revid in self.heads:
 
184
                self.head_mark[last_revid] = 'alive'
 
185
            else:
 
186
                self.head_mark[last_revid] = 'tip'
 
187
            escaped = unescape_for_display(b.base, encoding)
 
188
            self.tips.setdefault(last_revid, []).append(escaped)
 
189
 
 
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
 
200
#/class cmd_heads