/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

  • Committer: Robert Collins
  • Date: 2009-05-23 20:57:12 UTC
  • mfrom: (4371 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4441.
  • Revision ID: robertc@robertcollins.net-20090523205712-lcwbfqk6vwavinuv
MergeĀ .dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
"""DirState objects record the state of a directory and its bzr metadata.
18
18
 
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
186
187
the file on disk, and then immediately discard, the overhead of object creation
187
188
becomes a significant cost.
188
189
 
189
 
Figures: Creating a tuple from from 3 elements was profiled at 0.0625
 
190
Figures: Creating a tuple from 3 elements was profiled at 0.0625
190
191
microseconds, whereas creating a object which is subclassed from tuple was
191
192
0.500 microseconds, and creating an object with 3 elements and slots was 3
192
193
microseconds long. 0.1 milliseconds is 100 microseconds, and ideally we'll get
262
263
        # return '%X.%X' % (int(st.st_mtime), st.st_mode)
263
264
 
264
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
 
 
272
        :param abspath:  May be a filesystem encoded absolute path
 
273
             or a unicode path.
 
274
        """
 
275
        raise NotImplementedError(self.sha1)
 
276
 
 
277
    def stat_and_sha1(self, abspath):
 
278
        """Return the stat and sha1 of a file given its absolute path.
 
279
        
 
280
        :param abspath:  May be a filesystem encoded absolute path
 
281
             or a unicode path.
 
282
 
 
283
        Note: the stat should be the stat of the physical file
 
284
        while the sha may be the sha of its canonical content.
 
285
        """
 
286
        raise NotImplementedError(self.stat_and_sha1)
 
287
 
 
288
 
 
289
class DefaultSHA1Provider(SHA1Provider):
 
290
    """A SHA1Provider that reads directly from the filesystem."""
 
291
 
 
292
    def sha1(self, abspath):
 
293
        """Return the sha1 of a file given its absolute path."""
 
294
        return osutils.sha_file_by_name(abspath)
 
295
 
 
296
    def stat_and_sha1(self, abspath):
 
297
        """Return the stat and sha1 of a file given its absolute path."""
 
298
        file_obj = file(abspath, 'rb')
 
299
        try:
 
300
            statvalue = os.fstat(file_obj.fileno())
 
301
            sha1 = osutils.sha_file(file_obj)
 
302
        finally:
 
303
            file_obj.close()
 
304
        return statvalue, sha1
 
305
 
 
306
 
265
307
class DirState(object):
266
308
    """Record directory and metadata state for fast access.
267
309
 
320
362
    HEADER_FORMAT_2 = '#bazaar dirstate flat format 2\n'
321
363
    HEADER_FORMAT_3 = '#bazaar dirstate flat format 3\n'
322
364
 
323
 
    def __init__(self, path):
 
365
    def __init__(self, path, sha1_provider):
324
366
        """Create a  DirState object.
325
367
 
326
368
        :param path: The path at which the dirstate file on disk should live.
 
369
        :param sha1_provider: an object meeting the SHA1Provider interface.
327
370
        """
328
371
        # _header_state and _dirblock_state represent the current state
329
372
        # of the dirstate metadata and the per-row data respectiely.
355
398
        self._cutoff_time = None
356
399
        self._split_path_cache = {}
357
400
        self._bisect_page_size = DirState.BISECT_PAGE_SIZE
 
401
        self._sha1_provider = sha1_provider
358
402
        if 'hashcache' in debug.debug_flags:
359
403
            self._sha1_file = self._sha1_file_and_mutter
360
404
        else:
361
 
            self._sha1_file = osutils.sha_file_by_name
 
405
            self._sha1_file = self._sha1_provider.sha1
362
406
        # These two attributes provide a simple cache for lookups into the
363
407
        # dirstate in-memory vectors. By probing respectively for the last
364
408
        # block, and for the next entry, we save nearly 2 bisections per path
380
424
        :param kind: The kind of the path, as a string like 'file',
381
425
            'directory', etc.
382
426
        :param stat: The output of os.lstat for the path.
383
 
        :param fingerprint: The sha value of the file,
 
427
        :param fingerprint: The sha value of the file's canonical form (i.e.
 
428
            after any read filters have been applied),
384
429
            or the target of a symlink,
385
430
            or the referenced revision id for tree-references,
386
431
            or '' for directories.
1194
1239
        return entry_index, present
1195
1240
 
1196
1241
    @staticmethod
1197
 
    def from_tree(tree, dir_state_filename):
 
1242
    def from_tree(tree, dir_state_filename, sha1_provider=None):
1198
1243
        """Create a dirstate from a bzr Tree.
1199
1244
 
1200
1245
        :param tree: The tree which should provide parent information and
1201
1246
            inventory ids.
 
1247
        :param sha1_provider: an object meeting the SHA1Provider interface.
 
1248
            If None, a DefaultSHA1Provider is used.
1202
1249
        :return: a DirState object which is currently locked for writing.
1203
1250
            (it was locked by DirState.initialize)
1204
1251
        """
1205
 
        result = DirState.initialize(dir_state_filename)
 
1252
        result = DirState.initialize(dir_state_filename,
 
1253
            sha1_provider=sha1_provider)
1206
1254
        try:
1207
1255
            tree.lock_read()
1208
1256
            try:
1569
1617
        # when -Dhashcache is turned on, this is monkey-patched in to log
1570
1618
        # file reads
1571
1619
        trace.mutter("dirstate sha1 " + abspath)
1572
 
        return osutils.sha_file_by_name(abspath)
 
1620
        return self._sha1_provider.sha1(abspath)
1573
1621
 
1574
1622
    def _is_executable(self, mode, old_executable):
1575
1623
        """Is this file executable?"""
1829
1877
            return None, None
1830
1878
 
1831
1879
    @classmethod
1832
 
    def initialize(cls, path):
 
1880
    def initialize(cls, path, sha1_provider=None):
1833
1881
        """Create a new dirstate on path.
1834
1882
 
1835
1883
        The new dirstate will be an empty tree - that is it has no parents,
1836
1884
        and only a root node - which has id ROOT_ID.
1837
1885
 
1838
1886
        :param path: The name of the file for the dirstate.
 
1887
        :param sha1_provider: an object meeting the SHA1Provider interface.
 
1888
            If None, a DefaultSHA1Provider is used.
1839
1889
        :return: A write-locked DirState object.
1840
1890
        """
1841
1891
        # This constructs a new DirState object on a path, sets the _state_file
1843
1893
        # stock empty dirstate information - a root with ROOT_ID, no children,
1844
1894
        # and no parents. Finally it calls save() to ensure that this data will
1845
1895
        # persist.
1846
 
        result = cls(path)
 
1896
        if sha1_provider is None:
 
1897
            sha1_provider = DefaultSHA1Provider()
 
1898
        result = cls(path, sha1_provider)
1847
1899
        # root dir and root dir contents with no children.
1848
1900
        empty_tree_dirblocks = [('', []), ('', [])]
1849
1901
        # a new root directory, with a NULLSTAT.
1982
2034
        return len(self._parents) - len(self._ghosts)
1983
2035
 
1984
2036
    @staticmethod
1985
 
    def on_file(path):
1986
 
        """Construct a DirState on the file at path path.
 
2037
    def on_file(path, sha1_provider=None):
 
2038
        """Construct a DirState on the file at path "path".
1987
2039
 
 
2040
        :param path: The path at which the dirstate file on disk should live.
 
2041
        :param sha1_provider: an object meeting the SHA1Provider interface.
 
2042
            If None, a DefaultSHA1Provider is used.
1988
2043
        :return: An unlocked DirState object, associated with the given path.
1989
2044
        """
1990
 
        result = DirState(path)
 
2045
        if sha1_provider is None:
 
2046
            sha1_provider = DefaultSHA1Provider()
 
2047
        result = DirState(path, sha1_provider)
1991
2048
        return result
1992
2049
 
1993
2050
    def _read_dirblocks_if_needed(self):
2482
2539
        :param minikind: The type for the entry ('f' == 'file', 'd' ==
2483
2540
                'directory'), etc.
2484
2541
        :param executable: Should the executable bit be set?
2485
 
        :param fingerprint: Simple fingerprint for new entry: sha1 for files,
2486
 
            referenced revision id for subtrees, etc.
 
2542
        :param fingerprint: Simple fingerprint for new entry: canonical-form
 
2543
            sha1 for files, referenced revision id for subtrees, etc.
2487
2544
        :param packed_stat: Packed stat value for new entry.
2488
2545
        :param size: Size information for new entry
2489
2546
        :param path_utf8: key[0] + '/' + key[1], just passed in to avoid doing
2845
2902
            and stat_value.st_ctime < state._cutoff_time
2846
2903
            and len(entry[1]) > 1
2847
2904
            and entry[1][1][0] != 'a'):
