Rev 2328: Update update_entry to use the path_info API. in file:///home/robertc/source/baz/dirstate2/

Robert Collins robertc at robertcollins.net
Fri Mar 9 15:52:24 GMT 2007


At file:///home/robertc/source/baz/dirstate2/

------------------------------------------------------------
revno: 2328
revision-id: robertc at robertcollins.net-20070309155213-fciselcj7bjb6swy
parent: robertc at robertcollins.net-20070309143019-8y1a649z5hzryiuh
committer: Robert Collins <robertc at robertcollins.net>
branch nick: dirstate2
timestamp: Sat 2007-03-10 02:52:13 +1100
message:
  Update update_entry to use the path_info API.
modified:
  bzrlib/dirstate.py             dirstate.py-20060728012006-d6mvoihjb3je9peu-1
  bzrlib/osutils.py              osutils.py-20050309040759-eeaff12fbf77ac86
  bzrlib/tests/test_dirstate.py  test_dirstate.py-20060728012006-d6mvoihjb3je9peu-2
  bzrlib/tests/test_osutils.py   test_osutils.py-20051201224856-e48ee24c12182989
  bzrlib/workingtree_4.py        workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
=== modified file 'bzrlib/dirstate.py'
--- a/bzrlib/dirstate.py	2007-03-09 04:23:52 +0000
+++ b/bzrlib/dirstate.py	2007-03-09 15:52:13 +0000
@@ -215,7 +215,7 @@
     osutils,
     trace,
     )
-from bzrlib.path_info import pack_stat
+from bzrlib.path_info import pack_stat, kind_missing
 
 
 class _Bisector(object):
@@ -1055,13 +1055,12 @@
             raise
         return result
 
-    def update_entry(self, entry, abspath, stat_value=None):
+    def update_entry(self, entry, abspath, path_info, kind_missing=kind_missing):
         """Update the entry based on what is actually on disk.
 
         :param entry: This is the dirblock entry for the file in question.
         :param abspath: The path on disk for this file.
-        :param stat_value: (optional) if we already have done a stat on the
-            file, re-use it.
+        :param path_info: A tuple as returned by path_info.path_info.
         :return: The sha1 hexdigest of the file (40 bytes) or link target of a
                 symlink.
         """
@@ -1069,31 +1068,19 @@
         # the internal _dirblocks. So the dirblock state must have already been
         # read.
         assert self._dirblock_state != DirState.NOT_IN_MEMORY
-        if stat_value is None:
-            try:
-                # We could inline os.lstat but the common case is that
-                # stat_value will be passed in, not read here.
-                stat_value = self._lstat(abspath, entry)
-            except (OSError, IOError), e:
-                if e.errno in (errno.ENOENT, errno.EACCES,
-                               errno.EPERM):
-                    # The entry is missing, consider it gone
-                    return None
-                raise
-
-        kind = osutils.file_kind_from_stat_mode(stat_value.st_mode)
+        if path_info[0] is kind_missing:
+            return None
         try:
-            minikind = DirState._kind_to_minikind[kind]
+            minikind = DirState._kind_to_minikind[path_info[0]]
         except KeyError: # Unknown kind
             return None
-        packed_stat = pack_stat(stat_value)
         (saved_minikind, saved_link_or_sha1, saved_file_size,
          saved_executable, saved_packed_stat) = entry[1][0]
 
         if (minikind == saved_minikind
-            and packed_stat == saved_packed_stat
+            and path_info[4] == saved_packed_stat
             # size should also be in packed_stat
-            and saved_file_size == stat_value.st_size):
+            and saved_file_size == path_info[1]):
             # The stat hasn't changed since we saved, so we can potentially
             # re-use the saved sha hash.
             if minikind == 'd':
@@ -1102,8 +1089,7 @@
             if self._cutoff_time is None:
                 self._sha_cutoff_time()
 
-            if (stat_value.st_mtime < self._cutoff_time
-                and stat_value.st_ctime < self._cutoff_time):
+            if path_info[3] < self._cutoff_time:
                 # Return the existing fingerprint
                 return saved_link_or_sha1
 
@@ -1112,13 +1098,12 @@
         link_or_sha1 = None
         if minikind == 'f':
             link_or_sha1 = self._sha1_file(abspath, entry)
-            executable = self._is_executable(stat_value.st_mode,
-                                             saved_executable)
-            entry[1][0] = ('f', link_or_sha1, stat_value.st_size,
-                           executable, packed_stat)
+            executable = self._is_executable(path_info[2], saved_executable)
+            entry[1][0] = ('f', link_or_sha1, path_info[1],
+                           executable, path_info[4])
         elif minikind == 'd':
             link_or_sha1 = None
-            entry[1][0] = ('d', '', 0, False, packed_stat)
+            entry[1][0] = ('d', '', 0, False, path_info[4])
             if saved_minikind != 'd':
                 # This changed from something into a directory. Make sure we
                 # have a directory block for it. This doesn't happen very
@@ -1129,8 +1114,7 @@
                                    osutils.pathjoin(entry[0][0], entry[0][1]))
         elif minikind == 'l':
             link_or_sha1 = self._read_link(abspath, saved_link_or_sha1)
-            entry[1][0] = ('l', link_or_sha1, stat_value.st_size,
-                           False, packed_stat)
+            entry[1][0] = ('l', link_or_sha1, 0, False, path_info[4])
         self._dirblock_state = DirState.IN_MEMORY_MODIFIED
         return link_or_sha1
 
@@ -1159,9 +1143,9 @@
         finally:
             f.close()
 
-    def _is_executable(self, mode, old_executable):
+    def _is_executable(self, disk_executable, old_executable):
         """Is this file executable?"""
-        return bool(S_IEXEC & mode)
+        return disk_executable
 
     def _is_executable_win32(self, mode, old_executable):
         """On win32 the executable bit is stored in the dirstate."""

=== modified file 'bzrlib/osutils.py'
--- a/bzrlib/osutils.py	2007-03-09 06:16:08 +0000
+++ b/bzrlib/osutils.py	2007-03-09 15:52:13 +0000
@@ -49,6 +49,7 @@
 from bzrlib import (
     cache_utf8,
     errors,
+    path_info,
     win32utils,
     )
 """)
@@ -1047,7 +1048,7 @@
         raise errors.IllegalPath(path)
 
 
-def walkdirs(top, prefix=""):
+def walkdirs(top, prefix="", path_info=path_info.path_info):
     """Yield data about all the directories in a tree.
     
     This yields all the data about the contents of a directory at a time.
@@ -1083,11 +1084,13 @@
     _lstat = os.lstat
     _directory = _directory_kind
     _listdir = os.listdir
-    _kind_from_mode = _formats.get
-    pending = [(safe_unicode(prefix), "", _directory, None, safe_unicode(top))]
+    # 0 - relpath, 1- basename, 2- kind, 3 - size, 4- exe, 5-stattime, 6- statcache, 7-toppath
+    # But we don't actually uses 1-6 in pending, so set them to None
+    pending = [(safe_unicode(prefix), "", _directory, None, None, None, None, safe_unicode(top))]
+    native_encoding = sys.getfilesystemencoding()
     while pending:
-        # 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
-        relroot, _, _, _, top = pending.pop()
+        # 0 - relpath, 1- basename, 2- kind, 3 - size, 4- exe, 5- statcache, 6-toppath
+        relroot, _, _, _, _, _, _, top = pending.pop()
         if relroot:
             relprefix = relroot + u'/'
         else:
@@ -1098,9 +1101,9 @@
         append = dirblock.append
         for name in sorted(_listdir(top)):
             abspath = top_slash + name
-            statvalue = _lstat(abspath)
-            kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
-            append((relprefix + name, name, kind, statvalue, abspath))
+            info = path_info(abspath.encode(native_encoding))
+            append((relprefix + name, name, info[0], info[1], info[2], info[3],
+                info[4], abspath))
         yield (relroot, top), dirblock
 
         # push the user specified dirs from dirblock
@@ -1129,7 +1132,7 @@
         return _walkdirs_fs_utf8(top, prefix=prefix)
 
 
