/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/bzr/debug_commands.py

  • Committer: Jelmer Vernooij
  • Date: 2019-03-02 23:49:52 UTC
  • mto: This revision was merged to the branch mainline in revision 7292.
  • Revision ID: jelmer@jelmer.uk-20190302234952-ft6nx2trqimd841q
Avoid using time.clock, which is going away in python 3.8.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005-2012 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
"""Debug commands for the bzr formats."""
 
18
 
 
19
from __future__ import absolute_import
 
20
 
 
21
from io import BytesIO
 
22
 
 
23
from .. import (
 
24
    errors,
 
25
    osutils,
 
26
    static_tuple,
 
27
    transport,
 
28
    )
 
29
from ..workingtree import WorkingTree
 
30
from ..commands import (
 
31
    Command,
 
32
    display_command,
 
33
    )
 
34
from ..option import Option
 
35
from ..sixish import PY3
 
36
from . import (
 
37
    btree_index,
 
38
    )
 
39
 
 
40
 
 
41
class cmd_dump_btree(Command):
 
42
    __doc__ = """Dump the contents of a btree index file to stdout.
 
43
 
 
44
    PATH is a btree index file, it can be any URL. This includes things like
 
45
    .bzr/repository/pack-names, or .bzr/repository/indices/a34b3a...ca4a4.iix
 
46
 
 
47
    By default, the tuples stored in the index file will be displayed. With
 
48
    --raw, we will uncompress the pages, but otherwise display the raw bytes
 
49
    stored in the index.
 
50
    """
 
51
 
 
52
    # TODO: Do we want to dump the internal nodes as well?
 
53
    # TODO: It would be nice to be able to dump the un-parsed information,
 
54
    #       rather than only going through iter_all_entries. However, this is
 
55
    #       good enough for a start
 
56
    hidden = True
 
57
    encoding_type = 'exact'
 
58
    takes_args = ['path']
 
59
    takes_options = [Option('raw', help='Write the uncompressed bytes out,'
 
60
                                        ' rather than the parsed tuples.'),
 
61
                     ]
 
62
 
 
63
    def run(self, path, raw=False):
 
64
        dirname, basename = osutils.split(path)
 
65
        t = transport.get_transport(dirname)
 
66
        if raw:
 
67
            self._dump_raw_bytes(t, basename)
 
68
        else:
 
69
            self._dump_entries(t, basename)
 
70
 
 
71
    def _get_index_and_bytes(self, trans, basename):
 
72
        """Create a BTreeGraphIndex and raw bytes."""
 
73
        bt = btree_index.BTreeGraphIndex(trans, basename, None)
 
74
        bytes = trans.get_bytes(basename)
 
75
        bt._file = BytesIO(bytes)
 
76
        bt._size = len(bytes)
 
77
        return bt, bytes
 
78
 
 
79
    def _dump_raw_bytes(self, trans, basename):
 
80
        import zlib
 
81
 
 
82
        # We need to parse at least the root node.
 
83
        # This is because the first page of every row starts with an
 
84
        # uncompressed header.
 
85
        bt, bytes = self._get_index_and_bytes(trans, basename)
 
86
        for page_idx, page_start in enumerate(range(0, len(bytes),
 
87
                                                    btree_index._PAGE_SIZE)):
 
88
            page_end = min(page_start + btree_index._PAGE_SIZE, len(bytes))
 
89
            page_bytes = bytes[page_start:page_end]
 
90
            if page_idx == 0:
 
91
                self.outf.write('Root node:\n')
 
92
                header_end, data = bt._parse_header_from_bytes(page_bytes)
 
93
                self.outf.write(page_bytes[:header_end])
 
94
                page_bytes = data
 
95
            self.outf.write('\nPage %d\n' % (page_idx,))
 
96
            if len(page_bytes) == 0:
 
97
                self.outf.write('(empty)\n')
 
98
            else:
 
99
                decomp_bytes = zlib.decompress(page_bytes)
 
100
                self.outf.write(decomp_bytes)
 
101
                self.outf.write('\n')
 
102
 
 
103
    def _dump_entries(self, trans, basename):
 
104
        try:
 
105
            st = trans.stat(basename)
 
106
        except errors.TransportNotPossible:
 
107
            # We can't stat, so we'll fake it because we have to do the 'get()'
 
108
            # anyway.
 
109
            bt, _ = self._get_index_and_bytes(trans, basename)
 
110
        else:
 
111
            bt = btree_index.BTreeGraphIndex(trans, basename, st.st_size)
 
112
        for node in bt.iter_all_entries():
 
113
            # Node is made up of:
 
114
            # (index, key, value, [references])
 
115
            try:
 
116
                refs = node[3]
 
117
            except IndexError:
 
118
                refs_as_tuples = None
 
119
            else:
 
120
                refs_as_tuples = static_tuple.as_tuples(refs)
 
121
            if PY3:
 
122
                if refs_as_tuples is not None:
 
123
                    refs_as_tuples = tuple(
 
124
                        tuple(tuple(r.decode('utf-8')
 
125
                                    for r in t1) for t1 in t2)
 
126
                        for t2 in refs_as_tuples)
 
127
                as_tuple = (
 
128
                    tuple([r.decode('utf-8') for r in node[1]]),
 
129
                    node[2].decode('utf-8'),
 
130
                    refs_as_tuples)
 
131
            else:
 
132
                as_tuple = (tuple(node[1]), node[2], refs_as_tuples)
 
133
            self.outf.write('%s\n' % (as_tuple,))
 
134
 
 
135
 
 
136
class cmd_file_id(Command):
 
137
    __doc__ = """Print file_id of a particular file or directory.
 
138
 
 
139
    The file_id is assigned when the file is first added and remains the
 
140
    same through all revisions where the file exists, even when it is
 
141
    moved or renamed.
 
142
    """
 
143
 
 
144
    hidden = True
 
145
    _see_also = ['inventory', 'ls']
 
146
    takes_args = ['filename']
 
147
 
 
148
    @display_command
 
149
    def run(self, filename):
 
150
        tree, relpath = WorkingTree.open_containing(filename)
 
151
        file_id = tree.path2id(relpath)
 
152
        if file_id is None:
 
153
            raise errors.NotVersionedError(filename)
 
154
        else:
 
155
            self.outf.write(file_id.decode('utf-8') + '\n')
 
156
 
 
157
 
 
158
class cmd_file_path(Command):
 
159
    __doc__ = """Print path of file_ids to a file or directory.
 
160
 
 
161
    This prints one line for each directory down to the target,
 
162
    starting at the branch root.
 
163
    """
 
164
 
 
165
    hidden = True
 
166
    takes_args = ['filename']
 
167
 
 
168
    @display_command
 
169
    def run(self, filename):
 
170
        tree, relpath = WorkingTree.open_containing(filename)
 
171
        fid = tree.path2id(relpath)
 
172
        if fid is None:
 
173
            raise errors.NotVersionedError(filename)
 
174
        segments = osutils.splitpath(relpath)
 
175
        for pos in range(1, len(segments) + 1):
 
176
            path = osutils.joinpath(segments[:pos])
 
177
            self.outf.write("%s\n" % tree.path2id(path))