2848
 
                # Could check for size changes for further optimised
2849
 
                # avoidance of sha1's. However the most prominent case of
2850
 
                # over-shaing is during initial add, which this catches.
 
2905
            # Could check for size changes for further optimised
 
2906
            # avoidance of sha1's. However the most prominent case of
 
2907
            # over-shaing is during initial add, which this catches.
 
2908
            # Besides, if content filtering happens, size and sha
 
2909
            # are calculated at the same time, so checking just the size
 
2910
            # gains nothing w.r.t. performance.
2851
2911
            link_or_sha1 = state._sha1_file(abspath)
2852
2912
            entry[1][0] = ('f', link_or_sha1, stat_value.st_size,
2853
2913
                           executable, packed_stat)
3006
3066
                        if target_details[2] == source_details[2]:
3007
3067
                            if link_or_sha1 is None:
3008
3068
                                # Stat cache miss:
3009
 
                                file_obj = file(path_info[4], 'rb')
3010
 
                                try:
3011
 
                                    statvalue = os.fstat(file_obj.fileno())
3012
 
                                    link_or_sha1 = osutils.sha_file(file_obj)
3013
 
                                finally:
3014
 
                                    file_obj.close()
 
3069
                                statvalue, link_or_sha1 = \
 
3070
                                    self.state._sha1_provider.stat_and_sha1(
 
3071
                                    path_info[4])
3015
3072
                                self.state._observed_sha1(entry, link_or_sha1,
3016
3073
                                    statvalue)
3017
3074
                            content_change = (link_or_sha1 != source_details[1])