1""" 2Filename globbing utility. Mostly a copy of `glob` from Python 3.5. 3 4Changes include: 5 * `yield from` and PEP3102 `*` removed. 6 * `bytes` changed to `six.binary_type`. 7 * Hidden files are not ignored. 8""" 9 10import os 11import re 12import fnmatch 13from setuptools.extern.six import binary_type 14 15__all__ = ["glob", "iglob", "escape"] 16 17 18def glob(pathname, recursive=False): 19 """Return a list of paths matching a pathname pattern. 20 21 The pattern may contain simple shell-style wildcards a la 22 fnmatch. However, unlike fnmatch, filenames starting with a 23 dot are special cases that are not matched by '*' and '?' 24 patterns. 25 26 If recursive is true, the pattern '**' will match any files and 27 zero or more directories and subdirectories. 28 """ 29 return list(iglob(pathname, recursive=recursive)) 30 31 32def iglob(pathname, recursive=False): 33 """Return an iterator which yields the paths matching a pathname pattern. 34 35 The pattern may contain simple shell-style wildcards a la 36 fnmatch. However, unlike fnmatch, filenames starting with a 37 dot are special cases that are not matched by '*' and '?' 38 patterns. 39 40 If recursive is true, the pattern '**' will match any files and 41 zero or more directories and subdirectories. 42 """ 43 it = _iglob(pathname, recursive) 44 if recursive and _isrecursive(pathname): 45 s = next(it) # skip empty string 46 assert not s 47 return it 48 49 50def _iglob(pathname, recursive): 51 dirname, basename = os.path.split(pathname) 52 if not has_magic(pathname): 53 if basename: 54 if os.path.lexists(pathname): 55 yield pathname 56 else: 57 # Patterns ending with a slash should match only directories 58 if os.path.isdir(dirname): 59 yield pathname 60 return 61 if not dirname: 62 if recursive and _isrecursive(basename): 63 for x in glob2(dirname, basename): 64 yield x 65 else: 66 for x in glob1(dirname, basename): 67 yield x 68 return 69 # `os.path.split()` returns the argument itself as a dirname if it is a 70 # drive or UNC path. Prevent an infinite recursion if a drive or UNC path 71 # contains magic characters (i.e. r'\\?\C:'). 72 if dirname != pathname and has_magic(dirname): 73 dirs = _iglob(dirname, recursive) 74 else: 75 dirs = [dirname] 76 if has_magic(basename): 77 if recursive and _isrecursive(basename): 78 glob_in_dir = glob2 79 else: 80 glob_in_dir = glob1 81 else: 82 glob_in_dir = glob0 83 for dirname in dirs: 84 for name in glob_in_dir(dirname, basename): 85 yield os.path.join(dirname, name) 86 87 88# These 2 helper functions non-recursively glob inside a literal directory. 89# They return a list of basenames. `glob1` accepts a pattern while `glob0` 90# takes a literal basename (so it only has to check for its existence). 91 92 93def glob1(dirname, pattern): 94 if not dirname: 95 if isinstance(pattern, binary_type): 96 dirname = os.curdir.encode('ASCII') 97 else: 98 dirname = os.curdir 99 try: 100 names = os.listdir(dirname) 101 except OSError: 102 return [] 103 return fnmatch.filter(names, pattern) 104 105 106def glob0(dirname, basename): 107 if not basename: 108 # `os.path.split()` returns an empty basename for paths ending with a 109 # directory separator. 'q*x/' should match only directories. 110 if os.path.isdir(dirname): 111 return [basename] 112 else: 113 if os.path.lexists(os.path.join(dirname, basename)): 114 return [basename] 115 return [] 116 117 118# This helper function recursively yields relative pathnames inside a literal 119# directory. 120 121 122def glob2(dirname, pattern): 123 assert _isrecursive(pattern) 124 yield pattern[:0] 125 for x in _rlistdir(dirname): 126 yield x 127 128 129# Recursively yields relative pathnames inside a literal directory. 130def _rlistdir(dirname): 131 if not dirname: 132 if isinstance(dirname, binary_type): 133 dirname = binary_type(os.curdir, 'ASCII') 134 else: 135 dirname = os.curdir 136 try: 137 names = os.listdir(dirname) 138 except os.error: 139 return 140 for x in names: 141 yield x 142 path = os.path.join(dirname, x) if dirname else x 143 for y in _rlistdir(path): 144 yield os.path.join(x, y) 145 146 147magic_check = re.compile('([*?[])') 148magic_check_bytes = re.compile(b'([*?[])') 149 150 151def has_magic(s): 152 if isinstance(s, binary_type): 153 match = magic_check_bytes.search(s) 154 else: 155 match = magic_check.search(s) 156 return match is not None 157 158 159def _isrecursive(pattern): 160 if isinstance(pattern, binary_type): 161 return pattern == b'**' 162 else: 163 return pattern == '**' 164 165 166def escape(pathname): 167 """Escape all special characters. 168 """ 169 # Escaping is done by wrapping any of "*?[" between square brackets. 170 # Metacharacters do not work in the drive part and shouldn't be escaped. 171 drive, pathname = os.path.splitdrive(pathname) 172 if isinstance(pathname, binary_type): 173 pathname = magic_check_bytes.sub(br'[\1]', pathname) 174 else: 175 pathname = magic_check.sub(r'[\1]', pathname) 176 return drive + pathname 177