/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 bzrlib/dirstate.py

merge bzr.dev r4164

Show diffs side-by-side

added added

removed removed

Lines of Context:
82
82
'a' is an absent entry: In that tree the id is not present at this path.
83
83
'd' is a directory entry: This path in this tree is a directory with the
84
84
    current file id. There is no fingerprint for directories.
85
 
'f' is a file entry: As for directory, but its a file. The fingerprint is a
86
 
    sha1 value.
 
85
'f' is a file entry: As for directory, but it's a file. The fingerprint is the
 
86
    sha1 value of the file's canonical form, i.e. after any read filters have
 
87
    been applied to the convenience form stored in the working tree.
87
88
'l' is a symlink entry: As for directory, but a symlink. The fingerprint is the
88
89
    link target.
89
90
't' is a reference to a nested subtree; the fingerprint is the referenced
215
216
    cache_utf8,
216
217
    debug,
217
218
    errors,
218
 
    filters,
219
219
    inventory,
220
220
    lock,
221
221
    osutils,
263
263
        # return '%X.%X' % (int(st.st_mtime), st.st_mode)
264
264
 
265
265
 
 
266
class SHA1Provider(object):
 
267
    """An interface for getting sha1s of a file."""
 
268
 
 
269
    def sha1(self, abspath):
 
270
        """Return the sha1 of a file given its absolute path."""
 
271
        raise NotImplementedError(self.sha1)
 
272
 
 
273
    def stat_and_sha1(self, abspath):
 
274
        """Return the stat and sha1 of a file given its absolute path.
 
275
        
 
276
        Note: the stat should be the stat of the physical file
 
277
        while the sha may be the sha of its canonical content.
 
278
        """
 
279
        raise NotImplementedError(self.stat_and_sha1)
 
280
 
 
281
 
 
282
class DefaultSHA1Provider(SHA1Provider):
 
283
    """A SHA1Provider that reads directly from the filesystem."""
 
284
 
 
285
    def sha1(self, abspath):
 
286
        """Return the sha1 of a file given its absolute path."""
 
287
        return osutils.sha_file_by_name(abspath)
 
288
 
 
289
    def stat_and_sha1(self, abspath):
 
290
        """Return the stat and sha1 of a file given its absolute path."""
 
291
        file_obj = file(abspath, 'rb')
 
292
        try:
 
293
            statvalue = os.fstat(file_obj.fileno())
 
294
            sha1 = osutils.sha_file(file_obj)
 
295
        finally:
 
296
            file_obj.close()
 
297
        return statvalue, sha1
 
298
 
 
299
 
266
300
class DirState(object):
267
301
    """Record directory and metadata state for fast access.
268
302
 
321
355
    HEADER_FORMAT_2 = '#bazaar dirstate flat format 2\n'
322
356
    HEADER_FORMAT_3 = '#bazaar dirstate flat format 3\n'
323
357
 
324
 
    def __init__(self, path, content_filter_stack_provider=None):
 
358
    def __init__(self, path, sha1_provider):
325
359
        """Create a  DirState object.
326
360
 
327
361
        :param path: The path at which the dirstate file on disk should live.
328
 
        :param content_filter_stack_provider: a function that takes a
329
 
            path (relative to the top of the tree) and a file-id as
330
 
            parameters and returns a stack of ContentFilters.
331
 
            If None, no content filtering is performed.
 
362
        :param sha1_provider: an object meeting the SHA1Provider interface.
332
363
        """
333
364
        # _header_state and _dirblock_state represent the current state
334
365
        # of the dirstate metadata and the per-row data respectiely.
360
391
        self._cutoff_time = None
361
392
        self._split_path_cache = {}
362
393
        self._bisect_page_size = DirState.BISECT_PAGE_SIZE
 
394
        self._sha1_provider = sha1_provider
363
395
        if 'hashcache' in debug.debug_flags:
364
 
            self._size_sha1_file = self._size_sha1_file_and_mutter
 
396
            self._sha1_file = self._sha1_file_and_mutter
365
397
        else:
366
 
            self._size_sha1_file = filters.internal_size_sha_file_byname
 
398
            self._sha1_file = self._sha1_provider.sha1
367
399
        # These two attributes provide a simple cache for lookups into the
368
400
        # dirstate in-memory vectors. By probing respectively for the last
369
401
        # block, and for the next entry, we save nearly 2 bisections per path
370
402
        # during commit.
371
403
        self._last_block_index = None
372
404
        self._last_entry_index = None
373
 
        # Content filtering setup
374
 
        self._filter_provider = content_filter_stack_provider
375
405
 
376
406
    def __repr__(self):
377
407
        return "%s(%r)" % \
387
417
        :param kind: The kind of the path, as a string like 'file',
388
418
            'directory', etc.
389
419
        :param stat: The output of os.lstat for the path.
390
 
        :param fingerprint: The sha value of the file,
 
420
        :param fingerprint: The sha value of the file's canonical form (i.e.
 
421
            after any read filters have been applied),
391
422
            or the target of a symlink,
392
423
            or the referenced revision id for tree-references,
393
424
            or '' for directories.
1201
1232
        return entry_index, present
1202
1233
 
1203
1234
    @staticmethod
1204
 
    def from_tree(tree, dir_state_filename):
 
1235
    def from_tree(tree, dir_state_filename, sha1_provider=None):
1205
1236
        """Create a dirstate from a bzr Tree.
