/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
3640.2.4 by John Arbash Meinel
Copyright updates
1
# Copyright (C) 2007, 2008 Canonical Ltd
2474.1.57 by John Arbash Meinel
Move code around to refactor according to our pyrex extension design.
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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2474.1.57 by John Arbash Meinel
Move code around to refactor according to our pyrex extension design.
16
6379.6.7 by Jelmer Vernooij
Move importing from future until after doc string, otherwise the doc string will disappear.
17
"""Python implementations of Dirstate Helper functions."""
18
6379.6.1 by Jelmer Vernooij
Import absolute_import in a few places.
19
from __future__ import absolute_import
20
6169.1.1 by Martin Packman
Move pack_stat to python dirstate helpers and expose and use pyrex version
21
import binascii
2474.1.58 by John Arbash Meinel
(broken) Try to properly implement DirState._bisect*
22
import os
6169.1.1 by Martin Packman
Move pack_stat to python dirstate helpers and expose and use pyrex version
23
import struct
2474.1.58 by John Arbash Meinel
(broken) Try to properly implement DirState._bisect*
24
2474.1.65 by John Arbash Meinel
Found an import dependency bug if the compiled version is not available.
25
# We cannot import the dirstate module, because it loads this module
26
# All we really need is the IN_MEMORY_MODIFIED constant
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
27
from breezy import errors
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
28
from .dirstate import DirState
6651.2.2 by Martin
Apply 2to3 xrange fix and fix up with sixish range
29
from .sixish import (
30
    range,
31
    )
2474.1.63 by John Arbash Meinel
Found a small bug in the python version of _read_dirblocks.
32
2474.1.58 by John Arbash Meinel
(broken) Try to properly implement DirState._bisect*
33
6169.1.3 by Martin Packman
Abbreviate pack_stat struct format to '>6L'
34
def pack_stat(st, _b64=binascii.b2a_base64, _pack=struct.Struct('>6L').pack):
6169.1.1 by Martin Packman
Move pack_stat to python dirstate helpers and expose and use pyrex version
35
    """Convert stat values into a packed representation
36
37
    Not all of the fields from the stat included are strictly needed, and by
38
    just encoding the mtime and mode a slight speed increase could be gained.
39
    However, using the pyrex version instead is a bigger win.
40
    """
41
    # base64 encoding always adds a final newline, so strip it off
6169.2.2 by Martin Packman
Merge fix for overflow issues in pack_stat from 2.4
42
    return _b64(_pack(st.st_size & 0xFFFFFFFF, int(st.st_mtime) & 0xFFFFFFFF,
43
        int(st.st_ctime) & 0xFFFFFFFF, st.st_dev & 0xFFFFFFFF,
44
        st.st_ino & 0xFFFFFFFF, st.st_mode))[:-1]
6169.1.1 by Martin Packman
Move pack_stat to python dirstate helpers and expose and use pyrex version
45
46
47
def _unpack_stat(packed_stat):
48
    """Turn a packed_stat back into the stat fields.
49
50
    This is meant as a debugging tool, should not be used in real code.
51
    """
52
    (st_size, st_mtime, st_ctime, st_dev, st_ino,
6169.1.3 by Martin Packman
Abbreviate pack_stat struct format to '>6L'
53
     st_mode) = struct.unpack('>6L', binascii.a2b_base64(packed_stat))
6169.1.1 by Martin Packman
Move pack_stat to python dirstate helpers and expose and use pyrex version
54
    return dict(st_size=st_size, st_mtime=st_mtime, st_ctime=st_ctime,
55
                st_dev=st_dev, st_ino=st_ino, st_mode=st_mode)
56
57
4459.2.2 by Vincent Ladeuil
Use the same method or function names for _dirstate_helpers in pyrex and
58
def _bisect_path_left(paths, path):
2474.1.58 by John Arbash Meinel
(broken) Try to properly implement DirState._bisect*
59
    """Return the index where to insert path into paths.
60
61
    This uses the dirblock sorting. So all children in a directory come before
62
    the children of children. For example::
63
64
        a/
65
          b/
66
            c
67
          d/
68
            e
69
          b-c
70
          d-e
71
        a-a
72
        a=c
73
74
    Will be sorted as::
75
76
        a
77
        a-a
78
        a=c
79
        a/b
80
        a/b-c
81
        a/d
82
        a/d-e
83
        a/b/c
84
        a/d/e
85
86
    :param paths: A list of paths to search through
87
    :param path: A single path to insert
88
    :return: An offset where 'path' can be inserted.
89
    :seealso: bisect.bisect_left
90
    """
91
    hi = len(paths)
92
    lo = 0
93
    while lo < hi:
94
        mid = (lo + hi) // 2
95
        # Grab the dirname for the current dirblock
96
        cur = paths[mid]
4459.2.2 by Vincent Ladeuil
Use the same method or function names for _dirstate_helpers in pyrex and
97
        if _cmp_path_by_dirblock(cur, path) < 0:
2474.1.58 by John Arbash Meinel
(broken) Try to properly implement DirState._bisect*
98
            lo = mid + 1
99
        else:
100
            hi = mid
101
    return lo
102
103
4459.2.2 by Vincent Ladeuil
Use the same method or function names for _dirstate_helpers in pyrex and
104
def _bisect_path_right(paths, path):
2474.1.58 by John Arbash Meinel
(broken) Try to properly implement DirState._bisect*
105
    """Return the index where to insert path into paths.
106
107
    This uses a path-wise comparison so we get::
108
        a
109
        a-b
110
        a=b
111
        a/b
112
    Rather than::
113
        a
114
        a-b
115
        a/b
116
        a=b
117
    :param paths: A list of paths to search through
118
    :param path: A single path to insert
119
    :return: An offset where 'path' can be inserted.
120
    :seealso: bisect.bisect_right
121
    """
122
    hi = len(paths)
123
    lo = 0
124
    while lo < hi:
125
        mid = (lo+hi)//2
126
        # Grab the dirname for the current dirblock
127
        cur = paths[mid]
4459.2.2 by Vincent Ladeuil
Use the same method or function names for _dirstate_helpers in pyrex and
128
        if _cmp_path_by_dirblock(path, cur) < 0:
2474.1.58 by John Arbash Meinel
(broken) Try to properly implement DirState._bisect*
129
            hi = mid
130
        else:
131
            lo = mid + 1
132
    return lo
133
2474.1.57 by John Arbash Meinel
Move code around to refactor according to our pyrex extension design.
134
4459.2.2 by Vincent Ladeuil
Use the same method or function names for _dirstate_helpers in pyrex and
135
def bisect_dirblock(dirblocks, dirname, lo=0, hi=None, cache={}):
2474.1.57 by John Arbash Meinel
Move code around to refactor according to our pyrex extension design.
136
    """Return the index where to insert dirname into the dirblocks.
137
138
    The return value idx is such that all directories blocks in dirblock[:idx]
139
    have names < dirname, and all blocks in dirblock[idx:] have names >=
140
    dirname.
141
142
    Optional args lo (default 0) and hi (default len(dirblocks)) bound the
143
    slice of a to be searched.
144
    """
145
    if hi is None:
146
        hi = len(dirblocks)
147
    try:
148
        dirname_split = cache[dirname]
149
    except KeyError:
150
        dirname_split = dirname.split('/')
151
        cache[dirname] = dirname_split
152
    while lo < hi:
2474.1.58 by John Arbash Meinel
(broken) Try to properly implement DirState._bisect*
153
        mid = (lo + hi) // 2
2474.1.57 by John Arbash Meinel
Move code around to refactor according to our pyrex extension design.
154
        # Grab the dirname for the current dirblock
155
        cur = dirblocks[mid][0]
156
        try:
157
            cur_split = cache[cur]
158
        except KeyError:
159
            cur_split = cur.split('/')
160
            cache[cur] = cur_split
2474.1.58 by John Arbash Meinel
(broken) Try to properly implement DirState._bisect*
161
        if cur_split < dirname_split: lo = mid + 1
2474.1.57 by John Arbash Meinel
Move code around to refactor according to our pyrex extension design.
162
        else: hi = mid
163
    return lo
164
165
4459.2.2 by Vincent Ladeuil
Use the same method or function names for _dirstate_helpers in pyrex and
166
def cmp_by_dirs(path1, path2):
2474.1.66 by John Arbash Meinel
Some restructuring.
167
    """Compare two paths directory by directory.
168
169
    This is equivalent to doing::
170
171
       cmp(path1.split('/'), path2.split('/'))
172
173
    The idea is that you should compare path components separately. This
174
    differs from plain ``cmp(path1, path2)`` for paths like ``'a-b'`` and
175
    ``a/b``. "a-b" comes after "a" but would come before "a/b" lexically.
176
177
    :param path1: first path
178
    :param path2: second path
2872.4.10 by Martin Pool
docstrings for cmp_ functions seem to be backwards
179
    :return: negative number if ``path1`` comes first,
2474.1.66 by John Arbash Meinel
Some restructuring.
180
        0 if paths are equal,
2872.4.10 by Martin Pool
docstrings for cmp_ functions seem to be backwards
181
        and positive number if ``path2`` sorts first
2474.1.66 by John Arbash Meinel
Some restructuring.
182
    """
