Rev 3508: We have walkdirs basically working, only without timestamps in http://bzr.arbash-meinel.com/branches/bzr/1.6-dev/win32_find_files

John Arbash Meinel john at arbash-meinel.com
Thu Jul 17 00:29:36 BST 2008


At http://bzr.arbash-meinel.com/branches/bzr/1.6-dev/win32_find_files

------------------------------------------------------------
revno: 3508
revision-id: john at arbash-meinel.com-20080716232929-pcyg06005uxpveav
parent: john at arbash-meinel.com-20080716220622-m6zsz00j08co7l5g
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: win32_find_files
timestamp: Wed 2008-07-16 18:29:29 -0500
message:
  We have walkdirs basically working, only without timestamps
-------------- next part --------------
=== modified file 'bzrlib/_walkdirs_win32.pyx'
--- a/bzrlib/_walkdirs_win32.pyx	2008-07-16 22:06:22 +0000
+++ b/bzrlib/_walkdirs_win32.pyx	2008-07-16 23:29:29 +0000
@@ -52,14 +52,19 @@
     cdef int FindNextFileW(HANDLE search, WIN32_FIND_DATAW *data)
     cdef int FindClose(HANDLE search)
 
+    cdef DWORD FILE_ATTRIBUTE_READONLY
     cdef DWORD FILE_ATTRIBUTE_DIRECTORY
 
     cdef int GetLastError()
 
+    # Wide character functions
+    DWORD wcslen(WCHAR *)
+
 
 cdef extern from "Python.h":
     WCHAR *PyUnicode_AS_UNICODE(object)
     Py_ssize_t PyUnicode_GET_SIZE(object)
+    object PyUnicode_FromUnicode(WCHAR *, Py_ssize_t)
 
 
 import codecs
@@ -83,24 +88,6 @@
         """Create a new Stat object, based on the WIN32_FIND_DATA tuple"""
         pass
 
-    def set_stuff(self):
-        (attrib, ctime, atime, wtime, size_high, size_low,
-         res0, res1, name, alt_name) = win32_find_data_record
-        self.st_ctime = int(ctime)
-        self.st_mtime = int(wtime)
-        self.st_atime = int(atime)
-        self.st_size = (size_high * 1<<32) + size_low
-
-        mode_bits = 0100666 # writeable file, the most common
-        if (win32file.FILE_ATTRIBUTE_READONLY & attrib ==
-            win32file.FILE_ATTRIBUTE_READONLY):
-            mode_bits ^= 0222 # remove writable bits
-        if (win32file.FILE_ATTRIBUTE_DIRECTORY & attrib ==
-            win32file.FILE_ATTRIBUTE_DIRECTORY):
-            # Remove the FILE bit, set the DIR bit, and set the EXEC bits
-            mode_bits ^= 0140111
-        self.st_mode = mode_bits
-
     def __repr__(self):
         """Repr is the same as a Stat object.
 
@@ -118,8 +105,8 @@
     cdef object _prefix
 
     cdef object _utf8_encode
-    cdef object _directory
-    cdef object _file
+    cdef object _directory_kind
+    cdef object _file_kind
 
     cdef object _pending
     cdef object _last_dirblock
@@ -129,8 +116,8 @@
         self._prefix = prefix
 
         self._utf8_encode = codecs.getencoder('utf8')
-        self._directory = osutils._directory_kind
-        self._file = osutils._formats[stat.S_IFREG]
+        self._directory_kind = osutils._directory_kind
+        self._file_kind = osutils._formats[stat.S_IFREG]
 
         self._pending = [(osutils.safe_utf8(prefix), None, None, None,
                           osutils.safe_unicode(top))]
@@ -139,7 +126,53 @@
     def __iter__(self):
         return self
 
-    def _get_files_in(self, directory):
+    cdef object _get_name(self, WIN32_FIND_DATAW *data):
+        """Extract the Unicode name for this file/dir."""
+        name_unicode = PyUnicode_FromUnicode(data.cFileName,
+                                             wcslen(data.cFileName))
+        return name_unicode
+
+    cdef int _get_mode_bits(self, WIN32_FIND_DATAW *data):
+        cdef int mode_bits
+
+        mode_bits = 0100666 # writeable file, the most common
+        if data.dwFileAttributes & FILE_ATTRIBUTE_READONLY == FILE_ATTRIBUTE_READONLY:
+            mode_bits ^= 0222 # remove the write bits
+        if data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY:
+            # Remove the FILE bit, set the DIR bit, and set the EXEC bits
+            mode_bits ^= 0140111
+        return mode_bits
+
+    cdef object _get_size(self, WIN32_FIND_DATAW *data):
+        return long(data.nFileSizeLow) + (long(data.nFileSizeHigh) << 32)
+
+    cdef object _get_stat_value(self, WIN32_FIND_DATAW *data):
+        """Get the filename and the stat information."""
+        statvalue = _Win32Stat()
+        statvalue.st_mode = self._get_mode_bits(data)
+        # TODO: Convert the filetimes
+        statvalue.st_ctime = 0
+        statvalue.st_atime = 0
+        statvalue.st_mtime = 0
+        statvalue.st_size = self._get_size(data)
+        return statvalue
+
+    cdef object _get_kind(self, WIN32_FIND_DATAW *data):
+        if data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY:
+            return self._directory_kind
+        return self._file_kind
+
+    cdef int _should_skip(self, WIN32_FIND_DATAW *data):
+        """Is this '.' or '..' so we should skip it?"""
+        if (data.cFileName[0] != c'.'):
+            return False
+        if data.cFileName[1] == c'\0':
+            return True
+        if data.cFileName[1] == c'.' and data.cFileName[2] == c'\0':
+            return True
+        return False
+
+    def _get_files_in(self, directory, relprefix):
         cdef WIN32_FIND_DATAW search_data
         cdef HANDLE hFindFile
         cdef int last_err
@@ -163,12 +196,18 @@
             result = 1
             while result:
                 # Skip '.' and '..'
-                if (search_data.cFileName[0] == c'.'
-                    and (search_data.cFileName[1] == c'\0'
-                         or (search_data.cFileName[1] == c'.'
-                             and search_data.cFileName[2] == c'\0'))):
+                if self._should_skip(&search_data):
                     result = FindNextFileW(hFindFile, &search_data)
                     continue
+                name_unicode = self._get_name(&search_data)
+                name_utf8 = self._utf8_encode(name_unicode)[0]
+                relpath = relprefix + name_utf8
+                abspath = directory + name_unicode
+                append((relpath, name_utf8, 
+                        self._get_kind(&search_data),
+                        self._get_stat_value(&search_data),
+                        abspath))
+
                 result = FindNextFileW(hFindFile, &search_data)
         finally:
             result = FindClose(hFindFile)
@@ -197,7 +236,7 @@
             # we do this here, because we allow the user to modified the
             # queue before the next iteration
             for d in reversed(self._last_dirblock):
-                if d[2] == _directory:
+                if d[2] == self._directory_kind:
                     self._pending.append(d)
 
         if not self._pending:
@@ -213,7 +252,7 @@
             relprefix = ''
         top_slash = top + '/'
 
-        dirblock = self._get_files_in(top_slash)
+        dirblock = self._get_files_in(top_slash, relprefix)
         dirblock.sort(key=operator.itemgetter(1))
         self._last_dirblock = dirblock
         return (relroot, top), dirblock
@@ -224,50 +263,4 @@
 
     This uses the find files api to both list the files and to stat them.
     """
