Commit c071a613 authored by Éric Araujo's avatar Éric Araujo

Merge 3.2

parents afdac030 2e0a0e16
...@@ -201,6 +201,7 @@ class FileList: ...@@ -201,6 +201,7 @@ class FileList:
Return True if files are found, False otherwise. Return True if files are found, False otherwise.
""" """
# 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)
self.debug_print("include_pattern: applying regex r'%s'" % self.debug_print("include_pattern: applying regex r'%s'" %
...@@ -284,11 +285,14 @@ def glob_to_re(pattern): ...@@ -284,11 +285,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
...@@ -312,9 +316,11 @@ def translate_pattern(pattern, anchor=1, prefix=None, is_regex=0): ...@@ -312,9 +316,11 @@ def translate_pattern(pattern, anchor=1, prefix=None, is_regex=0):
if prefix is not None: if prefix is not None:
# 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
......
"""Tests for distutils.filelist.""" """Tests for distutils.filelist."""
import os
import re import re
import unittest import unittest
from distutils import debug from distutils import debug
...@@ -9,6 +10,26 @@ from distutils.filelist import glob_to_re, translate_pattern, FileList ...@@ -9,6 +10,26 @@ from distutils.filelist import glob_to_re, translate_pattern, FileList
from test.support import captured_stdout, run_unittest from test.support import captured_stdout, run_unittest
from distutils.tests import support from distutils.tests import support
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
"""
def make_local_path(s):
"""Converts '/' in a string to os.sep"""
return s.replace('/', os.sep)
class FileListTestCase(support.LoggingSilencer, class FileListTestCase(support.LoggingSilencer,
unittest.TestCase): unittest.TestCase):
...@@ -22,16 +43,62 @@ class FileListTestCase(support.LoggingSilencer, ...@@ -22,16 +43,62 @@ class FileListTestCase(support.LoggingSilencer,
self.clear_logs() self.clear_logs()
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 = re.escape(os.sep)
self.assertEqual(glob_to_re('foo??'), 'foo[^/][^/]\\Z(?ms)')
for glob, regex in (
# simple cases
('foo*', r'foo[^%(sep)s]*\Z(?ms)'),
('foo?', r'foo[^%(sep)s]\Z(?ms)'),
('foo??', r'foo[^%(sep)s][^%(sep)s]\Z(?ms)'),
# special cases # special cases
self.assertEqual(glob_to_re(r'foo\\*'), r'foo\\\\[^/]*\Z(?ms)') (r'foo\\*', r'foo\\\\[^%(sep)s]*\Z(?ms)'),
self.assertEqual(glob_to_re(r'foo\\\*'), r'foo\\\\\\[^/]*\Z(?ms)') (r'foo\\\*', r'foo\\\\\\[^%(sep)s]*\Z(?ms)'),
self.assertEqual(glob_to_re('foo????'), r'foo[^/][^/][^/][^/]\Z(?ms)') ('foo????', r'foo[^%(sep)s][^%(sep)s][^%(sep)s][^%(sep)s]\Z(?ms)'),
self.assertEqual(glob_to_re(r'foo\\??'), r'foo\\\\[^/][^/]\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
file_list = FileList()
l = make_local_path
# simulated file list
file_list.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
file_list.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(file_list.files, wanted)
def test_debug_print(self): def test_debug_print(self):
file_list = FileList() file_list = FileList()
...@@ -117,6 +184,7 @@ class FileListTestCase(support.LoggingSilencer, ...@@ -117,6 +184,7 @@ class FileListTestCase(support.LoggingSilencer,
self.assertEqual(file_list.allfiles, ['a.py', 'b.txt']) self.assertEqual(file_list.allfiles, ['a.py', 'b.txt'])
def test_process_template(self): def test_process_template(self):
l = make_local_path
# invalid lines # invalid lines
file_list = FileList() file_list = FileList()
for action in ('include', 'exclude', 'global-include', for action in ('include', 'exclude', 'global-include',
...@@ -127,7 +195,7 @@ class FileListTestCase(support.LoggingSilencer, ...@@ -127,7 +195,7 @@ class FileListTestCase(support.LoggingSilencer,
# include # include
file_list = FileList() file_list = FileList()
file_list.set_allfiles(['a.py', 'b.txt', 'd/c.py']) file_list.set_allfiles(['a.py', 'b.txt', l('d/c.py')])
file_list.process_template_line('include *.py') file_list.process_template_line('include *.py')
self.assertEqual(file_list.files, ['a.py']) self.assertEqual(file_list.files, ['a.py'])
...@@ -139,31 +207,31 @@ class FileListTestCase(support.LoggingSilencer, ...@@ -139,31 +207,31 @@ class FileListTestCase(support.LoggingSilencer,
# exclude # exclude
file_list = FileList() file_list = FileList()
file_list.files = ['a.py', 'b.txt', 'd/c.py'] file_list.files = ['a.py', 'b.txt', l('d/c.py')]
file_list.process_template_line('exclude *.py') file_list.process_template_line('exclude *.py')
self.assertEqual(file_list.files, ['b.txt', 'd/c.py']) self.assertEqual(file_list.files, ['b.txt', l('d/c.py')])
self.assertNoWarnings() self.assertNoWarnings()
file_list.process_template_line('exclude *.rb') file_list.process_template_line('exclude *.rb')
self.assertEqual(file_list.files, ['b.txt', 'd/c.py']) self.assertEqual(file_list.files, ['b.txt', l('d/c.py')])
self.assertWarnings() self.assertWarnings()
# global-include # global-include
file_list = FileList() file_list = FileList()
file_list.set_allfiles(['a.py', 'b.txt', 'd/c.py']) file_list.set_allfiles(['a.py', 'b.txt', l('d/c.py')])
file_list.process_template_line('global-include *.py') file_list.process_template_line('global-include *.py')
self.assertEqual(file_list.files, ['a.py', 'd/c.py']) self.assertEqual(file_list.files, ['a.py', l('d/c.py')])
self.assertNoWarnings() self.assertNoWarnings()
file_list.process_template_line('global-include *.rb') file_list.process_template_line('global-include *.rb')
self.assertEqual(file_list.files, ['a.py', 'd/c.py']) self.assertEqual(file_list.files, ['a.py', l('d/c.py')])
self.assertWarnings() self.assertWarnings()
# global-exclude # global-exclude
file_list = FileList() file_list = FileList()
file_list.files = ['a.py', 'b.txt', 'd/c.py'] file_list.files = ['a.py', 'b.txt', l('d/c.py')]
file_list.process_template_line('global-exclude *.py') file_list.process_template_line('global-exclude *.py')
self.assertEqual(file_list.files, ['b.txt']) self.assertEqual(file_list.files, ['b.txt'])
...@@ -175,50 +243,52 @@ class FileListTestCase(support.LoggingSilencer, ...@@ -175,50 +243,52 @@ class FileListTestCase(support.LoggingSilencer,
# recursive-include # recursive-include
file_list = FileList() file_list = FileList()
file_list.set_allfiles(['a.py', 'd/b.py', 'd/c.txt', 'd/d/e.py']) file_list.set_allfiles(['a.py', l('d/b.py'), l('d/c.txt'),
l('d/d/e.py')])
file_list.process_template_line('recursive-include d *.py') file_list.process_template_line('recursive-include d *.py')
self.assertEqual(file_list.files, ['d/b.py', 'd/d/e.py']) self.assertEqual(file_list.files, [l('d/b.py'), l('d/d/e.py')])
self.assertNoWarnings() self.assertNoWarnings()
file_list.process_template_line('recursive-include e *.py') file_list.process_template_line('recursive-include e *.py')
self.assertEqual(file_list.files, ['d/b.py', 'd/d/e.py']) self.assertEqual(file_list.files, [l('d/b.py'), l('d/d/e.py')])
self.assertWarnings() self.assertWarnings()
# recursive-exclude # recursive-exclude
file_list = FileList() file_list = FileList()
file_list.files = ['a.py', 'd/b.py', 'd/c.txt', 'd/d/e.py'] file_list.files = ['a.py', l('d/b.py'), l('d/c.txt'), l('d/d/e.py')]
file_list.process_template_line('recursive-exclude d *.py') file_list.process_template_line('recursive-exclude d *.py')
self.assertEqual(file_list.files, ['a.py', 'd/c.txt']) self.assertEqual(file_list.files, ['a.py', l('d/c.txt')])
self.assertNoWarnings() self.assertNoWarnings()
file_list.process_template_line('recursive-exclude e *.py') file_list.process_template_line('recursive-exclude e *.py')
self.assertEqual(file_list.files, ['a.py', 'd/c.txt']) self.assertEqual(file_list.files, ['a.py', l('d/c.txt')])
self.assertWarnings() self.assertWarnings()
# graft # graft
file_list = FileList() file_list = FileList()
file_list.set_allfiles(['a.py', 'd/b.py', 'd/d/e.py', 'f/f.py']) file_list.set_allfiles(['a.py', l('d/b.py'), l('d/d/e.py'),
l('f/f.py')])
file_list.process_template_line('graft d') file_list.process_template_line('graft d')
self.assertEqual(file_list.files, ['d/b.py', 'd/d/e.py']) self.assertEqual(file_list.files, [l('d/b.py'), l('d/d/e.py')])
self.assertNoWarnings() self.assertNoWarnings()
file_list.process_template_line('graft e') file_list.process_template_line('graft e')
self.assertEqual(file_list.files, ['d/b.py', 'd/d/e.py']) self.assertEqual(file_list.files, [l('d/b.py'), l('d/d/e.py')])
self.assertWarnings() self.assertWarnings()
# prune # prune
file_list = FileList() file_list = FileList()
file_list.files = ['a.py', 'd/b.py', 'd/d/e.py', 'f/f.py'] file_list.files = ['a.py', l('d/b.py'), l('d/d/e.py'), l('f/f.py')]
file_list.process_template_line('prune d') file_list.process_template_line('prune d')
self.assertEqual(file_list.files, ['a.py', 'f/f.py']) self.assertEqual(file_list.files, ['a.py', l('f/f.py')])
self.assertNoWarnings() self.assertNoWarnings()
file_list.process_template_line('prune e') file_list.process_template_line('prune e')
self.assertEqual(file_list.files, ['a.py', 'f/f.py']) self.assertEqual(file_list.files, ['a.py', l('f/f.py')])
self.assertWarnings() self.assertWarnings()
......
...@@ -7,6 +7,12 @@ import zipfile ...@@ -7,6 +7,12 @@ import zipfile
from os.path import join from os.path import join
from textwrap import dedent from textwrap import dedent
try:
import zlib
ZLIB_SUPPORT = True
except ImportError:
ZLIB_SUPPORT = False
from test.support import captured_stdout, check_warnings, run_unittest from test.support import captured_stdout, check_warnings, run_unittest
from distutils.command.sdist import sdist, show_formats from distutils.command.sdist import sdist, show_formats
...@@ -28,6 +34,7 @@ setup(name='fake') ...@@ -28,6 +34,7 @@ setup(name='fake')
MANIFEST = """\ MANIFEST = """\
# file GENERATED by distutils, do NOT edit # file GENERATED by distutils, do NOT edit
README README
buildout.cfg
inroot.txt inroot.txt
setup.py setup.py
data%(sep)sdata.dt data%(sep)sdata.dt
...@@ -39,13 +46,6 @@ somecode%(sep)sdoc.dat ...@@ -39,13 +46,6 @@ somecode%(sep)sdoc.dat
somecode%(sep)sdoc.txt somecode%(sep)sdoc.txt
""" """
try:
import zlib
ZLIB_SUPPORT = True
except ImportError:
ZLIB_SUPPORT = False
class SDistTestCase(PyPIRCCommandTestCase): class SDistTestCase(PyPIRCCommandTestCase):
def setUp(self): def setUp(self):
...@@ -143,7 +143,7 @@ class SDistTestCase(PyPIRCCommandTestCase): ...@@ -143,7 +143,7 @@ class SDistTestCase(PyPIRCCommandTestCase):
dist_folder = join(self.tmp_dir, 'dist') dist_folder = join(self.tmp_dir, 'dist')
result = os.listdir(dist_folder) result = os.listdir(dist_folder)
result.sort() result.sort()
self.assertEqual(result, ['fake-1.0.tar', 'fake-1.0.tar.gz'] ) self.assertEqual(result, ['fake-1.0.tar', 'fake-1.0.tar.gz'])
os.remove(join(dist_folder, 'fake-1.0.tar')) os.remove(join(dist_folder, 'fake-1.0.tar'))
os.remove(join(dist_folder, 'fake-1.0.tar.gz')) os.remove(join(dist_folder, 'fake-1.0.tar.gz'))
...@@ -180,11 +180,18 @@ class SDistTestCase(PyPIRCCommandTestCase): ...@@ -180,11 +180,18 @@ class SDistTestCase(PyPIRCCommandTestCase):
self.write_file((data_dir, 'data.dt'), '#') self.write_file((data_dir, 'data.dt'), '#')
some_dir = join(self.tmp_dir, 'some') some_dir = join(self.tmp_dir, 'some')
os.mkdir(some_dir) os.mkdir(some_dir)
# make sure VCS directories are pruned (#14004)
hg_dir = join(self.tmp_dir, '.hg')
os.mkdir(hg_dir)
self.write_file((hg_dir, 'last-message.txt'), '#')
# a buggy regex used to prevent this from working on windows (#6884)
self.write_file((self.tmp_dir, 'buildout.cfg'), '#')
self.write_file((self.tmp_dir, 'inroot.txt'), '#') self.write_file((self.tmp_dir, 'inroot.txt'), '#')
self.write_file((some_dir, 'file.txt'), '#') self.write_file((some_dir, 'file.txt'), '#')
self.write_file((some_dir, 'other_file.txt'), '#') self.write_file((some_dir, 'other_file.txt'), '#')
dist.data_files = [('data', ['data/data.dt', dist.data_files = [('data', ['data/data.dt',
'buildout.cfg',
'inroot.txt', 'inroot.txt',
'notexisting']), 'notexisting']),
'some/file.txt', 'some/file.txt',
...@@ -214,15 +221,15 @@ class SDistTestCase(PyPIRCCommandTestCase): ...@@ -214,15 +221,15 @@ class SDistTestCase(PyPIRCCommandTestCase):
zip_file.close() zip_file.close()
# making sure everything was added # making sure everything was added
self.assertEqual(len(content), 11) self.assertEqual(len(content), 12)
# checking the MANIFEST # checking the MANIFEST
f = open(join(self.tmp_dir, 'MANIFEST')) f = open(join(self.tmp_dir, 'MANIFEST'))
try: try:
manifest = f.read() manifest = f.read()
self.assertEqual(manifest, MANIFEST % {'sep': os.sep})
finally: finally:
f.close() f.close()
self.assertEqual(manifest, MANIFEST % {'sep': os.sep})
@unittest.skipUnless(ZLIB_SUPPORT, 'Need zlib support to run') @unittest.skipUnless(ZLIB_SUPPORT, 'Need zlib support to run')
def test_metadata_check_option(self): def test_metadata_check_option(self):
......
...@@ -498,6 +498,9 @@ Core and Builtins ...@@ -498,6 +498,9 @@ Core and Builtins
Library Library
------- -------
- Issue #6884: Fix long-standing bugs with MANIFEST.in parsing in distutils
on Windows.
- 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