2474.1.70 by John Arbash Meinel
Lot's of fixes from Martin's comments.
183
    if not isinstance(path1, str):
184
        raise TypeError("'path1' must be a plain string, not %s: %r"
185
                        % (type(path1), path1))
186
    if not isinstance(path2, str):
187
        raise TypeError("'path2' must be a plain string, not %s: %r"
188
                        % (type(path2), path2))
2474.1.66 by John Arbash Meinel
Some restructuring.
189
    return cmp(path1.split('/'), path2.split('/'))
190
191
4459.2.2 by Vincent Ladeuil
Use the same method or function names for _dirstate_helpers in pyrex and
192
def _cmp_path_by_dirblock(path1, path2):
2474.1.66 by John Arbash Meinel
Some restructuring.
193
    """Compare two paths based on what directory they are in.
194
195
    This generates a sort order, such that all children of a directory are
196
    sorted together, and grandchildren are in the same order as the
197
    children appear. But all grandchildren come after all children.
198
199
    :param path1: first path
200
    :param path2: the second path
2872.4.10 by Martin Pool
docstrings for cmp_ functions seem to be backwards
201
    :return: negative number if ``path1`` comes first,
2474.1.66 by John Arbash Meinel
Some restructuring.
202
        0 if paths are equal
2872.4.10 by Martin Pool
docstrings for cmp_ functions seem to be backwards
203
        and a positive number if ``path2`` sorts first
2474.1.66 by John Arbash Meinel
Some restructuring.
204
    """
2474.1.70 by John Arbash Meinel
Lot's of fixes from Martin's comments.
205
    if not isinstance(path1, str):
206
        raise TypeError("'path1' must be a plain string, not %s: %r"
207
                        % (type(path1), path1))
208
    if not isinstance(path2, str):
209
        raise TypeError("'path2' must be a plain string, not %s: %r"
210
                        % (type(path2), path2))
2474.1.66 by John Arbash Meinel
Some restructuring.
211
    dirname1, basename1 = os.path.split(path1)
212
    key1 = (dirname1.split('/'), basename1)
213
    dirname2, basename2 = os.path.split(path2)
214
    key2 = (dirname2.split('/'), basename2)
215
    return cmp(key1, key2)
216
217
4459.2.2 by Vincent Ladeuil
Use the same method or function names for _dirstate_helpers in pyrex and
218
def _read_dirblocks(state):
2474.1.57 by John Arbash Meinel
Move code around to refactor according to our pyrex extension design.
219
    """Read in the dirblocks for the given DirState object.
220
221
    This is tightly bound to the DirState internal representation. It should be
222
    thought of as a member function, which is only separated out so that we can
223
    re-write it in pyrex.
224
225
    :param state: A DirState object.
226
    :return: None
227
    """
228
    state._state_file.seek(state._end_of_header)
229
    text = state._state_file.read()
230
    # TODO: check the crc checksums. crc_measured = zlib.crc32(text)
231
232
    fields = text.split('\0')
233
    # Remove the last blank entry
234
    trailing = fields.pop()
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
235
    if trailing != '':
3640.2.5 by John Arbash Meinel
Change from using AssertionError to using DirstateCorrupt in a few places
236
        raise errors.DirstateCorrupt(state,
237
            'trailing garbage: %r' % (trailing,))
2474.1.57 by John Arbash Meinel
Move code around to refactor according to our pyrex extension design.
238
    # consider turning fields into a tuple.
239
240
    # skip the first field which is the trailing null from the header.
241
    cur = 1
242
    # Each line now has an extra '\n' field which is not used
243
    # so we just skip over it
244
    # entry size:
245
    #  3 fields for the key
246
    #  + number of fields per tree_data (5) * tree count
247
    #  + newline
248
    num_present_parents = state._num_present_parents()
249
    tree_count = 1 + num_present_parents
250
    entry_size = state._fields_per_entry()