-def _walkdirs_fs_utf8(top, prefix=""):
+def _walkdirs_fs_utf8(top, prefix="", path_info=path_info.path_info):
     """See _walkdirs_utf8.
 
     This sub-function is called when we know the filesystem is already in utf8
@@ -1140,11 +1143,11 @@
     _listdir = os.listdir
     _kind_from_mode = _formats.get
 
-    # 0 - relpath, 1- basename, 2- kind, 3- stat, 4-toppath
-    # But we don't actually uses 1-3 in pending, so set them to None
-    pending = [(safe_utf8(prefix), None, None, None, safe_utf8(top))]
+    # 0 - relpath, 1- basename, 2- kind, 3 - size, 4- exe, 5-stattime, 6- statcache, 7-toppath
+    # But we don't actually uses 1-6 in pending, so set them to None
+    pending = [(safe_utf8(prefix), None, None, None, None, None, None, safe_utf8(top))]
     while pending:
-        relroot, _, _, _, top = pending.pop()
+        relroot, _, _, _, _, _, _, top = pending.pop()
         if relroot:
             relprefix = relroot + '/'
         else:
@@ -1155,16 +1158,16 @@
         append = dirblock.append
         for name in sorted(_listdir(top)):
             abspath = top_slash + name
-            statvalue = _lstat(abspath)
-            kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
-            append((relprefix + name, name, kind, statvalue, abspath))
+            info = path_info(abspath)
+            append((relprefix + name, name, info[0], info[1], info[2], info[3],
+                info[4], abspath))
         yield (relroot, top), dirblock
 
         # push the user specified dirs from dirblock
         pending.extend(d for d in reversed(dirblock) if d[2] == _directory)
 
 
-def _walkdirs_unicode_to_utf8(top, prefix=""):
+def _walkdirs_unicode_to_utf8(top, prefix="", path_info=path_info.path_info):
     """See _walkdirs_utf8
 
     Because Win32 has a Unicode api, all of the 'path-from-top' entries will be
@@ -1179,10 +1182,13 @@
     _directory = _directory_kind
     _listdir = os.listdir
     _kind_from_mode = _formats.get
+    fs_encoder = codecs.getencoder(sys.getfilesystemencoding())
 
-    pending = [(safe_utf8(prefix), None, None, None, safe_unicode(top))]
+    # 0 - relpath, 1- basename, 2- kind, 3 - size, 4- exe, 5-stattime, 6- statcache, 7-toppath
+    # But we don't actually uses 1-6 in pending, so set them to None
+    pending = [(safe_utf8(prefix), None, None, None, None, None, None, safe_unicode(top))]
     while pending:
-        relroot, _, _, _, top = pending.pop()
+        relroot, _, _, _, _, _, _, top = pending.pop()
         if relroot:
             relprefix = relroot + '/'
         else:
@@ -1194,9 +1200,8 @@
         for name in sorted(_listdir(top)):
             name_utf8 = _utf8_encode(name)[0]
             abspath = top_slash + name
-            statvalue = _lstat(abspath)
-            kind = _kind_from_mode(statvalue.st_mode & 0170000, 'unknown')
-            append((relprefix + name_utf8, name_utf8, kind, statvalue, abspath))
+            info = path_info(fs_encoder(abspath)[0])
+            append((relprefix + name_utf8, name_utf8, info[0], info[1], info[2], info[3], info[4], abspath))
         yield (relroot, top), dirblock
 
         # push the user specified dirs from dirblock
@@ -1240,8 +1245,10 @@
     if not os.path.exists(to_path):
         real_handlers['directory'](from_path, to_path)
 
+    if from_path.__class__ != str:
+        from_path = from_path.encode(sys.getfilesystemencoding())
     for dir_info, entries in walkdirs(from_path, prefix=to_path):
-        for relpath, name, kind, st, abspath in entries:
+        for relpath, _, kind, _, _, _, _, abspath in entries:
             real_handlers[kind](abspath, relpath)
 
 

=== modified file 'bzrlib/tests/test_dirstate.py'
--- a/bzrlib/tests/test_dirstate.py	2007-03-07 08:00:48 +0000
+++ b/bzrlib/tests/test_dirstate.py	2007-03-09 15:52:13 +0000
@@ -24,6 +24,7 @@
     dirstate,
     errors,
     osutils,
+    path_info,
     )
 from bzrlib.memorytree import MemoryTree
 from bzrlib.tests import TestCase, TestCaseWithTransport
@@ -1138,20 +1139,17 @@
         self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
                          state._dirblock_state)
 
-        stat_value = os.lstat('a')
-        packed_stat = dirstate.pack_stat(stat_value)
-        link_or_sha1 = state.update_entry(entry, abspath='a',
-                                          stat_value=stat_value)
+        info = path_info.path_info('a')
+        link_or_sha1 = state.update_entry(entry, abspath='a', path_info=info)
         self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
                          link_or_sha1)
 
         # The dirblock entry should be updated with the new info
-        self.assertEqual([('f', link_or_sha1, 14, False, packed_stat)],
+        self.assertEqual([('f', link_or_sha1, 14, False, info[4])],
                          entry[1])
         self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
                          state._dirblock_state)
