Branch merge

This commit is contained in:
Éric Araujo 2011-08-01 14:48:19 +02:00
commit 0db7f72cc7
7 changed files with 113 additions and 55 deletions

View File

@ -111,12 +111,22 @@ per line, regular files (or symlinks to them) only. If you do supply your own
:file:`MANIFEST`, you must specify everything: the default set of files :file:`MANIFEST`, you must specify everything: the default set of files
described above does not apply in this case. described above does not apply in this case.
.. versionadded:: 2.7 .. versionchanged:: 2.7
An existing generated :file:`MANIFEST` will be regenerated without
:command:`sdist` comparing its modification time to the one of
:file:`MANIFEST.in` or :file:`setup.py`.
.. versionchanged:: 2.7.1
:file:`MANIFEST` files start with a comment indicating they are generated. :file:`MANIFEST` files start with a comment indicating they are generated.
Files without this comment are not overwritten or removed. Files without this comment are not overwritten or removed.
.. versionchanged:: 2.7.3
:command:`sdist` will read a :file:`MANIFEST` file if no :file:`MANIFEST.in`
exists, like it did before 2.7.
See :ref:`manifest_template` section for a syntax reference. See :ref:`manifest_template` section for a syntax reference.
.. _manifest-options: .. _manifest-options:
Manifest-related options Manifest-related options
@ -124,16 +134,16 @@ Manifest-related options
The normal course of operations for the :command:`sdist` command is as follows: The normal course of operations for the :command:`sdist` command is as follows:
* if the manifest file, :file:`MANIFEST` doesn't exist, read :file:`MANIFEST.in` * if the manifest file (:file:`MANIFEST` by default) exists and the first line
and create the manifest does not have a comment indicating it is generated from :file:`MANIFEST.in`,
then it is used as is, unaltered
* if the manifest file doesn't exist or has been previously automatically
generated, read :file:`MANIFEST.in` and create the manifest
* if neither :file:`MANIFEST` nor :file:`MANIFEST.in` exist, create a manifest * if neither :file:`MANIFEST` nor :file:`MANIFEST.in` exist, create a manifest
with just the default file set with just the default file set
* if either :file:`MANIFEST.in` or the setup script (:file:`setup.py`) are more
recent than :file:`MANIFEST`, recreate :file:`MANIFEST` by reading
:file:`MANIFEST.in`
* use the list of files now in :file:`MANIFEST` (either just generated or read * use the list of files now in :file:`MANIFEST` (either just generated or read
in) to create the source distribution archive(s) in) to create the source distribution archive(s)
@ -271,8 +281,3 @@ character, and ``[range]`` matches any of the characters in *range* (e.g.,
``a-z``, ``a-zA-Z``, ``a-f0-9_.``). The definition of "regular filename ``a-z``, ``a-zA-Z``, ``a-f0-9_.``). The definition of "regular filename
character" is platform-specific: on Unix it is anything except slash; on Windows character" is platform-specific: on Unix it is anything except slash; on Windows
anything except backslash or colon. anything except backslash or colon.
.. versionchanged:: 2.7
An existing generated :file:`MANIFEST` will be regenerated without
:command:`sdist` comparing its modification time to the one of
:file:`MANIFEST.in` or :file:`setup.py`.

View File

