Commit 7d32e7e5 authored by Éric Araujo's avatar Éric Araujo

Port the #6884 fix to packaging

parent f7165452
...@@ -272,6 +272,7 @@ class Manifest(object): ...@@ -272,6 +272,7 @@ class Manifest(object):
Return True if files are found. Return True if files are found.
""" """
# XXX docstring lying about what the special chars are?
files_found = False files_found = False
pattern_re = _translate_pattern(pattern, anchor, prefix, is_regex) pattern_re = _translate_pattern(pattern, anchor, prefix, is_regex)
...@@ -335,11 +336,14 @@ def _glob_to_re(pattern): ...@@ -335,11 +336,14 @@ def _glob_to_re(pattern):
# IMHO is wrong -- '?' and '*' aren't supposed to match slash in Unix, # IMHO is wrong -- '?' and '*' aren't supposed to match slash in Unix,
# and by extension they shouldn't match such "special characters" under # and by extension they shouldn't match such "special characters" under
# any OS. So change all non-escaped dots in the RE to match any # any OS. So change all non-escaped dots in the RE to match any
# character except the special characters. # character except the special characters (currently: just os.sep).
# XXX currently the "special characters" are just slash -- i.e. this is sep = os.sep
# Unix-only. if os.sep == '\\':
pattern_re = re.sub(r'((?<!\\)(\\\\)*)\.', r'\1[^/]', pattern_re) # we're using a regex to manipulate a regex, so we need
# to escape the backslash twice
sep = r'\\\\'
escaped = r'\1[^%s]' % sep
pattern_re = re.sub(r'((?<!\\)(\\\\)*)\.', escaped, pattern_re)
return pattern_re return pattern_re
...@@ -366,8 +370,10 @@ def _translate_pattern(pattern, anchor=True, prefix=None, is_regex=False): ...@@ -366,8 +370,10 @@ def _translate_pattern(pattern, anchor=True, prefix=None, is_regex=False):
# ditch end of pattern character # ditch end of pattern character
empty_pattern = _glob_to_re('') empty_pattern = _glob_to_re('')
prefix_re = _glob_to_re(prefix)[:-len(empty_pattern)] prefix_re = _glob_to_re(prefix)[:-len(empty_pattern)]
# paths should always use / in manifest templates sep = os.sep
pattern_re = "^%s/.*%s" % (prefix_re, pattern_re) if os.sep == '\\':
sep = r'\\'
pattern_re = "^" + sep.join((prefix_re, ".*" + pattern_re))
else: # no prefix -- respect anchor flag else: # no prefix -- respect anchor flag
if anchor: if anchor:
pattern_re = "^" + pattern_re pattern_re = "^" + pattern_re
......
...@@ -7,7 +7,22 @@ from packaging.manifest import Manifest, _translate_pattern, _glob_to_re ...@@ -7,7 +7,22 @@ from packaging.manifest import Manifest, _translate_pattern, _glob_to_re
from packaging.tests import unittest, support from packaging.tests import unittest, support
_MANIFEST = """\ MANIFEST_IN = """\
include ok
include xo
exclude xo
include foo.tmp
include buildout.cfg
global-include *.x
global-include *.txt
global-exclude *.tmp
recursive-include f *.oo
recursive-exclude global *.x
graft dir
prune dir3
"""
MANIFEST_IN_2 = """\
recursive-include foo *.py # ok recursive-include foo *.py # ok
# nothing here # nothing here
...@@ -17,12 +32,17 @@ recursive-include bar \\ ...@@ -17,12 +32,17 @@ recursive-include bar \\
*.dat *.txt *.dat *.txt
""" """
_MANIFEST2 = """\ MANIFEST_IN_3 = """\
README README
file1 file1
""" """
def make_local_path(s):
"""Converts '/' in a string to os.sep"""
return s.replace('/', os.sep)
class ManifestTestCase(support.TempdirManager, class ManifestTestCase(support.TempdirManager,
support.LoggingCatcher, support.LoggingCatcher,
unittest.TestCase): unittest.TestCase):
...@@ -37,7 +57,7 @@ class ManifestTestCase(support.TempdirManager, ...@@ -37,7 +57,7 @@ class ManifestTestCase(support.TempdirManager,
tmpdir = self.mkdtemp() tmpdir = self.mkdtemp()
MANIFEST = os.path.join(tmpdir, 'MANIFEST.in') MANIFEST = os.path.join(tmpdir, 'MANIFEST.in')
with open(MANIFEST, 'w') as f: with open(MANIFEST, 'w') as f:
f.write(_MANIFEST) f.write(MANIFEST_IN_2)
manifest = Manifest() manifest = Manifest()
manifest.read_template(MANIFEST) manifest.read_template(MANIFEST)
...@@ -63,27 +83,74 @@ class ManifestTestCase(support.TempdirManager, ...@@ -63,27 +83,74 @@ class ManifestTestCase(support.TempdirManager,
os.chdir(tmpdir) os.chdir(tmpdir)
self.write_file('README', 'xxx') self.write_file('README', 'xxx')
self.write_file('file1', 'xxx') self.write_file('file1', 'xxx')
content = StringIO(_MANIFEST2) content = StringIO(MANIFEST_IN_3)
manifest = Manifest() manifest = Manifest()
manifest.read_template(content) manifest.read_template(content)
self.assertEqual(['README', 'file1'], manifest.files) self.assertEqual(['README', 'file1'], manifest.files)
def test_glob_to_re(self): def test_glob_to_re(self):
# simple cases sep = os.sep
self.assertEqual(_glob_to_re('foo*'), 'foo[^/]*\\Z(?ms)') if os.sep == '\\':
self.assertEqual(_glob_to_re('foo?'), 'foo[^/]\\Z(?ms)') sep = r'\\'
self.assertEqual(_glob_to_re('foo??'), 'foo[^/][^/]\\Z(?ms)')
for glob, regex in (
# special cases # simple cases
self.assertEqual(_glob_to_re(r'foo\\*'), r'foo\\\\[^/]*\Z(?ms)') ('foo*', r'foo[^%(sep)s]*\Z(?ms)'),
self.assertEqual(_glob_to_re(r'foo\\\*'), r'foo\\\\\\[^/]*\Z(?ms)') ('foo?', r'foo[^%(sep)s]\Z(?ms)'),
self.assertEqual(_glob_to_re('foo????'), r'foo[^/][^/][^/][^/]\Z(?ms)') ('foo??', r'foo[^%(sep)s][^%(sep)s]\Z(?ms)'),
self.assertEqual(_glob_to_re(r'foo\\??'), r'foo\\\\[^/][^/]\Z(?ms)') # special cases
(r'foo\\*', r'foo\\\\[^%(sep)s]*\Z(?ms)'),
(r'foo\\\*', r'foo\\\\\\[^%(sep)s]*\Z(?ms)'),
('foo????', r'foo[^%(sep)s][^%(sep)s][^%(sep)s][^%(sep)s]\Z(?ms)'),
(r'foo\\??', r'foo\\\\[^%(sep)s][^%(sep)s]\Z(?ms)'),
):
regex = regex % {'sep': sep}
self.assertEqual(_glob_to_re(glob), regex)
def test_process_template_line(self):
# testing all MANIFEST.in template patterns
manifest = Manifest()
l = make_local_path
# simulated file list
manifest.allfiles = ['foo.tmp', 'ok', 'xo', 'four.txt',
'buildout.cfg',
# filelist does not filter out VCS directories,
# it's sdist that does
l('.hg/last-message.txt'),
l('global/one.txt'),
l('global/two.txt'),
l('global/files.x'),
l('global/here.tmp'),
l('f/o/f.oo'),
l('dir/graft-one'),
l('dir/dir2/graft2'),
l('dir3/ok'),
l('dir3/sub/ok.txt'),
]
for line in MANIFEST_IN.split('\n'):
if line.strip() == '':
continue
manifest._process_template_line(line)
wanted = ['ok',
'buildout.cfg',
'four.txt',
l('.hg/last-message.txt'),
l('global/one.txt'),
l('global/two.txt'),
l('f/o/f.oo'),
l('dir/graft-one'),
l('dir/dir2/graft2'),
]
self.assertEqual(manifest.files, wanted)
def test_remove_duplicates(self): def test_remove_duplicates(self):
manifest = Manifest() manifest = Manifest()
manifest.files = ['a', 'b', 'a', 'g', 'c', 'g'] manifest.files = ['a', 'b', 'a', 'g', 'c', 'g']
# files must be sorted beforehand # files must be sorted beforehand (like sdist does)
manifest.sort() manifest.sort()
manifest.remove_duplicates() manifest.remove_duplicates()
self.assertEqual(manifest.files, ['a', 'b', 'c', 'g']) self.assertEqual(manifest.files, ['a', 'b', 'c', 'g'])
...@@ -143,6 +210,7 @@ class ManifestTestCase(support.TempdirManager, ...@@ -143,6 +210,7 @@ class ManifestTestCase(support.TempdirManager,
self.assertEqual(manifest.allfiles, ['a.py', 'b.txt']) self.assertEqual(manifest.allfiles, ['a.py', 'b.txt'])
def test_process_template(self): def test_process_template(self):
l = make_local_path
# invalid lines # invalid lines
manifest = Manifest() manifest = Manifest()
for action in ('include', 'exclude', 'global-include', for action in ('include', 'exclude', 'global-include',
...@@ -153,7 +221,7 @@ class ManifestTestCase(support.TempdirManager, ...@@ -153,7 +221,7 @@ class ManifestTestCase(support.TempdirManager,
# implicit include # implicit include
manifest = Manifest() manifest = Manifest()
manifest.allfiles = ['a.py', 'b.txt', 'd/c.py'] manifest.allfiles = ['a.py', 'b.txt', l('d/c.py')]
manifest._process_template_line('*.py') manifest._process_template_line('*.py')
self.assertEqual(manifest.files, ['a.py']) self.assertEqual(manifest.files, ['a.py'])
...@@ -161,7 +229,7 @@ class ManifestTestCase(support.TempdirManager, ...@@ -161,7 +229,7 @@ class ManifestTestCase(support.TempdirManager,
# include # include
manifest = Manifest() manifest = Manifest()
manifest.allfiles = ['a.py', 'b.txt', 'd/c.py'] manifest.allfiles = ['a.py', 'b.txt', l('d/c.py')]
manifest._process_template_line('include *.py') manifest._process_template_line('include *.py')
self.assertEqual(manifest.files, ['a.py']) self.assertEqual(manifest.files, ['a.py'])
...@@ -173,31 +241,31 @@ class ManifestTestCase(support.TempdirManager, ...@@ -173,31 +241,31 @@ class ManifestTestCase(support.TempdirManager,
# exclude # exclude
manifest = Manifest() manifest = Manifest()
manifest.files = ['a.py', 'b.txt', 'd/c.py'] manifest.files = ['a.py', 'b.txt', l('d/c.py')]
manifest._process_template_line('exclude *.py') manifest._process_template_line('exclude *.py')
self.assertEqual(manifest.files, ['b.txt', 'd/c.py']) self.assertEqual(manifest.files, ['b.txt', l('d/c.py')])
self.assertNoWarnings() self.assertNoWarnings()
manifest._process_template_line('exclude *.rb') manifest._process_template_line('exclude *.rb')
self.assertEqual(manifest.files, ['b.txt', 'd/c.py']) self.assertEqual(manifest.files, ['b.txt', l('d/c.py')])
self.assertWarnings() self.assertWarnings()
# global-include # global-include
manifest = Manifest() manifest = Manifest()
manifest.allfiles = ['a.py', 'b.txt', 'd/c.py'] manifest.allfiles = ['a.py', 'b.txt', l('d/c.py')]
manifest._process_template_line('global-include *.py') manifest._process_template_line('global-include *.py')
self.assertEqual(manifest.files, ['a.py', 'd/c.py']) self.assertEqual(manifest.files, ['a.py', l('d/c.py')])
self.assertNoWarnings() self.assertNoWarnings()
manifest._process_template_line('global-include *.rb') manifest._process_template_line('global-include *.rb')
self.assertEqual(manifest.files, ['a.py', 'd/c.py']) self.assertEqual(manifest.files, ['a.py', l('d/c.py')])
self.assertWarnings() self.assertWarnings()
# global-exclude # global-exclude
manifest = Manifest() manifest = Manifest()
manifest.files = ['a.py', 'b.txt', 'd/c.py'] manifest.files = ['a.py', 'b.txt', l('d/c.py')]
manifest._process_template_line('global-exclude *.py') manifest._process_template_line('global-exclude *.py')
self.assertEqual(manifest.files, ['b.txt']) self.assertEqual(manifest.files, ['b.txt'])
...@@ -209,50 +277,50 @@ class ManifestTestCase(support.TempdirManager, ...@@ -209,50 +277,50 @@ class ManifestTestCase(support.TempdirManager,
# recursive-include # recursive-include
manifest = Manifest() manifest = Manifest()
manifest.allfiles = ['a.py', 'd/b.py', 'd/c.txt', 'd/d/e.py'] manifest.allfiles = ['a.py', l('d/b.py'), l('d/c.txt'), l('d/d/e.py')]
manifest._process_template_line('recursive-include d *.py') manifest._process_template_line('recursive-include d *.py')
self.assertEqual(manifest.files, ['d/b.py', 'd/d/e.py']) self.assertEqual(manifest.files, [l('d/b.py'), l('d/d/e.py')])
self.assertNoWarnings() self.assertNoWarnings()
manifest._process_template_line('recursive-include e *.py') manifest._process_template_line('recursive-include e *.py')
self.assertEqual(manifest.files, ['d/b.py', 'd/d/e.py']) self.assertEqual(manifest.files, [l('d/b.py'), l('d/d/e.py')])
self.assertWarnings() self.assertWarnings()
# recursive-exclude # recursive-exclude
manifest = Manifest() manifest = Manifest()
manifest.files = ['a.py', 'd/b.py', 'd/c.txt', 'd/d/e.py'] manifest.files = ['a.py', l('d/b.py'), l('d/c.txt'), l('d/d/e.py')]
manifest._process_template_line('recursive-exclude d *.py') manifest._process_template_line('recursive-exclude d *.py')
self.assertEqual(manifest.files, ['a.py', 'd/c.txt']) self.assertEqual(manifest.files, ['a.py', l('d/c.txt')])
self.assertNoWarnings() self.assertNoWarnings()
manifest._process_template_line('recursive-exclude e *.py') manifest._process_template_line('recursive-exclude e *.py')
self.assertEqual(manifest.files, ['a.py', 'd/c.txt']) self.assertEqual(manifest.files, ['a.py', l('d/c.txt')])
self.assertWarnings() self.assertWarnings()
# graft # graft
manifest = Manifest() manifest = Manifest()
manifest.allfiles = ['a.py', 'd/b.py', 'd/d/e.py', 'f/f.py'] manifest.allfiles = ['a.py', l('d/b.py'), l('d/d/e.py'), l('f/f.py')]
manifest._process_template_line('graft d') manifest._process_template_line('graft d')
self.assertEqual(manifest.files, ['d/b.py', 'd/d/e.py']) self.assertEqual(manifest.files, [l('d/b.py'), l('d/d/e.py')])
self.assertNoWarnings() self.assertNoWarnings()
manifest._process_template_line('graft e') manifest._process_template_line('graft e')
self.assertEqual(manifest.files, ['d/b.py', 'd/d/e.py']) self.assertEqual(manifest.files, [l('d/b.py'), l('d/d/e.py')])
self.assertWarnings() self.assertWarnings()
# prune # prune
manifest = Manifest() manifest = Manifest()
manifest.files = ['a.py', 'd/b.py', 'd/d/e.py', 'f/f.py'] manifest.files = ['a.py', l('d/b.py'), l('d/d/e.py'), l('f/f.py')]
manifest._process_template_line('prune d') manifest._process_template_line('prune d')
self.assertEqual(manifest.files, ['a.py', 'f/f.py']) self.assertEqual(manifest.files, ['a.py', l('f/f.py')])
self.assertNoWarnings() self.assertNoWarnings()
manifest._process_template_line('prune e') manifest._process_template_line('prune e')
self.assertEqual(manifest.files, ['a.py', 'f/f.py']) self.assertEqual(manifest.files, ['a.py', l('f/f.py')])
self.assertWarnings() self.assertWarnings()
......
...@@ -502,7 +502,7 @@ Library ...@@ -502,7 +502,7 @@ Library
scripts found in the Tools directory. scripts found in the Tools directory.
- Issue #6884: Fix long-standing bugs with MANIFEST.in parsing in distutils - Issue #6884: Fix long-standing bugs with MANIFEST.in parsing in distutils
on Windows. on Windows. Also fixed in packaging.
- Issue #8033: sqlite3: Fix 64-bit integer handling in user functions - Issue #8033: sqlite3: Fix 64-bit integer handling in user functions
on 32-bit architectures. Initial patch by Philippe Devalkeneer. on 32-bit architectures. Initial patch by Philippe Devalkeneer.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment