Stefan H. Holek avatar Stefan H. Holek committed 86d7748

Make sure the manifest never contains decomposed UTF-8.

Comments (0)

Files changed (2)

setuptools/command/egg_info.py

 
 
 
+def compose(path):
+    # Apple's HFS Plus returns decomposed UTF-8. Since just about
+    # everyone else chokes on it, we must make sure to return fully
+    # composed UTF-8 only.
+    if sys.getfilesystemencoding().lower() == 'utf-8':
+        from unicodedata import normalize
+        if sys.version_info >= (3,):
+            path = normalize('NFC', path)
+        else:
+            path = normalize('NFC', path.decode('utf-8')).encode('utf-8')
+    return path
+
+
 class manifest_maker(sdist):
 
     template = "MANIFEST.in"
         self.prune_file_list()
         self.filelist.sort()
         self.filelist.remove_duplicates()
+        self.filelist.files = [compose(path) for path in self.filelist.files]
         self.write_manifest()
 
     def write_manifest (self):

setuptools/tests/test_sdist.py

+# -*- coding: utf-8 -*-
 """sdist tests"""
 
 
 
         manifest = cmd.filelist.files
 
-        self.assert_(os.path.join('sdist_test', 'a.txt') in manifest)
-        self.assert_(os.path.join('sdist_test', 'b.txt') in manifest)
-        self.assert_(os.path.join('sdist_test', 'c.rst') not in manifest)
+        self.assertTrue(os.path.join('sdist_test', 'a.txt') in manifest)
+        self.assertTrue(os.path.join('sdist_test', 'b.txt') in manifest)
+        self.assertTrue(os.path.join('sdist_test', 'c.rst') not in manifest)
+
+    def test_filelist_is_fully_composed(self):
+        # Test for #303. Requires HFS Plus to fail.
+
+        # Add file with non-ASCII filename
+        filename = os.path.join('sdist_test', 'smörbröd.py')
+        open(filename, 'w').close()
+
+        dist = Distribution(SETUP_ATTRS)
+        dist.script_name = 'setup.py'
+        cmd = sdist(dist)
+        cmd.ensure_finalized()
+
+        # squelch output
+        old_stdout = sys.stdout
+        old_stderr = sys.stderr
+        sys.stdout = StringIO()
+        sys.stderr = StringIO()
+        try:
+            cmd.run()
+        finally:
+            sys.stdout = old_stdout
+            sys.stderr = old_stderr
+
+        self.assertTrue(filename in cmd.filelist.files)
+
+
+def test_suite():
+    return unittest.defaultTestLoader.loadTestsFromName(__name__)
+
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.