[Zope3-checkins] SVN: Zope3/trunk/src/zope/fssync/ Fixed some encoding problems on OS X.

Uwe Oestermeier uwe_oestermeier at iwm-kmrc.de
Tue Mar 6 12:16:45 EST 2007


Log message for revision 73012:
  Fixed some encoding problems on OS X.

Changed:
  U   Zope3/trunk/src/zope/fssync/copier.py
  U   Zope3/trunk/src/zope/fssync/fsmerger.py
  U   Zope3/trunk/src/zope/fssync/fssync.py
  U   Zope3/trunk/src/zope/fssync/fsutil.py
  U   Zope3/trunk/src/zope/fssync/main.py
  U   Zope3/trunk/src/zope/fssync/merger.py
  U   Zope3/trunk/src/zope/fssync/metadata.py
  U   Zope3/trunk/src/zope/fssync/snarf.py

-=-
Modified: Zope3/trunk/src/zope/fssync/copier.py
===================================================================
--- Zope3/trunk/src/zope/fssync/copier.py	2007-03-06 16:52:59 UTC (rev 73011)
+++ Zope3/trunk/src/zope/fssync/copier.py	2007-03-06 17:16:44 UTC (rev 73012)
@@ -56,7 +56,7 @@
 
     def listDirectory(self, dir):
         return [fn
-                for fn in os.listdir(dir)
+                for fn in fsutil.listdir(dir)
                 if fn != "@@Zope"
                 if not self.sync.fsmerger.ignore(fn)]
 

Modified: Zope3/trunk/src/zope/fssync/fsmerger.py
===================================================================
--- Zope3/trunk/src/zope/fssync/fsmerger.py	2007-03-06 16:52:59 UTC (rev 73011)
+++ Zope3/trunk/src/zope/fssync/fsmerger.py	2007-03-06 17:16:44 UTC (rev 73012)
@@ -118,7 +118,7 @@
         rentrynames = self.metadata.getnames(remotedir)
         lentry = self.metadata.getentry(localdir)
         rentry = self.metadata.getentry(remotedir)
-
+                
         if not lentrynames and not rentrynames:
 
             if not lentry:
@@ -181,7 +181,7 @@
                     return
 
             lnames = dict([(normcase(name), name)
-                           for name in os.listdir(localdir)])
+                           for name in fsutil.listdir(localdir)])
         else:
             if flag == "removed":
                 self.reportdir("R", localdir)
@@ -198,7 +198,7 @@
 
         if exists(remotedir):
             rnames = dict([(normcase(name), name)
-                           for name in os.listdir(remotedir)])
+                           for name in fsutil.listdir(remotedir)])
         else:
             rnames = {}
 

Modified: Zope3/trunk/src/zope/fssync/fssync.py
===================================================================
--- Zope3/trunk/src/zope/fssync/fssync.py	2007-03-06 16:52:59 UTC (rev 73011)
+++ Zope3/trunk/src/zope/fssync/fssync.py	2007-03-06 17:16:44 UTC (rev 73012)
@@ -577,7 +577,7 @@
             raise Error("can't add '%s': its parent is not registered", path)
         if "path" not in pentry:
             raise Error("can't add '%s': its parent has no 'path' key", path)
-        zpath = pentry["path"]
+        zpath = fsutil.encode(pentry["path"])
         if not zpath.endswith("/"):
             zpath += "/"
         zpath += tail
@@ -704,7 +704,7 @@
             if entry:
                 # Recurse down the directory
                 namesdir = {}
-                for name in os.listdir(target):
+                for name in fsutil.listdir(target):
                     ncname = normcase(name)
                     if ncname != fsutil.nczope:
                         namesdir[ncname] = name

Modified: Zope3/trunk/src/zope/fssync/fsutil.py
===================================================================
--- Zope3/trunk/src/zope/fssync/fsutil.py	2007-03-06 16:52:59 UTC (rev 73011)
+++ Zope3/trunk/src/zope/fssync/fsutil.py	2007-03-06 17:16:44 UTC (rev 73012)
@@ -32,6 +32,8 @@
 """
 
 import os
+import sys
+import unicodedata
 
 class Error(Exception):
     """User-level error, e.g. non-existent file.