-    cdef WIN32_FIND_DATAW find_data
-
-    _utf8_encode = codecs.getencoder('utf8')
-
-    # WIN32_FIND_DATA object looks like:
-    # (FILE_ATTRIBUTES, createTime, accessTime, writeTime, nFileSizeHigh,
-    #  nFileSizeLow, reserved0, reserved1, name, alternateFilename)
-    _directory = osutils._directory_kind
-    _file = osutils._formats[stat.S_IFREG]
-
-    # Possible attributes:
-    DIRECTORY = FILE_ATTRIBUTE_DIRECTORY
-
-    pending = [(osutils.safe_utf8(prefix), None, None, None,
-                osutils.safe_unicode(top))]
-    while pending:
-        relroot, _, _, _, top = pending.pop()
-        if relroot:
-            relprefix = relroot + '/'
-        else:
-            relprefix = ''
-        top_slash = top + '/'
-        top_star = top_slash + '*'
-
-        dirblock = []
-        append = dirblock.append
-        for record in FindFilesIterator(top_star):
-            name = record[-2]
-            if name in ('.', '..'):
-                continue
-            attrib = record[0]
-            statvalue = osutils._Win32Stat(record)
-            name_utf8 = _utf8_encode(name)[0]
-            abspath = top_slash + name
-            if DIRECTORY & attrib == DIRECTORY:
-                kind = _directory
-            else:
-                kind = _file
-            append((relprefix + name_utf8, name_utf8, kind, statvalue, abspath))
-        dirblock.sort(key=operator.itemgetter(1))
-        yield (relroot, top), dirblock
-
-        # push the user specified dirs from dirblock
-        for d in reversed(dirblock):
-            if d[2] == _directory:
-                pending.append(d)
-
+    return Win32Finder(top, prefix=prefix)

=== modified file 'bzrlib/osutils.py'
--- a/bzrlib/osutils.py	2008-07-16 22:06:22 +0000
+++ b/bzrlib/osutils.py	2008-07-16 23:29:29 +0000
@@ -1272,91 +1272,13 @@
         pending.extend(d for d in reversed(dirblock) if d[2] == _directory)
 
 
-class _Win32Stat(object):
-    """Represent a 'stat' result generated from WIN32_FIND_DATA"""
-
-    __slots__ = ['st_mode', 'st_ctime', 'st_mtime', 'st_atime',
-                 'st_size']
-
-    # os.stat always returns 0, so we hard code it here
-    st_dev = 0
-    st_ino = 0
-
-    def __init__(self, win32_find_data_record):
-        """Create a new Stat object, based on the WIN32_FIND_DATA tuple"""
-        (attrib, ctime, atime, wtime, size_high, size_low,
-         res0, res1, name, alt_name) = win32_find_data_record
-        self.st_ctime = int(ctime)
-        self.st_mtime = int(wtime)
-        self.st_atime = int(atime)
-        self.st_size = (size_high * 1<<32) + size_low
-
-        mode_bits = 0100666 # writeable file, the most common
-        if (win32file.FILE_ATTRIBUTE_READONLY & attrib ==
-            win32file.FILE_ATTRIBUTE_READONLY):
-            mode_bits ^= 0222 # remove writable bits
-        if (win32file.FILE_ATTRIBUTE_DIRECTORY & attrib ==
-            win32file.FILE_ATTRIBUTE_DIRECTORY):
-            # Remove the FILE bit, set the DIR bit, and set the EXEC bits
-            mode_bits ^= 0140111
-        self.st_mode = mode_bits
-
-    def __repr__(self):
-        """Repr is the same as a Stat object.
-
-        (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime)
-        """
-        return repr((self.st_mode, 0, 0, 0, 0, 0, self.st_size, self.st_atime,
-                     self.st_mtime, self.st_ctime))
-
-
 def _walkdirs_utf8_win32_find_file(top, prefix=""):
     """
     Because Win32 has a Unicode api, all of the 'path-from-top' entries will be
     Unicode paths.
     """
-    import operator
-    _utf8_encode = codecs.getencoder('utf8')
-
-    # WIN32_FIND_DATA object looks like:
-    # (FILE_ATTRIBUTES, createTime, accessTime, writeTime, nFileSizeHigh,
-    #  nFileSizeLow, reserved0, reserved1, name, alternateFilename)
-    _directory = _directory_kind
-    _file = _formats[stat.S_IFREG]
-
-    # Possible attributes:
-    DIRECTORY = win32file.FILE_ATTRIBUTE_DIRECTORY
-
-    pending = [(safe_utf8(prefix), None, None, None, safe_unicode(top))]
-    while pending:
-        relroot, _, _, _, top = pending.pop()
-        if relroot:
-            relprefix = relroot + '/'
-        else:
-            relprefix = ''
-        top_slash = top + u'/'
-        top_star = top_slash + u'*'
-
-        dirblock = []
-        append = dirblock.append
-        for record in win32file.FindFilesIterator(top_star):
-            name = record[-2]
-            if name in (u'.', u'..'):
-                continue
-            attrib = record[0]
-            statvalue = _Win32Stat(record)
-            name_utf8 = _utf8_encode(name)[0]
-            abspath = top_slash + name
-            if DIRECTORY & attrib == DIRECTORY:
-                kind = _directory
-            else:
-                kind = _file
-            append((relprefix + name_utf8, name_utf8, kind, statvalue, abspath))
-        dirblock.sort(key=operator.itemgetter(1))
-        yield (relroot, top), dirblock
-
-        # push the user specified dirs from dirblock
-        pending.extend(d for d in reversed(dirblock) if d[2] == _directory)
+    from bzrlib._walkdirs_win32 import _walkdirs_utf8_win32_find_file as wd
+    return wd(top, prefix=prefix)
 
 
 def copy_tree(from_path, to_path, handlers={}):

=== modified file 'bzrlib/tests/test__walkdirs_win32.py'
--- a/bzrlib/tests/test__walkdirs_win32.py	2008-07-16 22:06:22 +0000
+++ b/bzrlib/tests/test__walkdirs_win32.py	2008-07-16 23:29:29 +0000
@@ -41,11 +41,20 @@
 
     def assertWalkdirs(self, expected, top, prefix=''):
         from bzrlib._walkdirs_win32 import (
-            Win32Finder,
+            _walkdirs_utf8_win32_find_file as walkdirs_utf8,
             )
-        finder = Win32Finder(top, prefix=prefix)
-        result = list(finder)
+        finder = walkdirs_utf8(top, prefix=prefix)
+        result = []
+        for dirname, dirblock in finder:
+            block_no_stat = [info[:3] + info[4:] for info in dirblock]
+            result.append((dirname, block_no_stat))
         self.assertEqual(expected, result)
 
     def test_empty_directory(self):
         self.assertWalkdirs([(('', u'.'), [])], u'.')
+
+    def test_file_in_dir(self):
+        self.build_tree(['foo'])
+        self.assertWalkdirs([
+            (('', u'.'), [('foo', 'foo', 'file', u'./foo')])
+            ], u'.')



More information about the bazaar-commits mailing list