251
    expected_field_count = entry_size * state._num_entries
252
    field_count = len(fields)
253
    # this checks our adjustment, and also catches file too short.
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
254
    if field_count - cur != expected_field_count:
3640.2.5 by John Arbash Meinel
Change from using AssertionError to using DirstateCorrupt in a few places
255
        raise errors.DirstateCorrupt(state,
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
256
            'field count incorrect %s != %s, entry_size=%s, '\
257
            'num_entries=%s fields=%r' % (
2474.1.57 by John Arbash Meinel
Move code around to refactor according to our pyrex extension design.
258
            field_count - cur, expected_field_count, entry_size,
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
259
            state._num_entries, fields))
2474.1.57 by John Arbash Meinel
Move code around to refactor according to our pyrex extension design.
260
261
    if num_present_parents == 1:
262
        # Bind external functions to local names
263
        _int = int
264
        # We access all fields in order, so we can just iterate over
265
        # them. Grab an straight iterator over the fields. (We use an
266
        # iterator because we don't want to do a lot of additions, nor
267
        # do we want to do a lot of slicing)
6634.2.1 by Martin
Apply 2to3 next fixer and make compatible
268
        _iter = iter(fields)
269
        # Get a local reference to the compatible next method
270
        next = getattr(_iter, '__next__', None)
271
        if next is None:
272
            next = _iter.next
2474.1.57 by John Arbash Meinel
Move code around to refactor according to our pyrex extension design.
273
        # Move the iterator to the current position
6651.2.2 by Martin
Apply 2to3 xrange fix and fix up with sixish range
274
        for x in range(cur):
2474.1.57 by John Arbash Meinel
Move code around to refactor according to our pyrex extension design.
275
            next()
276
        # The two blocks here are deliberate: the root block and the
277
        # contents-of-root block.
278
        state._dirblocks = [('', []), ('', [])]
279
        current_block = state._dirblocks[0][1]
280
        current_dirname = ''
281
        append_entry = current_block.append
6651.2.2 by Martin
Apply 2to3 xrange fix and fix up with sixish range
282
        for count in range(state._num_entries):
2474.1.57 by John Arbash Meinel
Move code around to refactor according to our pyrex extension design.
283
            dirname = next()
284
            name = next()
285
            file_id = next()
286
            if dirname != current_dirname:
287
                # new block - different dirname
288
                current_block = []
289
                current_dirname = dirname
290
                state._dirblocks.append((current_dirname, current_block))
291
                append_entry = current_block.append
292
            # we know current_dirname == dirname, so re-use it to avoid
293
            # creating new strings
294
            entry = ((current_dirname, name, file_id),
295
                     [(# Current Tree
296
                         next(),                # minikind
297
                         next(),                # fingerprint
298
                         _int(next()),          # size
299
                         next() == 'y',         # executable
300
                         next(),                # packed_stat or revision_id
301
                     ),
302
                     ( # Parent 1
303
                         next(),                # minikind
304
                         next(),                # fingerprint
305
                         _int(next()),          # size
306
                         next() == 'y',         # executable
307
                         next(),                # packed_stat or revision_id
308
                     ),
309
                     ])
310
            trailing = next()
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
311
            if trailing != '\n':
312
                raise ValueError("trailing garbage in dirstate: %r" % trailing)
2474.1.57 by John Arbash Meinel
Move code around to refactor according to our pyrex extension design.
313
            # append the entry to the current block
314
            append_entry(entry)
315
        state._split_root_dirblock_into_contents()
316
    else:
317
        fields_to_entry = state._get_fields_to_entry()
318
        entries = [fields_to_entry(fields[pos:pos+entry_size])
6651.2.2 by Martin
Apply 2to3 xrange fix and fix up with sixish range
319
                   for pos in range(cur, field_count, entry_size)]
2474.1.57 by John Arbash Meinel
Move code around to refactor according to our pyrex extension design.
320
        state._entries_to_current_state(entries)
321
    # To convert from format 2  => format 3
322
    # state._dirblocks = sorted(state._dirblocks,
323
    #                          key=lambda blk:blk[0].split('/'))
324
    # To convert from format 3 => format 2
325
    # state._dirblocks = sorted(state._dirblocks)
2474.1.65 by John Arbash Meinel
Found an import dependency bug if the compiled version is not available.
326
    state._dirblock_state = DirState.IN_MEMORY_UNMODIFIED