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