From 3e4a3dcb23d849fa0ce5f5009e83606abaef15aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Araujo?= Date: Sat, 8 Dec 2012 14:21:51 -0500 Subject: [PATCH 1/4] Ignore .nfs* files in distutils (#7719). These files are created by some NFS clients a file is edited and removed concurrently (see added link in doc for more info). If such a file is removed between distutils calls listdir and copy, it will get confused. Other special files are ignored in sdist (namely VCS directories), but this has to be filtered out earlier. --- Doc/distutils/apiref.rst | 6 ++++++ Lib/distutils/dir_util.py | 4 ++++ Lib/distutils/tests/test_dir_util.py | 21 ++++++++++++++++----- Lib/distutils/tests/test_sdist.py | 7 ++++--- Misc/NEWS | 3 +++ 5 files changed, 33 insertions(+), 8 deletions(-) diff --git a/Doc/distutils/apiref.rst b/Doc/distutils/apiref.rst index e15dc76c83c..74fba4ada7f 100644 --- a/Doc/distutils/apiref.rst +++ b/Doc/distutils/apiref.rst @@ -992,6 +992,12 @@ directories. destination of the symlink will be copied. *update* and *verbose* are the same as for :func:`copy_file`. + Files in *src* that begin with :file:`.nfs` are skipped (more information on + these files is available in answer D2 of the `NFS FAQ page + `_. + + .. versionchanged:: 3.2.4 + NFS files are ignored. .. function:: remove_tree(directory[, verbose=0, dry_run=0]) diff --git a/Lib/distutils/dir_util.py b/Lib/distutils/dir_util.py index 30daf49a6ea..2826ff805d7 100644 --- a/Lib/distutils/dir_util.py +++ b/Lib/distutils/dir_util.py @@ -141,6 +141,10 @@ def copy_tree(src, dst, preserve_mode=1, preserve_times=1, src_name = os.path.join(src, n) dst_name = os.path.join(dst, n) + if n.startswith('.nfs'): + # skip NFS rename files + continue + if preserve_symlinks and os.path.islink(src_name): link_dest = os.readlink(src_name) if verbose >= 1: diff --git a/Lib/distutils/tests/test_dir_util.py b/Lib/distutils/tests/test_dir_util.py index ce74589dde5..1589f1297db 100644 --- a/Lib/distutils/tests/test_dir_util.py +++ b/Lib/distutils/tests/test_dir_util.py @@ -76,7 +76,6 @@ class DirUtilTestCase(support.TempdirManager, unittest.TestCase): remove_tree(self.root_target, verbose=0) - def test_copy_tree_verbosity(self): mkpath(self.target, verbose=0) @@ -88,11 +87,8 @@ class DirUtilTestCase(support.TempdirManager, unittest.TestCase): mkpath(self.target, verbose=0) a_file = os.path.join(self.target, 'ok.txt') - f = open(a_file, 'w') - try: + with open(a_file, 'w') as f: f.write('some content') - finally: - f.close() wanted = ['copying %s -> %s' % (a_file, self.target2)] copy_tree(self.target, self.target2, verbose=1) @@ -101,6 +97,21 @@ class DirUtilTestCase(support.TempdirManager, unittest.TestCase): remove_tree(self.root_target, verbose=0) remove_tree(self.target2, verbose=0) + def test_copy_tree_skips_nfs_temp_files(self): + mkpath(self.target, verbose=0) + + a_file = os.path.join(self.target, 'ok.txt') + nfs_file = os.path.join(self.target, '.nfs123abc') + for f in a_file, nfs_file: + with open(f, 'w') as fh: + fh.write('some content') + + copy_tree(self.target, self.target2) + self.assertEqual(os.listdir(self.target2), ['ok.txt']) + + remove_tree(self.root_target, verbose=0) + remove_tree(self.target2, verbose=0) + def test_ensure_relative(self): if os.sep == '/': self.assertEqual(ensure_relative('/home/foo'), 'home/foo') diff --git a/Lib/distutils/tests/test_sdist.py b/Lib/distutils/tests/test_sdist.py index 1ba2a1a6a9a..e6359d6a8af 100644 --- a/Lib/distutils/tests/test_sdist.py +++ b/Lib/distutils/tests/test_sdist.py @@ -83,9 +83,8 @@ class SDistTestCase(PyPIRCCommandTestCase): @unittest.skipUnless(ZLIB_SUPPORT, 'Need zlib support to run') def test_prune_file_list(self): - # this test creates a package with some vcs dirs in it - # and launch sdist to make sure they get pruned - # on all systems + # this test creates a project with some VCS dirs and an NFS rename + # file, then launches sdist to check they get pruned on all systems # creating VCS directories with some files in them os.mkdir(join(self.tmp_dir, 'somecode', '.svn')) @@ -99,6 +98,8 @@ class SDistTestCase(PyPIRCCommandTestCase): self.write_file((self.tmp_dir, 'somecode', '.git', 'ok'), 'xxx') + self.write_file((self.tmp_dir, 'somecode', '.nfs0001'), 'xxx') + # now building a sdist dist, cmd = self.get_cmd() diff --git a/Misc/NEWS b/Misc/NEWS index 3c9f382fe3f..02e4d4882d5 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -177,6 +177,9 @@ Library - Issue #16628: Fix a memory leak in ctypes.resize(). +- Issue #7719: Make distutils ignore ``.nfs*`` files instead of choking later + on. Initial patch by SilentGhost and Jeff Ramnani. + - Issue #13120: Allow to call pdb.set_trace() from thread. Patch by Ilya Sandler. From d61926e6bef6c4d8105a2848362377dce91d7fc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Araujo?= Date: Sat, 8 Dec 2012 14:51:47 -0500 Subject: [PATCH 2/4] Create ~/.pypirc securely (#13512). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There was a window between the write and the chmod where the user’s password would be exposed, depending on default permissions. Philip Jenvey’s patch fixes it. --- Lib/distutils/config.py | 11 +---------- Misc/ACKS | 1 + Misc/NEWS | 3 +++ 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/Lib/distutils/config.py b/Lib/distutils/config.py index 5b625f3f7d2..1fd53346e96 100644 --- a/Lib/distutils/config.py +++ b/Lib/distutils/config.py @@ -4,7 +4,6 @@ Provides the PyPIRCCommand class, the base class for the command classes that uses .pypirc in the distutils.command package. """ import os -import sys from configparser import ConfigParser from distutils.cmd import Command @@ -43,16 +42,8 @@ class PyPIRCCommand(Command): def _store_pypirc(self, username, password): """Creates a default .pypirc file.""" rc = self._get_rc_file() - f = open(rc, 'w') - try: + with os.fdopen(os.open(rc, os.O_CREAT | os.O_WRONLY, 0o600), 'w') as f: f.write(DEFAULT_PYPIRC % (username, password)) - finally: - f.close() - try: - os.chmod(rc, 0o600) - except OSError: - # should do something better here - pass def _read_pypirc(self): """Reads the .pypirc file.""" diff --git a/Misc/ACKS b/Misc/ACKS index 9e662f6a731..05670693d8c 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -512,6 +512,7 @@ Zbyszek Jędrzejewski-Szmek Drew Jenkins Flemming Kjær Jensen Philip H. Jensen +Philip Jenvey MunSic Jeong Chris Jerdonek Pedro Diaz Jimenez diff --git a/Misc/NEWS b/Misc/NEWS index 02e4d4882d5..3adc531ab65 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -177,6 +177,9 @@ Library - Issue #16628: Fix a memory leak in ctypes.resize(). +- Issue #13512: Create ~/.pypirc securely (CVE-2011-4944). Initial patch by + Philip Jenvey, tested by Mageia and Debian. + - Issue #7719: Make distutils ignore ``.nfs*`` files instead of choking later on. Initial patch by SilentGhost and Jeff Ramnani. From 9bc9ab5f853b0ac39b399dc22517a7aa96ffc8d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Araujo?= Date: Sat, 8 Dec 2012 18:35:31 -0500 Subject: [PATCH 3/4] Fix a few markup/grammar nits --- Doc/library/abc.rst | 6 +++--- Doc/library/io.rst | 2 +- Doc/library/sys.rst | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/library/abc.rst b/Doc/library/abc.rst index 1048b24c088..dcec19a3a76 100644 --- a/Doc/library/abc.rst +++ b/Doc/library/abc.rst @@ -126,7 +126,7 @@ This module provides the following class: It also provides the following decorators: -.. decorator:: abstractmethod(function) +.. decorator:: abstractmethod A decorator indicating abstract methods. @@ -161,7 +161,7 @@ It also provides the following decorators: multiple-inheritance. -.. decorator:: abstractclassmethod(function) +.. decorator:: abstractclassmethod A subclass of the built-in :func:`classmethod`, indicating an abstract classmethod. Otherwise it is similar to :func:`abstractmethod`. @@ -176,7 +176,7 @@ It also provides the following decorators: .. versionadded:: 3.2 -.. decorator:: abstractstaticmethod(function) +.. decorator:: abstractstaticmethod A subclass of the built-in :func:`staticmethod`, indicating an abstract staticmethod. Otherwise it is similar to :func:`abstractmethod`. diff --git a/Doc/library/io.rst b/Doc/library/io.rst index 7cab6850e61..1939352bc12 100644 --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -236,7 +236,7 @@ I/O Base Classes Note that calling any method (even inquiries) on a closed stream is undefined. Implementations may raise :exc:`IOError` in this case. - IOBase (and its subclasses) support the iterator protocol, meaning that an + IOBase (and its subclasses) supports the iterator protocol, meaning that an :class:`IOBase` object can be iterated over yielding the lines in a stream. Lines are defined slightly differently depending on whether the stream is a binary stream (yielding bytes), or a text stream (yielding character diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 0e4adeca76b..a3c14e63179 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -739,7 +739,7 @@ always available. For other systems, the values are: ====================== =========================== - System :data:`platform` value + System ``platform`` value ====================== =========================== Linux (2.x *and* 3.x) ``'linux2'`` Windows ``'win32'`` From 8b503c0a4e82ba5aadd60215bf493529ce6e1821 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Araujo?= Date: Sat, 8 Dec 2012 22:41:11 -0500 Subject: [PATCH 4/4] Fix setup.py register failure with invalid rst in description (#13614). Original patch by Julien Courteau and Pierre Paul Lefebvre. --- Lib/distutils/command/check.py | 3 +++ Lib/distutils/tests/test_register.py | 34 +++++++++++++++++++--------- Misc/ACKS | 2 ++ Misc/NEWS | 3 +++ 4 files changed, 31 insertions(+), 11 deletions(-) diff --git a/Lib/distutils/command/check.py b/Lib/distutils/command/check.py index b67c7953087..22b9349dd60 100644 --- a/Lib/distutils/command/check.py +++ b/Lib/distutils/command/check.py @@ -23,6 +23,9 @@ try: def system_message(self, level, message, *children, **kwargs): self.messages.append((level, message, children, kwargs)) + return nodes.system_message(message, level=level, + type=self.levels[level], + *children, **kwargs) HAS_DOCUTILS = True except Exception: diff --git a/Lib/distutils/tests/test_register.py b/Lib/distutils/tests/test_register.py index 5863ae1422b..a86b8606e4e 100644 --- a/Lib/distutils/tests/test_register.py +++ b/Lib/distutils/tests/test_register.py @@ -1,5 +1,4 @@ """Tests for distutils.command.register.""" -import sys import os import unittest import getpass @@ -10,11 +9,14 @@ from test.support import check_warnings, run_unittest from distutils.command import register as register_module from distutils.command.register import register -from distutils.core import Distribution from distutils.errors import DistutilsSetupError -from distutils.tests import support -from distutils.tests.test_config import PYPIRC, PyPIRCCommandTestCase +from distutils.tests.test_config import PyPIRCCommandTestCase + +try: + import docutils +except ImportError: + docutils = None PYPIRC_NOPASSWORD = """\ [distutils] @@ -193,6 +195,7 @@ class RegisterTestCase(PyPIRCCommandTestCase): self.assertEqual(headers['Content-length'], '290') self.assertTrue((b'tarek') in req.data) + @unittest.skipUnless(docutils is not None, 'needs docutils') def test_strict(self): # testing the script option # when on, the register command stops if @@ -205,13 +208,6 @@ class RegisterTestCase(PyPIRCCommandTestCase): cmd.strict = 1 self.assertRaises(DistutilsSetupError, cmd.run) - # we don't test the reSt feature if docutils - # is not installed - try: - import docutils - except ImportError: - return - # metadata are OK but long_description is broken metadata = {'url': 'xxx', 'author': 'xxx', 'author_email': 'éxéxé', @@ -265,6 +261,22 @@ class RegisterTestCase(PyPIRCCommandTestCase): finally: del register_module.input + @unittest.skipUnless(docutils is not None, 'needs docutils') + def test_register_invalid_long_description(self): + description = ':funkie:`str`' # mimic Sphinx-specific markup + metadata = {'url': 'xxx', 'author': 'xxx', + 'author_email': 'xxx', + 'name': 'xxx', 'version': 'xxx', + 'long_description': description} + cmd = self._get_cmd(metadata) + cmd.ensure_finalized() + cmd.strict = True + inputs = Inputs('2', 'tarek', 'tarek@ziade.org') + register_module.input = inputs + self.addCleanup(delattr, register_module, 'input') + + self.assertRaises(DistutilsSetupError, cmd.run) + def test_check_metadata_deprecated(self): # makes sure make_metadata is deprecated cmd = self._get_cmd() diff --git a/Misc/ACKS b/Misc/ACKS index 05670693d8c..831885b6ba5 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -222,6 +222,7 @@ David Costanzo Scott Cotton Greg Couch David Cournapeau +Julien Courteau Steve Cousins Alex Coventry Matthew Dixon Cowles @@ -621,6 +622,7 @@ Thomas Lee Christopher Lee Tennessee Leeuwenburg Luc Lefebvre +Pierre Paul Lefebvre Glyph Lefkowitz Vincent Legoll Kip Lehman diff --git a/Misc/NEWS b/Misc/NEWS index 3adc531ab65..061952d2852 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -177,6 +177,9 @@ Library - Issue #16628: Fix a memory leak in ctypes.resize(). +- Issue #13614: Fix setup.py register failure with invalid rst in description. + Patch by Julien Courteau and Pierre Paul Lefebvre. + - Issue #13512: Create ~/.pypirc securely (CVE-2011-4944). Initial patch by Philip Jenvey, tested by Mageia and Debian.