@@ -117,3 +119,43 @@
     """
     if not os.path.isdir(path):
         os.makedirs(path)
+
+def normalize(name):
+    """Normalize a filename to normalization form C.
+    
+    Linux and (most?) other Unix-like operating systems use the normalization
+    form C (NFC) for UTF-8 encoding by default but do not enforce this.
+    Darwin, the base of Macintosh OSX, enforces normalization form D (NFD),
+    where a few characters are encoded in a different way.
+    """
+    if sys.platform == 'darwin':
+        if isinstance(name, unicode):
+            name = unicodedata.normalize("NFC", name)
+        elif sys.getfilesystemencoding() == 'utf-8':
+            name = unicode(name, encoding='utf-8')
+            name = unicodedata.normalize("NFC", name)
+            name = name.encode('utf-8')
+    return name
+    
+def encode(path, encoding=None):
+    """Encodes a path in its normalized form.
+    
+    Uses the filesystem encoding as a default encoding. Assumes that the given path
+    is also encoded in the filesystem encoding.
+    """
+    fsencoding = sys.getfilesystemencoding()
+    if encoding is None:
+        encoding = fsencoding
+    if isinstance(path, unicode):
+        return normalize(path).encode(encoding)
+    return unicode(path, encoding=fsencoding).encode(encoding)
+ 
+def listdir(path):
+    """Returns normalized filenames on OS X (see normalize above). 
+        
+    The standard file and os.path operations seem to work with both
+    encodings on OS X. Therefore we provide our own listdir, making sure
+    that the more common NFC encoding is used.
+    """
+    return [normalize(name) for name in os.listdir(path)]
+

Modified: Zope3/trunk/src/zope/fssync/main.py
===================================================================
--- Zope3/trunk/src/zope/fssync/main.py	2007-03-06 16:52:59 UTC (rev 73011)
+++ Zope3/trunk/src/zope/fssync/main.py	2007-03-06 17:16:44 UTC (rev 73012)
@@ -43,8 +43,8 @@
 
 from zope.fssync.command import Command, Usage
 from zope.fssync.fssync import FSSync
+from zope.fssync import fsutil
 
-
 def main():
     """Main program.
 

Modified: Zope3/trunk/src/zope/fssync/merger.py
===================================================================
--- Zope3/trunk/src/zope/fssync/merger.py	2007-03-06 16:52:59 UTC (rev 73011)
+++ Zope3/trunk/src/zope/fssync/merger.py	2007-03-06 17:16:44 UTC (rev 73012)
@@ -203,9 +203,12 @@
         'Spurious' or 'Nonexistent'.
         
         """
+        
+        
+        
         lmeta = self.getentry(local)
         rmeta = self.getentry(remote)
-
+        
         # Special-case sticky conflict
         if "conflict" in lmeta:
             return ("Nothing", "Conflict")
@@ -214,7 +217,6 @@
 
         if not lmeta and not rmeta:
             if exists(local):
-                # Local unregistered file
                 return ("Nothing", "Spurious")
             else:
                 # Why are we here?

Modified: Zope3/trunk/src/zope/fssync/metadata.py
===================================================================
--- Zope3/trunk/src/zope/fssync/metadata.py	2007-03-06 16:52:59 UTC (rev 73011)
+++ Zope3/trunk/src/zope/fssync/metadata.py	2007-03-06 17:16:44 UTC (rev 73012)
@@ -31,6 +31,8 @@
 from xml.sax import ContentHandler, parse, parseString
 from xml.sax.saxutils import quoteattr
 
+import fsutil
+
 case_insensitive = (normcase("ABC") == normcase("abc"))
 
 class Metadata(object):
@@ -130,6 +132,7 @@
 
         If there's no matching entry, an empty entry is created.
         """
+        name = fsutil.encode(name)
         if name in self.entries:
             return self.entries[name]
         if case_insensitive:
@@ -154,13 +157,15 @@
     names.sort()
     for name in names:
         entry = entries[name]
+        name = fsutil.encode(name, 'utf-8')
         sio.write("  <entry name=")
-        sio.write(quoteattr(name).encode('utf-8'))
+        sio.write(quoteattr(name))
         for k, v in entry.iteritems():
             if v is None:
                 continue
-            sio.write("\n         %s=%s"
-                      % (k.encode('utf-8'), quoteattr(v).encode('utf-8')))
+            k = fsutil.encode(k, 'utf-8')
+            v = fsutil.encode(v, 'utf-8')
+            sio.write("\n         %s=%s" % (k, quoteattr(v)))
         sio.write("\n         />\n")
     sio.write("</entries>\n")
     return sio.getvalue()
@@ -203,6 +208,7 @@
                 raise InvalidEntriesFile("illegal element nesting")
             else:
                 entryname = attrs.getValue("name")
+                entryname = fsutil.encode(entryname)
                 entry = {}
                 for n in attrs.getNames():
                     if n != "name":
@@ -214,6 +220,7 @@
                     "<entries> must be the document element")
         else:
             raise InvalidEntriesFile("unknown element <%s>" % name)
+      
         self.stack.append(name)
 
     def endElement(self, name):

Modified: Zope3/trunk/src/zope/fssync/snarf.py
===================================================================
--- Zope3/trunk/src/zope/fssync/snarf.py	2007-03-06 16:52:59 UTC (rev 73011)
+++ Zope3/trunk/src/zope/fssync/snarf.py	2007-03-06 17:16:44 UTC (rev 73012)
@@ -31,6 +31,7 @@
 """
 
 import os
+import fsutil
 
 class Snarfer(object):
 
@@ -59,7 +60,7 @@
         if filter is None:
             def filter(fspath):
                 return True
-        names = os.listdir(root)
+        names = fsutil.listdir(root)
         names.sort()
         for name in names:
             fspath = os.path.join(root, name)
@@ -92,6 +93,7 @@
         Raises IOError if reading istr returns an EOF condition before
         size bytes have been read.
         """
+        path = fsutil.encode(path, 'utf-8')
         self.ostr.write("%d %s\n" % (size, path))
         copybytes(size, istr, self.ostr)
 



More information about the Zope3-Checkins mailing list