-        mode = stat_value.st_mode
-        self.assertEqual([('sha1', 'a'), ('is_exec', mode, False)], state._log)
+        self.assertEqual([('sha1', 'a'), ('is_exec', False, False)], state._log)
 
         state.save()
         self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
@@ -1162,10 +1160,9 @@
         # guaranteed to look too new.
         state.adjust_time(-10)
 
-        link_or_sha1 = state.update_entry(entry, abspath='a',
-                                          stat_value=stat_value)
-        self.assertEqual([('sha1', 'a'), ('is_exec', mode, False),
-                          ('sha1', 'a'), ('is_exec', mode, False),
+        link_or_sha1 = state.update_entry(entry, abspath='a', path_info=info)
+        self.assertEqual([('sha1', 'a'), ('is_exec', False, False),
+                          ('sha1', 'a'), ('is_exec', False, False),
                          ], state._log)
         self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
                          link_or_sha1)
@@ -1176,26 +1173,11 @@
         # However, if we move the clock forward so the file is considered
         # "stable", it should just returned the cached value.
         state.adjust_time(20)
-        link_or_sha1 = state.update_entry(entry, abspath='a',
-                                          stat_value=stat_value)
-        self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
-                         link_or_sha1)
-        self.assertEqual([('sha1', 'a'), ('is_exec', mode, False),
-                          ('sha1', 'a'), ('is_exec', mode, False),
-                         ], state._log)
-
-    def test_update_entry_no_stat_value(self):
-        """Passing the stat_value is optional."""
-        state, entry = self.get_state_with_a()
-        state.adjust_time(-10) # Make sure the file looks new
-        self.build_tree(['a'])
-        # Add one where we don't provide the stat or sha already
-        link_or_sha1 = state.update_entry(entry, abspath='a')
-        self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
-                         link_or_sha1)
-        stat_value = os.lstat('a')
-        self.assertEqual([('lstat', 'a'), ('sha1', 'a'),
-                          ('is_exec', stat_value.st_mode, False),
+        link_or_sha1 = state.update_entry(entry, abspath='a', path_info=info)
+        self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
+                         link_or_sha1)
+        self.assertEqual([('sha1', 'a'), ('is_exec', False, False),
+                          ('sha1', 'a'), ('is_exec', False, False),
                          ], state._log)
 
     def test_update_entry_symlink(self):
@@ -1209,28 +1191,23 @@
         os.symlink('target', 'a')
 
         state.adjust_time(-10) # Make the symlink look new
-        stat_value = os.lstat('a')
-        packed_stat = dirstate.pack_stat(stat_value)
-        link_or_sha1 = state.update_entry(entry, abspath='a',
-                                          stat_value=stat_value)
+        info = path_info.path_info('a')
+        link_or_sha1 = state.update_entry(entry, abspath='a', path_info=info)
         self.assertEqual('target', link_or_sha1)
         self.assertEqual([('read_link', 'a', '')], state._log)
         # Dirblock is updated
-        self.assertEqual([('l', link_or_sha1, 6, False, packed_stat)],
-                         entry[1])
+        self.assertEqual([('l', link_or_sha1, 0, False, info[4])], entry[1])
         self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
                          state._dirblock_state)
 
         # Because the stat_value looks new, we should re-read the target
-        link_or_sha1 = state.update_entry(entry, abspath='a',
-                                          stat_value=stat_value)
+        link_or_sha1 = state.update_entry(entry, abspath='a', path_info=info)
         self.assertEqual('target', link_or_sha1)
         self.assertEqual([('read_link', 'a', ''),
                           ('read_link', 'a', 'target'),
                          ], state._log)
         state.adjust_time(+20) # Skip into the future, all files look old
-        link_or_sha1 = state.update_entry(entry, abspath='a',
-                                          stat_value=stat_value)
+        link_or_sha1 = state.update_entry(entry, abspath='a', path_info=info)
         self.assertEqual('target', link_or_sha1)
         # There should not be a new read_link call.
         # (this is a weak assertion, because read_link is fairly inexpensive,
@@ -1242,7 +1219,8 @@
     def test_update_entry_dir(self):
         state, entry = self.get_state_with_a()
         self.build_tree(['a/'])