@ -182,14 +182,20 @@ class sdist(Command):
reading the manifest, or just using the default file set -- it all reading the manifest, or just using the default file set -- it all
depends on the user's options. depends on the user's options.
""" """
# new behavior: # new behavior when using a template:
# the file list is recalculated everytime because # the file list is recalculated everytime because
# even if MANIFEST.in or setup.py are not changed # even if MANIFEST.in or setup.py are not changed
# the user might have added some files in the tree that # the user might have added some files in the tree that
# need to be included. # need to be included.
# #
# This makes --force the default and only behavior. # This makes --force the default and only behavior with templates.
template_exists = os.path.isfile(self.template) template_exists = os.path.isfile(self.template)
if not template_exists and self._manifest_is_not_generated():
self.read_manifest()
self.filelist.sort()
self.filelist.remove_duplicates()
return
if not template_exists: if not template_exists:
self.warn(("manifest template '%s' does not exist " + self.warn(("manifest template '%s' does not exist " +
"(using default file list)") % "(using default file list)") %
@ -352,14 +358,7 @@ class sdist(Command):
by 'add_defaults()' and 'read_template()') to the manifest file by 'add_defaults()' and 'read_template()') to the manifest file
named by 'self.manifest'. named by 'self.manifest'.
""" """
if os.path.isfile(self.manifest): if self._manifest_is_not_generated():
fp = open(self.manifest)
try:
first_line = fp.readline()
finally:
fp.close()
if first_line != '# file GENERATED by distutils, do NOT edit\n':
log.info("not writing to manually maintained " log.info("not writing to manually maintained "
"manifest file '%s'" % self.manifest) "manifest file '%s'" % self.manifest)
return return
@ -369,6 +368,18 @@ class sdist(Command):
self.execute(file_util.write_file, (self.manifest, content), self.execute(file_util.write_file, (self.manifest, content),
"writing manifest file '%s'" % self.manifest) "writing manifest file '%s'" % self.manifest)
def _manifest_is_not_generated(self):
# check for special comment used in 2.7.1 and higher
if not os.path.isfile(self.manifest):
return False
fp = open(self.manifest, 'rU')
try:
first_line = fp.readline()
finally:
fp.close()
return first_line != '# file GENERATED by distutils, do NOT edit\n'
def read_manifest(self): def read_manifest(self):
"""Read the manifest file (named by 'self.manifest') and use it to """Read the manifest file (named by 'self.manifest') and use it to
fill in 'self.filelist', the list of files to include in the source fill in 'self.filelist', the list of files to include in the source
@ -376,12 +387,11 @@ class sdist(Command):
""" """
log.info("reading manifest file '%s'", self.manifest) log.info("reading manifest file '%s'", self.manifest)
manifest = open(self.manifest) manifest = open(self.manifest)
while 1: for line in manifest:
line = manifest.readline() # ignore comments and blank lines
if line == '': # end of file line = line.strip()
break if line.startswith('#') or not line:
if line[-1] == '\n': continue
line = line[0:-1]
self.filelist.append(line) self.filelist.append(line)
manifest.close() manifest.close()

View File

@ -1,9 +1,11 @@
"""Tests for distutils.command.sdist.""" """Tests for distutils.command.sdist."""
import os import os
import unittest
import shutil
import zipfile
import tarfile import tarfile
import unittest
import warnings
import zipfile
from os.path import join
from textwrap import dedent
# zlib is not used here, but if it's not available # zlib is not used here, but if it's not available
# the tests that use zipfile may fail # the tests that use zipfile may fail
@ -19,19 +21,13 @@ try:
except ImportError: except ImportError:
UID_GID_SUPPORT = False UID_GID_SUPPORT = False
from os.path import join
import sys
import tempfile
import warnings
from test.test_support import captured_stdout, check_warnings, run_unittest from test.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
from distutils.core import Distribution from distutils.core import Distribution
from distutils.tests.test_config import PyPIRCCommandTestCase from distutils.tests.test_config import PyPIRCCommandTestCase
from distutils.errors import DistutilsExecError, DistutilsOptionError from distutils.errors import DistutilsOptionError
from distutils.spawn import find_executable from distutils.spawn import find_executable
from distutils.tests import support
from distutils.log import WARN from distutils.log import WARN
from distutils.archive_util import ARCHIVE_FORMATS from distutils.archive_util import ARCHIVE_FORMATS
@ -405,13 +401,33 @@ class SDistTestCase(PyPIRCCommandTestCase):
self.assertEqual(manifest[0], self.assertEqual(manifest[0],
'# file GENERATED by distutils, do NOT edit') '# file GENERATED by distutils, do NOT edit')
@unittest.skipUnless(zlib, 'requires zlib')
def test_manifest_comments(self):
# make sure comments don't cause exceptions or wrong includes
contents = dedent("""\
# bad.py
#bad.py
good.py
""")
dist, cmd = self.get_cmd()
cmd.ensure_finalized()
self.write_file((self.tmp_dir, cmd.manifest), contents)
self.write_file((self.tmp_dir, 'good.py'), '# pick me!')
self.write_file((self.tmp_dir, 'bad.py'), "# don't pick me!")
self.write_file((self.tmp_dir, '#bad.py'), "# don't pick me!")
cmd.run()
self.assertEqual(cmd.filelist.files, ['good.py'])
@unittest.skipUnless(zlib, "requires zlib") @unittest.skipUnless(zlib, "requires zlib")
def test_manual_manifest(self): def test_manual_manifest(self):
# check that a MANIFEST without a marker is left alone # check that a MANIFEST without a marker is left alone
dist, cmd = self.get_cmd() dist, cmd = self.get_cmd()
cmd.ensure_finalized() cmd.ensure_finalized()
self.write_file((self.tmp_dir, cmd.manifest), 'README.manual') self.write_file((self.tmp_dir, cmd.manifest), 'README.manual')
self.write_file((self.tmp_dir, 'README.manual'),
'This project maintains its MANIFEST file itself.')
cmd.run() cmd.run()
self.assertEqual(cmd.filelist.files, ['README.manual'])
f = open(cmd.manifest) f = open(cmd.manifest)
try: try:
@ -422,6 +438,15 @@ class SDistTestCase(PyPIRCCommandTestCase):
self.assertEqual(manifest, ['README.manual']) self.assertEqual(manifest, ['README.manual'])
archive_name = join(self.tmp_dir, 'dist', 'fake-1.0.tar.gz')
archive = tarfile.open(archive_name)
try:
filenames = [tarinfo.name for tarinfo in archive]
finally:
archive.close()
self.assertEqual(sorted(filenames), ['fake-1.0', 'fake-1.0/PKG-INFO',
'fake-1.0/README.manual'])
def test_suite(): def test_suite():
return unittest.makeSuite(SDistTestCase) return unittest.makeSuite(SDistTestCase)

View File

@ -177,22 +177,26 @@ from __future__ import print_function"""
self.assertEqual(results, expected) self.assertEqual(results, expected)
def check_file_refactoring(self, test_file, fixers=_2TO3_FIXERS): def check_file_refactoring(self, test_file, fixers=_2TO3_FIXERS):
tmpdir = tempfile.mkdtemp(prefix="2to3-test_refactor")
self.addCleanup(shutil.rmtree, tmpdir)
# make a copy of the tested file that we can write to
shutil.copy(test_file, tmpdir)
test_file = os.path.join(tmpdir, os.path.basename(test_file))
os.chmod(test_file, 0o644)
def read_file(): def read_file():
with open(test_file, "rb") as fp: with open(test_file, "rb") as fp:
return fp.read() return fp.read()
old_contents = read_file() old_contents = read_file()
rt = self.rt(fixers=fixers) rt = self.rt(fixers=fixers)
rt.refactor_file(test_file) rt.refactor_file(test_file)
self.assertEqual(old_contents, read_file()) self.assertEqual(old_contents, read_file())
try:
rt.refactor_file(test_file, True) rt.refactor_file(test_file, True)
new_contents = read_file() new_contents = read_file()
self.assertNotEqual(old_contents, new_contents) self.assertNotEqual(old_contents, new_contents)
finally:
with open(test_file, "wb") as fp:
fp.write(old_contents)
return new_contents return new_contents
def test_refactor_file(self): def test_refactor_file(self):

View File

@ -194,6 +194,7 @@ Ned Deily
Vincent Delft Vincent Delft
Arnaud Delobelle Arnaud Delobelle
Erik Demaine Erik Demaine
John Dennis
Roger Dev Roger Dev
Raghuram Devarakonda Raghuram Devarakonda
Catherine Devlin Catherine Devlin
@ -813,6 +814,7 @@ Mikhail Terekhov
Tobias Thelen Tobias Thelen
James Thomas James Thomas
Robin Thomas Robin Thomas
Stephen Thorne
Eric Tiedemann Eric Tiedemann
Tracy Tims Tracy Tims
Oren Tirosh Oren Tirosh

View File

@ -37,6 +37,9 @@ Core and Builtins
Library Library
------- -------
- Issues #11104, #8688: Fix the behavior of distutils' sdist command with
manually-maintained MANIFEST files.
- Issue #8887: "pydoc somebuiltin.somemethod" (or help('somebuiltin.somemethod') - Issue #8887: "pydoc somebuiltin.somemethod" (or help('somebuiltin.somemethod')
in Python code) now finds the doc of the method. in Python code) now finds the doc of the method.
@ -158,6 +161,9 @@ Tools/Demos
Tests Tests
----- -----
- Issue #12331: The test suite for lib2to3 can now run from an installed
Python.
- Issue #12549: Correct test_platform to not fail when OS X returns 'x86_64' - Issue #12549: Correct test_platform to not fail when OS X returns 'x86_64'
as the processor type on some Mac systems. as the processor type on some Mac systems.

View File

@ -4,11 +4,15 @@ import sys
import shutil import shutil
import os.path import os.path
import subprocess import subprocess
import sysconfig
import reindent import reindent
import untabify import untabify
SRCDIR = sysconfig.get_config_var('srcdir')
def n_files_str(count): def n_files_str(count):
"""Return 'N file(s)' with the proper plurality on 'file'.""" """Return 'N file(s)' with the proper plurality on 'file'."""
return "{} file{}".format(count, "s" if count != 1 else "") return "{} file{}".format(count, "s" if count != 1 else "")
@ -36,7 +40,7 @@ def status(message, modal=False, info=None):
info=lambda x: n_files_str(len(x))) info=lambda x: n_files_str(len(x)))
def changed_files(): def changed_files():
"""Get the list of changed or added files from the VCS.""" """Get the list of changed or added files from the VCS."""
if os.path.isdir('.hg'): if os.path.isdir(os.path.join(SRCDIR, '.hg')):
vcs = 'hg' vcs = 'hg'
cmd = 'hg status --added --modified --no-status' cmd = 'hg status --added --modified --no-status'
elif os.path.isdir('.svn'): elif os.path.isdir('.svn'):
@ -75,7 +79,7 @@ def normalize_whitespace(file_paths):
reindent.makebackup = False # No need to create backups. reindent.makebackup = False # No need to create backups.
fixed = [] fixed = []
for path in (x for x in file_paths if x.endswith('.py')): for path in (x for x in file_paths if x.endswith('.py')):
if reindent.check(path): if reindent.check(os.path.join(SRCDIR, path)):
fixed.append(path) fixed.append(path)
return fixed return fixed
@ -85,10 +89,11 @@ def normalize_c_whitespace(file_paths):
"""Report if any C files """ """Report if any C files """
fixed = [] fixed = []
for path in file_paths: for path in file_paths:
with open(path, 'r') as f: abspath = os.path.join(SRCDIR, path)
with open(abspath, 'r') as f:
if '\t' not in f.read(): if '\t' not in f.read():
continue continue
untabify.process(path, 8, verbose=False) untabify.process(abspath, 8, verbose=False)
fixed.append(path) fixed.append(path)
return fixed return fixed
@ -99,13 +104,14 @@ ws_re = re.compile(br'\s+(\r?\n)$')
def normalize_docs_whitespace(file_paths): def normalize_docs_whitespace(file_paths):
fixed = [] fixed = []
for path in file_paths: for path in file_paths:
abspath = os.path.join(SRCDIR, path)
try: try:
with open(path, 'rb') as f: with open(abspath, 'rb') as f:
lines = f.readlines() lines = f.readlines()
new_lines = [ws_re.sub(br'\1', line) for line in lines] new_lines = [ws_re.sub(br'\1', line) for line in lines]
if new_lines != lines: if new_lines != lines:
shutil.copyfile(path, path + '.bak') shutil.copyfile(abspath, abspath + '.bak')
with open(path, 'wb') as f: with open(abspath, 'wb') as f:
f.writelines(new_lines) f.writelines(new_lines)
fixed.append(path) fixed.append(path)
except Exception as err: except Exception as err: