@@ -5,8 +5,10 @@ def scm_find_files(path, scm_files, scm_dirs):
55 """ setuptools compatible file finder that follows symlinks
66
77 - path: the root directory from which to search
8- - scm_files: set of scm controlled files
9- - scm_files: set of scm controlled directories
8+ - scm_files: set of scm controlled files and symlinks
9+ (including symlinks to directories)
10+ - scm_dirs: set of scm controlled directories
11+ (including directories containing no scm controlled files)
1012
1113 scm_files and scm_dirs must be absolute with symlinks resolved (realpath),
1214 with normalized case (normcase)
@@ -20,10 +22,31 @@ def scm_find_files(path, scm_files, scm_dirs):
2022 for dirpath , dirnames , filenames in os .walk (realpath , followlinks = True ):
2123 # dirpath with symlinks resolved
2224 realdirpath = os .path .normcase (os .path .realpath (dirpath ))
23- if realdirpath not in scm_dirs or realdirpath in seen :
25+
26+ def _link_not_in_scm (n ):
27+ fn = os .path .join (realdirpath , os .path .normcase (n ))
28+ return os .path .islink (fn ) and fn not in scm_files
29+
30+ if realdirpath not in scm_dirs :
31+ # directory not in scm, don't walk it's content
32+ dirnames [:] = []
33+ continue
34+ if os .path .islink (dirpath ) and \
35+ not os .path .relpath (realdirpath , realpath ).startswith (os .pardir ):
36+ # a symlink to a directory not outside path:
37+ # we keep it in the result and don't walk its content
38+ res .append (
39+ os .path .join (path , os .path .relpath (dirpath , path )))
40+ dirnames [:] = []
41+ continue
42+ if realdirpath in seen :
43+ # symlink loop protection
2444 dirnames [:] = []
2545 continue
46+ dirnames [:] = [dn for dn in dirnames if not _link_not_in_scm (dn )]
2647 for filename in filenames :
48+ if _link_not_in_scm (filename ):
49+ continue
2750 # dirpath + filename with symlinks preserved
2851 fullfilename = os .path .join (dirpath , filename )
2952 if os .path .normcase (os .path .realpath (fullfilename )) in scm_files :
0 commit comments