-        self.assertIs(None, state.update_entry(entry, 'a'))
+        info = path_info.path_info('a')
+        self.assertIs(None, state.update_entry(entry, 'a', info))
 
     def create_and_test_file(self, state, entry):
         """Create a file at 'a' and verify the state finds it.
@@ -1251,15 +1229,12 @@
         sure that state.update_entry recognizes it as a file.
         """
         self.build_tree(['a'])
-        stat_value = os.lstat('a')
-        packed_stat = dirstate.pack_stat(stat_value)
-
-        link_or_sha1 = state.update_entry(entry, abspath='a')
+        info = path_info.path_info('a')
+        link_or_sha1 = state.update_entry(entry, abspath='a', path_info=info)
         self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
                          link_or_sha1)
-        self.assertEqual([('f', link_or_sha1, 14, False, packed_stat)],
-                         entry[1])
-        return packed_stat
+        self.assertEqual([('f', link_or_sha1, 14, False, info[4])], entry[1])
+        return info[4]
 
     def create_and_test_dir(self, state, entry):
         """Create a directory at 'a' and verify the state finds it.
@@ -1268,14 +1243,13 @@
         sure that state.update_entry recognizes it as a directory.
         """
         self.build_tree(['a/'])
-        stat_value = os.lstat('a')
-        packed_stat = dirstate.pack_stat(stat_value)
+        info = path_info.path_info('a')
 
-        link_or_sha1 = state.update_entry(entry, abspath='a')
+        link_or_sha1 = state.update_entry(entry, abspath='a', path_info=info)
         self.assertIs(None, link_or_sha1)
-        self.assertEqual([('d', '', 0, False, packed_stat)], entry[1])
+        self.assertEqual([('d', '', 0, False, info[4])], entry[1])
 
-        return packed_stat
+        return info[4]
 
     def create_and_test_symlink(self, state, entry):
         """Create a symlink at 'a' and verify the state finds it.
@@ -1287,15 +1261,12 @@
         support.
         """
         os.symlink('path/to/foo', 'a')
-
-        stat_value = os.lstat('a')
-        packed_stat = dirstate.pack_stat(stat_value)
-
-        link_or_sha1 = state.update_entry(entry, abspath='a')
+        info = path_info.path_info('a')
+        link_or_sha1 = state.update_entry(entry, abspath='a', path_info=info)
         self.assertEqual('path/to/foo', link_or_sha1)
-        self.assertEqual([('l', 'path/to/foo', 11, False, packed_stat)],
+        self.assertEqual([('l', 'path/to/foo', 0, False, info[4])],
                          entry[1])
-        return packed_stat
+        return info[4]
 
     def test_update_missing_file(self):
         state, entry = self.get_state_with_a()
@@ -1303,7 +1274,8 @@
         # Now if we delete the file, update_entry should recover and
         # return None.
         os.remove('a')
-        self.assertIs(None, state.update_entry(entry, abspath='a'))
+        info = path_info.path_info('a')
+        self.assertIs(None, state.update_entry(entry, 'a', info))
         # And the record shouldn't be changed.
         digest = 'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
         self.assertEqual([('f', digest, 14, False, packed_stat)],
@@ -1315,7 +1287,8 @@
         # Now if we delete the directory, update_entry should recover and
         # return None.
         os.rmdir('a')
-        self.assertIs(None, state.update_entry(entry, abspath='a'))
+        info = path_info.path_info('a')
+        self.assertIs(None, state.update_entry(entry, 'a', info))
         self.assertEqual([('d', '', 0, False, packed_stat)], entry[1])
 
     def test_update_missing_symlink(self):
@@ -1324,9 +1297,10 @@
         state, entry = self.get_state_with_a()
         packed_stat = self.create_and_test_symlink(state, entry)
         os.remove('a')
-        self.assertIs(None, state.update_entry(entry, abspath='a'))
+        info = path_info.path_info('a')
+        self.assertIs(None, state.update_entry(entry, 'a', info))
         # And the record shouldn't be changed.
-        self.assertEqual([('l', 'path/to/foo', 11, False, packed_stat)],
+        self.assertEqual([('l', 'path/to/foo', 0, False, packed_stat)],
                          entry[1])
 
     def test_update_file_to_dir(self):
@@ -1388,16 +1362,15 @@
         # it is. With _is_executable_win32 we ignore what is on disk.
         entry[1][0] = ('f', '', 0, True, dirstate.DirState.NULLSTAT)
 
-        stat_value = os.lstat('a')
-        packed_stat = dirstate.pack_stat(stat_value)
+        info = path_info.path_info('a')
 
         state.adjust_time(-10) # Make sure everything is new
         # Make sure it wants to kkkkkkkk
-        state.update_entry(entry, abspath='a', stat_value=stat_value)
+        state.update_entry(entry, abspath='a', path_info=info)
 
         # The row is updated, but the executable bit stays set.
         digest = 'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
-        self.assertEqual([('f', digest, 14, True, packed_stat)], entry[1])
+        self.assertEqual([('f', digest, 14, True, info[4])], entry[1])
 
 
 class TestPackStat(TestCaseWithTransport):

=== modified file 'bzrlib/tests/test_osutils.py'
--- a/bzrlib/tests/test_osutils.py	2007-03-07 01:14:11 +0000
+++ b/bzrlib/tests/test_osutils.py	2007-03-09 15:52:13 +0000
@@ -25,6 +25,7 @@
 import bzrlib
 from bzrlib import (
     errors,
+    path_info,
     osutils,
     win32utils,
     )
@@ -521,16 +522,18 @@
             '2file'
             ]
         self.build_tree(tree)
+        stats = [os.lstat(path) for path in tree]
+        packs = [path_info.pack_stat(st) for st in stats]
         expected_dirblocks = [
                 (('', '.'),
-                 [('0file', '0file', 'file'),
-                  ('1dir', '1dir', 'directory'),
-                  ('2file', '2file', 'file'),
+                 [('0file', '0file', 'file', 18, False, stats[1].st_mtime, packs[1], './0file'),
+                  ('1dir', '1dir', 'directory', 0, False, stats[2].st_mtime, packs[2], './1dir'),
+                  ('2file', '2file', 'file', 18, False, stats[5].st_mtime, packs[5], './2file'),
                  ]
                 ),
                 (('1dir', './1dir'),
-                 [('1dir/0file', '0file', 'file'),
-                  ('1dir/1dir', '1dir', 'directory'),
+                 [('1dir/0file', '0file', 'file', 23, False, stats[3].st_mtime, packs[3], './1dir/0file'),
+                  ('1dir/1dir', '1dir', 'directory', 0, False, stats[4].st_mtime, packs[4], './1dir/1dir'),
                  ]
                 ),
                 (('1dir/1dir', './1dir/1dir'),
@@ -548,14 +551,12 @@
             result.append((dirdetail, dirblock))
 
         self.assertTrue(found_bzrdir)
-        self.assertEqual(expected_dirblocks,
-            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
+        self.assertEqual(expected_dirblocks, result)
         # you can search a subdir only, with a supplied prefix.
         result = []
         for dirblock in osutils.walkdirs('./1dir', '1dir'):
             result.append(dirblock)
-        self.assertEqual(expected_dirblocks[1:],
-            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
+        self.assertEqual(expected_dirblocks[1:], result)
 
     def test__walkdirs_utf8(self):
         tree = [
@@ -567,16 +568,18 @@
             '2file'
             ]
         self.build_tree(tree)
+        stats = [os.lstat(path) for path in tree]
+        packs = [path_info.pack_stat(st) for st in stats]
         expected_dirblocks = [
                 (('', '.'),
-                 [('0file', '0file', 'file'),
-                  ('1dir', '1dir', 'directory'),
-                  ('2file', '2file', 'file'),
+                 [('0file', '0file', 'file', 18, False, stats[1].st_mtime, packs[1], './0file'),
+                  ('1dir', '1dir', 'directory', 0, False, stats[2].st_mtime, packs[2], './1dir'),
+                  ('2file', '2file', 'file', 18, False, stats[5].st_mtime, packs[5], './2file'),
                  ]
                 ),
                 (('1dir', './1dir'),
-                 [('1dir/0file', '0file', 'file'),
-                  ('1dir/1dir', '1dir', 'directory'),
+                 [('1dir/0file', '0file', 'file', 23, False, stats[3].st_mtime, packs[3], './1dir/0file'),
+                  ('1dir/1dir', '1dir', 'directory', 0, False, stats[4].st_mtime, packs[4], './1dir/1dir'),
                  ]
                 ),
                 (('1dir/1dir', './1dir/1dir'),
@@ -594,14 +597,12 @@
             result.append((dirdetail, dirblock))
 
         self.assertTrue(found_bzrdir)
-        self.assertEqual(expected_dirblocks,
-            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
+        self.assertEqual(expected_dirblocks, result)
         # you can search a subdir only, with a supplied prefix.
         result = []
         for dirblock in osutils.walkdirs('./1dir', '1dir'):
             result.append(dirblock)
-        self.assertEqual(expected_dirblocks[1:],
-            [(dirinfo, [line[0:3] for line in block]) for dirinfo, block in result])
+        self.assertEqual(expected_dirblocks[1:], result)
 
     def _filter_out_stat(self, result):
         """Filter out the stat value from the walkdirs result"""
@@ -609,7 +610,7 @@
             new_dirblock = []
             for info in dirblock:
                 # Ignore info[3] which is the stat
-                new_dirblock.append((info[0], info[1], info[2], info[4]))
+                new_dirblock.append((info[0], info[1], info[2], info[7]))
             dirblock[:] = new_dirblock
 
     def test_unicode_walkdirs(self):
@@ -712,9 +713,9 @@
             for info in dirblock:
                 self.assertIsInstance(info[0], str)
                 self.assertIsInstance(info[1], str)
-                self.assertIsInstance(info[4], str)
+                self.assertIsInstance(info[7], str)
                 # Remove the stat information
-                new_dirblock.append((info[0], info[1], info[2], info[4]))
+                new_dirblock.append((info[0], info[1], info[2], info[7]))
             result.append((dirdetail, new_dirblock))
         self.assertEqual(expected_dirblocks, result)
 

=== modified file 'bzrlib/workingtree_4.py'
--- a/bzrlib/workingtree_4.py	2007-03-07 03:09:14 +0000
+++ b/bzrlib/workingtree_4.py	2007-03-09 15:52:13 +0000
@@ -52,6 +52,7 @@
     ignores,
     merge,
     osutils,
+    path_info,
     revisiontree,
     textui,
     transform,
@@ -394,8 +395,11 @@
 
         file_abspath = self.abspath(path)
         state = self.current_dirstate()
-        link_or_sha1 = state.update_entry(entry, file_abspath,
-                                          stat_value=stat_value)
+        # yes, this always stats. stat_value is not enough to update
+        # an entry, and whoever is statting should gather the info
+        # TODO: pdb if stat_value is given, and is a stat
+        info = path_info.path_info(file_abspath.encode(sys.getfilesystemencoding()))
+        link_or_sha1 = state.update_entry(entry, file_abspath, info)
         if entry[1][0][0] == 'f':
             return link_or_sha1
         return None
@@ -1756,12 +1760,12 @@
         def _process_entry(entry, path_info):
             """Compare an entry and real disk to generate delta information.
 
-            :param path_info: top_relpath, basename, kind, lstat, abspath for
-                the path of entry. If None, then the path is considered absent.
-                (Perhaps we should pass in a concrete entry for this ?)
-                Basename is returned as a utf8 string because we expect this
-                tuple will be ignored, and don't want to take the time to
-                decode.
+            :param path_info: top_relpath, basename, kind, size, exe,
+                statcache, abspath for the path of entry. If None, then the
+                path is considered absent.  (Perhaps we should pass in a
+                concrete entry for this ?) Basename is returned as a utf8
+                string because we expect this tuple will be ignored, and don't
+                want to take the time to decode.
             """
             if source_index is None:
                 source_details = NULL_PARENT_DETAILS
@@ -1770,9 +1774,10 @@
             target_details = entry[1][target_index]
             target_minikind = target_details[0]
             if path_info is not None and target_minikind in 'fdlt':
+                # we have a versioned path here, and there is disk data for it.
                 assert target_index == 0
-                link_or_sha1 = state.update_entry(entry, abspath=path_info[4],
-                                                  stat_value=path_info[3])
+                link_or_sha1 = state.update_entry(entry, path_info[7],
+                    path_info[2:7])
                 # The entry may have been modified by update_entry
                 target_details = entry[1][target_index]
                 target_minikind = target_details[0]
@@ -1814,13 +1819,14 @@
                 else:
                     # source and target are both versioned and disk file is present.
                     target_kind = path_info[2]
+                    # Target details is updated at update_entry time
+                    target_exec = target_details[3]
                     if target_kind == 'directory':
                         if source_minikind != 'd':
                             content_change = True
                         else:
                             # directories have no fingerprint
                             content_change = False
-                        target_exec = False
                     elif target_kind == 'file':
                         if source_minikind != 'f':
                             content_change = True
@@ -1828,25 +1834,16 @@
                             # We could check the size, but we already have the
                             # sha1 hash.
                             content_change = (link_or_sha1 != source_details[1])
-                        # Target details is updated at update_entry time
-                        if use_filesystem_for_exec:
-                            # We don't need S_ISREG here, because we are sure
-                            # we are dealing with a file.
-                            target_exec = bool(stat.S_IEXEC & path_info[3].st_mode)
-                        else:
-                            target_exec = target_details[3]
                     elif target_kind == 'symlink':
                         if source_minikind != 'l':
                             content_change = True
                         else:
                             content_change = (link_or_sha1 != source_details[1])
-                        target_exec = False
                     elif target_kind == 'tree-reference':
                         if source_minikind != 't':
                             content_change = True
                         else:
                             content_change = False
-                        target_exec = False
                     else:
                         raise Exception, "unknown kind %s" % path_info[2]
                 # parent id is the entry for the path in the target tree
@@ -1898,14 +1895,8 @@
                                                  path_utf8=entry[0][0])[0][2]
                     if parent_id == entry[0][2]:
                         parent_id = None
-                    if use_filesystem_for_exec:
-                        # We need S_ISREG here, because we aren't sure if this
-                        # is a file or not.
-                        target_exec = bool(
-                            stat.S_ISREG(path_info[3].st_mode)
-                            and stat.S_IEXEC & path_info[3].st_mode)
-                    else:
-                        target_exec = target_details[3]
+                    # updated at update_entry time.
+                    target_exec = target_details[3]
                     return ((entry[0][2], (None, path), True,
                             (False, True),
                             (None, parent_id),
@@ -1959,19 +1950,12 @@
             # found by their parents recursively.
             root_entries = _entries_for_path(current_root)
             root_abspath = self.target.abspath(current_root)
-            try:
-                root_stat = os.lstat(root_abspath)
-            except OSError, e:
-                if e.errno == errno.ENOENT:
-                    # the path does not exist: let _process_entry know that.
-                    root_dir_info = None
-                else:
-                    # some other random error: hand it up.
-                    raise
+            root_abspath_native = root_abspath.encode(sys.getfilesystemencoding())
+            root_info = path_info.path_info(root_abspath_native)
+            if root_info[0] is path_info.kind_missing:
+                root_dir_info = None
             else:
-                root_dir_info = ('', current_root,
-                    osutils.file_kind_from_stat_mode(root_stat.st_mode), root_stat,
-                    root_abspath)
+                root_dir_info = ('', current_root, root_info[0], root_info[1], root_info[2], root_info[3], root_info[4], root_abspath)
                 if root_dir_info[2] == 'directory':
                     if self.target._directory_is_tree_reference(
                         current_root.decode('utf8')):
@@ -2001,13 +1985,10 @@
                              utf8_decode(result[1][1])[0]),) + result[2:]
                         yield result
             if want_unversioned and not path_handled:
-                new_executable = bool(
-                    stat.S_ISREG(root_dir_info[3].st_mode)
-                    and stat.S_IEXEC & root_dir_info[3].st_mode)
                 yield (None, (None, current_root), True, (False, False),
                     (None, None),
                     (None, splitpath(current_root)[-1]),
-                    (None, root_dir_info[2]), (None, new_executable))
+                    (None, root_dir_info[2]), (None, root_dir_info[4]))
             dir_iterator = osutils._walkdirs_utf8(root_abspath, prefix=current_root)
             initial_key = (current_root, '', '')
             block_index, _ = state._find_block_index_from_key(initial_key)
@@ -2189,17 +2170,13 @@
                         if not path_handled:
                             # unversioned in all regards
                             if want_unversioned:
-                                new_executable = bool(
-                                    stat.S_ISREG(current_path_info[3].st_mode)
-                                    and stat.S_IEXEC & current_path_info[3].st_mode)
-                                if want_unversioned:
-                                    yield (None, (None, current_path_info[0]),
-                                        True,
-                                        (False, False),
-                                        (None, None),
-                                        (None, current_path_info[1]),
-                                        (None, current_path_info[2]),
-                                        (None, new_executable))
+                                yield (None, (None, current_path_info[0]),
+                                    True,
+                                    (False, False),
+                                    (None, None),
+                                    (None, current_path_info[1]),
+                                    (None, current_path_info[2]),
+                                    (None, current_path_info[4]))
                             # dont descend into this unversioned path if it is
                             # a dir
                             if current_path_info[2] in (



More information about the bazaar-commits mailing list