Skip to content

Commit 3cf202e

Browse files
committed
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.
1 parent 9653468 commit 3cf202e

6 files changed

Lines changed: 36 additions & 5 deletions

File tree

Doc/distutils/apiref.rst

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -973,8 +973,8 @@ directories.
973973
Copy an entire directory tree *src* to a new location *dst*. Both *src* and
974974
*dst* must be directory names. If *src* is not a directory, raise
975975
:exc:`DistutilsFileError`. If *dst* does not exist, it is created with
976-
:func:`mkpath`. The end result of the copy is that every file in *src* is
977-
copied to *dst*, and directories under *src* are recursively copied to *dst*.
976+
:func:`mkpath`. The end result of the copy is that every file in *src* is
977+
copied to *dst*, and directories under *src* are recursively copied to *dst*.
978978
Return the list of files that were copied or might have been copied, using their
979979
output name. The return value is unaffected by *update* or *dry_run*: it is
980980
simply the list of all files under *src*, with the names changed to be under
@@ -987,6 +987,10 @@ directories.
987987
destination of the symlink will be copied. *update* and *verbose* are the same
988988
as for :func:`copy_file`.
989989

990+
Files in *src* that begin with :file:`.nfs` are skipped (more information on
991+
these files is available in answer D2 of the `NFS FAQ page
992+
<http://nfs.sourceforge.net/#section_d>`_.
993+
990994

991995
.. function:: remove_tree(directory[, verbose=0, dry_run=0])
992996

Lib/distutils/dir_util.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,10 @@ def copy_tree(src, dst, preserve_mode=1, preserve_times=1,
144144
src_name = os.path.join(src, n)
145145
dst_name = os.path.join(dst, n)
146146

147+
if n.startswith('.nfs'):
148+
# skip NFS rename files
149+
continue
150+
147151
if preserve_symlinks and os.path.islink(src_name):
148152
link_dest = os.readlink(src_name)
149153
if verbose >= 1:

Lib/distutils/tests/test_dir_util.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,24 @@ def test_copy_tree_verbosity(self):
101101
remove_tree(self.root_target, verbose=0)
102102
remove_tree(self.target2, verbose=0)
103103

104+
def test_copy_tree_skips_nfs_temp_files(self):
105+
mkpath(self.target, verbose=0)
106+
107+
a_file = os.path.join(self.target, 'ok.txt')
108+
nfs_file = os.path.join(self.target, '.nfs123abc')
109+
for f in a_file, nfs_file:
110+
fh = open(f, 'w')
111+
try:
112+
fh.write('some content')
113+
finally:
114+
fh.close()
115+
116+
copy_tree(self.target, self.target2)
117+
self.assertEqual(os.listdir(self.target2), ['ok.txt'])
118+
119+
remove_tree(self.root_target, verbose=0)
120+
remove_tree(self.target2, verbose=0)
121+
104122
def test_ensure_relative(self):
105123
if os.sep == '/':
106124
self.assertEqual(ensure_relative('/home/foo'), 'home/foo')

Lib/distutils/tests/test_sdist.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,8 @@ def get_cmd(self, metadata=None):
9191

9292
@unittest.skipUnless(zlib, "requires zlib")
9393
def test_prune_file_list(self):
94-
# this test creates a package with some vcs dirs in it
95-
# and launch sdist to make sure they get pruned
96-
# on all systems
94+
# this test creates a project with some VCS dirs and an NFS rename
95+
# file, then launches sdist to check they get pruned on all systems
9796

9897
# creating VCS directories with some files in them
9998
os.mkdir(join(self.tmp_dir, 'somecode', '.svn'))
@@ -107,6 +106,8 @@ def test_prune_file_list(self):
107106
self.write_file((self.tmp_dir, 'somecode', '.git',
108107
'ok'), 'xxx')
109108

109+
self.write_file((self.tmp_dir, 'somecode', '.nfs0001'), 'xxx')
110+
110111
# now building a sdist
111112
dist, cmd = self.get_cmd()
112113

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,7 @@ Eduardo Pérez
688688
Brian Quinlan
689689
Anders Qvist
690690
Burton Radons
691+
Jeff Ramnani
691692
Brodie Rao
692693
Antti Rasinen
693694
Sridhar Ratnakumar

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ Core and Builtins
1414
longer raised due to a read system call returning EINTR from within these
1515
methods.
1616

17+
- Issue #7719: Make distutils ignore ``.nfs*`` files instead of choking later
18+
on. Initial patch by SilentGhost and Jeff Ramnani.
19+
1720
- Issue #10053: Don't close FDs when FileIO.__init__ fails. Loosely based on
1821
the work by Hirokazu Yamamoto.
1922

0 commit comments

Comments
 (0)