From 3cf202e9578cef4429254641599e8f6be6540309 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Araujo?= Date: Tue, 3 Jul 2012 01:12:42 -0400 Subject: [PATCH] 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 | 8 ++++++-- Lib/distutils/dir_util.py | 4 ++++ Lib/distutils/tests/test_dir_util.py | 18 ++++++++++++++++++ Lib/distutils/tests/test_sdist.py | 7 ++++--- Misc/ACKS | 1 + Misc/NEWS | 3 +++ 6 files changed, 36 insertions(+), 5 deletions(-) diff --git a/Doc/distutils/apiref.rst b/Doc/distutils/apiref.rst index ba4fc9f5a50..60c0dd8fe75 100644 --- a/Doc/distutils/apiref.rst +++ b/Doc/distutils/apiref.rst @@ -973,8 +973,8 @@ directories. Copy an entire directory tree *src* to a new location *dst*. Both *src* and *dst* must be directory names. If *src* is not a directory, raise :exc:`DistutilsFileError`. If *dst* does not exist, it is created with - :func:`mkpath`. The end result of the copy is that every file in *src* is - copied to *dst*, and directories under *src* are recursively copied to *dst*. + :func:`mkpath`. The end result of the copy is that every file in *src* is + copied to *dst*, and directories under *src* are recursively copied to *dst*. Return the list of files that were copied or might have been copied, using their output name. The return value is unaffected by *update* or *dry_run*: it is simply the list of all files under *src*, with the names changed to be under @@ -987,6 +987,10 @@ 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 + `_. + .. function:: remove_tree(directory[, verbose=0, dry_run=0]) diff --git a/Lib/distutils/dir_util.py b/Lib/distutils/dir_util.py index 9c5cf337c6c..5026e246685 100644 --- a/Lib/distutils/dir_util.py +++ b/Lib/distutils/dir_util.py @@ -144,6 +144,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 693f77cf646..d82d9133d04 100644 --- a/Lib/distutils/tests/test_dir_util.py +++ b/Lib/distutils/tests/test_dir_util.py @@ -101,6 +101,24 @@ 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: + fh = open(f, 'w') + try: + fh.write('some content') + finally: + fh.close() + + 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 3a89f73fa2b..7e7d98d096c 100644 --- a/Lib/distutils/tests/test_sdist.py +++ b/Lib/distutils/tests/test_sdist.py @@ -91,9 +91,8 @@ class SDistTestCase(PyPIRCCommandTestCase): @unittest.skipUnless(zlib, "requires zlib") 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')) @@ -107,6 +106,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/ACKS b/Misc/ACKS index e1adbe7006f..fed05535d90 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -688,6 +688,7 @@ Eduardo PĂ©rez Brian Quinlan Anders Qvist Burton Radons +Jeff Ramnani Brodie Rao Antti Rasinen Sridhar Ratnakumar diff --git a/Misc/NEWS b/Misc/NEWS index 94da2775349..063a6dbf3ef 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -14,6 +14,9 @@ Core and Builtins longer raised due to a read system call returning EINTR from within these methods. +- Issue #7719: Make distutils ignore ``.nfs*`` files instead of choking later + on. Initial patch by SilentGhost and Jeff Ramnani. + - Issue #10053: Don't close FDs when FileIO.__init__ fails. Loosely based on the work by Hirokazu Yamamoto.