1206
1237
 
1207
1238
        :param tree: The tree which should provide parent information and
1208
1239
            inventory ids.
 
1240
        :param sha1_provider: an object meeting the SHA1Provider interface.
 
1241
            If None, a DefaultSHA1Provider is used.
1209
1242
        :return: a DirState object which is currently locked for writing.
1210
1243
            (it was locked by DirState.initialize)
1211
1244
        """
1212
 
        result = DirState.initialize(dir_state_filename)
 
1245
        result = DirState.initialize(dir_state_filename,
 
1246
            sha1_provider=sha1_provider)
1213
1247
        try:
1214
1248
            tree.lock_read()
1215
1249
            try:
1572
1606
        """Return the os.lstat value for this path."""
1573
1607
        return os.lstat(abspath)
1574
1608
 
1575
 
    def _size_sha1_file_and_mutter(self, abspath, filter_list):
 
1609
    def _sha1_file_and_mutter(self, abspath):
1576
1610
        # when -Dhashcache is turned on, this is monkey-patched in to log
1577
1611
        # file reads
1578
1612
        trace.mutter("dirstate sha1 " + abspath)
1579
 
        return filters.internal_size_sha_file_byname(abspath, filter_list)
 
1613
        return self._sha1_provider.sha1(abspath)
1580
1614
 
1581
1615
    def _is_executable(self, mode, old_executable):
1582
1616
        """Is this file executable?"""
1595
1629
        #       already in memory. However, this really needs to be done at a
1596
1630
        #       higher level, because there either won't be anything on disk,
1597
1631
        #       or the thing on disk will be a file.
1598
 
        return os.readlink(abspath.encode(osutils._fs_enc))
 
1632
        fs_encoding = osutils._fs_enc
 
1633
        if isinstance(abspath, unicode):
 
1634
            # abspath is defined as the path to pass to lstat. readlink is
 
1635
            # buggy in python < 2.6 (it doesn't encode unicode path into FS
 
1636
            # encoding), so we need to encode ourselves knowing that unicode
 
1637
            # paths are produced by UnicodeDirReader on purpose.
 
1638
            abspath = abspath.encode(fs_encoding)
 
1639
        target = os.readlink(abspath)
 
1640
        if fs_encoding not in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968'):
 
1641
            # Change encoding if needed
 
1642
            target = target.decode(fs_encoding).encode('UTF-8')
 
1643
        return target
1599
1644
 
1600
1645
    def get_ghosts(self):
1601
1646
        """Return a list of the parent tree revision ids that are ghosts."""
1825
1870
            return None, None
1826
1871
 
1827
1872
    @classmethod
1828
 
    def initialize(cls, path):
 
1873
    def initialize(cls, path, sha1_provider=None):
1829
1874
        """Create a new dirstate on path.
1830
1875
 
1831
1876
        The new dirstate will be an empty tree - that is it has no parents,
1832
1877
        and only a root node - which has id ROOT_ID.
1833
1878
 
1834
1879
        :param path: The name of the file for the dirstate.
 
1880
        :param sha1_provider: an object meeting the SHA1Provider interface.
 
1881
            If None, a DefaultSHA1Provider is used.
1835
1882
        :return: A write-locked DirState object.
1836
1883
        """
1837
1884
        # This constructs a new DirState object on a path, sets the _state_file
1839
1886
        # stock empty dirstate information - a root with ROOT_ID, no children,
1840
1887
        # and no parents. Finally it calls save() to ensure that this data will
1841
1888
        # persist.
1842
 
        result = cls(path)
 
1889
        if sha1_provider is None:
 
1890
            sha1_provider = DefaultSHA1Provider()
 
1891
        result = cls(path, sha1_provider)
1843
1892
        # root dir and root dir contents with no children.
1844
1893
        empty_tree_dirblocks = [('', []), ('', [])]
1845
1894
        # a new root directory, with a NULLSTAT.
1873
1922
            size = 0
1874
1923
            executable = False
1875
1924
        elif kind == 'symlink':
1876
 
            # We don't support non-ascii targets for symlinks yet.
1877
 
            fingerprint = str(inv_entry.symlink_target or '')
 
1925
            if inv_entry.symlink_target is None:
 
1926
                fingerprint = ''
 
1927
            else:
 
1928
                fingerprint = inv_entry.symlink_target.encode('utf8')
1878
1929
            size = 0
1879
1930
            executable = False
1880
1931
        elif kind == 'file':
1976
2027
        return len(self._parents) - len(self._ghosts)
1977
2028
 
1978
2029
    @staticmethod
1979
 
    def on_file(path, content_filter_stack_provider=None):
 
2030
    def on_file(path, sha1_provider=None):
1980
2031
        """Construct a DirState on the file at path path.
1981
2032
 
1982
 
        :param content_filter_stack_provider: a function that takes a
1983
 
            path (relative to the top of the tree) and a file-id as
1984
 
            parameters and returns a stack of ContentFilters.
1985
 
            If None, no content filtering is performed.
 
2033
        :param path: The path at which the dirstate file on disk should live.
 
2034
        :param sha1_provider: an object meeting the SHA1Provider interface.
 
2035
            If None, a DefaultSHA1Provider is used.
1986
2036
        :return: An unlocked DirState object, associated with the given path.
1987
2037
        """
1988
 
        result = DirState(path, content_filter_stack_provider)
 
2038
        if sha1_provider is None:
 
2039
            sha1_provider = DefaultSHA1Provider()
 
2040
        result = DirState(path, sha1_provider)
1989
2041
        return result
1990
2042
 
1991
2043
    def _read_dirblocks_if_needed(self):
2480
2532
        :param minikind: The type for the entry ('f' == 'file', 'd' ==
2481
2533
                'directory'), etc.
2482
2534
        :param executable: Should the executable bit be set?
2483
 
        :param fingerprint: Simple fingerprint for new entry: sha1 for files,
2484
 
            referenced revision id for subtrees, etc.
 
2535
        :param fingerprint: Simple fingerprint for new entry: canonical-form
 
2536
            sha1 for files, referenced revision id for subtrees, etc.
2485
2537
        :param packed_stat: Packed stat value for new entry.
2486
2538
        :param size: Size information for new entry
2487
2539
        :param path_utf8: key[0] + '/' + key[1], just passed in to avoid doing
2818
2870
    (saved_minikind, saved_link_or_sha1, saved_file_size,
2819
2871
     saved_executable, saved_packed_stat) = entry[1][0]
2820
2872
 
 
2873
    if minikind == 'd' and saved_minikind == 't':
 
2874
        minikind = 't'
2821
2875
    if (minikind == saved_minikind
2822
2876
        and packed_stat == saved_packed_stat):
2823
2877
        # The stat hasn't changed since we saved, so we can re-use the
2841
2895
            and stat_value.st_ctime < state._cutoff_time
2842
2896
            and len(entry[1]) > 1
2843
2897
            and entry[1][1][0] != 'a'):
2844
 
                # Could check for size changes for further optimised
2845
 
                # avoidance of sha1's. However the most prominent case of
2846
 
                # over-shaing is during initial add, which this catches.
2847
 
                # Besides, if content filtering happens, size and sha
2848
 
                # need to be checked together - checking just the size
2849
 
                # would be wrong.
2850
 
            if state._filter_provider is None:
2851
 
                filter_list = []
2852
 
            else:
2853
 
                relpath = osutils.pathjoin(entry[0][0], entry[0][1])
2854
 
                file_id = entry[0][2]
2855
 
                filter_list = state._filter_provider(relpath, file_id)
2856
 
            link_or_sha1 = state._size_sha1_file(abspath, filter_list)[1]
 
2898
            # Could check for size changes for further optimised
 
2899
            # avoidance of sha1's. However the most prominent case of
 
2900
            # over-shaing is during initial add, which this catches.
 
2901
            # Besides, if content filtering happens, size and sha
 
2902
            # are calculated at the same time, so checking just the size
 
2903
            # gains nothing w.r.t. performance.
 
2904
            link_or_sha1 = state._sha1_file(abspath)
2857
2905
            entry[1][0] = ('f', link_or_sha1, stat_value.st_size,
2858
2906
                           executable, packed_stat)
2859
2907
        else:
3011
3059
                        if target_details[2] == source_details[2]:
3012
3060
                            if link_or_sha1 is None:
3013
3061
                                # Stat cache miss:
3014
 
                                file_obj = file(path_info[4], 'rb')
3015
 
                                try:
3016
 
                                    statvalue = os.fstat(file_obj.fileno())
3017
 
                                    link_or_sha1 = osutils.sha_file(file_obj)
3018
 
                                finally:
3019
 
                                    file_obj.close()
 
3062
                                statvalue, link_or_sha1 = \
 
3063
                                    self.state._sha1_provider.stat_and_sha1(
 
3064
                                    path_info[4])
3020
3065
                                self.state._observed_sha1(entry, link_or_sha1,
3021
3066
                                    statvalue)
3022
3067
                            content_change = (link_or_sha1 != source_details[1])
3425
3470
                while (current_entry is not None or
3426
3471
                    current_path_info is not None):
3427
3472
                    if current_entry is None:
3428
 
                        # the check for path_handled when the path is adnvaced
 
3473
                        # the check for path_handled when the path is advanced
3429
3474
                        # will yield this path if needed.
3430
3475
                        pass
3431
3476
                    elif current_path_info is None: